program versave(input, output); (* versave: save the file under the version number Dr. Thomas D. Schneider National Cancer Institute Laboratory of Experimental and Computational Biology Molecular Information Theory Group Frederick, Maryland 21702-1201 toms@ncifcrf.gov permanent email: toms@alum.mit.edu (use only if first address fails) http://www.lecb.ncifcrf.gov/~toms/ module libraries: delman, prgmods *) label 1; (* the end of the program *) const (* begin module version *) version = 1.12; (* of versave.p 2005 Jan 19 2005 Jan 19, 1.12: allow negative version numbers 1995 Dec 20, 1.11: upgrade this so it accepts string versions origin from verbop 2.04 *) (* end module version *) (* begin module describe.versave *) (* name versave: save the file under the version number synopsis versave(input: in, output: out) files input: a text file, with a version constant in the form 'version = ' followed by a real number. The name of the file (including dot extensions) must be found after the word 'of '. For example: version = 1.11; (@ of versave.p 1995 December 20 @) (where @ would be * in the actual program) Alternatively, the input line can be of the form: version = '6.09 of module.p 95Dec20 tds'; The program will handle either form. output: Four lines are produced: file (name of text file found after the 'of') version (the real number found after 'version = ') description Generate commands for worcha on how to change a script for saving the file. A script is then passed through worch to produce the executable commands. example For an input file containing: version = 1.00; (@ of versave.p 1989 April 4 The output is: file versave.p version 1.00 This is to be placed in the worcha parameter file, worchap. An example script is: cp file old/file.version echo saved file in old/file.version Using worcha with the script would become: cp versave.p old/versave.p.1.00 echo saved versave.p in old/versave.p.1.00 When executed, this will save the text. author thomas schneider see also worcha.p, verbop.p, ver.p, code.p bugs none known *) (* end module describe.versave *) (* begin module interact.const *) maxstring = 150; (* the maximum string *) (* end module interact.const version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module filler.const *) fillermax = 50; (* the size of the filler array for a string *) (* end module filler.const version = 'prgmod 3.98 86 nov 11 tds'; *) type (* begin module interact.type *) string = record (* a string of characters *) letters: array[1..maxstring] of char; (* the letters in the string *) length: integer; (* the number of characters in the string *) current: integer; (* the letter we are working on *) end; (* end module interact.type version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module trigger.type *) trigger = record (* an object to be searched for *) seek: string; (* the characters looked for *) state: integer; (* how close to triggering we are *) skip: boolean; (* trigger not found- skip the line *) found: boolean (* the trigger was found *) end; (* end module trigger.type version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module filler.type *) (* the following is an array used to fill a string. it is convenient to have it much shorter than the maxstring, so that it is easy to fill the string using procedure fillstring. the user must declare the value of constant fillermax. *) filler = packed array[1..fillermax] of char; (* end module filler.type version = 'prgmod 3.98 86 nov 11 tds'; *) var (* begin module versave.var *) source: text; (* the input and output file *) (* end module versave.var *) procedure halt; (* stop the program. the procedure performs a goto to the end of the program. you must have a label: label 1; declared, and also the end of the program must have this label: 1: end. examples are in the module libraries. this is the only goto in the delila system. *) begin writeln(output,'echo "program halt."'); goto 1 end; (* begin module interact.clearstring *) procedure clearstring(var ribbon: string); (* empty the string *) var index: integer; (* to the ribbon *) begin (* clearstring *) with ribbon do begin for index := 1 to maxstring do letters[index] := ' '; length := 0; current := 0; end end; (* clearstring *) (* end module interact.clearstring version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module interact.writestring *) procedure writestring(var tofile: text; var s: string); (* write the string s to file tofile, no writeln *) var i: integer; (* index to s *) begin (* writestring *) with s do for i := 1 to length do write(tofile, letters[i]) end; (* writestring *) (* end module interact.writestring version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module filler.fillstring *) procedure fillstring(var s: string; a: filler); (* this procedure makes it reasonably easy to fill the string s with characters. one calls the procedure as: *) (* 1 2 3 4 5 *) (* 12345678901234567890123456789012345678901234567890 *) (* fillstring(s, 'this-is-the-string '); the two comments make it easy to line the characters up. also, for this example, it was assumed that the length of filler as defined by the constant fillermax was 50. *) var length: integer; (* of the string without trailing blanks *) index: integer; (* of s *) begin (* fillstring *) clearstring(s); length := fillermax; while (length > 1) and (a[length] = ' ') do length := pred(length); if (length = 1) and (a[length] = ' ') then begin writeln(output, 'fillstring: the string is empty'); halt end; for index := 1 to length do s.letters[index] := a[index]; s.length := length; s.current := 1 end; (* fillstring *) (* end module filler.fillstring version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module filler.filltrigger *) procedure filltrigger(var t: trigger; a: filler); (* fill the trigger t *) begin (* filltrigger *) fillstring(t.seek,a) end; (* fillstring *) (* end module filler.filltrigger version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module trigger.proc *) (* this module allows one to scan a series of characters, as from an array or a file, and to "trigger" or detect a simple string in the series. the advantage of the trigger is that several triggers can "observe" a stream of characters at once, each looking for a different thing. some other modules required: interact.const, interact.type *) procedure resettrigger(var t: trigger); (* reset the trigger to ground state *) begin (* resettrigger *) with t do begin state := 0; skip := false; found := false end end; (* resettrigger *) procedure testfortrigger(ch: char; var t: trigger); (* look at the character ch. if it is part of the trigger (at the current trigger state), then the trigger state goes higher. if it is not part of the trigger then the trigger state is reset, skip is true and one should skip onward to find the trigger. if the trigger is found, found is true. *) begin (* testfortrigger *) with t do begin state := succ(state); (* if debugging then begin writestring(list,seek); writeln(list,'testfortrigger seek.letters[',state:1,']:', seek.letters[state],' ch:',ch); end;*) if seek.letters[state] = ch then begin skip := false; if state = seek.length then found := true else found := false end else begin (* reset trigger *) state := 0; skip := true; found := false end end end; (* testfortrigger *) (* end module trigger.proc version = 'prgmod 3.98 86 nov 11 tds'; *) (* begin module versave.capture *) procedure capture(var field: text; var rabbit: real); (* capture the rabbit in the field (ie, pickup the version number) 2005 Jan 19: allow negative numbers. *) begin (* capture *) (* galump across the field in search of a hole *) while (not eoln(field)) and ((field^ = ' ') (* skip blank field *) or (field^= '''')) (* don't be fooled by fake rabbit tails *) do get(field); (* is there a rabbit? *) if field^ in ['0'..'9','-'] (* poke a stick in the hole *) then read(field, rabbit) (* got it - yum *) else begin (* nothing edible *) writeln(output,'echo "version must be a real number"'); (* scream *) halt (* die of starvation *) end end; (* capture - do you think i overdid this one? *) (* end module versave.capture *) (* begin module versave.themain *) procedure themain(var source: text); (* the main procedure of the program *) var t: trigger; (* the version trigger *) n: string; (* the name of the source *) theversion: real; (* the version *) begin (* writeln(output,'#!/bin/csh -f'); writeln(output,'#(ie run the cshell on this but don''t read the .cshrc)'); writeln(output, '# versave ', version:4:2); *) reset(source); (* 1 2 3 4 5 *) (* 12345678901234567890123456789012345678901234567890 *) filltrigger(t, 'version = '); resettrigger(t); repeat testfortrigger(source^, t); get(source); until eof(source) or t.found; if t.found then begin capture(source, theversion); (* writeln(output, '# THE VERSION IS ', theversion:4:2); *) end else begin writeln(output, 'echo "no ''version ='' string"'); halt end; (* now locate the 'of' string *) (* 1 2 3 4 5 *) (* 12345678901234567890123456789012345678901234567890 *) filltrigger(t, 'of '); resettrigger(t); repeat testfortrigger(source^, t); get(source); until eof(source) or t.found; if source^ = ' ' then get(source) (* move past the space *) else begin writeln(output, 'echo " ''of'' not followed by a space"'); halt end; if t.found then begin (* capture the name string *) clearstring(n); while (not eoln(source)) and (source^<>' ') do with n do begin length := length + 1; letters[length] := source^; get(source) end; (* write(output,'# THE STRING FOUND IS <'); writestring(output,n); writeln(output,'>'); *) end else begin writeln(output, 'echo "no ''of'' string"'); halt end; writeln(output,'file'); writestring(output,n); writeln(output); writeln(output,'version'); writeln(output,theversion:4:2); end; (* end module versave.themain *) begin themain(input); 1: end. (* versave *)