luis@rice.edu (Luis Soltero) (10/11/90)
Submitted-by: Luis Soltero <luis@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@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@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 -@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@vixen.uucp X * March 1987 (V1.0) hitchens@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@sun.com / argv@ora.com Opinions expressed reflect those of the author only.