summaryrefslogtreecommitdiff
path: root/systems/unix/tex-fpc/mf.ch
diff options
context:
space:
mode:
Diffstat (limited to 'systems/unix/tex-fpc/mf.ch')
-rw-r--r--systems/unix/tex-fpc/mf.ch845
1 files changed, 845 insertions, 0 deletions
diff --git a/systems/unix/tex-fpc/mf.ch b/systems/unix/tex-fpc/mf.ch
new file mode 100644
index 0000000000..0b697ec3da
--- /dev/null
+++ b/systems/unix/tex-fpc/mf.ch
@@ -0,0 +1,845 @@
+% This is a change file of Metafont for FPC, Wolfgang Helbig, Nov. 2007
+[0] to print changed sections only
+@x
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+@y
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+\input webmac-fpc
+\emergencystretch 0.5in % avoid overfull boxes
+
+\let\maybe=\iftrue % print changed modules only.
+
+\def\name{\MF}
+
+\N0\*. \[0] About \namefpc.
+
+This is an adaption of Donald~E. Knuth's \MF, version 2.7182815
+from January 2014, to Free~Pascal (FPC) and Unix.
+
+The features added include treating the command line as the first
+input line and invoking a system editor, in this case \.{vi}, to
+let the user correct the input file.
+On exit, \namefpc\ passes its `history' to the operating system.
+
+The changes needed to make \namefpc\ compile and run to my satisfaction
+are very similar to those applied to \TeXfpc. Look in tex.tex for
+a thorough description of adaptions to Unix, FPC, and my taste.
+
+\hint
+
+Comments and questions are welcome!
+
+\bigskip
+\address
+\fi
+@z
+
+[2] Change the banner line
+@x
+@d banner=='This is METAFONT, Version 2.7182818' {printed when \MF\ starts}
+@y
+@d banner=='This is METAFONT-FPC, 2nd ed.' {printed when \MF\ starts}
+@z
+
+[4] terminal output and input
+@x
+@^system dependencies@>
+
+@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:}
+@y
+@^system dependencies@>
+
+@d term_in==i@&n@&p@&u@&t
+@d term_out==o@&u@&t@&p@&u@&t
+@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:}
+@z
+
+[4] terminal output and input
+@x
+program MF; {all file names are defined dynamically}
+@y
+program MF(@!term_in,@!term_out);
+{all other file names are defined dynamically}
+@z
+
+[4] forward declaration for signal handler
+@x
+procedure initialize; {this procedure gets things started properly}
+@y
+procedure catch_signal(i: integer); interrupt; forward;
+procedure initialize; {this procedure gets things started properly}
+@z
+
+Since @x, @y, and @z only define a change block when they begin a
+line, you deactivate a block by indenting it (shift right) and
+activate it by unindenting it (shift left). With vi set the
+cursor to the @x line and enter >} or <} to (un)indent a paragraph.
+
+[7] shift left to turn debugging on, right to turn it off
+ @x debug
+ @d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+ @d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+ @y
+ @d debug== {change this to `$\\{debug}\equiv\.{@@\{}$' when not debugging}
+ @d gubed== {change this to `$\\{gubed}\equiv\.{@@\}}$' when not debugging}
+ @z
+
+[7] shift left to turn on statistics, shift rigth to turn off statistics
+ @x stat
+ @d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
+ usage statistics}
+ @d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
+ usage statistics}
+ @y
+ @d stat== {change this to `$\\{stat}\equiv\.{@@\{}$' to turn off statistics}
+ @d tats== {change this to `$\\{tats}\equiv\.{@@\}}$' to turn off statistics}
+ @z
+
+ [8] shift left to build MF and right it to build INIMF.
+ @x inimf
+ @d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
+ @d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
+ @y
+ @d init==@{
+ @d tini==@}
+ @z
+
+[9] compiler directives, turn off I/O checking.
+@x
+@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
+@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
+@y
+@{$MODE@,ISO@} {turn on mode ISO}
+@{$Q+@} {turn on overflow checking}
+@{$R+@} {turn on range checking}
+@!debug @{Q+@}@,@{R+@}@+ gubed {turn checks off when debugging}
+@z
+
+[10] default case branch
+@x
+@d othercases == others: {default for cases not listed explicitly}
+@y
+@d othercases == @+ else {default for cases not listed explicitly}
+@z
+
+Shift left all `trap' blocks to prepare for TRAP.
+Shift right all `part' blocks to prepare for TRAP.
+[11]
+@x part
+@!mem_max=30000; {greatest index in \MF's internal |mem| array;
+@y
+@!mem_max=35000; {increased for ibycus4,
+ greatest index in \MF's internal |mem| array;
+@z
+
+[11]
+@x part
+@!max_strings=2000; {maximum number of strings; must not exceed |max_halfword|}
+@y
+@!max_strings=6000; {maximum number of strings; increased for ibycus4}
+@z
+
+@x part
+@!pool_size=32000; {maximum number of characters in strings, including all
+@y
+@!pool_size=60000; {increased for ibycus4,
+ maximum number of characters in strings, including all
+@z
+
+[11]
+ @x trap
+ @!mem_max=30000; {greatest index in \MF's internal |mem| array;
+ @y
+ @!mem_max=3000; {greatest index in \MF's internal |mem| array;
+ @z
+
+[11]
+ @x trap
+ @!error_line=72; {width of context lines on terminal error messages}
+ @!half_error_line=42; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+ @!max_print_line=79; {width of longest text lines output; should be at least 60}
+ @!screen_width=768; {number of pixels in each row of screen display}
+ @!screen_depth=1024; {number of pixels in each column of screen display}
+ @y
+ @!error_line=64; {width of context lines on terminal error messages}
+ @!half_error_line=32; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+ @!max_print_line=72; {width of longest text lines output; should be at least 60}
+ @!screen_width=100; {number of pixels in each row of screen display}
+ @!screen_depth=200; {number of pixels in each column of screen display}
+ @z
+
+[11]
+ @x trap
+ @!gf_buf_size=800; {size of the output buffer, must be a multiple of 8}
+ @y
+ @!gf_buf_size=8; {size of the output buffer, must be a multiple of 8}
+ @z
+
+[11] location of pool file
+@x
+@!pool_name='MFbases:MF.POOL ';
+@y
+@!pool_name='MFbases/mf.pool';
+@z
+
+
+[12]
+@x part
+@d mem_top==30000 {largest index in the |mem| array dumped by \.{INIMF};
+@y
+@d mem_top==35000 {largest index in the |mem| array dumped by \.{INIMF};
+@z
+
+[12]
+ @x trap
+ @d mem_top==30000 {largest index in the |mem| array dumped by \.{INIMF};
+ @y
+ @d mem_top==3000 {largest index in the |mem| array dumped by \.{INIMF};
+ @z
+
+[12] Silvio levy' greek fonts need more opened input files.
+@x part
+@d max_in_open=6 {maximum number of input files and error insertions that
+@y
+@d max_in_open=10 {maximum number of input files and error insertions that
+@z
+
+[22] accept tab and formfeed
+@x
+for i:=0 to @'37 do xchr[i]:=' ';
+@y
+for i:=0 to @'37 do xchr[i]:=' ';
+xchr[@'11] := chr(@'11); {accept horizontal tab}
+xchr[@'14] := chr(@'14); {accept form feed}
+@z
+
+[24] the type of text_files is text in ISO Pascal
+@x
+@!eight_bits=0..255; {unsigned one-byte quantity}
+@!alpha_file=packed file of text_char; {files that contain textual data}
+@y
+@!eight_bits=0..255; {unsigned one-byte quantity}
+@!alpha_file=t@&e@&x@&t; {coding trick is needed since |text| is a macro}
+@z
+
+[26] dynamic io
+@x
+@d reset_OK(#)==erstat(#)=0
+@d rewrite_OK(#)==erstat(#)=0
+@y
+@d fpc_io_result==i@&o@&r@&e@&s@&u@&l@&t
+@d fpc_assign==a@&s@&s@&i@&g@&n
+@d reset_OK(#)==fpc_io_result=0
+@d rewrite_OK(#)==fpc_io_result=0
+@d clear_io_result==@+if fpc_io_result=0 then do_nothing
+@z
+
+[26] opening for in- and output for all three file types
+alpha in
+@x
+@p function a_open_in(var @!f:alpha_file):boolean;
+ {open a text file for input}
+begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
+@y
+@p @{@&$I-@} {turn off I/O checking}
+@#
+function a_open_in(var @!f:alpha_file):boolean;
+ {open a text file for input}
+begin clear_io_result; fpc_assign(f,name_of_file);reset(f);
+a_open_in:=reset_OK(f);
+@z
+
+[26]
+alpha out
+@x
+begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); rewrite(f);
+a_open_out:=rewrite_OK(f);
+@z
+
+[26] byte out
+@x
+begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); rewrite(f);
+b_open_out:=rewrite_OK(f);
+@z
+
+[26] word in
+@x
+begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); reset(f);
+w_open_in:=reset_OK(f);
+@z
+
+[26] word out
+@x
+begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
+end;
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); rewrite(f);
+w_open_out:=rewrite_OK(f);
+end;
+@#
+@{@&$I+@} {turn on I/O checking}
+@z
+
+[30] bypass_eoln
+@x
+begin if bypass_eoln then if not eof(f) then get(f);
+@y
+begin
+@z
+
+[30] bypass_eoln
+@x
+ last:=last_nonblank; input_ln:=true;
+ end;
+@y
+ last:=last_nonblank; input_ln:=true;
+ read_ln(f);
+ end;
+@z
+
+[31] term_in and term_out are the standard pascal files
+@x
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@<Glob...@>=
+@!term_in:alpha_file; {the terminal as an input file}
+@!term_out:alpha_file; {the terminal as an output file}
+@y
+is considered an output file the file variable is |term_out|.
+The file |term_in| is declared as \\{input} and |term_out| as
+\\{output} in the program header.
+@^system dependencies@>
+@z
+
+[32]
+@x
+@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
+@d t_open_out==rewrite(term_out,'TTY:','/O')
+ {open the terminal for text output}
+@y
+@d t_open_in==do_nothing {open the terminal for text input}
+@d t_open_out==do_nothing {open the terminal for text output}
+@z
+
+[33]
+@x
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
+@y
+@d update_terminal == do_nothing {empty the terminal output buffer}
+@d clear_terminal == do_nothing {clear the terminal input buffer}
+@z
+
+[35] command line
+@x
+@d loc==cur_input.loc_field {location of first unread character in |buffer|}
+@y
+@d loc==cur_input.loc_field {location of first unread character in |buffer|}
+@d fpc_string == s@&h@&o@&r@&t@&s@&t@&r@&i@&n@&g
+@d fpc_length==l @& e @& n @& g @& t @& h
+@d fpc_param_count==p @& a @& r @& a @& m @& c @& o @& u @& n @& t
+@d fpc_param_str==p @& a @& r @& a @& m @&s @& t @& r
+ {FPC function returning the length of a |fpc_string|}
+@d fpc_int_to_str == i @& n @& t @& t @& o @& s @& t @& r
+
+@p procedure input_command_ln; {get the command line in |buffer|}
+var argc: integer; {argument counter}
+ arg: fpc_string; {argument}
+ cc: integer; {character counter in argument}
+begin last := first; argc := 1;
+while argc <= fpc_param_count do
+ begin cc := 1; arg := fpc_param_str(argc); incr(argc);
+ while cc <= fpc_length(arg) do
+ begin
+ if last+1>=buf_size then
+ @<Report overflow of the input buffer, and abort@>;
+ buffer[last] := xord[arg[cc]]; incr(last); incr(cc);
+ end;
+ if (argc <= fpc_param_count) then begin
+ buffer[last] := " "; incr(last);
+ end;
+ end;
+end;
+@z
+
+[36] command line
+@x
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@y
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in; input_command_ln;
+loc := first;
+if loc<last then
+ begin init_terminal:=true; return; {first line is the command line}
+ end;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@z
+
+[36] For Unix, End of file on the terminal is not remarkable
+@x
+ write(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+@y
+@z
+
+[36] control D
+@x
+ write_ln(term_out,'Please type the name of your input file.');
+@y
+ write_ln(term_out,'Please type the name of your input file or Control-D.');
+@z
+
+[51] leave pool file open
+@x
+@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#);
+ a_close(pool_file); get_strings_started:=false; return;
+ end
+@y
+@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#);
+ get_strings_started:=false; return;
+ end
+@z
+
+[51] lower case name of mf.pool
+@x
+else bad_pool('! I can''t read MF.POOL.')
+@y
+else bad_pool('! I can''t read mf.pool.')
+@z
+
+[74] start editor
+@x
+@!use_err_help:boolean; {should the |err_help| string be shown?}
+@y
+@!use_err_help:boolean; {should the |err_help| string be shown?}
+@!start_edit: boolean; {start \.{vi}?}
+@z
+
+[75] initial value for edit argument
+@x
+help_ptr:=0; use_err_help:=false; err_help:=0;
+@y
+help_ptr:=0; use_err_help:=false; err_help:=0;
+start_edit := false; { don't start \.{vi}}
+@z
+
+[79] set edit_cmd
+@x
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ slow_print(input_stack[file_ptr].name_field);
+ print(" at line "); print_int(line);@/
+ interaction:=scroll_mode; jump_out;
+ end;
+@y
+ begin {save values to be passed to the system editor}
+ start_edit := true;
+ interaction:=scroll_mode; jump_out;
+ end;
+@z
+
+[81] extra space on log file and terminate last terminal line
+@x
+"Q":begin print("batchmode"); decr(selector);
+ end;
+@y
+"Q":begin print("batchmode");
+ end;
+@z
+
+[81] continued
+@x
+print("..."); print_ln; update_terminal; return;
+@y
+print("..."); print_ln; update_terminal;
+if c="Q" then decr(selector); return;
+@z
+
+[194] date and time
+@x
+@p procedure fix_date_and_time;
+begin internal[time]:=12*60*unity; {minutes since midnight}
+internal[day]:=4*unity; {fourth day of the month}
+internal[month]:=7*unity; {seventh month of the year}
+internal[year]:=1776*unity; {Anno Domini}
+end;
+@y
+@p procedure fix_date_and_time;
+var yy,mm,dd: word;
+ hh,ss,ms: word;
+begin
+decodedate(now,yy,mm,dd); {current date}
+internal[day] := dd*unity;
+internal[month] := mm*unity;
+internal[year] := yy*unity;@/
+decodetime(now,hh,mm,ss,ms); {current time}
+internal[time] := (hh*60+mm)*unity; {minutes since midnight}
+end;
+@z
+
+[199] character class for tab and lf
+@x
+for k:=127 to 255 do char_class[k]:=invalid_class;
+@y
+for k:=127 to 255 do char_class[k]:=invalid_class;
+char_class[@'11] := space_class;
+char_class[@'14] := space_class;
+@z
+
+[326]
+@x
+no rows), we have |n_rover(h)=h|, and |n_pos(h)| is irrelevant.
+@y
+no rows), we have |n_rover(h)=h|, and |n_pos(h)| is irrelevant.
+
+The definition of |valid_range| was changed because the Free Pascal
+Compiler cannot compile expressions like |abs(a+b-4096)| when |a|
+and |b| are |half_words|. It does compile however |abs(int(a+b) -
+int(4096))|, and |abs(int(a+b-4096))| will throw an overflow exception.
+@z
+
+[326]
+@x
+@d valid_range(#)==(abs(#-4096)<4096) {is |#| strictly between 0 and 8192?}
+@y
+@d valid_range(#)==(abs(int(#)-int(4096))<4096) {is |#| strictly between 0 and 8192?}
+@z
+
+ [536] undo Knuth's change from mf-2008 to mf-2012, to explain the
+ diffs of pointer values in the trap.logs.
+ @x
+ done1: if (link(p)<>null) then free_node(link(p),knot_node_size);
+ link(p):=s; beta:=-y_coord(h);
+ @y
+ done1: link(p):=s; beta:=-y_coord(h);
+ @z
+
+[564]
+ @x trap
+ begin init_screen:=false;
+ @y
+ begin init_screen:=true;
+ @z
+
+[679] spurious empty line on terminal
+ @x chatty
+ print_ln; first:=start;
+ prompt_input("*"); {input on-line into |buffer|}
+ @y
+ @.Please type...@>
+ print_nl("");
+ first:=start; {avoid empty lines on terminal and log file}
+ prompt_input("*"); {input on-line into |buffer|}
+ @z
+
+[769] Path separator in Unix
+@x
+@d MF_area=="MFinputs:"
+@y
+@d MF_area=="MFinputs/"
+@z
+
+[771]
+@x
+else begin if (c=">")or(c=":") then
+@y
+else begin if c="/" then
+@z
+
+[774]
+@x
+@d append_to_name(#)==begin c:=#; incr(k);
+@y
+@d fpc_set_length==s@&e@&t@&l@&e@&n@&g@&t@&h
+@d append_to_name(#)==begin c:=#; incr(k);
+@z
+
+[774]
+@x
+@!j:pool_pointer; {index into |str_pool|}
+@y
+@!j:pool_pointer; {index into |str_pool|}
+rbs: fpc_string;
+@z
+
+[774]
+@x
+for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
+@y
+rbs := name_of_file;
+fpc_set_length(rbs, name_length);
+name_of_file := rbs;
+@z
+
+[776]
+@x
+MF_base_default:='MFbases:plain.base';
+@y
+MF_base_default:='MFbases/plain.base';
+@z
+
+[778]
+@x
+@!j:integer; {index into |buffer| or |MF_base_default|}
+@y
+@!j:integer; {index into |buffer| or |MF_base_default|}
+rbs: fpc_string;
+@z
+
+[778]
+@x
+for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
+@y
+rbs := name_of_file;
+fpc_set_length(rbs, name_length);
+name_of_file := rbs;
+@z
+
+[786]
+@x spaeter!
+print_nl("Please type another "); print(s);
+@y
+print_nl("Please type another "); print(s); print(" or Control-D");
+@z
+
+[793] name might be needed to be passed to vi
+@x
+if name=str_ptr-1 then {we can conserve string pool space now}
+ begin flush_string(name); name:=cur_name;
+ end;
+@y
+@^Editor@>
+@z
+
+
+ [1023] avoid blank line on terminal after mode command
+ @x chatty
+ mode_command: begin print_ln; interaction:=cur_mod;
+ @y
+ mode_command: begin print_nl(""); interaction:=cur_mod;
+ @z
+
+[1154] blockwrite for gf_buf
+@x
+output an array of words with one system call.
+@y
+output an array of words with one system call.
+
+@d fpc_blockwrite == b @& l @& o @& c @& k @& w @& r @& i @& t @& e
+@z
+
+@x
+begin for k:=a to b do write(gf_file,gf_buf[k]);
+@y
+begin fpc_blockwrite(gf_file,gf_buf[a],b-a+1);
+@z
+
+[1199]
+@x
+undump_int(x);@+if (x<>69069)or eof(base_file) then goto off_base
+@y
+undump_int(x);@+if (x<>69069) then goto off_base
+@z
+
+[1204]
+@x
+@p begin @!{|start_here|}
+@y
+@d fpc_halt == h@&a@&l@&t
+
+@p begin @!{|start_here|}
+@z
+
+[1204] start editor and pass history
+@x
+final_end: ready_already:=0;
+@y
+final_end:
+if start_edit then exec_editor; {user typed `\.{E}'}
+fpc_halt(history);
+ {pass |history| as the exit value to the system}
+@z
+
+[1205] terminate last line
+@x
+ slow_print(log_name); print_char(".");
+@y
+ slow_print(log_name); print_char("."); print_ln;
+@z
+
+[1212] return if eof
+@x
+ read(term_in,m);
+@y
+ if eof(term_in) then return;
+ {don't try to read past end of file}
+ read(term_in,m);
+@z
+
+[1212] return if eof
+@x
+ else begin read(term_in,n);
+@y
+ else begin if eof(term_in) then return;
+ {don't try to read past end of file}
+ read(term_in,n);
+@z
+
+[1213] return eof
+@x
+13: begin read(term_in,l); print_cmd_mod(n,l);
+@y
+13: begin if eof(term_in) then return;
+ {don't try to read past end of file}
+read(term_in,l); print_cmd_mod(n,l);
+@z
+
+[1214 and modules added for METAFONT-FPC]
+@x
+itself will get a new section number.
+@^system dependencies@>
+@y
+itself will get a new section number.
+@^system dependencies@>
+@^fpc Pascal@>
+
+@d edit_file == input_stack[file_ptr].name_field
+@d fpc_fp_exec_vp == fp_exec_vp
+@d fpc_pchar == pchar
+@d vi==@{ {change this to `$\\{vi}\equiv\null$' when you think \.{vi}
+is the system editor}
+@d iv==@t@>@} {change this to `$\\{iv}\equiv\null$' when you think \.{vi}
+is the sytem editor}
+@f vi == begin
+@f iv == end
+@d ed== {change this to `$\\{ed}\equiv\.{@@\{}$' when you think \.{vi}
+is the system editor}
+@d de== {change this to `$\\{de}\equiv\.{@@\}}$' when you think \.{vi}
+is the system editor}
+@f ed == begin
+@f de == end
+
+@<Last-minute...@>=
+procedure exec_editor;
+const arg_size = 100; {maximal size of each of the arguments}
+ vi editor = 'vi'; {name of the binary to be started}
+ iv
+ @#
+ ed editor = 'ed'; {name of the binary to be started}
+ de
+ @#
+ editor_length = 2; {length of the name}
+var i, l: integer; {index into args}
+ j: pool_pointer; {index into |str_pool|}
+ s: str_number; {string to hold line number}
+ sel: integer; { save selector }
+ editor_arg, line_arg, file_arg : array[1..arg_size] of char; { arguments }
+ argv: array [0..3] of fpc_pchar; { vector of arguments }
+begin
+ l := editor_length;
+ for j := 1 to l do editor_arg := editor[j];
+ editor_arg[l+1] := chr(0);
+
+ sel := selector;
+ selector := new_string;
+ print_int(line);
+ s := make_string;
+ @#
+ vi
+ line_arg[1] := '+';
+ j := str_start[s];
+ l := length(s)+1;
+ for i := 2 to l do begin line_arg[i] := xchr[str_pool[j]]; incr(j) end;
+ line_arg := chr(0);
+ iv
+ @#
+ ed
+ selector := term_only;
+ write('You want to edit at line '); print(s); print_ln;
+ de
+ @#
+ selector := sel;
+ j := str_start[edit_file];
+ l := length(edit_file);
+ if l+1 > arg_size then begin
+ write_ln('File name longer than 100 bytes! Nice try!');
+ halt(100);
+ end;
+ for i := 1 to l do
+ begin file_arg[i] := xchr[str_pool[j]]; incr(j)
+ end;
+ file_arg[l+1] := chr(0);
+ argv[0] := @@editor_arg;
+ vi
+ argv[1] := @@line_arg;
+ argv[2] := @@file_arg;
+ argv[3] := nil;
+ iv
+ @#
+ ed
+ argv[1] := @@file_arg;
+ argv[2] := nil;
+ de
+ @#
+ fpc_fp_exec_vp(editor, argv);
+ write_ln('Sorry, executing the editor failed.');
+end;
+@
+A signal handler is a procedure that takes one |integer| parameter.
+The procedure |fpc_fp_signal| takes two parameter, an integer and
+a signal handler. The integer is the number of the signal. Whenever
+the program receives a signal with the designated number, the signal handler
+gets invoked.
+
+The integer |SIGINT| is the number of the interrupt signal. The
+system sends an interrupt signal to the program, whenever the user
+types \.{\^C}.
+
+The function |fpc_fp_get_errno| returns an integer that is not zero,
+whenever something went wrong.
+
+The identifier |fpc_signal_handler| denotes the |type| of a
+pointer to a signal handler. Since this is foreign to ISO~Pascal,
+we use the type cast to |fpc_signal_handler| as a kludge.
+
+@^FPC Pascal@>
+@^system dependencies@>
+
+@d fpc_signal_handler == s@&i@&g@&n@&a@&l@&h@&a@&n@&d@&l@&e@&r
+@d fpc_fp_signal == f@&p@&s@&i@&g@&n@&a@&l
+@d fpc_fp_get_errno ==f@&p@&g@&e@&t@&e@&r@&r@&n@&o
+
+@<Set initial values ...@>+=
+
+fpc_fp_signal(SIGINT, fpc_signal_handler(catch_signal));
+if fpc_fp_get_errno <> 0 then
+ write_ln('Could not install signal handler:', fpc_fp_get_errno);
+
+@ The signal handler has the so called modifier |interrupt|.
+Modifiers are an extension of FPC Pascal. This one makes the compiler
+generate the code suitable for a signal handler, which must not
+return to the caller but to the instruction where the program was
+interrupted.
+
+@^FPC Pascal@>
+@^system dependencies@>
+
+@<Error handling ...@>+=
+procedure catch_signal; interrupt;
+begin
+ interrupt := i;
+end;
+@z