############################################################################ # # File: literat.icn # # Subject: Program to manage literature information # # Author: Matthias Heesch # # Date: March 26, 2002 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # Database system to manage information concerning literature. # ############################################################################ # # Written by: Dr. Matthias Heesch # Department of Protestant Theology (FB 02) # Johannes Gutenberg University # Saarstrasse 21 / D-W-6500 Mainz 1 / Germany # ############################################################################ # # Written and tested under: DR/MS-DOS, using ansi.sys # ############################################################################ # # See the comment lines concerning the single user defined # functions if you want to use them separately. Note that all screen # access assumes ansi.sys to be installed. # # Since arguments to the seek() function may be long integers, # long-integer support is required. # # The program uses standard files literat.fil, literat2.fil and # adress.fil to store its data on the disk. It has a predefined # structure of the items and predefined field labels to make it easy # to use and to cut down the source code length.for users having some # knowledge of the Icon language it shouldn't be difficult to # change the program. In this case the item length (now 846 byte) # the option lists in menue() and the field label list have to be # modified. The main changes then will concern user defined # function edit_item() where the number of fields within an item # is decided by *labels. In function in_itemm() the number of dummy # field separators has to be equal to the amount of fields desired. # (items := list(200,"##" if two fields are desired). Within the # other functions only the amount of bytes for a whole item within # reads() and seek() operation has to be changed accordingly. Note # that "literat"'s editor in its present version isn't able to scroll. # # See the description (comment lines) of user defined function # line() for details of the editing facilities. # # The menue accepts input by and the lower case short # hand key of every option. The selected option has to be activated # by . # # iNPUT: function to update an existing file literat.dat. When moving # the cursor out of the actual item, the last or following item will # be displayed and is available for the editing process. Input treats # literat.dat as a sequential file. Only the items to be added to the # existing file are in the computer's memory. This fastens the option # to switch between the (new) items. Otherwise it would have been # necessary to load the whole literat.dat into the RAM or to load # every new item from the disk. The first would consume too much # memory with the result of potential loss of new items, the second # would cost much time. In one session "literat" can accept no more # than 200 new items. # # tURN_OVER_ITEMS: literat.dat can be viewed and edited item by item # moving the cursor out of the actual item causes the next/last item # to be displayed. The edited items are written to file literat2.fil # # aDRESS file: type words to be indicated. If they are found, the # item numbers of their occurrence will be recorded in file adress.fil. # Moving the cursor out of the editor causes the indicating # process to start. New items to adress.fil are simply added to the # file. Therefore changes of existing material in adress.fil have to # be made by creating a new adress.fil. # # qUERY: searches item using the information in adress.fil. You are # prompted to type a word and if it's found in adress.fil the # programm will use the item numbers to compute arguments to the # seek()-function and then read the item. After viewing and if # desired editing the item it will be written to file literat2.fil. # # dEL: prompts for an item number and removes the corresponding item. # the file then is written to literat2.fil, literat.fil remains # as it was. # # AlPHA: alphabetical sorting, sorted file written to literat2.fil. # # eND: return to the operating system. # ############################################################################ # # Important message to the user: everybody who will find and remove # a bug or add any improvement to the program is kindly encouraged # to send a copy to the above address. # ############################################################################ # # Note: Clerical edits were made to this file by the Icon Project. # It's possible they introduced errors. # ############################################################################ # # Requires: large-integer arithmetic, ANSI terminal support # ############################################################################ ############################################################################ # # # linfield: line and field editing package # # # ############################################################################ # # ############################################################################ # # # set of user defined functions essential to the line editor line() # # # ############################################################################ # # newkey(): redirects keyboard to make some of the editing functions # accessable also by arrow/ctrl-arrow-keys. needs ansi.sys. # although newkey() isn't called by line() directly, a program # which uses line() should contain a call to newkey(), because # otherwise line()'S function won't be available for cursor keys. procedure newkey() local code, n_keys n_keys := list(9) # arrow left (cursor left) n_keys[1] := char(27) || "[0;77;1p" # arrow right (cursor right) n_keys[2] := char(27) || "[0;75;2p" # arrow up (quit, decreasing line_number) n_keys[3] := char(27) || "[0;72;14p" # arrow down (quit, increasing line_number) n_keys[4] := char(27) || "[0;80;21p" # ctrl/left n_keys[5] := char(27) || "[0;116;8p" # ctrl/right n_keys[6] := char(27) || "[0;115;9p" # home n_keys[7] := char(27) || "[0;71;4p" # end n_keys[8] := char(27) || "[0;79;5p" # deL n_keys[9] := char(27) || "[0;83;6p" # # activate codes while code := get(n_keys) do { writes(code) } end # # # function to set cursor position procedure locate(row,col) local cursor cursor := char(27) || "[" || row || ";" || col || "H" writes(cursor) end # # last(byte,string): detects the last occurrence of byte in # string and returns its position procedure last(byte,string) local a, r_string, rpos r_string := reverse(string) rpos := find(byte,r_string) a := (*string - rpos) return a end # # remword(string,acol): removes word at acol from string procedure remword(string,acol) local blank, string_a, string_b # if acol points to end of string, don`t do anything if acol + 1 > *string then return string # if acol points to a blank just remove the blank if string[acol + 1] == " " then { string ? { string_a := tab(acol + 1) move(1) string_b := tab(0) string := string_a || string_b return string } } # else delete actual word if acol = 0 then acol := 1 # crack string into two parts string ? { string_a := tab(acol + 1) string_b := tab(0) } # check string_a for the last blank if any if find(" ",string_a) then { blank := last(" ",string_a) string_a := string_a[1:blank + 1] } else string_a := "" # check string_b for the first blank if any if blank := find(" ",string_b) then { string_b := string_b[blank:*string_b + 1] } else string_b := "" # build string out of string_a ending at its last and string_b # beginning at its first blank. string := string_a || string_b if string[1] == " " then string[1] := "" return string end # # stat_line: function to display a status line with the actual row # and column procedure stat_line(column) locate(24,1) writes("LINE: ",lin_nm," COL: ",column," ","TIME: ",&clock," ") end # # global variable line_number to indicate the increase or decrease # of global variable lin_nm global line_number # # global variable lin_nm to increase or decrease actual line # in the field global lin_nm # # global variable field_flag: direction flag to increase or # decrease field number global field_flag # # global variable item_flag: direction flag to increase or # decrease item number global item_flag # ############################################################################ # # # line editor line() # # # ############################################################################ # # editing commands for the line editor: # ctrl/A: byte forward (arrow right) # ctrl/B: byte back (arrow left) # ctrl/D: beginning of line (home) # ctrl/E: end of line (end) # ctrl/F: del byte (del) # ctrl/G: del word # ctrl/H: word forward (ctrl/right) # ctrl/I: word back (ctrl/ left) # ctrl/L: perform block operation # 1. press ctrl/L # 2. enter relative adress (followed by ) for # block end. It must be an (numerical) offset # pointing right to the actual cursor. # 3. enter "r" (no !) for remove or "b" # to move block to the beginning of field # or "e" to transfer it to the end. # Annotation: "impossible" adresses (beyond string # length or negative) will be ignored. # alt/A : wrap line (+ 1) # esc : del line # ctrl/K: restore line # ctrl/n: quit line (- 1) (arrow up) # ctrl/U: quit line (+ 1) (arrow down) # ret : quit line (+ 1) ############################################################################ # # Function to edit a line. The function needs the following # arguments # row : (row of the line to be edited) # bnumber: (maximum size of the string to be # edited, further input will be # ignored.) # status: display actual line_number and col2 if # status == 1 else not # comment: (comment or input prompt) # field : (contains the string to be edited.) # # The function returns a list with the first element containing # The main part of FIELD and the second element containing # the wrapped part if any. # procedure line(row,bnumber,status,comment,field) local beg, blank, blanks, block, byte, byte_input, col, col2, dec_byte local dec_bytes, e1, e2, editing, fa, fb, field2, field_1, field_2 local field_a, field_b, fieldl, highl, lg, mark, n_blank, nb, normal local quit, r_field, rest # Define csets containing the keys for # input # editing functions # quit / wraP # # Characters permitted in the edited field n_blank := &ucase ++ &lcase ++ &digits ++ '?.,;!' byte_input := n_blank ++ ' ' # Characters for the editing functions e1 := set([char(1),char(2),char(4),char(5),char(6),char(7),char(8)]) e2 := set([char(27),char(11)]) editing := e1 ++ e2 # Characters to end editing quit := set([char(13),char(30),char(14),char(21)]) # # List to return result fieldl := list() # Initialize field_a/b for a concatenation, if scanning field # fails field_a := "" field_b := "" # Initialize r_field (variable to store completely deleted field # to keep it recoverable) r_field := "" # Codes to highlight screen output and to return to normal # screen outpuT highl := char(27) || "[7m" normal := char(27) || "[0m" # # Remove single initial blank if any if field[1] == " " then { field := field[2:(*field+1)] } # # Display field when beginning the editing process, place # cursor behind the end of field locate(row,1) writes(comment,field,repl(" ",(bnumber-*field))) # If status is set to 1 display line_number and col2 after the # initial printing of line if status == 1 then stat_line(*field+1) # col: absolute cursor position (comment and field) # col2: relative position in field col := (*comment + *field) + 1 col2 := *field + 1 locate(row,col) # # Editing loop: continue until end character appears while byte := getch() & not member(quit,byte) do { if find(byte,byte_input) & *field <= bnumber - 2 then { # If byte is a normal character (if member(byte_input,byte)) insert # it into field at cursor position. # field ? { field_a := tab(col2) field_b := tab(0) } field := field_a || byte || field_b locate(row,1) writes(comment,field) col +:= 1 col2 +:= 1 if status == 1 then stat_line(col2) locate(row,col) } # else perform editing operation else { case byte of { # backspace (ctrl/B) char(2) : if col2 > 1 then { col -:= 1 col2 -:= 1 if status == 1 then stat_line(col2) locate(row,col) } # byte forward (ctrl/A) char(1) : if col2 <= *field then { col +:= 1 col2 +:= 1 if status == 1 then stat_line(col2) locate(row,col) } # goto beginning of line (ctrl/D) char(4) : { col2 := 1 col := *comment + col2 if status == 1 then stat_line(col2) locate(row,col) } # goto end of line (ctrl/E) char(5) : { col2 := (*field + 1) col := *comment + col2 if status == 1 then stat_line(col2) locate(row,col) } # delete byte at cursor position (ctrl/F) char(6) : { if col2 <= *field then { field ? { beg := tab(col2) rest := tab(0) } rest[1] := "" field := beg || rest locate(row,1) writes(comment,field," ") locate(row,col) } } # # delete the actual word (ctrl/G) char(7) : { field2 := remword(field,col2 - 1) blanks := *field - *field2 field := field2 col2 := col2 - blanks if col2 <= 0 then col2 := 1 col := *comment + col2 locate(row,1) writes(comment,field,repl(" ",blanks)) if status == 1 then stat_line(col2) locate(row,col) } # move to the beginning of the following word (ctrl/H) char(8) : { if find(" ",field[col2:*field]) then { string := field[col2:*field] blank := find(" ",string) col2 := col2 + blank col := *comment + col2 if status == 1 then stat_line(col2) locate(row,col) } } # # move to the beginning of the recent word (ctrl/I) char(9) : { # jump over the blank preceding the actual word if col2 = 1 then locate(row,col) else { if find(" ",field[1:(col2 - 2)]) then { string := field[1:(col2 - 2)] col2 := (last(" ",string) + 2) } else { col2 := 1 } col := *comment + col2 if status == 1 then stat_line(col2) locate(row,col) } } # # Delete complete line, deleted line is assigned to r_field # to be recoverable char(27) : { lg := *field r_field := field field := "" col2 := 1 col := *comment + col2 locate(row,1) writes(comment,repl(" ",lg)) if status == 1 then stat_line(col2) locate(row,col) } # Restore deleted line (overwrite new actual line, assigning it # to r_field) char(11) : { if *r_field >= 1 then { field :=: r_field col2 := *field + 1 col := *comment + col2 locate(row,1) blanks := bnumber - *field writes(comment,field,repl(" ",blanks)) if status == 1 then stat_line(col2) locate(row,col) } } # Perform block operation char(12) : { mark := "" dec_bytes := "" while nb := getch() & nb ~== char(13) do { mark ||:= nb } if mark < 1 then mark := 1 # Place cursor to field's beginning if it points to its end if col2 >= *field then col2 := 1 field ? { fa := tab(col2) block := move(mark) fb := tab(0) } locate(row,1) writes(comment,fa,highl,block,normal,fb) dec_byte := getch() if dec_byte == ("r" | "R") then { field := fa || fb locate(row,1) writes(comment,field,repl(" ",*block + 1)) col2 := col2 - *block if col2 < 1 then col2 := 1 col := *comment + col2 if status == 1 then stat_line(col2) locate(row,col) } else { if dec_byte == ("b" | "B") then { field := block || fa || fb } if dec_byte == ("e" | "E") then { field := fa || fb || block locate(row,1) } locate(row,1) writes(comment,field) locate(row,col) } } # right brace closing case control structure } # right brace closing else structure (editing keys) } # right brace closing while-do loop } # # if while-do loop stops it must be because of a key in quit. # Therefore perform final operation and return. # # wrap: divide field at the last possible blank, assign the # first part to the first element of list result, the second # part to the second element. if byte == char(30) & find(" ",field) then { blank := last(" ",field) field_1 := field[1:(blank + 1)] field_2 := field[(blank + 2):(*field + 1)] locate(row,(*comment + 1)) writes(field_1,repl(" ",*field_2)) put(fieldl,field_1) put(fieldl,field_2) # Increase lnumber by 1 line_number := 1 # Return list with main part and wrapped part as its elements return fieldl } # # normal termination by or if byte == (char(13) | char(21)) then { put(fieldl,field) put(fieldl,"") line_number := 1 return fieldl } # normal termination by alt/e else { if byte == char(14) then { put(fieldl,field) put(fieldl,"") line_number := -1 return fieldl } } end # ############################################################################ # # # field editor edit_field() # # # ############################################################################ # # edit_field: user-defined function to divide a long string into # lines and edit them as a field. uses: line() and all user- # defined functions called by line(). # edit_field() accepts its data in a single string which is # cracked apart before editing and put together afterwards. # exceeding the size of the field (lnumber) by moving the # cursor out of it, finishes the editing process. # # Annotation: edit_field() doesn't contain anything needed # by line() and therefore should be removed if only line() # is to be used. # # arguments to the function: # startline : first line on the screen # lnumber : number of lines within field # byte_n : number of bytes permitted within a line # label : label to be displayed as field's headline # string : string to be edited procedure edit_field(startline,lnumber,byte_n,label,string) local feld, item, lin, liste, n, res, rest # Fail if "editing beyond the end of screen" is tried or byte_n is # too big if {(lnumber + startline > 24) | (byte_n > 77)} then { write("ERROR: ILLEGAL ARGUMENT!") fail } n := 1 # Initialize feld as a list to contain string's contents feld := list(lnumber,"") # Crack apart string into byte_n-byte items. while lin := string[1:byte_n] do { # Assign every item's substring upto the last " " to field[n] feld[n] := lin[1:last(" ",lin)+1] # Assign the rest to rest rest := lin[(last(" ",lin)+2):*lin+1] # Delete the first byte_n bytes, then concatenate rest and string string[1:byte_n] := "" string := rest || string n +:= 1 } feld[n] := string # Display field's contents n := 1 locate(startline-1,1) writes(center(label,(byte_n-5)," ")) while n <= lnumber do { locate(startline-1+n,1) writes(feld[n]) n +:= 1 } # Begin editing process line_number := 1 lin_nm := 1 # Stop if access to non permitted line number (0,>lnumber) is # tried. while lin_nm >= 1 & lin_nm <= lnumber do { # locate(23,40) # write("ZEILENTYP: ",type(startline)) # read() liste := line(startline,byte_n,1," ",feld[lin_nm]) feld[lin_nm] := liste[1] locate(startline,1) writes(feld[lin_nm],repl(" ",byte_n-*feld[lin_nm]+1)) startline +:= line_number lin_nm +:= line_number # If wrap demanded and the following line is capable to contain # the wrapped rest of the line before and its original content, # perform wrap. if *liste[2] + *feld[lin_nm] <= byte_n then { feld[lin_nm] := liste[2] || " " || feld[lin_nm] } } # Set flag field_flag to -1/1 to indicate the direction # in which the field has been quitted. if lin_nm <= 1 then field_flag := -1 if lin_nm >= lnumber then field_flag := 1 # Put the string to be returned together of feld's elements. res := "" while item := pop(feld) do { res := res || " " || item } return res end # # show_field: see edit field (except editing routines) for # details. procedure show_field(startline,lnumber,byte_n,label,string) local feld, lin, n, rest if {(lnumber + startline > 24) | (byte_n > 77)} then { write("ERROR: ILLEGAL ARGUMENT!") fail } n := 1 feld := list(lnumber,"") while lin := string[1:byte_n] do { feld[n] := lin[1:last(" ",lin)+1] rest := lin[(last(" ",lin)+2):*lin+1] string[1:byte_n] := "" string := rest || string n +:= 1 } feld[n] := string n := 1 locate(startline-1,1) writes(center(label,(byte_n-5)," ")) while n <= lnumber do { locate(startline-1+n,1) writes(feld[n]) n +:= 1 } end # # edit_item(): function to edit the entry concerning one item # of literature. This function makes it necessary to declare # a fixed structure of every item within the function # "#" separates the fields from each other. it shouldn't be # contained in the data given to edit_item(). # # Structure of an item: # TITLE # AUTHOR # YEAR # TYPE # COMMENT1 # COMMENT2 procedure edit_item(item) local ct, feld, felder, felder2, item2, labels, lin_e, n, zeile felder := list() felder2 := list() labels := ["AUTHOR","TITLE","YEAR","TYPE","COMMENT1","COMMENT2"] item ? { while feld := tab(upto("#")) do { move(1) put(felder,feld) put(felder2,feld) } } zeile := 2 # Display the fields n := 1 while feld := get(felder) do { show_field(zeile,2,70,labels[n],feld) n +:= 1 zeile +:= 4 } # Start editing process ct := 1 zeile := 2 while zeile >= 2 & zeile <= 22 do { felder2[ct] := edit_field(zeile,2,70,labels[ct],trim(felder2[ct])) ct +:= field_flag if field_flag = 1 then zeile +:= 4 else zeile -:= 4 } # Indicate the direction in which item has been quitted using # global variable item_flag if zeile < 2 then item_flag := -1 else item_flag := 1 item2 := "" # Format result: item's fields are brought up to a standard length # of 140 bytes using blanks. while lin_e := get(felder2) do { item2 ||:= lin_e || repl(" ",(140 - *lin_e)) || "#" } return item2 end # # brightwrite(string): function to highlight a string procedure brightwrite(string) local highl, normal highl := char(27) || "[7m" normal := char(27) || "[0m" writes(highl,string,normal) end # # findlist(wlist,item): function to return the first # position of item in wlist. procedure findlist(wlist,item) local n n := 1 while n <= *wlist do { if wlist[n] == item then return n n +:= 1 } fail end # # menue(header,wlist,klist): function to build up a menuE # Arguments: header, list of options (wlist) and list of # shorthand keys (key list). # because menue() fails if a non defined key (not contained # in klist, no arrow key), calls to menue() should be made # within a loop terminated on menue()'s success, see below # main(). procedure menue(header,wlist,klist) local add, byte, n locate(4,10) writes(header) n := 5 while (n - 4) <= *wlist do { locate(n,10) writes(wlist[n-4]) n +:= 1 } n := 5 locate(n,10) brightwrite(wlist[n-4]) while byte := getch() & { byte == (char(21) | char(14)) | findlist(klist,byte) } do { # If byte Is element of klist (shorthandkey) the element number # within the list + 4 indicates option. if add := findlist(klist,byte) then { locate(n,10) writes(wlist[n-4]) n := 4 + add locate(n,10) brightwrite(wlist[n-4]) } # else increase/decrease actual element by one. else { if byte == char(14) then add := -1 if byte == char(21) then add := 1 locate(n,10) writes(wlist[n-4]) n +:= add if (n - 4) < 1 then n +:= 1 if (n - 4) > *wlist then n -:= 1 locate(n,10) brightwrite(wlist[n-4]) } } if byte == char(13) then return wlist[(n-4)] else fail end # # in_itemm(): function to create new items. Standard file is literat.fil # The new items are handled as a sequential file which is added to the # existing file when input process is finished. procedure in_itemm() local answer, count, items, itnum, out_item item_flag := 1 items := list(200,"######") itnum := 0 repeat { itnum +:= item_flag if itnum < 1 then itnum := 1 items[itnum] := edit_item(items[itnum]) writes(char(27),"[2J") write("NEW ITEM? Yy/Nn!") answer := getch() if answer == ("n" | "N") then break } count := 1 out_item := open("literat.fil","a") while items[count] ~== "######" do { writes(out_item,items[count]) count +:= 1 } close(out_item) end # # turn_over(): view and edit literat.fil item by item procedure turn_over() local answer, in_item, it, out_item in_item := open("literat.fil","r") out_item := open("literat2.fil","w") repeat { it := reads(in_item,846) it := edit_item(it) writes(out_item,it) writes(char(27),"[2J") write("NEW ITEM? Yy/Nn!") answer := getch() if answer == ("n" | "N") then break # If item_flag is -1 seek -1692 (2 items) to access the beginning of the # previous item because the internal file pointer points to the end of # the actual item. if item_flag == -1 then seek(in_item,where(in_item)-1692) } close(in_item) close(out_item) end # # del(num) remove numth item from filE procedure del() local fil, in_item, itm, n, num, out_item writes(char(27),"[2J") write("NUMBER OF ITEM TO BE REMOVED?") num := read() write("READING...") fil := list() in_item := open("literat.fil","r") while itm := reads(in_item,846) do { put(fil,itm) } close(in_item) write("START OVERWRITE PROCESS...") n := num while n < *fil do { fil[n] := fil[n+1] n +:= 1 } fil[*fil] := "" out_item := open("literat2.fil","w") write("WRITING...") while itm := get(fil) & itm ~== "" do { writes(out_item,itm) } close(out_item) write("DONE...") end # # alpha: sorting in alphabetical order procedure alpha() local fil, in_item, itm, out_item writes(char(27),"[2J") write("READING...") fil := list() in_item := open("literat.fil","r") while itm := reads(in_item,846) do { put(fil,itm) } close(in_item) write("ARRANGING DATA IN ALPHABETICAL ORDER...") fil := sort(fil) write("WRITING...") out_item := open("literat2.fil","w") while itm := get(fil) & itm ~== "" do { writes(out_item,itm) } close(out_item) write("DONE...") end # # m_adress: function to generate a file with arguments to the seek() # function. The file (adress.fil) will be used for sequential # search in the computer's ram, (function (query()). The results enable # the seek() function to place the internal file pointer on the desired # item in literat.fil. procedure m_adress() local a, adr, b, in_item, item, m, n, out_adr, out_line, wlist, wlist_2 out_line := "" adr := edit_field(4,10,70,"FORMAT: ;;ETC.","") writes(char(27),"[2J") write("GENERATING WORD LIST...") wlist := list() n := 1 adr ? { while put(wlist,tab(upto(";"))) do { move(1) write("ACTUAL WORD: ",wlist[n]) n +:= 1 } } in_item := open("literat.fil","r") n := 1 wlist_2 := copy(wlist) # Insert ; between word in wlist_2 and seqence of record numbers # to be found out later. while n <= *wlist_2 do { wlist_2[n] ||:= ";" n +:= 1 } n := 1 while n <= *wlist do { write("COMPARING WORD NUMBER: ",n,".") # counter m: indicates record number m := 1 while item := reads(in_item,846) do { if find(wlist[n],item) then { wlist_2[n] ||:= m || ";" } m +:= 1 } wlist_2[n] ? { a := tab(upto(";")) b := tab(0) } if b == ";" then b := ";0" wlist_2[n] := a || b out_line ||:= wlist_2[n] || ":" # When every item has been compared with wlist[n], move file # pointer to the beginning of in_item and increase n by 1. seek(in_item,1) n +:= 1 } close(in_item) # Remove trailing blank if any if out_line[1] := " " then { out_line := out_line[2:(*out_line+1)] } write("WRITING ADRESS FILE") out_adr := open("adress.fil","a") writes(out_adr,out_line) close(out_adr) write("OK") end # # query(): find items using the numbers in adress.fil * 846 as # arguments to the seek() function procedure query() local byte, in_item, in_line, in_query, it_key, kkey, out_item, word, wrd writes(char(27),"[2J") in_query := open("adress.fil","r") in_line := read(in_query) close(in_query) in_item := open("literat.fil","r") out_item := open("literat2.fil","a") wrd := line(10,20,0,"TYPE WORD TO BE LOOKED FOR: ","") word := wrd[1] if byte := find(word,in_line) then { in_line ? { move(byte) it_key := tab(upto(":")) } } else { locate(10,25) writes("ERROR: UNKNOWN WORD! PRESS KEY!") getch() fail } # place internal cursor behind the first ; to get the first # number: it_key := it_key[find(";",it_key)+1:*it_key+1] it_key ? { while kkey := tab(upto(";")) do { if kkey <= 0 then { locate(10,25) writes("ERROR: UNKNOWN WORD! PRESS KEY!") getch() fail } seek(in_item,(kkey-1)*846) writes(out_item,edit_item(reads(in_item,846))) move(1) } } close(in_item) close(out_item) write("OK") end # # main program. see the description of the program's functionS # at the beginning of the source code and of every user-defined # function if you are in doubt how to use them. # procedure main() local alist, blist, opt newkey() alist := { ["iNPUT","tURN OVER ITEMS","aDRESS FILE","qUERY","dEL","AlPHA","eND"] } blist := ["i","t","a","q","d","l","e"] repeat { repeat { writes(char(27),"[2J") locate(1,10) write("LITERAT: EASY DATABASE SYSTEM") locate(2,10) write("WRITTEN BY: MATTHIAS HEESCH 1992") if opt := menue("MENUE",alist,blist) then break } writes(char(27),"[2J") case opt of { "iNPUT" : in_itemm() "tURN OVER ITEMS" : turn_over() "aDRESS FILE" : m_adress() "qUERY" : query() "dEL" : del() "AlPHA" : alpha() "eND" : break } } end