Subject: v13i050: Screen-oriented rolodex program, Part02/04 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: Dave Ihnat Posting-number: Volume 13, Issue 50 Archive-name: rolodex/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 './datadef.h' <<'END_OF_FILE' X/* datadef.h */ X#define ABORTSTRING "\\" X#define ABORTCHAR '\\' X X#define MAXMATCHES 17 X X#define N_BASIC_FIELDS 8 X#define OTHER -1 X X#ifdef UNIX X#ifdef SYS5 X#define rindex(a,b) strrchr(a,b) X#define index(a,b) strchr(a,b) X#endif X#ifdef BSD X#include X#endif X#endif X Xtypedef enum Basic_Field { X X R_NAME = 0, R_WORK_PHONE, R_HOME_PHONE, R_COMPANY, R_WORK_ADDRESS, X R_HOME_ADDRESS, R_REMARKS, R_UPDATED X X }; X Xextern char *Field_Names[]; X X/* A Rolodex entry */ X Xtypedef struct { X X char *basicfields[N_BASIC_FIELDS]; X int n_others; X char **other_fields; X X } Rolo_Entry, *Ptr_Rolo_Entry; X X X#define get_basic_rolo_field(n,x) (((x) -> basicfields)[(n)]) X#define get_n_others(x) ((x) -> n_others) X#define get_other_field(n,x) (((x) -> other_fields)[n]) X X#define set_basic_rolo_field(n,x,s) (((x) -> basicfields[(n)]) = (s)) X#define set_n_others(x,n) (((x) -> n_others) = (n)) X#define incr_n_others(x) (((x) -> n_others)++) X#define set_other_field(n,x,s) ((((x) -> other_fields)[n]) = (s)) X Xtypedef struct link { X X#ifndef VMS X Ptr_Rolo_Entry entry; X#else X Ptr_Rolo_Entry ventry; X#endif X int matched; X struct link *prev; X#ifndef M_V7 X struct link *next; X#else X struct link *lnext; X#endif X X } Rolo_List, *Ptr_Rolo_List; X X X#ifndef M_V7 X#define get_next_link(x) ((x) -> next) X#else X#define get_next_link(x) ((x) -> lnext) X#endif X#define get_prev_link(x) ((x) -> prev) X#ifndef VMS X#define get_entry(x) ((x) -> entry) X#else X#define get_entry(x) ((x) -> ventry) X#endif X#define get_matched(x) ((x) -> matched) X X#ifndef M_V7 X#define set_next_link(x,y) (((x) -> next) = (y)) X#else X#define set_next_link(x,y) (((x) -> lnext) = (y)) X#endif X#define set_prev_link(x,y) (((x) -> prev) = (y)) X#ifndef VMS X#define set_entry(x,y) (((x) -> entry) = (y)) X#else X#define set_entry(x,y) (((x) -> ventry) = (y)) X#endif X#define set_matched(x) (((x) -> matched) = 1) X#define unset_matched(x) (((x) -> matched) = 0); X Xextern Ptr_Rolo_List Begin_Rlist; Xextern Ptr_Rolo_List End_Rlist; X X#define MAXLINELEN 80 X#define DIRPATHLEN 100 X Xextern int changed; Xextern int name_changed; Xextern int reorder_file; Xextern int rololocked; Xextern int read_only; X Xextern char *rolo_emalloc(); Xextern char *malloc(); Xextern Ptr_Rolo_List new_link_with_entry(); Xextern char *copystr(); Xextern int compare_links(); Xextern char *timestring(); Xextern char *homedir(), *libdir(); Xextern char *getenv(); Xextern char *ctime(); Xextern char *select_search_string(); Xextern int in_search_mode; X X/* X * This structure allows documentation and internal access to help files X */ Xextern char *hlpfiles[]; END_OF_FILE if test 2603 -ne `wc -c <'./datadef.h'`; then echo shar: \"'./datadef.h'\" unpacked with wrong size! fi # end of './datadef.h' fi if test -f './options.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./options.c'\" else echo shar: Extracting \"'./options.c'\" \(7034 characters\) sed "s/^X//" >'./options.c' <<'END_OF_FILE' X/* options.c */ X#ifdef UNIX X#include X#include X#ifdef BSD X#include X#include X#else X#include X#endif X#endif X X#ifdef VMS X#include X#include X#include X#endif X X#ifdef MSDOS X#include X#include X#endif X X#include X#include X X#include X X#ifdef TMC X#include 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 Xprint_short () X X/* print the names and phone numbers of everyone in the rolodex. */ X X{ X X Ptr_Rolo_List rptr; X Ptr_Rolo_Entry lentry; X X rptr = Begin_Rlist; X if (rptr == 0) { X fprintf(stderr,"No entries to print out...\n"); X return; X } X X fprintf ( X stdout, X "\nNAME WORK PHONE HOME PHONE" X ); X fprintf ( X stdout, X "\n---- ---------- ----------\n\n\n" X ); X X while (rptr != 0) { X lentry = get_entry(rptr); X fprintf ( X stdout, X "%-25s %-25s %-25s\n", X get_basic_rolo_field((int) R_NAME,lentry), X get_basic_rolo_field((int) R_WORK_PHONE,lentry), X get_basic_rolo_field((int) R_HOME_PHONE,lentry) X ); X rptr = get_next_link(rptr); X } X X } X X Xperson_match (person,lentry) char *person; Ptr_Rolo_Entry lentry; X X/* Match against a rolodex entry's Name and Company fields. */ X/* Thus if I say 'rolo CCA' I will find people who work at CCA. */ X/* This is good because sometimes you will forget a name but remember */ X/* the company the person works for. */ X X{ X char *name, *company; X int len; X len = strlen(person); X name = get_basic_rolo_field((int) R_NAME,lentry); X company = get_basic_rolo_field((int) R_COMPANY,lentry); X if (strncsearch(name,strlen(name),person,len)) return(1); X if (strncsearch(company,strlen(company),person,len)) return(1); X return(0); X} X X Xint find_all_person_matches (person) char *person; X X{ X Ptr_Rolo_List rptr = Begin_Rlist; X int count = 0; X while (rptr != 0) { X unset_matched(rptr); X if (person_match(person,get_entry(rptr))) { X set_matched(rptr); X count++; X } X rptr = get_next_link(rptr); X } X return(count); X} X X Xlook_for_person (person) char *person; X X/* search against Name and Company over the rolodex. If a match is found */ X/* display the entry and give the user a choice of what to do next. */ X X{ X Ptr_Rolo_List rptr; X int found = 0,result,nmatches; X static displayed_menu = 0; X char *response; X X rptr = Begin_Rlist; X while (rptr != 0) { X if (person_match(person,get_entry(rptr))) { X clear_the_screen(); X display_entry(get_entry(rptr)); X if (!found) { X nmatches = find_all_person_matches(person); X if (nmatches > 1) { X printf ( X "There are %d other entries which match '%s'\n\n", X nmatches - 1, person X ); X } X } X found = 1; X try_again : X if (!displayed_menu) cathelpfile(POPTIONMENU,(char *)NULL,0); X displayed_menu = 1; X menu_match ( X &result, X &response, X "Select option (? for help): ", X 0,1,1,1,6, X "Continue",P_CONTINUE, X "",P_CONTINUE, X "Next",P_NEXT_PERSON, X "\\",P_ABORT, X "Help",P_HELP, X "?",P_HELP X ); X switch (result) { X case P_CONTINUE : X break; X case P_NEXT_PERSON : X return(0); X /* break; */ X case P_ABORT : X roloexit(0); X break; X case P_HELP : X cathelpfile(POPTIONSHELP,"person search options",1); X goto try_again; X default : X fprintf(stderr,"Impossible return from menu_match\n"); X exit(-1); X } X } X rptr = get_next_link(rptr); X } X if (!found) { X fprintf(stderr,"\nNo entry found for '%s'\n\n",person); X sleep(2); X } X else { X printf("No further matches for '%s'\n",person); X sleep(2); X } X return(0); X} X X Xprint_people () X X{ X int index; X char *person; X index = 1; X while (T) { X if (0 == (person = non_option_arg(index++))) break; X look_for_person(person); X } X} X X Xinteractive_rolo () X X/* Top level of the iteractive rolodex. This code is just a big switch */ X/* which passes responsibility off to various routines in 'operatns.c' */ X/* and 'update.c' */ X X{ X X int result,rval,field_index; X char *response,*field_name,*search_string; X X fprintf(stdout,"\n\nTMC ROLODEX, Version %s\n\n\n",VERSION); X X while (1) { X X cathelpfile(MAINMENU,(char *)NULL,0); X rval = menu_match ( X &result, X &response, X "Select option (? for help): ", X 0,1,0,1,7, X "+",M_ADD, X "%",M_PERUSE, X "\\",M_EXIT, X "?",M_HELP, X "*",M_SAVE, X "$",M_SEARCH_BY_OTHER, X "!",M_PRINT_TO_LASER_PRINTER X ); X X switch (rval) { X X case MENU_AMBIGUOUS : X case MENU_ERROR : X fprintf(stderr,"Impossible return 1 from main menu_match\n"); X exit(-1); X break; X X case MENU_NO_MATCH : X response = copystr(response); X rolo_search_mode((int) R_NAME,Field_Names[(int) R_NAME],response); X break; X X case MENU_MATCH : X X switch (result) { X case M_ADD : X rolo_add(); X break; X case M_SEARCH_BY_OTHER : X if ((-1 == select_field_to_search_by(&field_index,&field_name)) || X (0 == (search_string = select_search_string()))) { X break; X } X rolo_search_mode(field_index,field_name,search_string); X break; X case M_PRINT_TO_LASER_PRINTER : X /* fprintf(stderr,"Not implemented\n"); */ X pretty_print(); X sleep(1); X break; X case M_PERUSE : X rolo_peruse_mode(Begin_Rlist); X break; X case M_EXIT : X save_and_exit(0); X break; X case M_SAVE : X if (changed) { X save_to_disk(); X sleep(1); X } X else { X printf("No changes to be saved...\n"); X sleep(2); X } X break; X case M_HELP : X cathelpfile(MOPTIONHELP,"top level menu",1); X any_char_to_continue(); X break; X default : X fprintf(stderr,"Impossible result from menu_match...\n"); X save_and_exit(-1); X } X break; X X case MENU_EOF : X user_eof(); X break; X X default : X fprintf(stderr,"Impossible return 2 from menu_match\n"); X save_and_exit(-1); X X } X X clear_the_screen(); X X } X X} END_OF_FILE if test 7034 -ne `wc -c <'./options.c'`; then echo shar: \"'./options.c'\" unpacked with wrong size! fi # end of './options.c' fi if test -f './rlist.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./rlist.c'\" else echo shar: Extracting \"'./rlist.c'\" \(2570 characters\) sed "s/^X//" >'./rlist.c' <<'END_OF_FILE' X/* rlist.c */ X#include "datadef.h" X X Xint rlength (rlist) Ptr_Rolo_List rlist; X{ X return((rlist == 0) ? 0 : 1 + rlength(get_next_link(rlist))); X} X X XPtr_Rolo_List new_link_with_entry () X{ X Ptr_Rolo_List newlink; X Ptr_Rolo_Entry newentry; X newlink = (Ptr_Rolo_List) rolo_emalloc(sizeof(Rolo_List)); X unset_matched(newlink); X newentry = (Ptr_Rolo_Entry) rolo_emalloc(sizeof(Rolo_Entry)); X set_n_others(newentry,0); X newentry -> other_fields = 0; X set_entry(newlink,newentry); X return(newlink); X} X X Xrolo_insert (link,compare) Ptr_Rolo_List link; int (*compare)(); X X{ X Ptr_Rolo_List rptr; X X if (Begin_Rlist == 0) { X Begin_Rlist = link; X End_Rlist = link; X set_prev_link(link,0); X set_next_link(link,0); X return; X } X X /* find the element it goes before, alphabetically, and insert it */ X X rptr = Begin_Rlist; X while (rptr != 0) { X if (1 == (*compare)(rptr,link)) { X set_prev_link(link,get_prev_link(rptr)); X set_next_link(link,rptr); X if (get_prev_link(rptr) != 0) X set_next_link(get_prev_link(rptr),link); X else X Begin_Rlist = link; X set_prev_link(rptr,link); X return; X } X rptr = get_next_link(rptr); X } X X /* it goes at the end */ X X set_next_link(End_Rlist,link); X set_prev_link(link,End_Rlist); X set_next_link(link,0); X End_Rlist = link; X return; X X} X X Xrolo_delete (link) Ptr_Rolo_List link; X X{ X if (read_only) X { X printf("Readonly mode: Cannot delete entries.\n"); X sleep(2); X return(1); X } X X if (get_next_link(link) == 0 && get_prev_link(link) == 0) { X Begin_Rlist = 0; X End_Rlist = 0; X return(0); X } X X if (get_prev_link(link) == 0) { X Begin_Rlist = get_next_link(link); X set_prev_link(Begin_Rlist,0); X return(0); X } X X if (get_next_link(link) == 0) { X End_Rlist = get_prev_link(link); X set_next_link(End_Rlist,0); X return(0); X } X X set_next_link(get_prev_link(link),get_next_link(link)); X set_prev_link(get_next_link(link),get_prev_link(link)); X return(0); X X} X X Xcompare_links (l1,l2) Ptr_Rolo_List l1,l2; X X{ X Ptr_Rolo_Entry e1,e2; X char *n1,*n2; X e1 = get_entry(l1); X e2 = get_entry(l2); X n1 = get_basic_rolo_field((int) R_NAME,e1); X n2 = get_basic_rolo_field((int) R_NAME,e2); X return(nocase_compare(n1,strlen(n1),n2,strlen(n2))); X} X X Xrolo_reorder () X{ X Ptr_Rolo_List rptr,oldlink; X rptr = Begin_Rlist; X Begin_Rlist = 0; X while (rptr != 0) { X oldlink = get_next_link(rptr); X rolo_insert(rptr,compare_links); X rptr = oldlink; X } X} END_OF_FILE if test 2570 -ne `wc -c <'./rlist.c'`; then echo shar: \"'./rlist.c'\" unpacked with wrong size! fi # end of './rlist.c' fi if test -f './rolo.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./rolo.1'\" else echo shar: Extracting \"'./rolo.1'\" \(2616 characters\) sed "s/^X//" >'./rolo.1' <<'END_OF_FILE' X.TH ROLO 1 "18 November 1984" X.UC 4 X.SH NAME Xrolo \- use an online rolodex, containing information about people. X.SH SYNOPSIS X.B rolo X[ name1 name2 ... \-u otheruser \-s \-l \-r ] X.SH DESCRIPTION XBy default X.I rolo Xreads in a rolodex data file from the user's home directory, prints Xout a menu of choices, and lets the user scan, update, delete and add to Xhis personal database of people. If no rolodex database exists one Xis created. X.I rolo Xchecks to see that the rolodex database is not already in use. X.PP XThe command line options are: X.TP X.B \-u otheruser XUses the rolodex database in the 'otheruser' home directory. This may Xnot be possible if the directory or the database is read or write protected. XFor VMS or DOS, it will simply use files found in directory 'otheruser'; Xthis need not be the home directory. X.TP X.B \-s XPrints people's names, work phone numbers and home phone numbers in a nice Xformat to standard output. X.TP X.B \-l XNormally the rolodex database is locked when being used. This option Xunlocks the database as soon as it is read in. The \-s option implies this. X.TP X.B \-r XReadonly mode. Assuming that the files may be read, this allows readonly Xaccess to the database. X.PP XInvoking X.I rolo Xfollowed by a list of names causes X.I Xrolo Xto search the database for all people whose names or company Xaffiliations contain any of the name arguments as substrings. All the Xinformation about each person is printed to standard output, the program Xpausing after each record is printed. Using this feature causes the Xdatabase to become unlocked, since this is a read-only mode. X.PP XExtensive help is available on-line. Typing '?' or 'help' will generally Xprint a help file for you. X.SH FILES X/usr/local/src/rolo for the source. X.PP X/usr/local/lib/rolo for help files. X.PP X/usr/local/bin/rolo the executable image. X.PP X.PP X.SH AUTHOR XPeter Webb wrote the first rolodex program. X.PP XJP Massar revised and then complete rewrote this older version. XNet address: massar@think.com, ihnp4!think!massar. X.PP XDave Ihnat revised the program to work for VMS and MS/PC-DOS; and to support Xthe readonly command-line flag. Numerous other minor enhancements, bug fixes, Xdelinting, etc. XNet address: ihnp4!homebru!ignatz. X X.PP XSteve Steiner implemented the pretty-print option, and with Dave Ihnat hammered Xout the current version which runs on VMS, AT&T Unix Sys III/V, BSD 4.x Unix, Xand MS/PC-DOS under Microsoft C and Turbo-C. (*whew!*) XNet address: ihnp4!aicchi!steiner. X.SH BUGS XThere is no way to keep certain entries private. X.PP XYou can't get a short summary of only a subset of people. END_OF_FILE if test 2616 -ne `wc -c <'./rolo.1'`; then echo shar: \"'./rolo.1'\" unpacked with wrong size! fi # end of './rolo.1' fi if test -f './search.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./search.c'\" else echo shar: Extracting \"'./search.c'\" \(9196 characters\) sed "s/^X//" >'./search.c' <<'END_OF_FILE' X/* search.c */ X#include X#include X X#ifdef TMC X#include 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 Xchar *select_search_string () X X/* returns 0 if user wants to quit, otherwise returns a user-provided string */ X X{ X int rval; X char *response; X rval = rolo_menu_data_help_or_abort ( X "Enter string to search for: ", X SEARCHSTRINGHELP, X "string to search for", X &response X ); X switch (rval) { X case MENU_ABORT : X return(0); X /* break; */ X case MENU_DATA : X return(copystr(response)); X /* break; */ X } X X return(0); X} X X Xselect_field_to_search_by (ptr_index,ptr_name) int *ptr_index; char **ptr_name; X X/* returns -1 if the user wishes to abort, otherwise returns 0. */ X/* if the user wishes to search by a user-defined field, *ptr_index is OTHER */ X/* and *ptr_name is the user-provided name of the field. */ X X{ X char *response; X int nchoices = N_BASIC_FIELDS; X int field_index,rval; X X redo : X X /* list out each basic field that the user can search by. The user is */ X /* also given an option to search by a user-provided field. At the */ X /* moment you cannot search by 'Date Updated' */ X X display_field_names(); X X /* reask : */ X X rval = rolo_menu_number_help_or_abort ( X "Number of item to search by? ", X 1,nchoices,&field_index X ); X X switch (rval) { X X case MENU_ABORT : X return(-1); X /* break; */ X X case MENU_HELP : X cathelpfile(FIELDSEARCHHELP,"entering search field",1); X any_char_to_continue(); X goto redo; X /* break; */ X X case MENU_DATA : X X if (field_index != nchoices) { X *ptr_index = field_index - 1; X *ptr_name = copystr(Field_Names[*ptr_index]); X return(0); X } X X /* the user wants to search by a user-specified field */ X X else { X X /* reask2 : */ X X rval = rolo_menu_data_help_or_abort ( X "Name of user-defined field? ", X USERFIELDHELP, X "name of user field to search by", X &response X ); X switch (rval) { X case MENU_ABORT : X return(-1); X /* break; */ X case MENU_DATA : X *ptr_index = OTHER; X *ptr_name = copystr(response); X return(0); X /* break; */ X } X } X break; X } X return(0); X} X X Xmatch_by_name_or_company (search_string,sslen) char *search_string; int sslen; X X{ X char *name,*company; X Ptr_Rolo_Entry lentry; X Ptr_Rolo_List rlist; X int count = 0; X X rlist = Begin_Rlist; X while (rlist != 0) { X lentry = get_entry(rlist); X name = get_basic_rolo_field((int) R_NAME,lentry); X company = get_basic_rolo_field((int) R_COMPANY,lentry); X if (strncsearch(name,strlen(name),search_string,sslen) || X strncsearch(company,strlen(company),search_string,sslen)) { X set_matched(rlist); X count++; X } X } X return(count); X X} X X Xmatch_link (rlink,field_index,field_name,fnlen,search_string,sslen) X X /* if a match is present, sets the 'matched' field in the link, and */ X /* returns 1, otherwise returns 0. */ X X Ptr_Rolo_List rlink; X int field_index; X char *field_name; X int fnlen; X char *search_string; X int sslen; X X{ X Ptr_Rolo_Entry lentry; X char *field; X char name[100]; X int j; X X lentry = get_entry(rlink); X X if (field_index == OTHER) { X for (j = 0; j < get_n_others(lentry); j++) { X field = get_other_field(j,lentry); X while (*field != ':') *field++; X *field = '\0'; X remove_excess_blanks(name,get_other_field(j,lentry)); X *field++ = ':'; X if (0 != nocase_compare(name,strlen(name),field_name,fnlen)) { X continue; X } X if (strncsearch(field,strlen(field),search_string,sslen)) { X set_matched(rlink); X return(1); X } X } X return(0); X } X else { X field = get_basic_rolo_field(field_index,lentry); X if (strncsearch(field,strlen(field),search_string,sslen)) { X set_matched(rlink); X return(1); X } X return(0); X } X X} X X Xfind_all_matches (field_index,field_name,search_string,ptr_first_match) X X /* mark every entry in the rolodex which matches against the search_string */ X /* If the search_string is a substring of the data in the given field then */ X /* that is a match. Return the number of matches. If there are any */ X /* matches *ptr_first_match will contain the first matching link. */ X X int field_index; X char *field_name, *search_string; X Ptr_Rolo_List *ptr_first_match; X X{ X char buffer[100]; X int fnlen,sslen; X int count = 0; X Ptr_Rolo_List rlist = Begin_Rlist; X X remove_excess_blanks(buffer,field_name); X fnlen = strlen(buffer); X sslen = strlen(search_string); X X while (rlist != 0) { X unset_matched(rlist); X if (match_link(rlist,field_index,buffer,fnlen,search_string,sslen)) { X if (count++ == 0) *ptr_first_match = rlist; X } X rlist = get_next_link(rlist); X } X X return(count); X X} X X Xrolo_search_mode (field_index,field_name,search_string) X X int field_index; X char *field_name; X char *search_string; X X{ X int rval,n,j,menuval,ival; X char *response; X Ptr_Rolo_List first_match,rmatch,rlist; X X /* mark every entry in the rolodex that satisfies the search criteria */ X /* and return the number of items so marked. */ X X in_search_mode = 1; X n = find_all_matches(field_index,field_name,search_string,&first_match); X X if (n == 0) { X printf ( X "No match found for search string '%s' for field '%s'\n", X search_string, X field_name X ); X sleep(2); X goto rtn; X } X X /* if the match is unique, just display the entry. */ X X else if (n == 1) { X display_entry(get_entry(first_match)); X switch (entry_action(first_match)) { X case E_CONTINUE : X printf("No further matches...\n"); X sleep(2); X break; X default : X break; X } X goto rtn; X } X X /* if there are too many matches to itemize them on a single small */ X /* screen, tell the user that there are lots of matches and suggest */ X /* he specify a better search string, but give him the option of */ X /* iterating through every match. */ X X else if (n > MAXMATCHES) { X clear_the_screen(); X printf("There are %d entries that match '%s' !\n",n,search_string); X printf("Type 'v' to view them one by one,\n"); X printf("or '\\' to abort and enter a more specific search string: "); X rval = rolo_menu_data_help_or_abort ( X "",MANYMATCHHELP,"many matching entries",&response X ); X if (rval == MENU_ABORT) goto rtn; X display_list_of_entries(Begin_Rlist); X goto rtn; X } X X /* there are a small number of matching entries. List the name of each */ X /* matching entry and let the user select which one he wants to view, */ X /* or whether he wants to iterate through each matching entry. */ X X else { X relist : X summarize_entry_list(Begin_Rlist,search_string); X cathelpfile(PICKENTRYMENU,(char *)NULL,0); X rval = menu_match ( X &menuval,&response, X ": ", X 0,1,0,1,4, X "\\",S_ABORT, X "?",S_HELP, X "Help",S_HELP, X "",S_SCAN_ONE_BY_ONE X ); X switch (rval) { X case MENU_MATCH : X switch (menuval) { X case S_HELP : X cathelpfile(PICKENTRYHELP,"selecting entry to view",1); X any_char_to_continue(); X goto relist; X /* break; */ X case S_ABORT : X goto rtn; X /* break; */ X case S_SCAN_ONE_BY_ONE : X display_list_of_entries(Begin_Rlist); X goto rtn; X /* break; */ X } X break; X X /* make sure the user entered a valid integer, ival */ X /* if so, find the ivalth entry marked as matched in the rolodex */ X /* and display it. */ X X case MENU_NO_MATCH : X ival = str_to_pos_int(response,1,n); X if (ival < 0) { X printf("Not a valid number... Please try again\n"); X sleep(2); X goto relist; X } X rlist = Begin_Rlist; X for (j = 0; j < ival; j++) { X while (rlist != 0) { X if (get_matched(rmatch = rlist)) break; X rlist = get_next_link(rlist); X } X if (rlist != 0) rlist = get_next_link(rlist); X } X display_entry(get_entry(rmatch)); X switch (entry_action(rmatch)) { X case E_CONTINUE : X case E_PREV : X goto relist; X /* break; */ X default : X goto rtn; X /* break; */ X } X /* break; */ X } X } X X rtn : X in_search_mode = 0; X X} END_OF_FILE if test 9196 -ne `wc -c <'./search.c'`; then echo shar: \"'./search.c'\" unpacked with wrong size! fi # end of './search.c' fi if test -f './toolsdir/args.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./toolsdir/args.c'\" else echo shar: Extracting \"'./toolsdir/args.c'\" \(9032 characters\) sed "s/^X//" >'./toolsdir/args.c' <<'END_OF_FILE' X#include X#include X#include "basics.h" X#include "args.h" X#include "sys5.h" X X/***************************************************************************/ X/***************************************************************************/ X X /***** COMMAND LINE ARGUMENT PARSER *****/ X X/***************************************************************************/ X/***************************************************************************/ X X/* Author: JP Massar */ X X/* parses command line arguments in argv under the following rules: */ X/* any argument not beginning with '-' is treated as a unit. */ X/* any argument beginning with a '-' must have the remaining characters */ X/* be in the set {a-zA-Z}. Each character is considered a separate option. */ X/* (Thus -abc is equivalent to -a -b -c). Non-dashed arguments are */ X/* associated with the option that precedes them, e.g, 'cat -a foo -b bar' */ X/* has foo associated with 'a' and bar associated with 'b'. A non-dashed */ X/* argument preceding any option is not associated with any option. */ X/* users can specify whether duplicate options are errors. */ X X/* Non-dashed arguments are henceforth referred to as arguments, and */ X/* dashed arguments are henceforth referred to as options. */ X/* Arguments are ordered from left to right. */ X X/* 5/8/87 - D. M. Ihnat. Modified for DOS/VMS to honor '/' as a separator. X*/ X/* The following routines are available to users: */ X X/* get_args() called to parse argv. Detects syntactic errors */ X/* any_option_present() are any options present in the command line? */ X/* option_present() is an option present? */ X/* option_arg() returns an argument associated with an option */ X/* non_option_arg() returns an argument not associated with any option */ X/* non_dash_arg() returns an argument */ X/* n_option_args() returns number of args associated with an option */ X/* n_non_option_args() rtns number of args not associated with any option */ X/* n_non_dash_args() returns number of arguments. */ X/* check_option_args() checks bounds on number of args assoc with an option */ X/* legal_options() checks that options provided are a subset of a-zA-Z */ X/* set_option() turns on option */ X/* error_message() prints out an illegal syntax error message to stderr */ X X Xint option_to_index (achar) char achar; X{ X if (isupper(achar)) return(achar - 'A'); X if (islower(achar)) return(achar - 'a' + 26); X return(NO_OPTION); X} X Xchar index_to_option (index) int index; X{ X if (index < 26) return('A' + index); X return('a' + index - 26); X} X X X/* the command line arguments are parsed into Cmd when get_args returns */ X/* successfully */ X Xstatic Ptr_Cmd_Line Cmd = NIL; X Xint get_args (argc, argv, dup_error, print_msg) X X /* Returns one of NO_ARGS, ARG_ERROR, or ARGS_PRESENT */ X X int argc; X char **argv; X Bool print_msg, dup_error; X X{ X int i,j,dash_index; X Ptr_Cmd_Arg arg,last = NIL; X char echar, *optr; X X Cmd = (Ptr_Cmd_Line) malloc(sizeof(Cmd_Line)); X Cmd -> non_dash_arg_list = NIL; X for (j = 0; j < MAX_OPTIONS; j++) (Cmd -> dash_options)[j] = F; X X if (argc == 1) return(NO_ARGS); X X i = 0; X dash_index = NO_OPTION; X X while (++i < argc) { X X /* parse arguments (i.e., anything not beginning with '-' */ X X#ifdef UNIX X if (argv[i][0] != '-') { X#endif X#ifdef VMS X if ((argv[i][0] != '/') && (argv[i][0] != '-')) { X#endif X#ifdef MSDOS X if ((argv[i][0] != '/') && (argv[i][0] != '-')) { X#endif X arg = (Ptr_Cmd_Arg) malloc(sizeof(Cmd_Arg)); X arg -> option = argv[i]; X arg -> option_index = dash_index; X arg -> next = NIL; X if (last == NIL) { X Cmd -> non_dash_arg_list = arg; X last = arg; X } X else { X last -> next = arg; X last = arg; X } X continue; X } X X /* parse options. '-' by itself is illegal syntax */ X X if (strlen(argv[i]) < 2) { X#ifdef UNIX X echar = '-'; X#endif X#ifdef VMS X echar = '/'; X#endif X#ifdef MSDOS X echar = '/'; X#endif X goto parse_error; X } X optr = argv[i]; X optr++; X while (*optr != '\0') { X if (NO_OPTION == (dash_index = option_to_index(*optr))) { X echar = *optr; X goto parse_error; X }; X if ((Cmd -> dash_options)[dash_index] && dup_error) { X echar = *optr; X goto duplicate_error; X } X (Cmd -> dash_options)[dash_index] = T; X optr++; X } X X } X X return(ARGS_PRESENT); X X parse_error : X X if (print_msg) fprintf(stderr,"illegal option: %c\n",echar); X return(ARG_ERROR); X X duplicate_error: X X if (print_msg) fprintf(stderr,"duplicate option: %c\n",echar); X return(ARG_ERROR); X X} X X XBool option_present (achar) char achar; X{ X return((Cmd -> dash_options)[option_to_index(achar)]); X} X X XBool any_option_present () X{ X int j; X for (j = 0; j < MAX_OPTIONS; j++) { X if ((Cmd -> dash_options)[j]) return(T); X } X return(F); X} X X Xchar * get_option_arg (i,n) int i; int n; X X /* get the nth option associated with the option whose index is 'i' */ X X{ X int count; X Ptr_Cmd_Arg args; X args = Cmd -> non_dash_arg_list; X count = 0; X while (args != NIL) { X if (i == args -> option_index && ++count == n) { X return(args -> option); X } X args = args -> next; X } X return(NIL); X} X X Xchar * option_arg (achar,n) char achar; int n; X{ X return(get_option_arg(option_to_index(achar),n)); X} X X Xchar * non_option_arg (n) int n; X{ X return(get_option_arg(NO_OPTION,n)); X} X X Xchar * non_dash_arg (n) int n; X X{ X int count = 0; X Ptr_Cmd_Arg arg; X arg = Cmd -> non_dash_arg_list; X while (arg != NIL) { X if (++count == n) return(arg -> option); X arg = arg -> next; X } X return(NIL); X} X Xprint_args () X X /* debugging routine which prints out the Cmd structure in readable form */ X X{ X int j,i,n; X char *option,ochar; X X if (Cmd == NIL) { X printf("\n\nNo arguments\n\n"); X return; X } X X printf("\n\narguments not associated with options: "); X n = 1; X while (T) { X if (NIL == (option = non_option_arg(n++))) break; X printf("%s ",option); X } X printf("\n"); X X printf("\n\noptions and their arguments:\n\n"); X for (j = 0; j < MAX_OPTIONS; j++) { X ochar = index_to_option(j); X if (option_present(ochar)) { X printf("%c : \t",ochar); X i = 1; X while (T) { X if (NIL == (option = option_arg(ochar,i++))) break; X printf("%s ",option); X } X printf(" \t(# is %d)",n_option_args(ochar)); X printf("\n"); X } X } X X printf("\nnumber of non-dashed args is: %d\n",n_non_dash_args()); X printf("number of non-option args is : %d\n",n_non_option_args()); X X} X X X#define ALL -1 X#define NON_OPTION -2 X Xint arg_counter (type) int type; X X /* general routine which counts arguments */ X /* if type isn't ALL or NON_OPTION then type is an index of an option */ X X{ X int index,count; X Ptr_Cmd_Arg arg; X arg = Cmd -> non_dash_arg_list; X count = 0; X index = (type == NON_OPTION) ? NO_OPTION : type; X while (arg != NIL) { X if (type == ALL) { X count++; X } X else if (arg -> option_index == index) count++; X arg = arg -> next; X } X return(count); X} X Xint n_option_args (achar) char achar; X{ X return(arg_counter(option_to_index(achar))); X} X Xint n_non_option_args () X{ X return(arg_counter(NON_OPTION)); X} X Xint n_non_dash_args () X{ X return(arg_counter(ALL)); X} X X Xset_option (achar) char achar; X{ X (Cmd -> dash_options)[option_to_index(achar)] = T; X} X X Xerror_message (progname, argv, i, usage) X char *progname; char ** argv; int i; char *usage; X{ X fprintf(stderr,"\nillegal argument to %s : %s\n",progname,argv[i]); X if (usage) fprintf(stderr,"%s\n",usage); X} X X XBool Xcheck_option_args (achar,themin,themax) char achar; int themin,themax; X{ X int n; X if (themin > themax) return(T); X n = n_option_args(achar); X return ((Bool) (n >= themin && n <= themax)); X} X X Xchar legal_options (legalstring) char *legalstring; X X /* are all the options the user specified characters in legalstring? */ X /* returns ALL_LEGAL if so, otherwise the first option not in the string */ X X{ X int j; X char option, *s; X for (j = 0; j < MAX_OPTIONS; j++) { X if ((Cmd -> dash_options)[j]) { X option = index_to_option(j); X s = legalstring; X while (T) { X if (*s == '\0') return(option); X if (*s == option) break; X s++; X } X } X } X return(ALL_LEGAL); X} END_OF_FILE if test 9032 -ne `wc -c <'./toolsdir/args.c'`; then echo shar: \"'./toolsdir/args.c'\" unpacked with wrong size! fi # end of './toolsdir/args.c' fi if test -f './toolsdir/menu.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./toolsdir/menu.c'\" else echo shar: Extracting \"'./toolsdir/menu.c'\" \(8281 characters\) sed "s/^X//" >'./toolsdir/menu.c' <<'END_OF_FILE' X#include X#ifdef UNIX X#include X#endif X#ifdef VMS X#include X#endif X#ifdef MSDOS X#include X#endif X#include "basics.h" X#include "ctools.h" X#include "menu.h" X#include "sys5.h" X X Xstatic char line[MAX_MENU_RESPONSE_LENGTH]; X X Xmenu_match ( X X ptr_rval,ptr_ur,prompt,casetest,isub,r_no_match,r_ambiguous, X#ifndef MSDOS X n_options,va_alist X#else X n_options X#endif X X ) X X int *ptr_rval; X char **ptr_ur; X char *prompt; X int casetest; X int isub; X int r_no_match; X int r_ambiguous; X int n_options; X#ifdef VMS X va_dcl X#endif X#ifdef UNIX X int va_alist; X#endif X{ X X char sline[MAX_MENU_RESPONSE_LENGTH]; X char *options[MAX_MENU_OPTIONS]; X int rvals[MAX_MENU_OPTIONS]; X int j,found,len,optionlen,rval,compare,blankindex; X#ifdef VMS X int args_offset = 0; /* args_offset must be 0 in order for this to work */ X#endif X va_list pvar; X X if (n_options > MAX_MENU_OPTIONS) return(MENU_ERROR); X for (j = 0; j < MAX_MENU_RESPONSE_LENGTH; j++) line[j] = ' '; X X /* grab all the menu options and return values. */ X X blankindex = -1; X#ifdef VMS X va_start_1(pvar,args_offset); X#endif X#ifdef UNIX X va_start(pvar); X#endif X#ifdef MSDOS X va_start(pvar,n_options); X#endif X X for (j = 0; j < n_options; j++) { X options[j] = va_arg(pvar,char *); X if (0 == strlen(options[j])) { X if (blankindex == -1) blankindex = j; X } X rvals[j] = va_arg(pvar,int); X } X va_end(pvar); X X try_again : X X /* get the user's response */ X X printf("%s",prompt); X switch (rval = getline(stdin,line,MAX_MENU_RESPONSE_LENGTH)) { X case AT_EOF : X return(MENU_EOF); X /* break; */ X case TOO_MANY_CHARS : X fprintf(stderr,"Response is too long to handle. Please try again\n"); X goto try_again; X /* break; */ X default : X *ptr_ur = line; X remove_excess_blanks(sline,line); X len = strlen(sline); X break; X } X X found = 0; X rval = MENU_NO_MATCH; X X if (all_whitespace(sline)) { X if (blankindex == -1) goto try_again; X rval = MENU_MATCH; X *ptr_rval = rvals[blankindex]; X goto rtn; X } X X for (j = 0; j < n_options; j ++) { X X /* if what he typed in is longer than any option it can't match */ X X optionlen = strlen(options[j]); X if (len > optionlen) continue; X X /* if we aren't matching initial substrings, the response must */ X /* match exactly. */ X X if (!isub && len != optionlen) continue; X X /* use different comparision functions depending on whether case */ X /* is important or not. */ X X compare = casetest ? X strncmp(sline,options[j],len) : X nocase_compare(sline,len,options[j],len); X X /* if we must match exactly, if we find a match exit immediately. */ X /* if we can match on an initial substring, if we've already found */ X /* a match then we have an ambiguity, otherwise note that we've */ X /* matched and continue looking in case of ambiguities */ X X if (0 == compare) { X if (!isub) { X found = 1; X *ptr_rval = rvals[j]; X rval = MENU_MATCH; X break; X } X if (found && isub) { X rval = MENU_AMBIGUOUS; X break; X } X else { X found = 1; X *ptr_rval = rvals[j]; X rval = MENU_MATCH; X } X } X else { X continue; X } X } X X rtn : X X switch (rval) { X case MENU_MATCH : X break; X case MENU_NO_MATCH : X if (r_no_match) { X printf("Your response does not match any option. Try again\n"); X goto try_again; X } X break; X case MENU_AMBIGUOUS : X if (r_ambiguous) { X printf("Your response is ambiguous. Try again\n"); X goto try_again; X } X break; X default : X fprintf(stderr,"Impossible case value in menu_match\n"); X exit(-1); X } X X return(rval); X X} X X Xmenu_yes_no (prompt,allow_help) char *prompt; int allow_help; X X{ X int menuval,rval; X char *response; X X redo : X X if (!allow_help) { X rval = menu_match ( X &menuval,&response, X prompt, X 0,1,0,0,2, X "Yes",MENU_YES, X "No",MENU_NO X ); X } X else { X rval = menu_match ( X &menuval,&response, X prompt, X 0,1,0,0,4, X "Yes",MENU_YES, X "No",MENU_NO, X "?",MENU_HELP, X "Help",MENU_HELP X ); X } X switch (rval) { X case MENU_MATCH : X return(menuval); X /* break; */ X case MENU_NO_MATCH : X fprintf(stderr,"Please type 'Yes' or 'No'...\n"); X goto redo; X /* break; */ X case MENU_EOF : X return(MENU_EOF); X /* break; */ X default : X fprintf(stderr,"Fatal error: Impossible return in menu_yes_no\n"); X exit(-1); X } X X return(0); X} X X Xint menu_data_help_or_abort (prompt,abortstring,ptr_response) X X char *prompt, *abortstring, **ptr_response; X X{ X int rval,menuval; X rval = menu_match ( X &menuval,ptr_response, X prompt, X 0,1,0,1,3, X abortstring,MENU_ABORT, X "?",MENU_HELP, X "Help",MENU_HELP X ); X switch (rval) { X case MENU_NO_MATCH : X return(MENU_DATA); X /* break; */ X case MENU_MATCH : X return(menuval); X /* break; */ X case MENU_EOF : X return(MENU_EOF); X /* break; */ X default : X fprintf(stderr,"Impossible return from menu_data_help_or_abort\n"); X exit(-1); X } X X return(0); X} X X Xmenu_number_help_or_abort (prompt,abortstring,low,high,ptr_ival) X X char *prompt, *abortstring; X int low,high,*ptr_ival; X X{ X char *response,errprompt[80],numstring[MAX_MENU_RESPONSE_LENGTH]; X#ifdef MSDOS X int rval; X#else X int rval,check; X#endif X X#ifdef MSDOS X if (!(low <= high)) X#else X if (!(check = (low <= high))) X#endif X nbuffconcat(errprompt,1,"Please enter a non-negative number...\n\n"); X else X sprintf(errprompt,"Please enter a number between %d and %d\n\n",low,high); X X reask : X X rval = menu_data_help_or_abort(prompt,abortstring,&response); X switch (rval) { X case MENU_EOF : X case MENU_ABORT : X case MENU_HELP : X return(rval); X /* break; */ X case MENU_DATA : X remove_excess_blanks(numstring,response); X switch (*ptr_ival = str_to_pos_int(numstring,0,MAXINT)) { X case -1: X case -2: X fprintf(stderr,"%s",errprompt); X goto reask; X /* break; */ X default: X return(MENU_DATA); X /* break; */ X } X } X X return(0); X} X X Xmenu_yes_no_abort_or_help (prompt,abortstring,helpallowed,return_for_yes) X X/* X Returns one of MENU_YES, MENU_NO, MENU_ABORT or MENU_HELP. X If !helpallowed, MENU_HELP will not be returned. X If return_for_yes is 0, hitting return will re-prompt. X If it is 1, hitting return is like typing yes. X If it is any other value, hitting return is like typing no. X*/ X X char *prompt; X char *abortstring; X int helpallowed; X int return_for_yes; X X{ X int menuval,rval; X char *response; X X redo : X X if (!helpallowed) { X rval = menu_match ( X &menuval,&response, X prompt, X 0,1,0,0,4, X "Yes",MENU_YES, X "No",MENU_NO, X abortstring,MENU_ABORT, X "",MENU_RETURN X ); X } X else { X rval = menu_match ( X &menuval,&response, X prompt, X 0,1,0,0,6, X "Yes",MENU_YES, X "No",MENU_NO, X "?",MENU_HELP, X "Help",MENU_HELP, X abortstring,MENU_ABORT, X "",MENU_RETURN X ); X } X switch (rval) { X case MENU_MATCH : X if (menuval != MENU_RETURN) return(menuval); X switch (return_for_yes) { X case NO_DEFAULT : X goto redo; X /* break; */ X case DEFAULT_YES : X return(MENU_YES); X /* break; */ X default : X return(MENU_NO); X /* break; */ X } X /* break; */ X case MENU_NO_MATCH : X printf("Please type 'Yes' or 'No'...\n"); X goto redo; X /* break; */ X case MENU_EOF : X return(MENU_EOF); X /* break; */ X default : X fprintf(stderr,"Fatal error: Impossible return in menu_yes_no\n"); X exit(-1); X } X X return(0); X} END_OF_FILE if test 8281 -ne `wc -c <'./toolsdir/menu.c'`; then echo shar: \"'./toolsdir/menu.c'\" unpacked with wrong size! fi # end of './toolsdir/menu.c' fi if test -f './toolsdir/menu.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./toolsdir/menu.h'\" else echo shar: Extracting \"'./toolsdir/menu.h'\" \(4423 characters\) sed "s/^X//" >'./toolsdir/menu.h' <<'END_OF_FILE' X/* You must include "" before including this file. */ X X#define MENU_EOF -1 X#define MENU_MATCH 0 X#define MENU_AMBIGUOUS 1 X#define MENU_NO_MATCH 2 X#define MENU_ERROR 3 X#define MENU_RETURN 4 X X#define MAX_MENU_OPTIONS 20 X#define MAX_MENU_RESPONSE_LENGTH 255 X X Xextern int menu_match(); X X/* menu_match ( X X int *ptr_rval, X char **ptr_user_response, X char *prompt, X int case_significant, X int initial_substring_sufficient, X int repeat_if_no_match, X int repeat_if_ambiguous, X int n_options, X char *option1, int rval1, X char *option2, int rval2, X . X . X . X X ); X X Returns one of MENU_MATCH, MENU_AMBIGUOUS, MENU_NO_MATCH, and MENU_ERROR. X If MENU_MATCH is returned, *ptr_rval contains the value that the caller X asked to be returned. *ptr_user_response is what exactly what the user X typed in, minus the linefeed at the end. X X prompt is a character string that is printed out. A line of input is X then read from the terminal, stripped of excess blanks, and compared X with the menu items. Up to MAX_MENU_OPTIONS can be specified. Each X option is a character string and has an associated integer return value. X X If case_significant is not zero, the user's response will be checked X against the options with upper/lower case distinction. X If initial_substring_sufficient is not zero, then a match will occur X if the user's response is the same as an initial substring of an option, X otherwise the response must match the option exactly. X X If more than one menu option matches the response, MENU_AMBIGUOUS is X returned. If n_options exceeds MAX_MENU_OPTIONS or the read fails X MENU_ERROR is returned. If no option matches the response, MENU_NO_MATCH X is returned. However, if repeat_if_no_match and/or repeat_if_ambiguous X are non_zero, the user is prompted again until he answers correctly if X he answers wrongly/ambiguously, respectively. X X If "" is not specified as an option, and the user enters a blank line, X the routine simply prompts the user again. It is impossible to match X on a string of blanks (e.g., " "), because any blank line the user X types is considered to be "". X X If the response the user types is too long, an error message is printed X out and the user is asked to try again. X X*/ X X X#define MENU_NO 0 X#define MENU_YES 1 X#define MENU_HELP 2 X#define MENU_ABORT 3 X#define MENU_DATA 4 X Xextern int menu_yes_no(); X X/* menu_yes_no (prompt,allow_help) char *prompt; int allow_help; X X returns one of MENU_NO, MENU_YES or, if help is allowed, X MENU_HELP. Help can be obtained via "?" or any initial X substring of "Help", case independently. Returns MENU_EOF X if end of file encountered when reading. X X Yes or no can be obtained via any case independent initial X substring of "Yes" or "No" respectively. X X*/ X X X#define DEFAULT_YES 0 X#define DEFAULT_NO 1 X#define NO_DEFAULT 2 X Xextern int menu_yes_no_abort_or_help (); X X/* menu_yes_no_abort_or_help (prompt,abortstring,helpallowed,return_for_yes) X X char *prompt, *abortstring; X int helpallowed; X int return_for_yes; X X Returns one of MENU_YES, MENU_NO, MENU_ABORT, MENU_HELP or MENU_EOF. X If !helpallowed, MENU_HELP will not be returned. X If return_for_yes is DEFAULT_NO, hitting return will re-prompt. X If it is DEFAULT_YES, hitting return is like typing yes. X If it is any other value, hitting return is like typing no. X X*/ X Xextern int menu_data_help_or_abort (); X X/* X Xextern int menu_data_help_or_abort (prompt,abortstring,ptr_response) X X char *prompt, *abortstring, **ptr_response; X X Returns either MENU_ABORT, MENU_HELP or MENU_DATA. If MENU_DATA is X returned, *response contains the user's response. MENU_HELP is X returned in the user types in "?" or any initial substring of "Help" X (case independently). X X*/ X X Xextern int menu_number_help_or_abort (); X X/* Xmenu_number_help_or_abort (prompt,abortstring,low,high,ptr_ival) X X char *prompt; *abortstring; X int low,high,*ptr_ival; X X Returns either MENU_DATA, MENU_ABORT, MENU_HELP or MENU_EOF. X If low > high any number will be considered valid, otherwise the X range is checked, inclusivewise. If MENU_DATA is returned, *ptr_ival X contains the number entered. X X At the moment number can only be non-negative. X*/ END_OF_FILE if test 4423 -ne `wc -c <'./toolsdir/menu.h'`; then echo shar: \"'./toolsdir/menu.h'\" unpacked with wrong size! fi # end of './toolsdir/menu.h' fi if test -f './update.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./update.c'\" else echo shar: Extracting \"'./update.c'\" \(6171 characters\) sed "s/^X//" >'./update.c' <<'END_OF_FILE' X/* update.c */ X#include X#include X X#ifdef TMC X#include 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 X X Xchar *get_new_value () X{ X char buffer[200]; X int rval; X switch (rval = getline(stdin,buffer,199)) { X case AT_EOF : X user_eof(); X break; X case TOO_MANY_CHARS : X fprintf(stderr,"Line too long, truncated...\n"); X sleep(1); X break; X default : X if ('\\' == *buffer && rval == 1) return(0); X break; X } X return(copystr(buffer)); X} X X XPtr_Rolo_Entry copy_entry (lentry) Ptr_Rolo_Entry lentry; X{ X Ptr_Rolo_Entry new_entry; X int j,n; X char **otherfields; X X new_entry = (Ptr_Rolo_Entry) rolo_emalloc(sizeof(Rolo_Entry)); X X /* copy the basic fields, but get a new timestamp */ X X for (j = 0; j < N_BASIC_FIELDS - 1; j++) { X set_basic_rolo_field(j,new_entry,copystr(get_basic_rolo_field(j,lentry))); X } X set_basic_rolo_field(N_BASIC_FIELDS - 1,new_entry,timestring()); X X /* copy the user-defined fields, if necessary */ X X set_n_others(new_entry,n = get_n_others(lentry)); X if (n > 0) { X otherfields = (char **) rolo_emalloc(n * sizeof(char *)); X new_entry -> other_fields = otherfields; X for (j = 0; j < n; j++) { X set_other_field(j,new_entry,copystr(get_other_field(j,lentry))); X } X } X else new_entry -> other_fields = 0; X X return(new_entry); X X} X X Xrolo_update_mode (rlink) Ptr_Rolo_List rlink; X X/* Update the fields of an entry. The user is not allowed to modify the */ X/* timestamp field. */ X X{ X int rval,menuval,findex,updated,newlen,n,nfields,j,name_changed; X char *response,*s,*newfield,*newval,*other, **others; X Ptr_Rolo_Entry lentry,old_entry; X X if(read_only) X { X printf("Readonly mode: Updates not allowed.\n"); X sleep(2); X return(1); X } X X cancel_update : X X lentry = copy_entry(old_entry = get_entry(rlink)); X X updated = 0; X name_changed = 0; X X redisplay : X X display_entry_for_update(updated ? lentry : old_entry); X nfields = (N_BASIC_FIELDS - 1) + get_n_others(lentry); X X reask : X X cathelpfile(UPDATEMENU,(char *)NULL,0); X X rval = menu_match ( X &menuval,&response, X ": ", X 0,1,0,1,4, X "\\",U_ABORT, X "?",U_HELP, X "Help",U_HELP, X "",U_END_UPDATE X ); X X switch (rval) { X X case MENU_MATCH : X X switch (menuval) { X X case U_HELP : X cathelpfile(UPDATEHELP,"updating",1); X any_char_to_continue(); X clear_the_screen(); X goto redisplay; X X case U_ABORT : X if (updated) { X printf("Previous updates to fields in this entry ignored\n"); X } X return(0); X /* break; */ X X case U_END_UPDATE : X if (!updated) goto reask; X display_entry(lentry); X if (MENU_YES == rolo_menu_yes_no ( X "Confirm Update? ",DEFAULT_YES,1, X CONFIRMHELP,"confirming update" X )) { X printf("Update confirmed\n"); X sleep(1); X set_entry(rlink,lentry); X if (name_changed) { X rolo_delete(rlink); X rolo_insert(rlink,compare_links); X } X changed = 1; X return(0); X } X else { X printf("Updates ignored...\n"); X sleep(1); X updated = 0; X goto cancel_update; X } X /* break; */ X X } X break; X X case MENU_NO_MATCH : X X /* check that the response is an integer within range */ X X findex = str_to_pos_int(response,1,nfields+1); X if (findex < 0) { X printf("Not a valid number...Please try again\n"); X goto reask; X } X findex--; X X /* we can either be updating a standard field or a user-defined field */ X /* or adding a new field */ X X if (findex < N_BASIC_FIELDS - 1) { X name_changed = (findex == 0); X printf("Updating '%s'\n",Field_Names[findex]); X printf("Old value: %s\n",get_basic_rolo_field(findex,lentry)); X printf("New value: "); X if (0 == (newval = copystr(get_new_value()))) break; X set_basic_rolo_field(findex,lentry,newval); X updated = 1; X } X else if (findex != nfields) { X findex -= N_BASIC_FIELDS - 1; X printf("Updating \'"); X s = other = get_other_field(findex,lentry); X while (*s != ':') putc(*s++,stdout); X printf("\' field\n"); X printf("Old value: %s\n",++s); X printf("New value: "); X if (0 == (newval = copystr(get_new_value()))) break; X if (strlen(newval) == 0) { X for (j = findex; j < get_n_others(lentry); j++) { X set_other_field(j,lentry,get_other_field(j+1,lentry)); X } X set_n_others(lentry,get_n_others(lentry) - 1); X } X else { X *s = '\0'; X newlen = strlen(other) + strlen(newval) + 2; X newfield = rolo_emalloc(newlen); X nbuffconcat(newfield,3,other," ",newval); X set_other_field(findex,lentry,newfield); X } X updated = 1; X } X else { X loop: X printf("New field (: ): "); X if (0 == (newfield = copystr(get_new_value()))) break; X if (0 == (char *)index(newfield,':')) { X fprintf(stderr,"No field name. Use a ':'...\n"); X goto loop; X } X n = get_n_others(lentry); X set_n_others(lentry,n + 1); X others = (char **) rolo_emalloc((n + 1) * sizeof(char *)); X for (j = 0; j < n; j++) others[j] = get_other_field(j,lentry); X others[n] = newfield; X lentry -> other_fields = others; X updated = 1; X } X break; X X case MENU_EOF : X user_eof(); X break; X X default : X fprintf(stderr,"Impossible return from update menu_match\n"); X save_and_exit(-1); X break; X X } X X goto redisplay; X X} END_OF_FILE if test 6171 -ne `wc -c <'./update.c'`; then echo shar: \"'./update.c'\" unpacked with wrong size! fi # end of './update.c' fi echo shar: End of archive 2 \(of 4\). cp /dev/null ark2isdone 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