%%HP: T(3)A(R)F(.); \<< @ Start of Program @ @ PHONE V1.4 by Joe Ervin. 18-JAN-1991 @ @ NEW FEATURES FOR V1.4. @ Added handling of addresses, in addition to names and numbers. @ Included YN menu definition, rather than using an external reference. @ Added RCLF and STOF to preserve the state of the system. Also enforce @ STD display mode during execution. Ensures a nice display during PHSEARCH. @ @ NEW FEATURES FOR V1.3. @ Added a PREV menu choice in the PHSEARCH routine to allow the user to @ move backwards through the list of matches. CLEAR {} @ Dummy value to hold place for PHNAMES. @ {} @ Dummy value to hold place for PHNUMBERS. @ {} 0 0 \-> PHNAMES PHNUMBERS ADDRESSES PHSIZE FLAGS @ Creates local storage for names and numbers. @ \<< @ Surounds the procedures as well as main routine. @ \<< @Start definition of PHSEARCH routine.@ CLEAR 0 0 0 {} 0 \-> SRCHNAME @ Local variable to hold the search name. @ DONE @ Local variable to detect when search has finished. @ MATCHNUM @ Local variable to store the number of matches. @ MATCHLIST @ Stores list of matches. @ MATCHINDEX @ Used to index into the match list. @ @ What we are going to do now is to step through each name in the list, and @ @ for each name, we will do a pattern match of the search name within each@ @ name in the list. If the searchname is found within a given name, then @ @ the index corresponding to the matched name will be added to MATCHLIST. @ @ This routine uses flag 1 to indicate success or failure to the calling @ @ routine. (SET = success, CLEAR = failure - i.e. no matches. @ @ Flag 2 is also used to indicate whether the main routine should exit @ @ or prompt the user for another choice whether to search or edit the @ @ phone list. @ \<< @This delimiter surrounds PHSEARCH's local variables@ @ The following are definitions for four different menus which @ are used by the PHSEARCH facility. These definitions are defined @ here as local variables for reasons of performace; it ran @ kinda slow when I built these menus in real time. Defining them @ here and then just calling them speeds things up considerably. @ Here is the menu definition for MENADR @ {{"Next" \<< CONT \>> } {"Prev" \<< \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM-1' EVAL CONT ELSE X CONT END END 'X==2' THEN MATCHNUM CONT END @ So next index will be 1. 'X-2' EVAL CONT @ Do this by default to back up one index. END \>> @ end of case statement 1. \>> } {} { "Addr" \<< 6 SF \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM' EVAL CONT ELSE X CONT END END 'X-1' EVAL CONT @ Do this by default to replay last index. END \>> @ end of case statement 2. \>>} {} {"Exit" \<< 1 'DONE' STO CONT \>>} } @ Here is the menu definition for MENNUM {{"Next" \<< CONT \>> } {"Prev" \<< \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM-1' EVAL CONT ELSE X CONT END END @So next index will be MATCHNUM. 'X==2' THEN MATCHNUM CONT END @ So next index will be 1. 'X-2' EVAL CONT @ Do this by default to back up one index. END \>> @ end of case statement 3. \>> } {} { "Num" \<< 6 CF \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM' EVAL CONT ELSE X CONT END END 'X-1' EVAL CONT @ Do this by default to replay last index. END \>> @ end of case statement 4. \>> } {} {"Exit" \<< 1 'DONE' STO CONT \>>} } @ Here is the menu definition for MENPICKADR {{"Next" \<< CONT \>> } {"Prev" \<< \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM-1' EVAL CONT ELSE X CONT END END 'X==2' THEN MATCHNUM CONT END @ So next index will be 1. 'X-2' EVAL CONT @ Do this by default to back up one index. END \>> @ end of case statement 5. \>> } {"Pick" \<>} { "Addr" \<< 6 SF \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM' EVAL CONT ELSE X CONT END END 'X-1' EVAL CONT @ Do this by default to replay last index. END \>> @ end of case statement 6. \>>} {} {"Exit" \<< 1 'DONE' STO 1 CF 2 SF CONT \>>} } @ Here is the menu definition for MENPICKNUM {{"Next" \<< CONT \>> } {"Prev" \<< \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM-1' EVAL CONT ELSE X CONT END END 'X==2' THEN MATCHNUM CONT END @ So next index will be 1. 'X-2' EVAL CONT @ Do this by default to back up one index. END \>> @ end of case statement 7. \>> } {"Pick" \<>} { "Num" \<< 6 CF \-> X \<< CASE 'X==1' THEN IF 'MATCHNUM>1' @ Do nothing if only 1 match. THEN 'MATCHNUM' EVAL CONT ELSE X CONT END END 'X-1' EVAL CONT @ Do this by default to replay last index. END \>> @ end of case statement 8. \>> } {} {"Exit" \<< 1 'DONE' STO 1 CF 2 SF CONT \>>} } \-> MENADR @ Menu definitions used within PHSEARCH. MENNUM MENPICKADR MENPICKNUM \<< @ This delimeter surrounds the defining procedure for the above @ menu definitions. {} TMENU @ Just to clear the menu from the main routine. @ "Enter name..." {":Name:" \Ga} INPUT @Prompt user for name to search.@ IF DUP SIZE 6 \<= @ If no name was entered. @ THEN 1 SF @ To indicate successfull completion of search routine. @ 2 SF @ To cause the calling routine to ask again: SEARCH or EDIT. @ 4 CF @ Just in case this routine was called from PHEDIT. @ ELSE DUP SIZE 7 SWAP SUB 'SRCHNAME' STO PHNAMES OBJ\->@ Puts the list of names on the stack.@ IF SRCHNAME "*" SAME THEN 3 SF END 1 SWAP FOR I @ Step through the whole list of names. @ SRCHNAME @ Put the string to search for on the stack. @ IF POS 3 FS? OR @ If SRCHNAME exists anywhere within the name...@ THEN 'MATCHNUM' INCR DROP @ Add one to the number of matches. @ 'PHSIZE - I + 1' EVAL 'MATCHLIST' STO+ @ Add the match index to list of match indices. @ END @ End this match check. @ NEXT @ End loop checking for matches. @ 3 CF IF MATCHNUM 0 \=/ @ IF there were at least some matches...@ THEN 1 SF 2 CF @ To indicate success to the calling routine. @ MATCHLIST 1 @ To initialize index into matchlist. @ DO @ Display list of matches until done. @ GETI @ Fetch the next item pointed to by the matchindex. @ 'MATCHINDEX' STO DUP IF 1 == THEN MATCHNUM ELSE DUP 1 - END @ Now display which match we are looking at. @ CLLCD "Match " SWAP + " of " + MATCHNUM + 1 DISP ":Name:" PHNAMES MATCHINDEX GET + @ Concatenates label to name. @ " " + @ Adds a LF to the end of the NAME string. IF 6 FC? @ If we are in "numbers" mode... THEN ":Number:" PHNUMBERS MATCHINDEX GET + @ Concatenates label to number. @ + @ Concatenates the NUMBER string to the NAME string. 4 DISP ELSE " " ADDRESSES MATCHINDEX GET + @ Concatenates label to address. @ + @ Concatenates the ADDRESS string to the NAME string. 3 DISP END 3 FREEZE @ Now we need to call in the proper menu definition depending on what @ display mode we are in (flag 6) and whether PHSEARCH was called from @ PHEDIT or from the main routine. IF 4 FC? @ PHSEARCH was called from main routine. THEN IF 6 FC? @ If in "numbers" mode... THEN @ We need to add a menu item to switch to "addresses" mode. MENADR ELSE @ We are in "address" mode... MENNUM END ELSE @ PHSEARCH was called from PHEDIT. IF 6 FC? @ If in "numbers" mode... THEN @ We need to add a menu item to switch to "addresses" mode. MENPICKADR ELSE @ We are in "address" mode... MENPICKNUM END END TMENU HALT @ Display the menu and stop for input. UNTIL DONE END ELSE @ If there were no matches...@ "The specified name was not found" @ To indicate search failure. @ 1 CF 2 CF @ To indicate failure to the calling routine. @ CLLCD 1200 .1 BEEP 2 DISP 1 WAIT END END \>> @ This delimeter surrounds the defining procedure for the @ menu definitions. \>> \>> @Ends definition of PHSEARCH routine.@ \-> PHSEARCH @ Creates the subroutine PHSEARCH. @ \<< \<< @ Definition of the PHEDIT routine starts here. @ \-> P1 @ Take the parameter passed in on the stack. @ \<< IF P1 "INT" SAME THEN @ At this point, the local variables "PHNAMES" and "PHNUMBERS" contain the @ @ names and numbers of the list to be edited. Now we need to present the @ @ user with a meaningful display from which to choose actions. The actions @ @ allowed include "MODIFY" and "ADD". The following code prompts the user @ @ to choose between these two options, and then performs the simple editing @ @ function. @ "Do you want to add to the list, modify an existing entry, or delete an entry?" CLLCD 1 DISP 3 FREEZE {{"Add" \<<"ADD" CONT\>>} {"Mdfy" \<<"MODIFY" 5 CF CONT\>>} {"Del" \<<"MODIFY" 5 SF CONT \>>} {} {} {"EXIT" \<<2 SF CONT\>>}} TMENU HALT ELSE CLEAR "ADD" @ This is for when PHEDIT was called by main with @ @ P1 of "NEW". @ END @ This is for the case when PHEDIT was called by the main routine for @ @ the case where there was no phone list. @ IF 2 FC?C THEN {} TMENU @ Clear the menu from what was previously there. @ 0 0 0 0 \-> X TEMP LEN LEN2 DONE \<< CASE @ Note the creation of the scratch variables 'TEMP', 'LEN', 'LEN2'.@ @ 'TEMP' is scratch for the name, LEN is scratch for the name's length, @ @ and 'LEN2' is scratch for the length of the phone number. @ @ DONE is used for the repeat loop. @ @ X gets the "ADD" or "MODIFY" string from the above prompt. @ X "ADD" SAME @ Here we are adding to the list of names. @ THEN DO "Enter name..." {":Name:" \Ga} INPUT @ Prompts the user to enter the name for this entry. @ @ Now we need to build up the command line for the INPUT command @ @ which will pull in the number for this entry. We want to @ @ display the name above where the user is going to enter the @ @ number. @ DUP SIZE 'LEN' STO 'TEMP' STO IF LEN 6 > THEN "Enter number..." TEMP EVAL " :Number:" + { 2 9 } \Ga 3 \->LIST INPUT @ The current prompt shows the name and prompts for @ @ the phone number. @ @ Now save the new information and update PHSIZE. DUP DUP SIZE 'LEN2' STO 7 LEN SUB PHNAMES + 'PHNAMES' STO LEN 10 + LEN2 SUB PHNUMBERS + 'PHNUMBERS' STO PHNAMES SIZE 'PHSIZE' STO @ Now we need to prompt for the address information... "Enter address..." TEMP EVAL " :Addr:" + { 2 7 } \Ga 3 \->LIST INPUT @ The current prompt shows the name and prompts for @ @ the address. @ @ Now save the new ADDRESS information. DUP SIZE 'LEN2' STO LEN 8 + LEN2 SUB ADDRESSES + 'ADDRESSES' STO ELSE 1 'DONE' STO END UNTIL DONE END END @"ADD"@ X "MODIFY" SAME THEN @ User wants to edit the list @ CLEAR 0 0 "" \-> INDEX @ Stores the index of the entry to be edited. @ DONE @ Used to terminate DO UNTIL loop. @ EDITSTRING @ Stores the modified string. @ \<< @ Basically what I want to do here is to call the PHSEARCH routine @ @ in a way that it will get the user to pick a specific entry. @ @ I want to use the PHSEARCH routine to do this since so much of @ @ the code needed to do this is alread done. The result of the @ @ PHSEARCH routine is to return an index indicating the exact @ @ entry which is to be edited. This routine then needs only @ @ display it in an input statement in such a way that the user @ @ can modify it as it sits on the display. When the user presses @ @ ENTER, the modified entries (name and number) will be written @ @ back into the database. @ @ This routine also checks flag 5 to determine whether the user @ @ wants to delete the record or simply modify it. @ DO 2 CF 4 SF PHSEARCH EVAL @ Get the index of entry to be modified. @ UNTIL 1 FS?C @ Repeat search routine until user selects an entry @ @ or gives up. @ END 4 CF @ Flag 4 was set only to indicate to PHSEARCH to use "pick" in @ @ the menu so user could choose the item to edit. IF 2 FC?C @ If flag 2 is set, then the user must have given up @ @ trying to select an entry to edit. @ THEN @ Let's edit the selected entry @ 'INDEX' STO IF 5 FC?C THEN DO @ This section of code was modified in v1.4 to handle the editing of @ addresses. For this reason, I use several IFTE commands below to @ differentiate between editing the PHNUMBERS field and the @ ADDRESSES field. INDEX DUP PHNAMES SWAP GET @ Gets the name to be modified. @ SWAP 6 FC? 'PHNUMBERS' 'ADDRESSES' IFTE @ Gets PHNUMBERS or ADDRESSES, depending on the @ state of flag 6. SWAP GET @ Gets number/address to be modified. @ @ The stack now has @ 2: name @ 1: number/addr @ Now reformat the information for the INPUT command. 6 FC? ":Number:" ":Addr:" IFTE SWAP + SWAP ":Name:" SWAP + @ Adds tags to the name and num/addr. " " + SWAP + @ Creates one long string with a carraige return @ @ to separate the name and num/addr strings. @ @ Now display this information using INPUT so the user can @ @ edit the strings. @ "Edit entry..." SWAP 0 2 \->LIST {} TMENU INPUT @ At this point, the user has been prompted with the name and @ @ number to be modified. The keyboard is in overstrike mode @ @ and the cursor was left at the end of the number. @ @ Now we must recover the new name and number from the @ @ string on the stack. @ DUP 'EDITSTRING' STO @ Save a copy of the string. IF DUP ":Name:" POS 1 == @ Test for existence of the name... SWAP DUP 6 FC? ":Number:" ":Addr:" IFTE POS @ ...and number tags within the string. DUP 'TEMP' STO @ Save location of num/addr tag. ROT AND THEN @ The user entered valid data. @ @ Update the database with new name.@ DUP 7 TEMP 2 - SUB @ Extract the modified name. @ 1 \->LIST PHNAMES SWAP INDEX SWAP REPL 'PHNAMES' STO @ Save modified name in PHNAMES. @ Update the database with the new number/address. TEMP 6 FC? 8 6 IFTE + EDITSTRING SIZE SUB @ Extract the new name/addr. 1 \->LIST 6 FC? 'PHNUMBERS' 'ADDRESSES' IFTE SWAP INDEX SWAP REPL 6 FC? "'PHNUMBERS'" "'ADDRESSES'" IFTE OBJ\-> STO 1 'DONE' STO CLEAR ELSE CLLCD 1200 .1 BEEP "Invalid Entry" 2 DISP 2 WAIT END UNTIL DONE END ELSE @ The user wants to delete the entry. @ CLEAR INDEX DUP PHNAMES SWAP GET @ Gets the name to be modified. @ SWAP PHNUMBERS SWAP GET @ Gets number to be modified. @ @ The stack now has @ @ 2: name @ @ 1: number @ @ Now reformat the information for the INPUT command. @ ":Number:" SWAP + SWAP ":Name:" SWAP + @ Adds tags to the name and number. @ " " + SWAP + @ Creates one long string with a carraige return @ @ to separate the name and number strings. @ @ Now display this information and prompt user to verify that @ @ this record should be deleted. CLLCD "Delete entry?" 1 DISP 4 DISP 1200 .1 BEEP 3 FREEZE { { "Yes" \<< 1 CONT \>> } { } { } { } { } { "No" \<< 0 CONT \>> } } TMENU HALT IF @ yes @ THEN PHNAMES OBJ\-> DROP @ Put the list of names on the stack. @ PHSIZE INDEX 1 - - ROLL DROP @ Deletes the entry pointed to by INDEX. @ PHSIZE 1 - \->LIST 'PHNAMES' STO PHNUMBERS OBJ\-> DROP @ Put the list of names on the stack. @ PHSIZE INDEX 1 - - ROLL DROP @ Deletes the entry pointed to by INDEX. @ PHSIZE 1 - \->LIST 'PHNUMBERS' STO ADDRESSES OBJ\-> DROP @ Put the list of names on the stack. @ PHSIZE INDEX 1 - - ROLL DROP @ Deletes the entry pointed to by INDEX. @ 'PHSIZE' DECR \->LIST 'ADDRESSES' STO END END ELSE 5 CF END \>> END END \>> @end case@ END @IF 2 FC?C ADDRESSES PHNUMBERS PHNAMES 3 \->LIST 'PHDAT' STO \>> @ Surrounds PHEDIT's parameters. @ \>> @ Ends the definition of PHEDIT and pushes PHEDIT on the stack @ @ to be defined later.@ \-> PHEDIT @ Defines the subroutine "PHEDIT", which edits the database. @ @ PHEDIT takes as parameters a single string which must have the @ @ value "NEW", indicating a new list should be created, @ @ or "INT", indicating the old list should be prompted as to @ whether the current list is to be added to or edited. @ \<< @ The main routine starts here. @ 64 STWS @ Sets the word size to 64. Needed for RCLF RCLF DUP 'FLAGS' STO 2 {#0d} REPL STOF @ Clear user flags. STD @ Set display to STD mode. Looks nicer. IF 'PHDAT' VTYPE -1 == THEN CLLCD "Phone Database does" 2 DISP "not exist. Do you" 3 DISP "want to create it?" 4 DISP 3 FREEZE { { "Yes" \<< 1 CONT \>> } { } { } { } { } { "No" \<< 0 CONT \>> } } TMENU HALT @ Prompt the user for yes/no @ IF THEN {} DUP 'PHNAMES' STO 'PHNUMBERS' STO "NEW" PHEDIT EVAL @ tells PHEDIT to go directly to the @ @ edit input mode on a new list @ @ After the user exits PHEDIT, control falls down to main routine below.@ ELSE "You must create a phone database before any further action can be taken." 2 DISP CLEAR 2 MENU 1200 .1 BEEP 3 FREEZE 3 WAIT 0 DOERR @ Obviously, the user is a pinhead. @ END END @ We need to start the main routine.@ 0 \-> DONE \<< @ First we need to suck in the database. @ {} DUP 'PHNAMES' STO 'PHNUMBERS' STO CLEAR @ Clear the stack, so the following DEPTH command will work. PHDAT EVAL @ At this point, we need to determine if the current database is in @ the new format used with V1.4 and later. If the database does not @ contain the list of ADDRESSES, then we need to add them and write it back @ out. IF DEPTH 2 == THEN @ We must update the database structure. CLLCD "Reformating PHDAT. Please wait..." 2 DISP 1 WAIT DUP @ Create a spare copy of PHNAMES. {} @ Put a null list on the stack. SWAP SIZE 1 SWAP FOR I "" + NEXT @ Creates a list of null strings. 3 ROLLD 3 \->LIST 'PHDAT' STO @ Adds the empty address list to the database. CLEAR PHDAT EVAL END 'PHNAMES' STO 'PHNUMBERS' STO @ copies the database in the local @ @ variables 'PHNAMES' , 'PHNUMBERS' @ 'ADDRESSES' STO @ and 'ADDRESSES'. PHNAMES SIZE 'PHSIZE' STO @ Indicates the number of names in the list. @ DO @ Here we want to ask the user whether we are searching or editing. @ "Do you want to search the list or edit the list?" CLLCD 1 DISP 3 FREEZE {{"SRCH" \<< DO PHSEARCH EVAL UNTIL 1 FS?C END CONT \>>} {"EDIT" \<< "INT" PHEDIT EVAL CONT \>>} {} {} {} {"Exit" \<<1 'DONE' STO CONT \>>}} TMENU HALT @ "INT" for PHEDIT here to tell PHEDIT to prompt the user as to @ @ whether he wants to edit (modify) the phone list or simply add to it. @ UNTIL DONE @ Keep on doing this loop until DONE. @ END \>> @ DO @ CLEAR 2 MENU FLAGS STOF @ Resets the state of the system and user flags. \>> @ Defines bounds for which PHSEARCH is defined. \>> @ Main Routine. \>> @ Main routine and procedures. \>> @ End of Program.