v09i085: xrolo -- an XView rolodex, Part02/03
Luis Soltero
luis at rice.edu
Thu Oct 11 07:38:58 AEST 1990
Submitted-by: Luis Soltero <luis at rice.edu>
Posting-number: Volume 9, Issue 85
Archive-name: xrolo/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 3)."
# Contents: Makefile cards.c
# Wrapped by luis at oort on Wed Oct 10 15:56:18 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(9108 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile generated by imake - do not edit!
X# $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $
X#
X# The cpp used on this machine replaces all newlines and multiple tabs and
X# spaces in a macro expansion with a single space. Imake tries to compensate
X# for this, but is not always successful.
X#
X
X###########################################################################
X# Makefile generated from "Imake.tmpl" and </tmp/IIf.a13794>
X# $XConsortium: Imake.tmpl,v 1.77 89/12/18 17:01:37 jim Exp $
X#
X# Platform-specific parameters may be set in the appropriate .cf
X# configuration files. Site-wide parameters may be set in the file
X# site.def. Full rebuilds are recommended if any parameters are changed.
X#
X# If your C preprocessor doesn't define any unique symbols, you'll need
X# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
X# "make Makefile", "make Makefiles", or "make World").
X#
X# If you absolutely can't get imake to work, you'll need to set the
X# variables at the top of each Makefile as well as the dependencies at the
X# bottom (makedepend will do this automatically).
X#
X
X###########################################################################
X# platform-specific configuration parameters - edit sun.cf to change
X
X# platform: $XConsortium: sun.cf,v 1.38 89/12/23 16:10:10 jim Exp $
X# operating system: SunOS 4.0.3
X
X###########################################################################
X# site-specific configuration parameters - edit site.def to change
X
X# site: $XConsortium: site.def,v 1.21 89/12/06 11:46:50 jim Exp $
X
X SHELL = /bin/sh
X
X TOP = .
X CURRENT_DIR = .
X
X AR = ar cq
X BOOTSTRAPCFLAGS =
X CC = cc
X
X COMPRESS = compress
X CPP = /lib/cpp $(STD_CPP_DEFINES)
X PREPROCESSCMD = cc -E $(STD_CPP_DEFINES)
X INSTALL = install
X LD = ld
X LINT = lint
X LINTLIBFLAG = -C
X LINTOPTS = -axz
X LN = ln -s
X MAKE = make
X MV = mv
X CP = cp
X RANLIB = ranlib
X RANLIBINSTFLAGS =
X RM = rm -f
X STD_INCLUDES =
X STD_CPP_DEFINES =
X STD_DEFINES =
X EXTRA_LOAD_FLAGS =
X EXTRA_LIBRARIES =
X TAGS = ctags
X
X SHAREDCODEDEF = -DSHAREDCODE
X SHLIBDEF = -DSUNSHLIB
X
X PROTO_DEFINES =
X
X INSTPGMFLAGS =
X
X INSTBINFLAGS = -m 0755
X INSTUIDFLAGS = -m 4755
X INSTLIBFLAGS = -m 0664
X INSTINCFLAGS = -m 0444
X INSTMANFLAGS = -m 0444
X INSTDATFLAGS = -m 0444
X INSTKMEMFLAGS = -m 4755
X
X DESTDIR =
X
X TOP_INCLUDES = -I$(INCROOT)
X
X CDEBUGFLAGS = -O
X CCOPTIONS = -pipe
X COMPATFLAGS =
X
X ALLINCLUDES = $(STD_INCLUDES) $(TOP_INCLUDES) $(INCLUDES) $(EXTRA_INCLUDES)
X ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(DEFINES) $(COMPATFLAGS)
X CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES)
X LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES)
X LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
X LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS)
X LDCOMBINEFLAGS = -X -r
X
X MACROFILE = sun.cf
X RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut
X
X IMAKE_DEFINES =
X
X IRULESRC = $(CONFIGDIR)
X IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES)
X
X ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules \
X $(IRULESRC)/Project.tmpl $(IRULESRC)/site.def \
X $(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES)
X
X###########################################################################
X# X Window System Build Parameters
X# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $
X
X###########################################################################
X# X Window System make variables; this need to be coordinated with rules
X# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $
X
X PATHSEP = /
X USRLIBDIR = $(DESTDIR)/usr/lib
X BINDIR = $(DESTDIR)/usr/bin/X11
X INCROOT = $(DESTDIR)/usr/include
X BUILDINCROOT = $(TOP)
X BUILDINCDIR = $(BUILDINCROOT)/X11
X BUILDINCTOP = ..
X INCDIR = $(INCROOT)/X11
X ADMDIR = $(DESTDIR)/usr/adm
X LIBDIR = $(USRLIBDIR)/X11
X CONFIGDIR = $(LIBDIR)/config
X LINTLIBDIR = $(USRLIBDIR)/lint
X
X FONTDIR = $(LIBDIR)/fonts
X XINITDIR = $(LIBDIR)/xinit
X XDMDIR = $(LIBDIR)/xdm
X AWMDIR = $(LIBDIR)/awm
X TWMDIR = $(LIBDIR)/twm
X GWMDIR = $(LIBDIR)/gwm
X MANPATH = $(DESTDIR)/usr/man
X MANSOURCEPATH = $(MANPATH)/man
X MANDIR = $(MANSOURCEPATH)n
X LIBMANDIR = $(MANSOURCEPATH)3
X XAPPLOADDIR = $(LIBDIR)/app-defaults
X
X SOXLIBREV = 4.2
X SOXTREV = 4.0
X SOXAWREV = 4.0
X SOOLDXREV = 4.0
X SOXMUREV = 4.0
X SOXEXTREV = 4.0
X
X FONTCFLAGS = -t
X
X INSTAPPFLAGS = $(INSTDATFLAGS)
X
X IMAKE = imake
X DEPEND = makedepend
X RGB = rgb
X FONTC = bdftosnf
X MKFONTDIR = mkfontdir
X MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier.sh
X
X CONFIGSRC = $(TOP)/config
X CLIENTSRC = $(TOP)/clients
X DEMOSRC = $(TOP)/demos
X LIBSRC = $(TOP)/lib
X FONTSRC = $(TOP)/fonts
X INCLUDESRC = $(TOP)/X11
X SERVERSRC = $(TOP)/server
X UTILSRC = $(TOP)/util
X SCRIPTSRC = $(UTILSRC)/scripts
X EXAMPLESRC = $(TOP)/examples
X CONTRIBSRC = $(TOP)/../contrib
X DOCSRC = $(TOP)/doc
X RGBSRC = $(TOP)/rgb
X DEPENDSRC = $(UTILSRC)/makedepend
X IMAKESRC = $(CONFIGSRC)
X XAUTHSRC = $(LIBSRC)/Xau
X XLIBSRC = $(LIBSRC)/X
X XMUSRC = $(LIBSRC)/Xmu
X TOOLKITSRC = $(LIBSRC)/Xt
X AWIDGETSRC = $(LIBSRC)/Xaw
X OLDXLIBSRC = $(LIBSRC)/oldX
X XDMCPLIBSRC = $(LIBSRC)/Xdmcp
X BDFTOSNFSRC = $(FONTSRC)/bdftosnf
X MKFONTDIRSRC = $(FONTSRC)/mkfontdir
X EXTENSIONSRC = $(TOP)/extensions
X
X DEPEXTENSIONLIB = $(USRLIBDIR)/libXext.a
X EXTENSIONLIB = -lXext
X
X DEPXLIB = $(DEPEXTENSIONLIB)
X XLIB = $(EXTENSIONLIB) -lX11
X
X DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
X XAUTHLIB = -lXau
X
X DEPXMULIB =
X XMULIB = -lXmu
X
X DEPOLDXLIB =
X OLDXLIB = -loldX
X
X DEPXTOOLLIB =
X XTOOLLIB = -lXt
X
X DEPXAWLIB =
X XAWLIB = -lXaw
X
X LINTEXTENSIONLIB = $(USRLIBDIR)/llib-lXext.ln
X LINTXLIB = $(USRLIBDIR)/llib-lX11.ln
X LINTXMU = $(USRLIBDIR)/llib-lXmu.ln
X LINTXTOOL = $(USRLIBDIR)/llib-lXt.ln
X LINTXAW = $(USRLIBDIR)/llib-lXaw.ln
X
X XWLIBSRC = $(CONTRIBSRC)/toolkits/Xw
X DEPXWLIB = $(USRLIBDIR)/libXw.a
X XWLIB = -lXw
X
X DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
X
X DEPLIBS1 = $(DEPLIBS)
X DEPLIBS2 = $(DEPLIBS)
X DEPLIBS3 = $(DEPLIBS)
X
X###########################################################################
X# Imake rules for building libraries, programs, scripts, and data files
X# rules: $XConsortium: Imake.rules,v 1.67 89/12/18 17:14:15 jim Exp $
X
X###########################################################################
X# start of Imakefile
X
X#
X# xrolo - an XView tool to implement a rolodex-style list of notes.
X#
X# --Luis Soltero (luis at rice.edu), 10/10/90
X#
X
X#
X# linking against openlook libraries on suns after patching ol_button.c.
X# see README for details.
XLOCAL_LIBRARIES = -L$$OPENWINHOME/lib -lxview -Bstatic -lolgx -Bdynamic
X
X#
X# linking against XView libraries compiled from mit distribution after
X# patching ol_button.c. see README for details.
X# LOCAL_LIBRARIES = -lxview -lolgx
X
X SRCS = main.c panel.c cards.c popup.c
X OBJS = main.o panel.o cards.o popup.o
X INCLUDES = -I$$OPENWINHOME/include
X DEFINES = -DSTANDALONE
X
Xall:: xrolo
X
Xxrolo: $(OBJS) $(DEPLIBS)
X $(RM) $@
X $(CC) -o $@ $(OBJS) $(LDOPTIONS) $(LOCAL_LIBRARIES) $(LDLIBS) $(XLIB) $(EXTRA_LOAD_FLAGS)
X
Xclean::
X $(RM) xrolo
X
Xinstall:: xrolo
X $(INSTALL) -c $(INSTPGMFLAGS) xrolo $(BINDIR)
X
Xinstall.man:: xrolo.man
X $(INSTALL) -c $(INSTMANFLAGS) xrolo.man $(MANDIR)/xrolo.n
X
Xdepend::
X $(DEPEND) -s "# DO NOT DELETE" -- $(ALLDEFINES) -- $(SRCS)
X
X###########################################################################
X# common rules for all Makefiles - do not edit
X
Xemptyrule::
X
Xclean::
X $(RM_CMD) \#*
X
XMakefile::
X - at if [ -f Makefile ]; then \
X echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
X $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
X else exit 0; fi
X $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
X
Xtags::
X $(TAGS) -w *.[ch]
X $(TAGS) -xw *.[ch] > TAGS
X
X###########################################################################
X# empty rules for directories that do not have SUBDIRS - do not edit
X
Xinstall::
X @echo "install in $(CURRENT_DIR) done"
X
Xinstall.man::
X @echo "install.man in $(CURRENT_DIR) done"
X
XMakefiles::
X
Xincludes::
X
X###########################################################################
X# dependencies generated by makedepend
X
END_OF_FILE
if test 9108 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'cards.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cards.c'\"
else
echo shar: Extracting \"'cards.c'\" \(20514 characters\)
sed "s/^X//" >'cards.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char sccsid[] = "@(#)cards.c 2.2 8/14/88";
X#endif
X
X/*
X * Routines for manipulating cards
X */
X
X
X/*
X * -------------------------------------------------------------------------
X * ROLO - A Sun Tool to implement a Rolodex-style list of notes
X *
X * This code manipulates "cards" in a visual manner approximating
X * a rolodex file. All the cards are stored in one real file, the
X * cards are seperated by a ^L (form-feed). The default path
X * name is $HOME/.rolo. A different pathname may be specified at
X * startup on the command line. The pathname is relative to the
X * user's home directory.
X *
X * Due to bugs in the 3.0 distribution, especially with text subwindows,
X * this code is only guaranteed to compile and run properly with 3.2
X * or greater.
X *
X * This code is public domain, anyone and everyone is welcome to it.
X * All I ask is that my name and this notice remain on it. If Sun would
X * like to bundle it with their product they are welcome to do so,
X * I only ask that the sources be included in the binary distribution.
X *
X * Please return any fixes, improvements, gripes, etc to me.
X *
X * Ron Hitchens ronbo at vixen.uucp
X * March 1987 (V1.0) hitchens at cs.utexas.edu
X * August 1988 (V2.0)
X * -------------------------------------------------------------------------
X */
X
X
X
X#include <stdio.h>
X#include <xview/xview.h>
X#include <sys/file.h>
X#include <ctype.h>
X
X#include "defs.h"
X
X
X/* --------------------------- Exports ------------------------------------- */
X
Xint need_save = FALSE;
X
Xstruct card *first = NULL_CARD, *last, *current;
X
Xstruct card *make_card (), *insert_card (), *undelete_card (),
X *pop_card ();
X
Xvoid dispose_card (), push_card (), nuke_active_cards ();
X
Xchar *first_char (), *check_args ();
X
Xcaddr_t undel_menu_card ();
X
X/* --------------------------- Imports ------------------------------------- */
X
Xextern char *rolofile;
X
Xextern void show_card (), set_slider_max ();
X
Xextern char *malloc(), *realloc (), *calloc (), *getenv(),
X *strcpy(), *strcat(), *strncpy (), *index (),
X *sys_errlist [];
X
Xextern int errno;
X
X
X/* --------------------------- Locals -------------------------------------- */
X
Xstatic struct card *dead;
X
Xstatic int eof = FALSE;
X
Xstatic char *dummy_card = DUMMY_CARD_CONTENTS;
X
Xstatic char *trim (), *catbuf (), *get_card ();
X
Xstatic void load_rolo (), write_err ();
X
X
X/* ------------------------------------------------------------------------- */
X
X
X/*
X * Initialize the card list. First, we cd to the home directory,
X * then we try to open the named file. If we don't find one then
X * we create a new empty one and re-open it. Once we have the file
X * open, we try to load cards in. If no cards are loaded by load_rolo(),
X * then we create a dummy card out of thin air.
X */
X
Xvoid
Xinit_rolo (filename)
X char *filename;
X{
X char *c;
X int fd;
X FILE *f;
X
X (void) chdir (getenv ("HOME"));
X if ((f = fopen (filename, "r")) == NULL) {
X if ((fd = open (filename, O_CREAT, NEWMODE)) < 0) {
X msg ("init_rolo: can't create %s: %s", filename,
X sys_errlist [errno]);
X goto skipload;
X }
X (void) close (fd);
X if ((f = fopen (filename, "r")) == NULL) {
X msg ("init_rolo: can't reopen new %s\n",
X filename);
X goto skipload;
X }
X }
X load_rolo (f);
X (void) fclose (f);
X
Xskipload:
X if (first == NULL_CARD) {
X c = malloc (strlen (dummy_card) + 1);
X (void) strcpy (c, dummy_card);
X (void) insert_card (make_card (c), NULL_CARD);
X set_slider_max (renumber (first));
X }
X
X show_card (first);
X}
X
X
X/*
X * Concatenate the second string onto the first. If the first string
X * pointer is null, copy and return the second.
X */
X
Xstatic
Xchar *
Xcatbuf (c, p)
X char *c, *p;
X{
X if (c == NULL) {
X c = malloc (strlen (p) + 1);
X return (strcpy (c, p));
X } else {
X c = realloc (c, strlen (c) + strlen (p) + 1);
X return (strcat (c, p));
X }
X}
X
X
X/*
X * Return the pointer to the first non-blank char in the given string.
X * If the string is all white space, a pointer to the trailing null
X * will be returned.
X */
X
Xchar *
Xfirst_char (c)
X char *c;
X{
X while ((*c != '\0') && (isspace(*c)))
X c++;
X return (c);
X}
X
X
X/*
X * Trim trailing blanks from a string. The trimmed blanks, if any, are
X * not freed. Return the address of the string passed. If a null
X * pointer is passed, this is a no-op.
X */
X
Xstatic
Xchar *
Xtrim (c)
X char *c;
X{
X int i, l;
X
X if (c == NULL) {
X return (c);
X }
X l = strlen (c) - 1;
X
X for (i = l; i >= 0; i--) {
X if ( ! isspace(c [i]))
X break;
X }
X
X c [++i] = '\0';
X return (c);
X}
X
X
X/*
X * Get one card from the provided file. Data is read, a line at a time,
X * until a form-feed char is encountered. The FF is expected to be
X * on a line by itself, the cards are written out that way. Blanks cards
X * will be discarded.
X * The #ifdef'ed code will trim off leading blank lines, it is disabled
X * since users may wish to include leading white space in a card. The
X * routines which look at card values (such as for sorting) will skip
X * leading white space anyway.
X */
X
Xstatic
Xchar *
Xget_card (f)
X FILE *f;
X{
X char *c;
X char buf [1024];
X
X if (eof) {
X return (NULL);
X }
X c = NULL;
X while (fgets (buf, sizeof buf, f) != NULL) {
X if (buf [0] == '\f') { /* card separator */
X if (c == NULL || strlen (c) == 0) {
X if (c != NULL) {
X free (c);
X }
X c = NULL;
X continue;
X }
X return (trim(c));
X }
X#ifdef notdef
X if (c == NULL) { /* drop leading blank lines */
X int i, j, allblank;
X
X j = strlen (buf);
X allblank = TRUE;
X for (i = 0; i < j; i++) {
X if ( ! isspace(buf[i])) {
X allblank = FALSE;
X break;
X }
X }
X if (allblank) {
X continue;
X }
X }
X#endif
X c = catbuf (c, buf);
X }
X eof = TRUE;
X return (trim(c));
X}
X
X
X/*
X * Load all the cards from the provided file.
X */
X
Xstatic
Xvoid
Xload_rolo (f)
X FILE *f;
X{
X char *c;
X
X eof = FALSE;
X first = last = current = dead = NULL_CARD;
X while ((c = get_card (f)) != NULL) {
X (void) insert_card (make_card (c), last);
X }
X set_slider_max (renumber (first));
X need_save = FALSE;
X}
X
X
X/*
X * Renumber the cards in the list, begnning with the card pointed to
X * by p (this should normally be the first card in the list). This must
X * be done whenever the population of the list changes, such as adding
X * or deleting a card. The first card is number 1. The card number
X * is generally used for display to human types. The number of cards
X * in the list is returned.
X */
X
Xint
Xrenumber (p)
X struct card *p;
X{
X int i;
X
X for (i = 0; p != NULL_CARD; p = p->c_next)
X p->c_num = ++i;
X
X return (i);
X}
X
X
X/*
X * Make a new card, and place the text pointed to by c into it. If
X * the text pointer is null, allocate an empty string for the text,
X * the text pointer in the card's c_text slot must be free-able later
X * if the user modifies the text. If a text pointer is provided it
X * is assumed to have been malloc'ed and is not copied. The address of
X * the new card is returned, it is not inserted into the list.
X */
X
Xstruct card *
Xmake_card (c)
X char *c;
X{
X struct card *p;
X
X p = (struct card *) malloc (sizeof (struct card));
X if (p == NULL_CARD) {
X msg ("Can't allocate memory for new card");
X return (NULL);
X }
X
X p->c_next = p->c_prev = NULL_CARD;
X if (c == NULL) {
X p->c_text = malloc (1);
X *p->c_text = '\0';
X } else {
X p->c_text = c;
X }
X return (p);
X}
X
X
X/*
X * Insert the card p into the list of cards after the card pointed to
X * by after. If after is null, then insert before the first card. If
X * the list is initially empty, after is ignored and p is made the only
X * card in the list. The card list is doubly linked, standard textbook
X * stuff. The global pointers first, last and current are set as
X * side-effects by this function. The address of the card being
X * inserted is returned as a convenience to the caller (see undelete_card)
X */
X
Xstruct card *
Xinsert_card (p, after)
X struct card *p, *after;
X{
X if (p == NULL_CARD) {
X return (p); /* paranoid programming */
X }
X
X if (first == NULL_CARD) { /* list is initially empty */
X p->c_next = p->c_prev = NULL;
X first = last = current = p;
X return (p);
X }
X
X if (after == NULL_CARD) { /* at front of list */
X first->c_prev = p;
X p->c_next = first;
X p->c_prev = NULL_CARD;
X first = p;
X return (p);
X }
X
X p->c_next = after->c_next;
X p->c_prev = after;
X
X if (after == last) {
X last = p; /* at end of list */
X } else {
X after->c_next->c_prev = p;
X }
X
X after->c_next = p;
X
X return (p);
X}
X
X
X/*
X * Delete the card pointed to by p from the list. More textbook stuff
X * here. The card is not destroyed, it is clipped out of the list and
X * pushed onto a stack of deleted cards.
X */
X
Xvoid
Xdelete_card (p)
X struct card *p;
X{
X if (p == first) {
X first = p->c_next;
X } else {
X p->c_prev->c_next = p->c_next;
X }
X
X if (p == last) {
X last = p->c_prev;
X } else {
X p->c_next->c_prev = p->c_prev;
X }
X
X push_card (p);
X}
X
X
X/*
X * Undelete a card. The top card on the deleted stack is popped and
X * inserted into the list after the card pointed to by after.
X */
X
Xstruct card *
Xundelete_card (after)
X struct card *after;
X{
X struct card *p;
X
X p = pop_card ();
X if (p == NULL_CARD) {
X return (NULL_CARD);
X }
X return (insert_card (p, after));
X}
X
X
X/*
X * Destroy the entire list and all the cards in it. The cards on the
X * deleted stack are not disturbed.
X */
X
Xvoid
Xnuke_active_cards ()
X{
X struct card *p = first;
X
X while (p != NULL_CARD) {
X struct card *q;
X
X q = p->c_next;
X dispose_card (p);
X p = q;
X }
X
X first = last = current = NULL_CARD;
X}
X
X
X/*
X * Destroy the card pointed to by p, and free its storage. The pointer
X * p is no longer valid after calling this function.
X */
X
Xvoid
Xdispose_card (p)
X struct card *p;
X{
X free (p->c_text);
X free (p);
X}
X
X
X/*
X * Push the card pointed to by p onto the stack of deleted cards. Double
X * link the new node onto the front of the list so that any arbitrary
X * card can be easily unlinked without needing to scan the list.
X */
X
Xvoid
Xpush_card (p)
X struct card *p;
X{
X if (strlen (first_char (p->c_text)) == 0) {
X dispose_card (p);
X return; /* don't keep empty cards */
X }
X
X p->c_prev = NULL_CARD; /* this guy will be first in the list */
X p->c_next = dead; /* current #1 will be new #2 */
X if (dead != NULL_CARD) { /* if list was non-empty, back-point */
X dead->c_prev = p; /* the first one to the new one */
X }
X dead = p; /* head of list is now the new one */
X}
X
X
X/*
X * Pop the top card off the deleted stack and and return its address,
X * or a nil pointer if the stack is empty.
X */
X
Xstruct card *
Xpop_card ()
X{
X struct card *p;
X
X if (dead == NULL_CARD) {
X return (NULL_CARD); /* sorry, fresh out */
X }
X
X p = dead; /* returning first one in the list */
X dead = p->c_next; /* head of list is now second node */
X if (dead != NULL_CARD) { /* If any nodes left in the list, */
X dead->c_prev = NULL_CARD; /* clear back pointer of first one */
X }
X
X return (p); /* here's the top card, Bud */
X}
X
X
X/*
X * Remove the card pointed to by p from the deleted stack. The function
X * is called by the action proc for the undeleted pullright menu. The
X * node pointed to may be any one of the cards on the stack. The node
X * is clipped out of the deleted list.
X */
X
Xvoid
Xunstack_card (p)
X struct card *p;
X{
X if (p == dead) { /* is it the first one? */
X dead = p->c_next; /* head of list is now next */
X } else {
X /* point the upstream guy at the downstream guy */
X p->c_prev->c_next = p->c_next;
X }
X
X if (p->c_next != NULL_CARD) {
X /* point the downstream guy at the one upstream of me */
X p->c_next->c_prev = p->c_prev;
X }
X
X p->c_next = p->c_prev = NULL_CARD; /* this guy is alone now */
X}
X
X
X/*
X * Write the contents of all the cards out to disk. Blank cards are
X * not written out, and trailing white space is trimmed from the ones
X * which are written. The cards are seperated in the file by a
X * form-feed (^L) on a line by itself.
X */
X
Xvoid
Xdump_rolo (p, fn)
X struct card *p;
X char *fn;
X{
X int fd;
X
X fd = open (fn, O_WRONLY|O_TRUNC, NEWMODE);
X if (fd < 0) {
X msg ("Can't open %s for save: %s", fn,
X sys_errlist [errno]);
X return;
X }
X
X for ( ; p != NULL_CARD; p = p->c_next) {
X if (strlen (trim (p->c_text)) == 0)
X continue;
X if (write (fd, p->c_text, strlen (p->c_text)) == -1) {
X write_err (fd, fn);
X return;
X }
X if (write (fd, "\n\f\n", 3) == -1) {
X write_err (fd, fn);
X return;
X }
X }
X
X (void) close (fd);
X need_save = FALSE;
X}
X
X
X/*
X * Write the cards out to the named file. If the file exists already,
X * ask if it's ok to overwrite. Check permissions. Pre-create the
X * file if it doesn't already exist.
X */
X
Xvoid
Xwrite_rolo (filename)
X char *filename;
X{
X int fd;
X
X if (access (filename, F_OK) == -1) {
X if ((fd = open (filename, O_CREAT, NEWMODE)) < 0) {
X msg ("write_rolo: can't create %s: %s", filename,
X sys_errlist [errno]);
X return;
X }
X (void) close (fd);
X goto do_dump;
X }
X
X if (access (filename, W_OK) == -1) {
X msg ("Sorry, you don't have write access to %s", filename);
X return;
X }
X
X if (confirm ("%s exists, ok to overwrite?", filename) == FALSE) {
X return;
X }
X
Xdo_dump:
X dump_rolo (first, filename);
X rolofile = filename;
X update_num_display (current->c_num);
X}
X
X
X/*
X * Read in a new Rolo card file. Check for readability before throwing
X * away the old cards.
X */
X
Xvoid
Xread_rolo (filename)
X char *filename;
X{
X if (access (filename, F_OK) == -1) {
X msg ("Sorry, %s doesn't exist.", filename);
X return;
X }
X
X if (access (filename, R_OK) == -1) {
X msg ("Sorry, you don't have permission to read %s", filename);
X return;
X }
X
X nuke_active_cards ();
X init_rolo (filename);
X rolofile = filename;
X update_num_display (current->c_num);
X}
X
X
X/*
X * Common error complaint routine used by dump_rolo above.
X */
X
Xstatic
Xvoid
Xwrite_err (fd, fn)
X int fd;
X char *fn;
X{
X (void) close (fd);
X msg ("Couldn't save to %s: %s", fn, sys_errlist [errno]);
X}
X
X
X/*
X * Glue routine for the qsort compare routine. Dereference the card
X * pointers and call strcmp to compare the text of the cards, beginning
X * with the first non-blank character in the card.
X */
X
Xstatic
Xint
Xsort_up (pp1, pp2)
X struct card **pp1, **pp2;
X{
X return (strcmp (first_char ((*pp1)->c_text),
X first_char ((*pp2)->c_text)));
X}
X
X
X/*
X * Same as above, but for sort descending. Strcmp is called with the
X * string pointers in the opposite order to invert the sense of the
X * comparison.
X */
X
Xstatic
Xint
Xsort_down (pp1, pp2)
X struct card **pp1, **pp2;
X{
X return (strcmp (first_char ((*pp2)->c_text),
X first_char ((*pp1)->c_text)));
X}
X
X
X/*
X * Sort the cards in the list into alphabetical order (actually plain
X * ascii order). Space is allocated for an array of all the pointers
X * to the cards in the list. The addresses of all the cards are then
X * placed in the array and qsort is called to sort them in order. The
X * list is then made empty by simply clearing the anchor pointers to
X * the list. Each card is then inserted back into the list in the order
X * they now occupy in the sorted array of pointers. The array is then
X * freed.
X */
X
Xvoid
Xsort_cards (descend)
X int descend;
X{
X struct card **a, *p;
X int i, cards = last->c_num;
X
X if (cards == 1) {
X msg ("Only have one active card, no need to sort");
X return;
X }
X
X a = (struct card **) calloc (cards, sizeof (struct card *));
X for (p = first, i = 0; p != NULL_CARD; p = p->c_next, i++)
X a [i] = p;
X
X if (descend == TRUE) {
X qsort ((char *)a, cards, sizeof (struct card *), sort_down);
X } else {
X qsort ((char *)a, cards, sizeof (struct card *), sort_up);
X }
X
X first = last = NULL_CARD;
X for (i = 0; i < cards; i++) {
X (a [i])->c_num = i + 1; /* renumber as we go */
X (void) insert_card (a [i], last);
X }
X
X show_card (first); /* display the first */
X
X free (a);
X}
X
X
X/*
X * Menu item gen proc for the undelete pullright item. Simply
X * checks to see if the delete stack is empty. If so, the item
X * is disabled, else it is enabled.
X * Due to the exceedingly brain-damaged way that notification is
X * done for pullright menus, it is necesssary to do some rather
X * silly tap-dancing to make everything work. One such kludge is
X * to use the client data slot in the base menu on the delete menu
X * as a temporary storage area for the selected item from the pullright.
X * So, when this function is called with MENU_DISPLAY, we clear the
X * client data slot of our parent, since we are beginning a new menu
X * cycle. Any snide remarks about the convolution of the following
X * three menu functions will be cheerfully ignored until and unless
X * you can show me some better code that implements the same
X * functionality and gets all the combinations right. It's much
X * trickier that it seems on the surface. Sun really blew it on
X * this one, it's basically impossible to properly manage dynamically
X * generated menus with the notification scheme as it is.
X */
X
XMenu_item
Xcheck_stack (menu_item, operation)
X Menu_item menu_item;
X Menu_generate operation;
X{
X if (operation == MENU_DISPLAY) {
X if (dead == NULL_CARD) {
X xv_set (menu_item, MENU_INACTIVE, TRUE, 0);
X } else {
X xv_set (menu_item, MENU_INACTIVE, FALSE, 0);
X }
X }
X
X return (menu_item);
X}
X
Xvoid undel_before_proc(menu, menu_item)
XMenu menu;
XMenu menu_item;
X{
X undel_menu_card(menu_item, 1);
X}
X
Xvoid undel_proc(menu, menu_item)
XMenu menu;
XMenu_item menu_item;
X{
X undel_menu_card(menu_item, 0);
X}
X
XMenu gen_undelete_menu(proc)
Xvoid *proc;
X{
X /*
X * The user has just pulled right on the item, so now we need
X * to build the menu which will be displayed to the right.
X * First we create a menu. Then we walk the deleted list
X * and make a menu item for each card on the stack and append
X * it to the new menu.
X */
X Menu_item menu_item;
X Menu menu = xv_create(NULL, MENU,
X MENU_NOTIFY_PROC, proc,
X NULL);
X struct card *p;
X
X for (p = dead; p != NULL_CARD; p = p->c_next) {
X char *q, buf [MAX_MENU_LEN + 1];
X
X q = first_char (p->c_text);
X if (strlen (q) == 0) {
X /* unlikely, push_card filters empty cards */
X continue;
X }
X
X /* yank and chop text from the card */
X (void) strncpy (buf, q, MAX_MENU_LEN);
X buf [MAX_MENU_LEN] = '\0';
X q = index (buf, '\n');
X if (q != NULL) {
X *q = '\0';
X }
X
X /* allocate and copy the string for use by the menu */
X q = malloc (strlen (buf) + 1);
X (void) strcpy (q, buf);
X
X menu_item = xv_create (NULL, MENUITEM,
X MENU_STRING, q,
X MENU_VALUE, p,
X /* menu_destroy() will free() name string */
X MENU_RELEASE_IMAGE,
X /* goes away when parent menu does */
X MENU_RELEASE,
X 0);
X
X xv_set (menu, MENU_APPEND_ITEM, menu_item, 0);
X }
X return(menu);
X}
X
X
XMenu
Xgen_undelete (menu_item, operation)
X Menu_item menu_item;
X Menu_generate operation;
X{
X static Menu menu;
X switch (operation) {
X case MENU_DISPLAY:
X return (gen_undelete_menu(undel_proc));
X
X case MENU_DISPLAY_DONE:
X xv_destroy_safe(menu);
X return (MENU_NULL);
X }
X return (MENU_NULL);
X}
X
XMenu
Xgen_undelete_before (menu_item, operation)
X Menu_item menu_item;
X Menu_generate operation;
X{
X static Menu menu;
X switch (operation) {
X case MENU_DISPLAY:
X return (menu=gen_undelete_menu(undel_before_proc));
X
X case MENU_DISPLAY_DONE:
X xv_destroy_safe(menu);
X return (MENU_NULL);
X }
X return(MENU_NULL);
X}
X
X
X/*
X * Action proc for the undelete pullright menu item. This
X * proc removes the card from the stack and inserts it back into the
X * active list. The pointer to the card selected from the menu is
X * the value of the menu item we're being called with. The menu
X * that this action proc is called from, the args passed to the proc,
X * is the dummy menu created in the MENU_NOTIFY step of the gen
X * proc above. Since this proc actually does the undelete, we want
X * to clear the menu value so that the event func which trapped the
X * right button event and brought the menu up in the first place
X * doesn't fake a button click after we've finished.
X */
X
X/*ARGSUSED*/
Xcaddr_t
Xundel_menu_card (menu_item, before)
X Menu_item menu_item;
X int before;
X{
X struct card *p;
X save_card (current);
X
X p = (struct card *) xv_get (menu_item, MENU_VALUE);
X
X if (p == NULL_CARD) {
X p = dead;
X }
X unstack_card (p);
X (void) insert_card (p, (before == TRUE) ? current->c_prev : current);
X need_save = TRUE;
X set_slider_max (renumber (first));
X show_card (p);
X return ((caddr_t)0);
X}
X
X
X/*
X * Check the arguments which SunView didn't consume to see if a filename
X * was provided.
X */
X
Xchar *
Xcheck_args (argc, argv)
X int argc;
X char **argv;
X{
X /* only know about a filename argument */
X if (argc < 2) {
X return (NULL);
X }
X
X argv++; argc--;
X if (**argv == '-') { /* ignore a switch if given */
X argv++; argc--;
X }
X
X if (argc == 0) {
X return (NULL);
X }
X
X return (*argv);
X}
END_OF_FILE
if test 20514 -ne `wc -c <'cards.c'`; then
echo shar: \"'cards.c'\" unpacked with wrong size!
fi
# end of 'cards.c'
fi
echo shar: End of archive 2 \(of 3\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
dan
----------------------------------------------------
O'Reilly && Associates argv at sun.com / argv at ora.com
Opinions expressed reflect those of the author only.
More information about the Comp.sources.x
mailing list