@x \def\version{1.0.1} @y \let\maybe=\iffalse \def\version{1.0.1, Rev.~2} @z @x \centerline{\titlefont The MAKEPROG processor} @y \centerline{\titlefont DOS Changes to the MAKEPROG processor} @z @x @d banner=='This is MAKEPROG, Version 1.0.1.' @y @d banner=='This is MAKEPROG, Version 1.0.1 (DOS Changes, Rev. 2).' @z @x @d end_of_MAKEPROG = 9999 {go here to wrap it up} @y @f uses == const @z @x program MAKEPROG(@!doc_file,@!change_file,@!prog_file); @y program MAKEPROG(@!output,@!doc_file,@!change_file,@!prog_file); @z @x label end_of_MAKEPROG; {go here to finish} @y uses CRT, DOS ; @z @x @t\4@>@@; @y @t\4@>@@; @t\4@>@@; @z x @d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging} @d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging} y @d debug== {we are debugging \.{MAKEPROG}} @d gubed== z @x @= @{@&@=$D-@> @} {no debug overhead} @!debug @{@&@=$D+@> @}@+ gubed @; {but turn everything on when debugging} @y @= @{@=$R-,B-,D-,E-,L-,S+,V-@>@} { R- no range checking } { B- boolean evaluation ... short circuit } { D- debug information off } { E- emulation off } { L- local symbols ... off } { S+ stack checking ... on } { V- var string checking ... relaxed } @z @x @d othercases == others: {default for cases not listed explicitly} @y @d othercases == else {default for cases not listed explicitly} @z @x @d last_text_char=127 {ordinal number of the largest element of |text_char|} @y @d last_text_char=255 {ordinal number of the largest element of |text_char|} @z @x @!text_file=packed file of text_char; @y @!text_file=text; @z @x for i:=1 to " "-1 do xchr[i]:=' '; @y for i:=1 to " "-1 do xchr[i]:=' '; xchr[tab_mark] := chr(tab_mark); @z @x is assumed to consist of characters of type |text_char|: @^system dependencies@> @d print(#)==write(term_out,#) {`|print|' means write on the terminal} @d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line} @d new_line==write_ln(term_out) {start new line} @d print_nl(#)== {print information starting on a new line} begin new_line; print(#); end @= @!term_out:text_file; {the terminal as an output file} @y is assumed to consist of characters of type |text_char|: @^system dependencies@> @d term_out == output {the output file is normaly the terminal} @# @d print(#)==write(term_out,#) {`|print|' means write on the terminal} @d print_ln(#)==write_ln(term_out,#) {`|print|' and then start new line} @d new_line==write_ln(term_out) {start new line} @d print_nl(#)== {print information starting on a new line} begin new_line; print(#); end @z @x rewrite(term_out,'TTY:'); {send |term_out| output to the terminal} @y do_nothing; {|output| is opened automatically} @z @x @d update_terminal == break(term_out) {empty the terminal output buffer} @y @d update_terminal == do_nothing {output to |output| is unbuffered} @z @x reset(doc_file); reset(change_file); @y @< Initialize the Turbo Pascal specific input/output related variables @>; tp_reset(doc_file, 'DOC', doc_buffer); tp_reset(change_file, 'CHF', chf_buffer); @z @x rewrite(prog_file); @y tp_rewrite(prog_file, prog_ext, prog_buffer); @z @x function input_ln(var f:text_file):boolean; {inputs a line or returns |false|} var final_limit:0..buf_size; {|limit| without trailing blanks} begin limit:=0; final_limit:=0; if eof(f) then input_ln:=false else begin while not eoln(f) do begin buffer[limit]:=xord[f^]; get(f); incr(limit); if (buffer[limit-1]<>" ") and (buffer[limit-1]<>tab_mark) then final_limit:=limit; if limit=buf_size then begin while not eoln(f) do get(f); decr(limit); {keep |buffer[buf_size]| empty} print_nl('! Input line too long'); error; mark_error; @.Input line too long@> end; end; read_ln(f); limit:=final_limit; input_ln:=true; end; end; @y function input_ln(var f:text_file):boolean; {inputs a line or returns |false|} var s: string; {temporary line storage} final_limit: 0..buf_size+1; {index into |s|} i: 0..buf_size; {index into |buffer|} begin if eof(f) then begin limit := 0; input_ln := false; end else begin read_ln(f,s); final_limit := ord(s[0]); while (final_limit > 0) and ((s[final_limit] = ' ') or (s[final_limit] = xchr[tab_mark])) do decr(final_limit); if final_limit > buf_size+1 then final_limit := buf_size + 1; for i:=0 to final_limit-1 do buffer[i] := xord[s[i+1]]; if final_limit >= buf_size then begin final_limit := buf_size - 1; {keep |buffer[buf_size]| empty} print_nl('! Input line too long'); error; mark_error; @.Input line too long@> end; limit := final_limit; input_ln := true ; end; end; @z @x procedure jump_out; begin goto end_of_MAKEPROG; end; @y procedure jump_out; begin close(prog_file); close(doc_file); close(change_file); @;@# @; halt; end; @z @x procedure put_line; var i: 0..buf_size; begin for i:=0 to limit-1 do write(prog_file, xchr[buffer[i]]); write_ln(prog_file); end; @y procedure put_line; var i: 0..buf_size; s: string; {temporary line storage} begin for i:=0 to limit-1 do s[i+1] := xchr[buffer[i]]; s[0] := chr(limit); write_ln(prog_file, s); end; @z @x end_of_MAKEPROG: @# {here files should be closed if the operating system requires it} @;@# @; @y jump_out; @z @x @= case history of spotless: print_nl('(No errors were found.)'); harmless_message: print_nl('(Did you see the warning message above?)'); error_message: print_nl('(Pardon me, but I think I spotted something wrong.)'); fatal_message: print_nl('(That was a fatal error, my friend.)'); end {there are no other cases} @y @= begin case history of spotless: print_nl('(No errors were found.)'); harmless_message: print_nl('(Did you see the warning message above?)'); error_message: print_nl('(Pardon me, but I think I spotted something wrong.)'); fatal_message: print_nl('(That was a fatal error, my friend.)'); end; {there are no other cases} new_line; end @z @x \noindent This module should be replaced, if necessary, by changes to the program that are necessary to make \MAKEPROG{} work at a particular installation. It is usually best to design your change file so that all changes to previous modules preserve the module numbering; then everybody's version will be consistent with the printed program. More extensive changes, which introduce new modules, can be inserted here; then only the index itself will get a new module number. @^system dependencies@> @y \noindent This module should be replaced, if necessary, by changes to the program that are necessary to make \MAKEPROG{} work at a particular installation. It is usually best to design your change file so that all changes to previous modules preserve the module numbering; then everybody's version will be consistent with the printed program. More extensive changes, which introduce new modules, can be inserted here; then only the index itself will get a new module number. @^system dependencies@> @* Resetting and rewriting files. \noindent Turbo Pascal allows the usage of command line parameters but does not connect external files with the internal file variables automatically. Therefore we demand the file name (without extension) in the command line---with this name we can open resp.\ create the files. The real opening of input files is done via |tp_reset| and the creating of output files is done via |tp_rewrite|. Both procedures have two parameters, the file variable and the extension which should be used together with the file name. The extension is passed without a dot. @< Glob... @>= @!file_name: string; @!prog_ext: string; @ But first we have to look at the command line. If there is no parameter present we print a usage message and finish the program afterwards. Here |jump_out| cannot be used because files would be closed that would be not open. @< Initialize the Turbo... @>= if param_count < 1 then begin print('! usage: makeprog [-ext] file_name'); halt; end else begin file_name := param_str(1); if (param_count = 2) and (file_name[1] = '-') then begin prog_ext := copy(file_name, 2, 3); file_name := param_str(2); end else prog_ext := 'PRG'; end; @ @< Type... @>= @!file_buffer=packed array[1..4096] of byte; @ @< Glob... @>= @!doc_buffer:file_buffer; {file buffer for primary input} @!chf_buffer:file_buffer; {file buffer for updates} @!prog_buffer:file_buffer; {file buffer for output} @ If an input file can't be opened we handle it just like a file that is not there. I.e., we use \.{NUL:} as the input file---|eof| will then always return true as presumed by the program. @< Turbo Pascal specific procedures @>= procedure tp_reset( var f: text_file; ext: string; var buf: file_buffer ); begin assign(f, file_name+'.'+ext); @/ @{@=$I-@>@} reset(f); @{@=$I+@>@} if io_result = 0 then settextbuf(f, buf) else begin assign(f, 'NUL'); reset(f); { |eof(f) = true| } end; end; @# procedure tp_rewrite( var f: text_file; ext: string; var buf: file_buffer ); begin assign(f, file_name+'.'+ext); rewrite(f); settextbuf(f, buf); end; @z