v13i051: Screen-oriented rolodex program, Part03/04

Rich Salz rsalz at bbn.com
Thu Feb 18 13:44:53 AEST 1988


Submitted-by: Dave Ihnat <ihnp4!homebru!ignatz>
Posting-number: Volume 13, Issue 51
Archive-name: rolodex/part03

#! /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 3 (of 4)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f './io.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./io.c'\"
else
echo shar: Extracting \"'./io.c'\" \(10740 characters\)
sed "s/^X//" >'./io.c' <<'END_OF_FILE'
X/* io.c */
X#include <stdio.h>
X#ifdef UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#ifdef BSD
X#include <sys/file.h>
X#else
X#include <fcntl.h>
X#endif
X#endif
X
X#ifdef VMS
X#include <types.h>
X#include <stat.h>
X#include <file.h>
X#endif
X
X#ifdef MSDOS
X#	ifdef MSC
X#	include <sys/types.h>
X#	endif	/* MSC */
X#include <sys/stat.h>
X#include <fcntl.h>
X#endif
X
X#include <ctype.h>
X
X#ifdef TMC
X#include <ctools.h>
X#else
X#include "ctools.h"
X#endif
X
X#include "rolofilz.h"
X#include "datadef.h"
X
X
Xchar *Field_Names[N_BASIC_FIELDS] = {
X        
X        "Name: ", "Work Phone: ", "Home Phone: ", "Company: ",
X        "Work Address: ", "Home Address: ", "Remarks: ", "Date Updated: "
X        
X     };
X
XPtr_Rolo_List Begin_Rlist = 0;
XPtr_Rolo_List End_Rlist = 0;
XPtr_Rolo_List Current_Entry = 0;
X
Xstatic char *rolofiledata;
X
X/*
X * The following has been added to accomplish two goals:
X *
X * 1)  Document all help files expected in the system, to avoid/identify
X *     lost elements in distribution.
X *
X * 2)  Allow a flexible, easily-modified way of changing filenames as
X *     necessary/desired to comply with different operating systems.
X */
Xchar *hlpfiles[] = {
X	"addhelp.hlp",	/* ADDHELP		*/
X	"addinfo.hlp",	/* ADDINFO		*/
X	"confirm.hlp",	/* CONFIRMHELP		*/
X	"entrymnu.hlp",	/* ENTRYMENU		*/
X	"escan.hlp",	/* ESCANHELP		*/
X	"esearch.hlp",	/* ESEARCHHELP	  	*/
X	"fldsrch.hlp",	/* FIELDSEARCHHELP  	*/
X#ifdef UNIX
X	"lockinfo.unx",	/* LOCKINFO	    	*/
X#endif
X#ifdef VMS
X	"lockinfo.vms",	/* LOCKINFO	    	*/
X#endif
X#ifdef MSDOS
X	"lockinfo.dos",	/* LOCKINFO	    	*/
X#endif
X	"mainmenu.hlp",	/* MAINMENU		*/
X	"mnymtch.hlp",	/* MANYMATCHHELP     	*/
X	"moption.hlp",	/* MOPTIONHELP	    	*/
X	"moptions.hlp",	/* MOPTIONSHELP	    	*/
X	"moreflds.hlp",	/* MOREFIELDSHELP    	*/
X	"newadd.hlp",	/* NEWADDHELP	     	*/
X	"otherfmt.hlp",	/* OTHERFORMATHELP 	*/
X	"pkentry.hlp",	/* PICKENTRYHELP     	*/
X	"pkntmenu.hlp",	/* PICKENTRYMENU	*/
X	"poptmenu.hlp",	/* POPTIONMENU	     	*/
X	"poptions.hlp",	/* POPTIONSHELP	     	*/
X	"srchstr.hlp",	/* SEARCHSTRINGHELP  	*/
X	"update.hlp",	/* UPDATEHELP	    	*/
X	"updatmnu.hlp",	/* UPDATEMENU	   	*/
X	"usrfld.hlp",	/* USERFIELDHELP     	*/
X};
X
X
Xread_rolodex (fd) int fd;
X                                             
X{
X  struct stat statdata;
X  long filesize;
X  int i,j,k,start_of_others,warning_given;
X  Ptr_Rolo_Entry newentry;
X  Ptr_Rolo_List newlink,rptr;
X  char *next_field,*next_other;
X  char **other_pointers;
X  int n_entries = 0;
X
X  /* find out how many bytes are in the file */
X
X  fstat(fd,&statdata);
X  if ((filesize = statdata.st_size) == 0) {
X     return(0);
X  }
X
X  /* create an array of characters that big */
X  
X  rolofiledata = rolo_emalloc(filesize);
X
X  /* read them all in at once for efficiency */
X  
X#ifdef MSDOS
X  /*
X   * Unlike Unix, MS-DOS compilers make a distinction between text and
X   * binary files.  Unfortunately, this means that in text mode, the file
X   * size is reported by the stat call won't necessarily match the value
X   * reported by the read, since there is CR/LF character translation.
X   * So, the best we can hope for here is that a failed read will give a
X   * zero or negative return value...
X   */
X  if ((filesize = read(fd,rolofiledata,filesize)) <= 0) {
X#else
X  if (filesize != read(fd,rolofiledata,filesize)) {
X#endif
X     fprintf(stderr,"rolodex read failed\n");
X     exit(-1);
X  }
X
X  j = 0;
X  
X  /* for each entry in the rolodex file */
X  
X  while (j < filesize) {
X
X      n_entries++;
X        
X      /* create the link and space for the data entry */
X        
X      newlink = new_link_with_entry();
X      newentry = get_entry(newlink);
X      if (j == 0) {
X         Begin_Rlist = newlink;
X         set_prev_link(newlink,0);
X         set_next_link(newlink,0);
X      }
X      else {
X          set_next_link(End_Rlist,newlink);
X          set_prev_link(newlink,End_Rlist);
X          set_next_link(newlink,0);
X      }
X      End_Rlist = newlink;
X
X      /* locate each required field in the character array and change */
X      /* the ending line feed to a null.  Insert a pointer to the */
X      /* beginning of the field into the data entry */
X
X      for (i = 0; i < N_BASIC_FIELDS; i++) {
X          next_field = rolofiledata + j;
X          while (rolofiledata[j] != '\n') {
X            j++;
X          }
X          rolofiledata[j] = '\0';
X          j++;
X          set_basic_rolo_field(i,newentry,next_field);
X      }
X
X      /* the end of an entry is indicated by two adjacent newlines */
X
X      if (rolofiledata[j] == '\n') {
X         j++;
X         newentry -> other_fields = 0;
X         continue;
X      }
X
X      /* there must be additional, user-inserted fields. Find out how many. */
X
X      start_of_others = j;
X      while (1) {
X        while (rolofiledata[j] != '\n') {
X          j++;
X        }
X        incr_n_others(newentry);
X        j++;
X        if (rolofiledata[j] == '\n') {
X           j++;
X           break;
X        }
X     }
X
X     /* allocate an array of character pointers to hold these fields */
X
X     other_pointers = (char **)rolo_emalloc(get_n_others(newentry)*sizeof(char *));
X
X     /* separate each field and insert a pointer to it in the char array */
X
X     k = start_of_others;
X     for (i = 0; i < get_n_others(newentry); i++) {
X         next_other = rolofiledata + k;
X         while (rolofiledata[k] != '\n') {
X           k++;
X         }
X         rolofiledata[k] = '\0';
X         other_pointers[i] = next_other;
X         k++;
X     }
X
X     /* insert the pointer to this character array into the data entry */
X
X     newentry -> other_fields = other_pointers;
X
X  }
X
X  /* check that all the entries are in alphabetical order by name */
X  
X  warning_given = 0;
X  rptr = get_next_link(Begin_Rlist);
X  while (rptr != 0) {
X    if (1 == compare_links(get_prev_link(rptr),rptr)) {
X       if (!warning_given) fprintf(stderr,"Warning, rolodex out of order\n");
X       warning_given = 1;
X       reorder_file = 1;
X    }
X    rptr = get_next_link(rptr);
X  }    
X    
X  return(n_entries);
X  
X}
X
X
Xwrite_rolo_list (fp) FILE *fp; 
X
X/* write the entire in-core rolodex to a file */
X
X{
X
X  Ptr_Rolo_List rptr;
X  Ptr_Rolo_Entry lentry;
X  int j;
X
X  rptr = Begin_Rlist;
X
X  while (rptr != 0) {
X    lentry = get_entry(rptr);
X    for (j = 0; j < N_BASIC_FIELDS; j++) {
X        fprintf(fp,"%s\n",get_basic_rolo_field(j,lentry));
X    }
X    for (j = 0; j < get_n_others(lentry); j++) {
X        fprintf(fp,"%s\n",get_other_field(j,lentry));
X    }
X    fprintf(fp,"\n");
X    rptr = get_next_link(rptr);
X  }
X
X}
X
X
Xwrite_rolo (fp1,fp2) FILE *fp1; FILE *fp2;
X
X{
X  write_rolo_list(fp1);
X  write_rolo_list(fp2);
X}
X
X
Xdisplay_basic_field (name,value,show,up) char *name; char *value; int show,up;
X{
X  int i;
X  if ((value == (char *)NULL) || (all_whitespace(value) && !show)) return;
X  printf("%-25s",name);
X  while (*value != '\0') {
X    if (*value == ';') {
X       while (*++value == ' '); 
X       putchar('\n');
X       for (i = 0; i < (up ? 28 : 25); i++) putchar(' ');
X    }
X    else {
X       putchar(*value++);
X    }
X  }
X  putchar('\n');
X}
X
X
Xdisplay_other_field (fieldstring) char *fieldstring;
X{
X  int already_put_sep = 0;        
X  int count = 0;
X  int i;
X  while (*fieldstring != '\0') {
X    if (*fieldstring == ';' && already_put_sep) {
X       while (*++fieldstring == ' ');
X       putchar('\n');
X       for (i = 0; i < 25; i++) putchar(' ');
X       continue;
X    }
X    putchar(*fieldstring);
X    count++;
X    if (*fieldstring == ':' && !already_put_sep) {
X       for (i = count; i < 24; i++) putchar(' ');
X       already_put_sep = 1;
X    }
X    fieldstring++;
X  }
X  putchar('\n');
X}
X
X
Xsummarize_entry_list (rlist,ss) Ptr_Rolo_List rlist; char *ss;
X
X/* print out the Name field for each entry that is tagged as matched */
X/* and number each entry. */
X
X{
X  int count = 1;
X  clear_the_screen();
X  printf("Entries that match '%s' :\n\n",ss);
X  while (rlist != 0) {
X    if (get_matched(rlist)) {
X       printf (
X          "%d. \t%s\n",
X          count++,
X          get_basic_rolo_field((int) R_NAME,get_entry(rlist))
X       );
X    }
X    rlist = get_next_link(rlist);    
X  }
X  putchar('\n');
X}
X
X
Xdisplay_field_names ()
X
X/* display and number each standard field name. */
X
X{
X  int j;
X  char *name;
X  clear_the_screen();
X  for (j = 0; j < N_BASIC_FIELDS - 1; j++) {        
X      name = Field_Names[j];        
X      printf("%d. ",j+1);
X      while (*name != ':') putchar(*name++);
X      putchar('\n');
X  }
X  printf("%d. ",N_BASIC_FIELDS);
X  printf("A user created item name\n\n");
X}  
X  
Xdisplay_entry (lentry) Ptr_Rolo_Entry lentry;
X{
X  int j,n_others;
X  char *string;
X  
X  clear_the_screen();
X  
X  /* display the standard fields other than Date Updated */
X  
X  for (j = 0; j < N_BASIC_FIELDS - 1; j++) {
X      string = get_basic_rolo_field(j,lentry);
X      display_basic_field(Field_Names[j],string,0,0);
X  }        
X      
X  /* display any additional fields the user has defined for this entry */
X  
X  n_others = get_n_others(lentry);
X  for (j = 0; j < n_others; j++) {
X      string = get_other_field(j,lentry);
X      display_other_field(string);
X   }
X
X   /* display the Date Updated field */
X   
X   j = N_BASIC_FIELDS - 1;
X   display_basic_field(Field_Names[j],get_basic_rolo_field(j,lentry),0,0);
X   fprintf(stdout,"\n");
X
X}
X
X
Xdisplay_entry_for_update (lentry) Ptr_Rolo_Entry lentry;
X
X/* same as display_entry, except each item is numbered and the Date Updated */
X/* item is not displayed */
X
X{
X  int j,n_others;
X  char *string;
X  int count = 1;
X  
X  clear_the_screen();
X  
X  for (j = 0; j < N_BASIC_FIELDS - 1; j++) {
X      string = get_basic_rolo_field(j,lentry);
X      printf("%d. ",count++);
X      display_basic_field(Field_Names[j],string,1,1);
X  }        
X      
X  n_others = get_n_others(lentry);
X  for (j = 0; j < n_others; j++) {
X      string = get_other_field(j,lentry);
X      printf("%d. ",count++);
X      display_other_field(string);
X  }
X  
X  printf("%d. Add a new user defined field\n",count);
X
X  fprintf(stdout,"\n");
X
X}
X
X
Xint cathelpfile (fileidx,helptopic,clear)
X
X  int fileidx;
X  char *helptopic; 
X  int clear;
X
X{
X  register char *filepath;
X  FILE *fp;
X  char buffer[MAXLINELEN];
X
X  if(fileidx > LAST_HELP) {
X	fprintf(stderr,
X		"INTERNAL ERROR:  Error file index, max: %d, requested: %d\n",
X		LAST_HELP,fileidx);
X	return;
X  }else
X  	filepath = libdir(hlpfiles[fileidx]);
X	
X  if (clear) clear_the_screen();
X  if (NULL == (fp = fopen(filepath,"r"))) {
X     if (helptopic) {
X        printf("No help available on %s, sorry.\n\n",helptopic); 
X     }
X     else {
X        fprintf(stderr,"Fatal error, can't open %s\n",filepath);
X        exit(-1);
X     }
X     return;
X  }
X  while (NULL != fgets(buffer,MAXLINELEN,fp)) printf("%s",buffer);  
X  printf("\n");
X  fclose(fp);
X  return;
X}
X
X
Xany_char_to_continue ()
X{
X  char buffer[80];
X  printf("RETURN to continue: ");
X  fgets(buffer,80,stdin);
X  return;
X}
END_OF_FILE
if test 10740 -ne `wc -c <'./io.c'`; then
    echo shar: \"'./io.c'\" unpacked with wrong size!
fi
# end of './io.c'
fi
if test -f './operatns.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./operatns.c'\"
else
echo shar: Extracting \"'./operatns.c'\" \(9950 characters\)
sed "s/^X//" >'./operatns.c' <<'END_OF_FILE'
X/* operatns.c */
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef TMC
X#include <ctools.h>
X#else
X#include "ctools.h"
X#endif
X#include "args.h"
X#include "menu.h"
X#include "mem.h"
X
X#include "rolofilz.h"
X#include "rolodefs.h"
X#include "datadef.h"
X#include "choices.h"
X
X#define index strchr 
Xchar *index();
X
Xextern char *ctime();
X
XPtr_Rolo_List create_entry (basicdata,otherdata) char **basicdata, **otherdata;
X{
X  Ptr_Rolo_List newlink;        
X  Ptr_Rolo_Entry newentry;
X  int i,j;
X  newlink = new_link_with_entry();        
X  newentry = get_entry(newlink);
X  for (j = 0; j < N_BASIC_FIELDS; j++) {
X      set_basic_rolo_field(j,newentry,basicdata[j]);
X  }
X  j = 0;
X  while (otherdata[j] != 0) j++;
X  set_n_others(newentry,j);
X  if (j > 0) {
X     newentry -> other_fields = (char **) rolo_emalloc(j*sizeof(char *));
X     for (i = 0; i < j; i++) {
X         set_other_field(i,newentry,otherdata[i]);
X     }
X  }
X  else newentry -> other_fields = 0;
X  return(newlink);
X}  
X  
X
Xother_fields () 
X{
X  int rval;
X  rval = rolo_menu_yes_no (
X             "Additional fields? ",DEFAULT_NO,1,
X             MOREFIELDSHELP, "additional fields"
X          );
X  return(rval == MENU_YES);
X}
X
X
Xadd_the_entry ()
X{
X  return(MENU_YES == rolo_menu_yes_no (
X              "Add new entry to rolodex? ",DEFAULT_YES,1,
X              NEWADDHELP, "adding newly entered entry"
X           ));
X}
X
X
Xrolo_add () 
X
X{
X  int i,j,k,rval,menuval;
X  char *response;
X  char *basicdata[N_BASIC_FIELDS], *otherdata[100];
X  Ptr_Rolo_List rlink;
X
X  if(read_only)
X  {
X	printf("Readonly mode: cannot add entries.\n");
X	sleep(2);
X	return(1);
X  }
X        
X  for (j = 0; j < 100; j++) otherdata[j] = (char *)NULL;
X  for (j = 0; j < N_BASIC_FIELDS; j++) basicdata[j] = (char *)NULL;
X  cathelpfile(ADDINFO,(char *)NULL,1);
X  
X  /* 'k' and 'kludge' are are kludge to allow us to back up from entering */
X  /* user defined fields to go an correct wrong basic field information. */
X  
X  k = 0;
X  
X  kludge :
X  
X  for (j = k; j < N_BASIC_FIELDS - 1; j++) {
X        
X      redo :
X        
X      rval = menu_match (
X           &menuval,&response,
X           Field_Names[j],
X           0,0,0,1,5,
X           "\\",A_ABORT_ADD,
X           "^",A_BACKUP,
X           "!",A_FILL_IN_REST,
X           "?",A_HELP,
X           "",A_NO_DATA
X        );
X        
X      switch (rval) {
X        
X        case MENU_NO_MATCH :
X          basicdata[j] = copystr(response);
X          if (j == 0 && strlen(basicdata[j]) == 0) {
X             printf("Each entry must have a name!\n\n");
X	     sleep(2);
X             goto redo;
X          }
X          break;
X
X        case MENU_MATCH :
X          switch (menuval) {
X            case A_BACKUP :
X              if (j == 0) return(0);
X              j--;
X              goto redo;
X              /* break; */
X            case A_ABORT_ADD :
X              return(0);
X              /* break; */
X            case A_FILL_IN_REST :
X              if (j == 0) {
X                 fprintf(stderr,"You must enter at least a name...\n\n");
X		 sleep(2);
X                 goto redo;
X              }
X              goto add_entry;
X              /* break; */
X            case A_HELP :
X              cathelpfile(ADDHELP,"adding entries",1);
X              any_char_to_continue();
X              clear_the_screen();
X              cathelpfile(ADDINFO,(char *)NULL,0);
X              for (i = 0; i < j; i++) {
X                  printf("%s%s\n",Field_Names[i],basicdata[i]);
X              }
X              goto redo;                            
X              /* break; */
X            case A_NO_DATA :
X              if (j == 0) {
X                 fprintf(stderr,"You must enter at least a name...\n\n");
X		 sleep(2);
X                 goto redo;
X              }
X
X              if (basicdata[j] != (char *)NULL)
X			basicdata[j][0] = '\0';
X	      else
X			basicdata[j] = "";
X              break;
X            default :
X              fprintf(stderr,"Impossible rval from rolo_add menu_match\n\n");
X              save_and_exit(-1);
X              break;
X          }
X          break;
X
X        case MENU_EOF :
X          user_eof();
X          break;
X          
X        case MENU_ERROR :
X        case MENU_AMBIGUOUS :
X        default :
X          fprintf(stderr,"Impossible return from rolo_add menu_match\n");
X          save_and_exit(-1);
X          break;
X
X      }
X
X  }
X
X  if (other_fields()) {
X     for (j = 0; j < 100; j++) {
X         redo_other :
X         rval = menu_match (
X              &menuval,&response,
X              "Enter <name>: <data> (type RETURN to quit) : ",
X              0,0,0,0,5,
X              "\\",O_ABORT,
X              "?",O_HELP,
X              "Help",O_HELP,
X              "^",O_BACKUP,
X              "",O_DONE_OTHERS
X           );
X         switch (rval) {
X           case MENU_MATCH :
X             switch (menuval) {
X               case O_DONE_OTHERS :
X                 goto add_entry;
X                 /* break; */
X               case O_BACKUP :
X                 if (j == 0) {
X                    k = N_BASIC_FIELDS - 2;
X                    goto kludge;
X                 }
X                 else {
X                    j--;
X                    printf("Deleting %s\n",otherdata[j]);
X                    goto redo_other;
X                 }
X                 /* break; */
X               case O_ABORT :
X                 return(0);
X                 /* break; */
X               case O_HELP :
X                 cathelpfile(OTHERFORMATHELP,"user-item format",1);
X                 any_char_to_continue();
X                 goto redo_other;
X              }   
X             break;
X           case MENU_NO_MATCH :
X             if ((index(response,':') == (char *)NULL) ||
X		 (*response == ':')) {
X                printf("No field name provided -- separate with a ':'.\n");
X                goto redo_other;
X             }
X             otherdata[j] = copystr(response);
X             break;
X           case MENU_EOF :
X             user_eof();
X             break;
X           case MENU_AMBIGUOUS :
X           case MENU_ERROR :
X           default :
X             fprintf(stderr,"Impossible rval from add_other menu_match\n");
X             save_and_exit(-1);
X         }
X     }
X  }
X
X  add_entry :   
X
X  basicdata[N_BASIC_FIELDS - 1] = timestring();
X  
X  rlink = create_entry(basicdata,otherdata);
X  clear_the_screen();
X  display_entry(get_entry(rlink));
X  if (add_the_entry()) {
X     printf (
X         "Adding entry for %s to rolodex\n",
X         get_basic_rolo_field((int) R_NAME,get_entry(rlink))
X      );
X     rolo_insert(rlink,compare_links);
X     changed = 1;
X     sleep(2);
X  }
X  else {
X     return(0);
X  }
X  return(0);	/* Should never hit this... */
X}
X
X
Xentry_action (rlink) Ptr_Rolo_List rlink;
X
X{
X  static entry_menu_displayed = 0;
X  int rval,menuval;
X  char *response;
X  
X  if (!entry_menu_displayed) cathelpfile(ENTRYMENU,(char *)NULL,0);
X#ifdef NEVERDEF
X  entry_menu_displayed = 1;	/* This may be turned off to provide verbose help */
X#endif
X
X  redo :
X  
X  rval = menu_match (
X       &menuval, &response,
X       "Action (? for help) : ",
X       0,1,1,1,7,
X       "\\",E_ABORT,
X       "?",E_HELP,
X       "",E_CONTINUE,
X       "-",E_DELETE,
X       "+",E_UPDATE,
X       "<",E_PREV,
X       "%",E_SCAN
X    );
X    
X  if (rval != MENU_MATCH) {
X     if (rval == MENU_EOF) user_eof();
X     fprintf(stderr,"Impossible return from entry_action menu_match\n");
X     save_and_exit(-1);
X  }
X
X  switch (menuval) {
X    case E_ABORT :
X    case E_CONTINUE :
X    case E_PREV :
X      break;
X    case E_SCAN :
X      rolo_peruse_mode(get_next_link(rlink));
X      break;
X    case E_UPDATE :
X      rolo_update_mode(rlink);
X      break;
X    case E_DELETE :
X      if(!rolo_delete(rlink))
X      	printf("Entry deleted\n");
X      sleep(1);
X      changed = 1;
X      break;
X    case E_HELP :
X      cathelpfile (
X          (in_search_mode ? ESEARCHHELP : ESCANHELP),
X          "entry actions",
X          1
X       );
X      any_char_to_continue();
X      clear_the_screen();
X      display_entry(get_entry(rlink));
X      goto redo;
X      /* break; */
X    default :
X      fprintf(stderr,"Impossible menuval in entry_action\n");
X      save_and_exit(-1);
X  }
X
X  return(menuval);
X  
X}
X
X
Xdisplay_list_of_entries (rlist) Ptr_Rolo_List rlist;
X
X{
X  Ptr_Rolo_List old,hold;
X
X  if(rlist != 0)
X	hold = get_next_link(rlist);	/* In case of change */
X        
X  while (rlist != 0) {        
X    
X    if (!get_matched(rlist)) goto next;
X        
X    loop :    
X
X    display_entry(get_entry(rlist));
X    
X    switch (entry_action(rlist)) {
X      case E_CONTINUE :
X        break;
X      case E_ABORT :
X        return(0);
X        /* break; */
X      case E_PREV :
X        old = rlist;
X        find_prev_match :
X        if (get_prev_link(rlist) == 0) {
X           rlist = old;
X           printf("No previous entry in scan list\n");
X           sleep(2);
X        }
X        else {
X           rlist = get_prev_link(rlist);
X           if (!get_matched(rlist)) goto find_prev_match;
X        }
X        goto loop;
X        /* break; */
X      case E_UPDATE :
X	if(name_changed)
X	{
X		printf("Continuing scan at next entry in scan list before change...\n");	
X		sleep(1);
X	 	rlist = hold;
X
X		break;
X	}
X	/* Deliberate fall-thru */
X      default :
X        printf("Displaying next entry in scan list...\n");
X        sleep(1);
X        break;
X    }
X    
X    next :
X    
X    if(!name_changed)
X	    rlist = get_next_link(rlist);
X    else
X	name_changed = 0;
X
X    if(rlist != 0)
X	hold = get_next_link(rlist);	/* In case of change */
X    
X  }
X  
X  printf("No further entries to scan...\n");
X  sleep(2);     
X  return(0);
X}
X  
X
Xrolo_peruse_mode (first_rlink) Ptr_Rolo_List first_rlink;
X
X{
X  Ptr_Rolo_List rlist = first_rlink;
X  if (0 == Begin_Rlist) {
X     fprintf(stderr,"No further entries in rolodex...\n");
X     sleep(2);
X     return(0);
X  }
X  while (rlist != 0) {  
X    set_matched(rlist);
X    rlist = get_next_link(rlist);
X  }    
X  display_list_of_entries(first_rlink);
X  rlist = first_rlink;
X  while (rlist != 0) {  
X    unset_matched(rlist);
X    rlist = get_next_link(rlist);
X  }    
X
X  return(0);
X}
END_OF_FILE
if test 9950 -ne `wc -c <'./operatns.c'`; then
    echo shar: \"'./operatns.c'\" unpacked with wrong size!
fi
# end of './operatns.c'
fi
if test -f './rolo.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./rolo.c'\"
else
echo shar: Extracting \"'./rolo.c'\" \(18313 characters\)
sed "s/^X//" >'./rolo.c' <<'END_OF_FILE'
X/* rolo.c */
X#ifdef UNIX
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#include <string.h>
X#ifdef BSD
X#include <sys/file.h>
X#else
X#include <fcntl.h>
X#endif
X#endif
X
X#ifdef VMS
X#include <types.h>
X#include <file.h>
X#include <stat.h>
X#include <string.h>
X#endif
X
X#ifdef MSDOS
X#include <fcntl.h>
X#	ifdef MSC
X#	include <sys	ypes.h>
X#	endif	/* MSC */
X#include <sys/stat.h>
X#include <errno.h>
X#include <string.h>
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X/* #include <sgtty.h> */
X#include <signal.h>
X
X
X#ifdef TMC
X#include <ctools.h>
X#else
X#include "ctools.h"
X#endif
X#include "args.h"
X#include "menu.h"
X#include "mem.h"
X
X#include "rolofilz.h"
X#include "rolodefs.h"
X#include "datadef.h"
X
X#ifndef BSD
X/* BSD Unix gives us these values but AT&T Unix, VMS and MSDOS don't */
X/* Used with 'access(2)' syscall */
X#define R_OK 04
X#define F_OK 00
X#define W_OK 02
X#endif
X
X#ifdef UNIX
X#define	DEF_PERM 0600	/* Default permissions: All, for owner only */
X#endif
X
X#ifdef VMS
X#define	DEF_PERM 0600	/* Default permissions: All, for owner only */
X#endif
X
X#ifdef MSDOS
X#define	DEF_PERM (S_IREAD | S_IWRITE)	/* Default permissions: All */
X#endif
X
X#define MAX_LINES	60		/* Max number of lines/page */
X
Xstatic struct stat stat_buf;
X
Xstatic char rolodir[DIRPATHLEN];        /* directory where rolo data is */
Xstatic char filebuf[DIRPATHLEN];        /* stores result of homedir() */
X
Xint changed = 0;
Xint name_changed = 0;
Xint reorder_file = 0;
Xint rololocked = 0;
Xint in_search_mode = 0;
Xint read_only = 0;
X
Xchar *rolo_emalloc (size) int size;
X
X/* error handling memory allocator */
X
X{
X  char *rval;        
X  char *malloc();
X  if (0 == (rval = malloc((unsigned)size))) {        
X     fprintf(stderr,"Fatal error:  out of memory\n");
X     save_and_exit(-1);                                               
X  }
X  return(rval);
X}  
X
X        
Xchar *copystr (s) char *s;
X
X/* memory allocating string copy routine */
X
X
X{
X char *copy;        
X if (s == 0) return(0);
X copy = rolo_emalloc(strlen(s) + 1);
X strcpy(copy,s);
X return(copy);
X}
X
X 
Xchar *timestring ()
X
X/* returns a string timestamp */
X
X{
X  char *s;        
X  long timeval;
X  long time();
X
X  time(&timeval);
X  s = ctime(&timeval);  
X  s[strlen(s) - 1] = '\0';
X  return(copystr(s));
X}  
X  
X
Xuser_interrupt ()
X
X/* if the user hits C-C (we assume he does it deliberately) */
X
X{
X#ifdef VMS
X  delete(homedir(ROLOLOCK));
X  delete(homedir(ROLOTEMP));
X#else
X  unlink(homedir(ROLOLOCK));
X  unlink(homedir(ROLOTEMP));
X#endif
X  fprintf(stderr,"\nAborting rolodex, no changes since last save recorded\n");
X  exit(-1);  
X}  
X
X
Xuser_eof ()
X
X/* if the user hits C-D */
X
X{
X#ifdef VMS
X  delete(homedir(ROLOLOCK));
X#else
X  unlink(homedir(ROLOLOCK));        
X#endif
X  fprintf(stderr,"\nUnexpected EOF on terminal. Saving rolodex and exiting\n");
X  save_and_exit(-1);        
X}
X
X
Xroloexit (rval) int rval;
X{
X  /* In case it hasn't been cleaned up, also clobber ROLOTEMP. */
X  clear_the_screen();
X  if (rololocked)
X#ifdef VMS
X  delete(homedir(ROLOTEMP));
X  delete(homedir(ROLOLOCK));
X  exit(rval==0?1:rval);
X#else
X  unlink(homedir(ROLOTEMP));
X  unlink(homedir(ROLOLOCK));
X  exit(rval);
X#endif
X}  
X      
X                                      
Xsave_to_disk ()
X
X/* move the old rolodex to a backup, and write out the new rolodex and */
X/* a copy of the new rolodex (just for safety) */
X
X{
X  FILE *tempfp,*copyfp;        
X  char *strcpy();
X  char d1[DIRPATHLEN], d2[DIRPATHLEN];
X
X#ifdef VMS
X  /*
X   * Since VMS keeps versions of files around, clobber any that are still
X   * hanging around.  If appropriate access permissions aren't granted,
X   * well, they'll just have to purge their directory...
X   */
X  delete(homedir(ROLOTEMP));	/* There will be a copy of this from earlier */
X
X  if(!access(homedir(ROLOCOPY),R_OK))
X	if(!access(homedir(ROLOCOPY),W_OK))	/* Implies delete permission */
X	delete(homedir(ROLOCOPY));
X#endif
X  tempfp = fopen(homedir(ROLOTEMP),"w");
X  if(tempfp == (FILE *)NULL)
X     perror(ROLOTEMP);
X
X  copyfp = fopen(homedir(ROLOCOPY),"w");
X  if(copyfp == (FILE *)NULL)
X     perror(ROLOCOPY);
X
X  if (tempfp == (FILE *)NULL || copyfp == (FILE *)NULL) {
X     fprintf(stderr,"Unable to write rolodex...\n");
X     fprintf(stderr,"Any changes made have not been recorded\n");
X     roloexit(-1);
X  }
X
X  /*
X   * Be sure to set proper permissions on the temp,copy files *before* putting
X   * data in them...
X   */
X#ifndef MSDOS
X  if(chmod(homedir(ROLOTEMP),(int)stat_buf.st_mode))
X	fprintf(stderr,"WARNING: Couldn't set permissions on %s\n",
X		homedir(ROLOTEMP));
X
X  if(chmod(homedir(ROLOCOPY),(int)stat_buf.st_mode))
X	fprintf(stderr,"WARNING: Couldn't set permissions on %s\n",
X		homedir(ROLOCOPY));
X#endif	/* MSDOS */
X
X  write_rolo(tempfp,copyfp);
X  
X  fclose(tempfp);    
X  fclose(copyfp);
X
X#ifdef UNIX
X  unlink(strcpy(d1,homedir(ROLOBAK)));              
X  link(strcpy(d1,homedir(ROLODATA)),strcpy(d2,homedir(ROLOBAK)));
X  unlink(strcpy(d1,homedir(ROLODATA)));
X
X  if(link(strcpy(d1,homedir(ROLOTEMP)),strcpy(d2,homedir(ROLODATA))))
X  {
X    	fprintf(stderr,"Link failed.  Revised rolodex is in %s\n",ROLOCOPY);
X	roloexit(-1);
X  }else
X  {
X   	unlink(strcpy(d1,homedir(ROLOTEMP)));
X   	unlink(strcpy(d1,homedir(ROLOCOPY)));
X  }
X#endif
X
X#ifdef VMS
X  delete(homedir(ROLOBAK));
X
X  if ((rename(strcpy(d1,homedir(ROLODATA)),strcpy(d2,homedir(ROLOBAK))) != 1) ||
X      (rename(strcpy(d1,homedir(ROLOTEMP)),strcpy(d2,homedir(ROLODATA)))) != 1) {
X     fprintf(stderr,"Rename failed.  Revised rolodex is in %s\n",ROLOCOPY);
X     roloexit(-1);
X  }else
X	delete(homedir(ROLOCOPY));	/* Don't really need this anymore */
X#endif
X
X#ifdef MSDOS
X  unlink(homedir(ROLOBAK));
X
X  if (rename(strcpy(d1,homedir(ROLODATA)),strcpy(d2,homedir(ROLOBAK))) ||
X      rename(strcpy(d1,homedir(ROLOTEMP)),strcpy(d2,homedir(ROLODATA)))) {
X     fprintf(stderr,"Rename failed.  Revised rolodex is in %s\n",ROLOCOPY);
X     perror(homedir(ROLODATA));
X     perror(homedir(ROLOBAK));
X     perror(homedir(ROLOTEMP));
X     roloexit(-1);
X  }else
X	unlink(homedir(ROLOCOPY));	/* Don't really need this anymore */
X#endif
X
X  printf("Rolodex saved\n");
X
X  sleep(1);
X  changed = 0;
X  name_changed = 0;
X}
X                   
X
Xsave_and_exit (rval) int rval;
X{
X  if (changed)
X	save_to_disk();
X  else
X#ifdef VMS
X	delete(homedir(ROLOTEMP));
X#endif
X#ifdef UNIX
X	unlink(homedir(ROLOTEMP));
X#endif
X#ifdef MSDOS
X	unlink(homedir(ROLOTEMP));
X#endif
X
X  roloexit(rval);        
X}
X                 
X#ifdef UNIX
Xextern struct passwd *getpwnam();
X
Xchar *home_directory (name) char *name;
X{
X  struct passwd *pwentry;
X  if (0 == (pwentry = getpwnam(name))) return("");
X  return(pwentry -> pw_dir);
X}
X#endif
X
X#ifdef VMS
X/*
X * This routine should never be called in VMS.
X */
Xchar *home_directory(name) char *name;
X{
X	fprintf(stderr,"INTERNAL ERROR: Called home_directory under VMS.\n");
X	exit(0);
X}
X#endif
X
X#ifdef MSDOS
X/*
X * This is rather simplistic. For drives A through C, try to find a directory
X * named 'name' under the root.  If not found on any of the drives, then
X * simply return the root directory of the current drive.
X */
Xchar *home_directory (name) char *name;
X{
X	char *drvspec = "A:\\";
X
X	static char dirbuff[128];
X	int fid;
X
X	for(;*drvspec <= 'C';(*drvspec)++)
X	{
X		strcpy(dirbuff,drvspec);
X		strcat(dirbuff,name);
X		
X		if((fid = open(dirbuff,O_RDONLY)) >= 0)
X		{
X			close(fid);
X			return(dirbuff);
X		}else
X			if(errno != ENOENT && errno != ENODEV)
X				return(dirbuff);
X	}
X
X      	return("/");
X}                       
X#endif
X
Xchar *homedir (filename) char *filename;
X
X/* e.g., given "rolodex.dat", create "/u/massar/rolodex.dat" */
X/* rolodir generally the user's home directory but could be someone else's */
X/* home directory if the -u option is used. */
X
X{
X#ifdef UNIX
X  nbuffconcat(filebuf,3,rolodir,"/",filename);
X#endif
X
X#ifdef MSDOS
X  nbuffconcat(filebuf,3,rolodir,"\\",filename);
X#endif
X
X#ifdef VMS
X  nbuffconcat(filebuf,2,rolodir,filename);
X#endif
X
X  return(filebuf);
X}
X
X
Xchar *libdir (filename) char *filename;
X
X/* return a full pathname into the rolodex library directory */
X/* the string must be copied if it is to be saved! */
X
X{
X#ifdef UNIX
X  nbuffconcat(filebuf,3,ROLOLIB,"/",filename);
X#endif
X
X#ifdef MSDOS
X  /*
X   * If there's no drive specifier in ROLOLIB, then prepend the current
X   * drive.
X   */
X  char *curdir;
X  char *getcwd();
X
X  curdir = ROLOLIB;
X
X  if(curdir[2] != ':')
X  {
X  	curdir = getcwd((char *)NULL,128);
X	curdir[3] = '\0';
X	nbuffconcat(filebuf,4,curdir,ROLOLIB,"\\",filename);
X	(void)free(curdir);
X  }else
X	nbuffconcat(filebuf,3,ROLOLIB,"\\",filename);
X#endif
X
X#ifdef VMS
X  nbuffconcat(filebuf,2,ROLOLIB,filename);
X#endif
X
X                 
X  return(filebuf);        
X}
X
X
Xrolo_only_to_read () 
X{
X  return((option_present(READONLYFLAG) << 1) |
X	(option_present(SUMMARYFLAG) || n_non_option_args()));
X}
X
X
Xlocked_action () 
X{
X  if (option_present(OTHERUSERFLAG)) {        
X     fprintf(stderr,"Someone else is modifying that rolodex, sorry\n");
X     exit(-1);
X  }
X  else {
X     cathelpfile(LOCKINFO,"locked rolodex",0);
X     exit(-1);
X  }
X}  
X  
X
Xpretty_print()
X{
X	int elt_lines, index, tmp_line_cnt;
X	int line_cnt = 0;
X	char *tmpptr;
X	char *strchr();
X	FILE *lstfp;
X	Ptr_Rolo_List rptr;
X	Ptr_Rolo_Entry lentry;
X
X	clear_the_screen();
X
X	fputs("\nPretty printing the Rolodex...\n",stdout);
X	fprintf(stdout,"Print the file %-30s\n", homedir(ROLOPRINT));
X
X	lstfp = fopen(homedir(ROLOPRINT),"w");
X	if(lstfp == (FILE *)NULL) {
X		perror(homedir(ROLOPRINT));
X		return;
X	}
X
X	rptr = Begin_Rlist;
X	if(rptr == 0) {
X		fputs("\n\nNo entries to print...\n",stderr);
X		return;
X	}
X
X	while (rptr != 0) {
X  		lentry = get_entry(rptr);
X
X		/* Find the number of lines this entry requires to print */
X		for(elt_lines = 0, index = 0; index < N_BASIC_FIELDS; index++) {
X			tmpptr = lentry->basicfields[index];
X			elt_lines++;	/* Even one for an empty line */
X
X			while((tmpptr = strchr(tmpptr,';')) != (char *)NULL) {
X				elt_lines++;
X				tmpptr++;
X			}
X		}
X		if(lentry->n_others) {
X			for(index=0; index < lentry->n_others; index++) {
X				elt_lines++;	/* As above, even if the entry is empty... */
X				tmpptr = lentry->other_fields[index];
X                        	
X                        	while((tmpptr = strchr(tmpptr,';')) != (char *)NULL) {
X                        		elt_lines++;
X                        		tmpptr++;
X                        	}
X			}
X		}
X
X		/*
X		 * Check to see if there is enough room on the current page
X		 * to print this entry... Otherwise advance to the top of the
X		 * next page
X		 */
X		tmp_line_cnt = line_cnt + elt_lines;
X		if(tmp_line_cnt > MAX_LINES) {
X			fputc('\f',lstfp);
X			line_cnt = 0;
X		}
X
X		/*
X		 * We can now start the printing of the actual entry
X		 */
X		fputs("Name:               ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_NAME,lentry),lstfp,20);
X		fputs("Home address:       ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_HOME_ADDRESS,lentry),lstfp,20);
X		fputs("Home phone:         ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_HOME_PHONE,lentry),lstfp,20);
X		fputs("Company:            ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_COMPANY,lentry),lstfp,20);
X		fputs("Work address:       ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_WORK_ADDRESS,lentry),lstfp,20);
X		fputs("Work phone:         ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_WORK_PHONE,lentry),lstfp,20);
X		fputs("Remarks:            ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_REMARKS,lentry),lstfp,20);
X
X		/* Now print any user defined fields */
X		if(lentry->n_others) {
X			fputs("*** User defined fields ***\n",lstfp);
X			line_cnt++;
X			for(index = 0;index < lentry->n_others; index++)
X				fprintf(lstfp,"%-30s\n",get_other_field(index,lentry));
X		}
X
X		/* Print the date this entry was last updated */
X		fputs("				LAST UPDATED:       ",lstfp);
X		prt_dump(get_basic_rolo_field((int)R_UPDATED,lentry),lstfp,20);
X
X		/* Print two(2) blank lines, and increment the line count */
X		fputs("\n\n",lstfp);
X		line_cnt += elt_lines;
X		line_cnt += 2;		/* For the two blank lines between entries */
X		rptr = get_next_link(rptr);
X	}
X	fclose(lstfp);
X}
X
Xprt_dump(strptr, stream, offset)
Xchar *strptr;
XFILE *stream;
Xint offset;
X{
X	int i;
X
X	if(*strptr == (char)NULL)
X		fputs("<<NONE>>\n",stream);
X	else {
X		for(; *strptr != '\0'; strptr++) {
X			if(*strptr == ';') {
X				fputc('\n',stream);
X				for(i = 0; i < offset; i++)
X					fputc(' ',stream);
X			}
X			else
X				fputc(*strptr,stream);
X		}
X		fputc('\n',stream);
X	}
X}
X
Xmain (argc,argv) int argc; char *argv[];
X
X{
X    int fd,in_use,rolofd;
X    Bool not_own_rolodex;        
X    char *user = "";
X    FILE *tempfp;
X    
X    clearinit();
X    clear_the_screen();
X    
X    /* parse the options and arguments, if any */
X    
X    switch (get_args(argc,argv,T,T)) {
X        case ARG_ERROR : 
X          roloexit(-1);
X        case NO_ARGS :
X          break;
X        case ARGS_PRESENT :
X          if (ALL_LEGAL != legal_options(LEGAL_OPTIONS)) {
X                fprintf(stderr,"illegal option\nusage: %s\n",USAGE);
X                roloexit(-1);
X          }
X    }
X    
X    /* find the directory in which the rolodex file we want to use is */
X    
X    not_own_rolodex = option_present(OTHERUSERFLAG);        
X    if (not_own_rolodex) {
X       if (NIL == (user = option_arg(OTHERUSERFLAG,1)) || 
X           n_option_args(OTHERUSERFLAG) != 1) {
X          fprintf(stderr,"Illegal syntax using -u option\nusage: %s\n",USAGE);
X          roloexit(-1);
X       }
X    }        
X#ifndef MSDOS
X    else {
X       if (0 == (user = getenv("HOME"))) {
X          fprintf(stderr,"Cant find your home directory, no HOME\n");
X          roloexit(-1);
X       }
X    }
X#endif
X    if (not_own_rolodex) {
X#ifndef MSDOS
X       strcpy(rolodir,user);
X#else
X       strcpy(rolodir,home_directory(user));
X#endif
X       if (*rolodir == '\0') {
X          fprintf(stderr,"No user %s is known to the system\n",user);
X          roloexit(-1);
X       }
X    }
X    else strcpy(rolodir,user);
X    
X    /* is the rolodex readable? */
X    
X    if (0 != access(homedir(ROLODATA),R_OK)) {
X        
X       /* No.  if it exists and we cant read it, that's an error */
X        
X       if (0 == access(homedir(ROLODATA),F_OK)) { 
X          fprintf(stderr,"Cant access rolodex data file to read\n");
X          roloexit(-1);
X       }
X       
X       /* if it doesn't exist, should we create one? */
X       /* Under Unix, only if it's our own.  On other systems, it depends.*/
X
X#ifdef UNIX       
X       if (option_present(OTHERUSERFLAG)) {
X          fprintf(stderr,"No rolodex file belonging to %s found\n",user);
X          roloexit(-1);
X       }
X#endif
X       /* try to create it, only if its our own */
X       
X       if (-1 == (fd = creat(homedir(ROLODATA),DEF_PERM))) {
X         if(option_present(OTHERUSERFLAG))
X	   fprintf(stderr,"couldn't create rolodex in %s\n",homedir(ROLODATA));
X	 else
X           fprintf(stderr,"couldn't create rolodex in your home directory\n");
X
X         roloexit(-1);
X       }      
X       
X       else {
X	 stat_buf.st_mode = DEF_PERM;	/* For later mode set */
X         close(fd);
X         fprintf(stderr,"Creating empty rolodex...\n");
X       }
X
X    }
X    
X    /* see if someone else is using it */
X    
X    in_use = (0 == access(homedir(ROLOLOCK),F_OK));
X    
X    /* are we going to access the rolodex only for reading? */
X    
X    if (!(read_only = rolo_only_to_read())) {
X    
X       /* No.  Make sure no one else has it locked. */
X        
X       if (in_use) {
X          locked_action();
X       }
X        
X       /* create a lock file.  Catch interrupts so that we can remove */
X       /* the lock file if the user decides to abort */
X               
X       if (!option_present(NOLOCKFLAG)) {
X          if ((fd = open(homedir(ROLOLOCK),O_EXCL|O_CREAT,00200|00400)) < 0) {
X             fprintf(stderr,"unable to create lock file...\n");
X#ifdef VMS
X	     exit(0);
X#else
X	     exit(1);
X#endif
X	  }
X          rololocked = 1;
X          close(fd);
X#ifdef MSDOS
X#	ifdef MSC
X	  signal(SIGINT,user_interupt);
X#	else
X	  ssignal(SIGINT,user_interrupt);	/* Very Turbo-ish */
X#	endif	/* MSC */
X#else
X          signal(SIGINT,user_interrupt);
X#endif
X       }
X        
X       /* open a temporary file for writing changes to make sure we can */
X       /* write into the directory */
X       
X       /* when the rolodex is saved, the old rolodex is moved to */
X       /* a '~' file (on Unix), the temporary is made to be the new rolodex, */
X       /* and a copy of the new rolodex is made */
X       
X       if (NULL == (tempfp = fopen(homedir(ROLOTEMP),"w"))) {
X           fprintf(stderr,"Can't open temporary file to write to\n");
X           roloexit(-1);
X       }        
X       fclose(tempfp);
X    
X    }
X       
X    allocate_memory_chunk(CHUNKSIZE);
X    
X    if (NULL == (rolofd = open(homedir(ROLODATA),O_RDONLY))) {
X        fprintf(stderr,"Can't open rolodex data file to read\n");
X        roloexit(-1);
X    }
X    
X    /* Get the current rolodex file's permissions */
X    if(fstat(rolofd,&stat_buf))
X    {
X	fprintf(stderr,"Can't fstat rolodex data file\n");
X	roloexit(-1);
X    }
X
X    /* read in the rolodex from disk */
X    /* It should never be out of order since it is written to disk ordered */
X    /* but just in case... */
X    
X    if (!(read_only & 1)) printf("Reading in rolodex from %s\n",homedir(ROLODATA));
X    read_rolodex(rolofd);
X    close(rolofd);
X    if (!(read_only & 1)) printf("%d entries listed\n",rlength(Begin_Rlist));
X    if (reorder_file && !read_only) {
X       fprintf(stderr,"Reordering rolodex...\n");
X       rolo_reorder();
X       fprintf(stderr,"Saving reordered rolodex to disk...\n");
X       save_to_disk();
X    }
X       
X    /* the following routines live in 'options.c' */
X    
X    /* -s option.  Prints a short listing of people and phone numbers to */
X    /* standard output */
X    
X    if (option_present(SUMMARYFLAG)) {
X        print_short();
X#ifdef VMS
X        exit(1);
X#else
X    	exit(0);         
X#endif 
X    }
X    
X    /* rolo <name1> <name2> ... */
X    /* print out info about people whose names contain any of the arguments */
X    
X    if (n_non_option_args() > 0) {
X       print_people();
X#ifdef VMS
X       exit(1);
X#else
X       exit(0);
X#endif
X    }
X    
X    /* regular rolodex program */
X    
X    interactive_rolo();
X#ifdef VMS
X    exit(1);
X#else
X    exit(0);
X#endif
X    
X}
X
X#ifdef MSC
Xsleep(sec)
Xint sec;
X{
X	register long tloc;
X	long time();
X
X	tloc = time((long *)NULL);
X
X	tloc += (long)sec;
X
X	while(time((long *)NULL) <= tloc);
X
X	return(0);
X}
X#endif
END_OF_FILE
if test 18313 -ne `wc -c <'./rolo.c'`; then
    echo shar: \"'./rolo.c'\" unpacked with wrong size!
fi
# end of './rolo.c'
fi
if test -f './toolsdir/ctools.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'./toolsdir/ctools.h'\"
else
echo shar: Extracting \"'./toolsdir/ctools.h'\" \(11422 characters\)
sed "s/^X//" >'./toolsdir/ctools.h' <<'END_OF_FILE'
X/* -*- Mode: C; Package: (CTOOLS C) -*- */
X
X#ifndef Bool
X#define Bool int
X#endif
X
X#ifndef T
X#define T 1
X#endif
X
X#ifndef F
X#define F 0
X#endif
X
X#ifdef VMS
X#ifndef MAXINT
X#define MAXINT 2147483647
X#define MAXINTSTR "2147483647"
X#endif
X#endif
X
X#ifdef VMS
X#ifndef MAXINT
X#define MAXINT 2147483647
X#define MAXINTSTR "2147483647"
X#endif
X#endif
X
X#ifndef MAXPATHLEN
X#define MAXPATHLEN 80
X#endif
X
Xextern char *emalloc();
X
X  /* int space; */
X  /* space must be greater than 0 */
X  /* Causes executution to halt with a 'Fatal error' message if memory */
X  /* cannot be allocated, otherwise returns pointer to malloc-ed space */
X
Xextern char *anewstr();
X
X  /* char *astring; */
X  /* emalloc's space and copies astring into that space.  Returns pointer */
X  /* to new string. */
X
X
Xextern int copy();
X
X  /* char *dest, *src; int n; */
X  /* copies exactly n bytes. */
X  /* return value undefined.  Use only as procedure. */
X
Xextern int fill();
X
X  /* char *addr, ch; int n; */
X  /* copies ch into n consecutive bytes. */
X  /* return value undefined.  Use only as procedure. */
X
Xextern int to_upper_if_lower();
X
X  /* char ch;  Returns possibly upper-cased value. */
X
Xextern int to_lower_if_upper();
X
X  /* char ch;  Returns possibly lower-cased value. */
X
Xextern int buffconcat();
X
X  /* char *buffer, *s1, *s2; */
X  /* s1 and s2 must be null terminated.  Buffer must be at least */
X  /* strlen(s1) + strlen(s2) + 1 characters long.  Buffer is null */
X  /* terminated upon completion. */
X
X  /* return value undefined.  Use only as procedure. */
X
Xextern int nbuffconcat();
X
X  /* char *buffer; int n; char *s1,*s2,*s3,*s4,*s5,*s6; */
X  /* all the strings must be null terminated.  Buffer must be big enough */
X  /* to hold the null terminated result.  0 < n < 7 ..  */
X  /* returns -1 if n is out of range, otherwise 0 */
X
Xextern int slcompare();
X
X  /* char *s1; int l1; char *s2; int l2 */
X  /* does not stop if it encounters a null character. */
X  /* returns 0 if equal, -1 if not equal */
X
Xextern int slge_compare();
X
X  /* char *s1; int l1; char *s2; int l2 */
X  /* does not stop if it encounters a null character. */
X  /* returns 0 if equal, -1 if s1 < s2, 1 if s1 > s2 */
X
Xextern int nocase_compare();
X
X  /* char *s1; int l1; char *s2; int l2 */
X  /* does not stop if it encounters a null character. */
X  /* returns 0 if equal, -1 if s1 < s2, 1 if s1 > s2  case independently. */
X
Xextern char * strfind();
X
X  /* char *s1; char *s2; int fast; */
X  /* finds s2 as a substring of s1.  s1 and s2 are null terminated. */
X  /* returns 0 if not found, otherwise pointer into s1 to first matching */
X  /* character. */
X
X  /* WARNING:  will access off the end of s1 in the interest of efficiency */
X  /* if 'fast' is non-zero. */
X
Xextern char * strncfind();
X
X  /* char *s1; char *s2; int fast; */
X  /* finds s2 as a substring of s1 case independently.  s1 and s2 are */
X  /* null terminated. */
X  /* returns 0 if not found, otherwise pointer into s1 to first matching */
X  /* character. */
X
X  /* WARNING:  will access off the end of s1 in the interest of efficiency */
X  /* if 'fast' is non-zero. */
X
Xextern char * strsearch();
X
X  /* char *s1; int l1; char *s2; int l2 */
X  /* finds s2 as a substring of s1.  Does not stop if it encounters a null. */
X  /* returns pointer into s1, otherwise (char *) 0 if search fails */
X  /* case dependent */
X
Xextern char * strncsearch();
X
X  /* char *s1; int l1; char *s2; int l2 */
X  /* finds s2 as a substring of s1. */
X  /* returns pointer into s1, otherwise (char *) 0 if search fails */
X  /* case independent */
X
Xextern int remove_excess_blanks();
X
X  /* char *newstring, *oldstring; */
X  /* newstring must be long enough to hold the result, which may be as */
X  /* long as oldstring.  oldstring must be null terminated. */
X  /* an excess blank is any blank before the first non-blank character, */
X  /* any blank after the last non-blank character, and any blank immediately */
X  /* following a blank. */
X  /* returns length of newstring */
X
Xextern int yes_or_no_check();
X
X  /* char *astring; */
X  /* returns 1 for yes, 0 for no, -1 for neither. */
X  /* astring must be one of "YES", "Y", "NO", "N" in any capitalization. */
X
X
X/* These routines return T if every char satisfies a certain condition. */
X/* These returns all returns T if given a null string. */
X
Xextern Bool all_digits();
Xextern Bool all_whitespace();
Xextern Bool all_uppercase();
Xextern Bool all_lowercase();
Xextern Bool all_alphabetic();
Xextern Bool all_alphanumeric();
Xextern Bool all_ascii();
X
X
Xextern int str_to_pos_int();
X
X  /* char *astring; int low,high; */
X  /* low must be >= 0. */
X  /* returns -1 if *astring is not composed of digits. */
X  /* returns -2 if the integer is out of range. */
X  /* despite its name, 0 can be returned as a legitimate value. */
X  /* treats all digit strings as decimal. */
X
X
Xextern int sreverse();
X
X  /* char *buffer; char *astring; */
X  /* puts the characters of astring in reverse order into buffer. */
X  /* buffer must be at least as long as astring + 1. */
X  /* buffer is null terminated when done. */
X  /* No return value.  Use only as procedure. */
X
Xextern char *ip_sreverse();
X
X  /* char *astring; */
X  /* Returns astring with its characters reversed. */
X  /* reversal is done in place. */
X
X
X
X#define PATH_MAXPATHLEN 256
X
Xchar *temp_path();
X
X/*
X  char *dir; char *filename;
X
X  Returns a pointer to a character string containing the string
X  <dir>/<filename>.  The pointer points to a buffer which will may get
X  overwritten if any functions in this package are subsequently called.
X  0 is returned if the pathname would exceed PATH_MAXPATHLEN-1 chars.
X*/
X
X
Xchar *perm_path();
X
X/*
X  char *dir; char *filename;
X
X  Same as temp_path, except the pathname string is malloc'ed and is thus
X  permanent unless specifically freed by the user.  Further, no limit
X  on the size of the path is made.
X*/
X
X
Xchar *make_path();
X
X/*
X  char *dir; char *filename; char *extension; Bool perm;
X
X  Creates <dir>/<filename><extension> .  The string returned is permanent
X  or not depending on 'perm'.  If perm is not true, 0 will be returned if
X  the resulting path exceeds PATH_MAXPATHLEN-1 chars.
X*/
X
X
Xchar *make_path_numeric_extension();
X
X/*
X  char *dir; char *filename; int extension; Bool perm;
X
X  Same as make_path except that extension is first converted into a
X  string using sprintf.
X*/
X
X
Xchar *just_filename();
X
X/*  
X  char *path; Bool new; Bool perm;
X
X  Given a path of the form /<x>/<y>/<z> returns <z>.  If new is not set
X  then a pointer into the original input string is returned.  If new is
X  set a copy is returned, either permanent or not depending on perm.
X*/
X
X
X#define ANSWER_NO 0
X#define ANSWER_YES 1
X#define ANSWER_HELP 2
X#define ANSWER_QUIT 3
X#define ANSWER_EOF 4
X
X#define AT_EOF -1
X#define TOO_MANY_CHARS -2
X#define IOERROR -3
X#define TOO_MANY_LINES -4
X#define LINE_TOO_LONG -5
X
Xextern read_yes_or_no ();
X
X  /* FILE *iport, *oport; char *prompt; char *helpstring; char *quitstring; */
X
X  /* prints prompt, then reads from iport until is gets 'Y', 'N', 'YES' or */
X  /* 'NO' (case independently).  If helpstring and/or quitstring are not */
X  /* "" or (char *) 0 then if the user types in one of those ANSWER_HELP */
X  /* or ANSWER_QUIT are returned, otherwise ANSWER_NO or ANSWER_YES are */
X  /* eventually returned. */
X
X
Xextern int getline ();
X
X  /* FILE *iport; char *buffer; int buflen; */
X
X  /* reads a line into buffer.  Does not put the '\n' into buffer. */
X  /* Returns AT_EOF if at end of file when called.  If it encounters */
X  /* end of file after reading at least one character, the eof is treated */
X  /* as if it were a newline.   Returns TOO_MANY_CHARS if more than */
X  /* buflen - 1 characters are read before encountering a newline. */        
X  /* In this case exactly buflen - 1 characters are read. */
X  /* The last character read is always follwed by a '\0'. */
X  /* if successful getline returns the number of characters read exclusive */
X  /* of a terminating newline or eof. */
X
X
Xextern int getlines();
X
X  /* FILE *fp; int n; char ***ptr_lines; char *linebuf; int maxlinelen; */
X  /* See documentation for getfile below */
X  /* If called, 'n' must have a value 0. */
X
Xextern int getfile();
X
X  /* char *filename; char ***ptr_lines; char *linebuf; int maxlinelen; */
X
X  /* read in a file as an array of character strings */
X  /* 'maxlinelen+1' is the maximum length a line of the file is allowed */
X  /* to be.  'linebuf' must be at least 'maxlinelen+1' characters long. */
X  /* Returns the number of lines in the file (and therefore the number */
X  /* of entries in *ptr_lines) if successful.  Returns IOERROR if it */
X  /* could not open the file to read from. Returns TOO_MANY_CHARS if */
X  /* it encounters a line longer than 'maxlinelen' characters.  */
X
X  /* Space for each line is malloc'ed as it is read in and the text for */
X  /* the jth line is stored in (*ptr_lines)[j] */
X
X  /* Only works for fairly small files as it recurses its way through the */
X  /* file and does a lot of malloc-ing.  Use read_file_into_buffer or */
X  /* ngetfile for large files. */
X
Xextern int ngetlines();
X
X /* FILE *fp; int n; char ***ptr_lines; char *linebuf; int maxlinelen; */
X /* Same as getlines, except at most 'n' lines will be read.  Returns */
X /* TOO_MANY_LINES if more than 'n' lines are present. */
X
Xextern int ngetfile();
X
X /* int n; char *filename; char ***ptr_lines; char *linebuf; int maxlinelen; */
X /* See ngetlines above. */
X
Xextern int read_file_into_buffer();
X
X  /* char *filename; 
X     char ***ptr_lines;
X     int maxlines;
X     char *buffer;
X     int buflen;
X     char *linebuffer;
X     int linebuflen;
X  */
X
X  /* *ptr_lines should be an array of character string pointers maxlines */
X  /* big.  buffer should be an array of characters buflen long.  The routine */
X  /* reads lines using getline and stores them into buffer, terminating each */
X  /* with a null.  A pointer to the nth line read is stored in *ptr_lines[n] */
X  /* Returns IOERROR if it cannot open the file for reading, TOO_MANY_LINES */
X  /* if more than maxlines were read in, TOO_MANY_CHARS if buffer is */
X  /* filled before end of file is reached, and LINE_TOO_LONG is any line is */
X  /* longer than linebuflen.  Returns number of lines read in if successful. */
X
Xextern char *efopen();  
X
X  /* char *filename; char *mode */
X
X  /* Actually returns a (FILE *), so one must cast the return value to this */
X  /* type.  It doesn't return a (FILE *) explicitly because then to include */
X  /* this file one would have to include <stdio.h> explicitly before it. */
X  /* The routine simply calls fopen with the same arguments, but prints a */
X  /* reasonable error message and calls exit if the call to fopen fails. */
X
X
Xextern int record_fseek();
X
X  /* FILE *fp; long rnum; int fromwhere; int rsize; int hdrsize; */
X
X  /* Assumes a file is divided into fixed length records with a fixed length */
X  /* header (possibly 0 bytes).  Performs a fseek which moves to the start */
X  /* of a given record.  Record numbers begin with 1. */
X
X  /* Returns what fseek returns. */
X
X  /* 'rnum' is either relative or absolute, depending on 'fromwhere' which */
X  /* corresponds to the 'ptrname' argument of fseek. */
X
X
XBool check_string();
X
X  /* char *str; long minlen; long maxlen; */
X
X  /* Returns T if str is not 0 and has a length between minlen and maxlen */
X  /* inclusived, otherwise returns F. */
X
X
X#ifndef check_int
X#define check_int(i,minval,maxval) ((i) >= (minval) && (i) <= (maxval))
X#endif
END_OF_FILE
if test 11422 -ne `wc -c <'./toolsdir/ctools.h'`; then
    echo shar: \"'./toolsdir/ctools.h'\" unpacked with wrong size!
fi
# end of './toolsdir/ctools.h'
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 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
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list