1% odvicopy.ch: web2c changes for odvicopy.web
2%
3% This file is part of the Omega project, which
4% is based in the web2c distribution of TeX.
5%
6% Copyright 2006 Karl Berry (to fix int_8 for AIX).
7% Copyright (c) 1994--1998 John Plaice and Yannis Haralambous
8% applies only to the changes to the original dvicopy.ch.
9%
10% dvicopy.ch for C compilation with web2c.
11% The original version of this file was created by Monika Jayme and
12% Klaus Guntermann at TH Darmstadt (THD), FR Germany.
13% Some parts are borrowed from the changes to dvitype, vftovp and vptovf.
14%
15%  July 90   THD  First versions for dvicopy 0.91 and 0.92
16%  Aug 09 90 THD  Updated to dvicopy 1.0 and released
17%  Mar 20 91 THD  Updated to dvicopy 1.2
18% (more recent changes in the ChangeLog)
19
20@x [0] WEAVE: print changes only
21\pageno=\contentspagenumber \advance\pageno by 1
22@y
23\pageno=\contentspagenumber \advance\pageno by 1
24\let\maybe=\iffalse
25@z
26
27@x [1] Define my_name
28@d banner=='This is ODVIcopy, Version 1.6' {printed when the program starts}
29@y
30@d my_name=='odvicopy'
31@d banner=='This is ODVIcopy, Version 1.6' {printed when the program starts}
32@z
33
34@x [2] No random reading on stdin, may be not seekable.
35@d random_reading==true {should we skip around in the file?}
36@y
37@<Globals in the outer block@>=
38@!random_reading:boolean; {should we skip around in the file?}
39@z
40
41@x [3] Set up kpathsea.
42procedure initialize; {this procedure gets things started properly}
43  var @<Local variables for initialization@>@/
44  begin print_ln(banner);@/
45@y
46@<Define |parse_arguments|@>
47procedure initialize; {this procedure gets things started properly}
48  var @<Local variables for initialization@>@/
49  begin
50    kpse_set_program_name (argv[0], my_name);
51    parse_arguments;
52    print (banner); print_ln (version_string);
53@z
54
55@x [5] Big enough arrays to convert the dvilj sample font document.
56@<Constants...@>=
57@!max_fonts=100; {maximum number of distinct fonts}
58@!max_chars=10000; {maximum number of different characters among all fonts}
59@!max_widths=3000; {maximum number of different characters widths}
60@!max_packets=5000; {maximum number of different characters packets;
61  must be less than 65536}
62@!max_bytes=30000; {maximum number of bytes for characters packets}
63@!max_recursion=10; {\.{VF} files shouldn't recurse beyond this level}
64@!stack_size=100; {\.{DVI} files shouldn't |push| beyond this depth}
65@!terminal_line_length=150; {maximum number of characters input in a single
66  line of input from the terminal}
67@!name_length=50; {a file name shouldn't be longer than this}
68@y
69@<Constants...@>=
70@!max_fonts=1000; {maximum number of distinct fonts}
71@!max_chars=750000; {maximum number of different characters among all fonts}
72@!max_widths=10000; {maximum number of different characters widths}
73@!max_packets=100000; {maximum number of different characters packets;
74  must be less than 65536}
75@!max_bytes=3000000; {maximum number of bytes for characters packets}
76@!max_recursion=10; {\.{VF} files shouldn't recurse beyond this level}
77@!stack_size=100; {\.{DVI} files shouldn't |push| beyond this depth}
78@!terminal_line_length=256; {maximum number of characters input in a single
79  line of input from the terminal}
80@z
81
82% [7] int_8 conflicts with <sys/inttypes.h> on AIX.
83% It just gets turned into schar anyway, so use that.
84@x
85@d int_32 == integer {signed 32~bit integers}
86@y
87@d int_32 == integer {signed 32~bit integers}
88@d int_8 == int_8_odvicopy {avoid C declaration collision on AIX}
89@z
90%
91@x
92@!int_8 = -@"80..@"7F; {signed 8~bit integer}
93@y
94@!int_8_odvicopy = -@"80..@"7F; {signed 8~bit integer}
95@z
96
97% [11] Redirect output, so it can go to either stdout or stderr,
98% depending on where the output dvi file is going.
99@x
100@d print(#)==write(output,#)
101@d print_ln(#)==write_ln(output,#)
102@d new_line==write_ln(output) {start new line}
103@y
104@d print(#)==write(term_out,#)
105@d print_ln(#)==write_ln(term_out,#)
106@d new_line==write_ln(term_out) {start new line}
107@z
108
109@x [14] Permissive input.
110@!ASCII_code=" ".."~"; {a subrange of the integers}
111@y
112@!ASCII_code=0..255; {a subrange of the integers}
113@z
114
115% [15] The text_char type is used as an array index into xord.  The
116% default type `char' produces signed integers, which are bad array
117% indices in C.
118@x
119@d text_char == char {the data type of characters in text files}
120@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
121@d last_text_char=127 {ordinal number of the largest element of |text_char|}
122@y
123@d text_char == ASCII_code {the data type of characters in text files}
124@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
125@d last_text_char=255 {ordinal number of the largest element of |text_char|}
126@z
127
128@x [23] Remove non-local goto, declare jump_out as noreturn
129@d abort(#)==begin print_ln(' ',#,'.'); jump_out;
130    end
131
132@<Error handling...@>=
133@<Basic printing procedures@>@;
134procedure close_files_and_terminate; forward;
135@#
136procedure jump_out;
137begin mark_fatal; close_files_and_terminate;
138goto final_end;
139end;
140@y
141@d abort(#)==begin write_ln(stderr, ' ',#,'.'); jump_out;
142    end
143
144@<Error handling...@>=
145@<Basic printing procedures@>@;
146procedure close_files_and_terminate; forward;
147@#
148noreturn procedure jump_out;
149begin mark_fatal; close_files_and_terminate;
150uexit(1);
151end;
152@z
153
154@x [24] Declare confusion as noreturn
155procedure confusion(@!p:pckt_pointer);
156@y
157noreturn procedure confusion(@!p:pckt_pointer);
158@z
159
160@x [25] Declare overflow as noreturn
161procedure overflow(@!p:pckt_pointer;@!n:int_16u);
162@y
163noreturn procedure overflow(@!p:pckt_pointer;@!n:int_16u);
164@z
165
166@x [62] cur_name is no longer a fixed-size array.
167@!cur_name:packed array[1..name_length] of char; {external name,
168  with no lower case letters}
169@y
170@!cur_name:^char;
171@z
172
173@x [63] Ignore arguments to make_font_name.
174@ For \.{TFM} and \.{VF} files we just append the appropriate extension
175to the file name packet; in addition a system dependent area part
176(usually different for \.{TFM} and \.{VF} files) is prepended if
177the file name packet contains no area part.
178@^system dependencies@>
179
180@d append_to_name(#)==
181  if l_cur_name<name_length then
182    begin incr(l_cur_name); cur_name[l_cur_name]:=#;
183    end
184  else overflow(str_name_length,name_length)
185@d make_font_name_end(#)==
186  append_to_name(#[l]); make_name
187@d make_font_name(#)==
188  l_cur_name:=0; for l:=1 to # do make_font_name_end
189@y
190@ Since files are actually searched through path definitions,
191the area definitions are ignored here.
192To reduce the required changes we simply ignore the parameters given
193to |make_font_name|.
194@^system dependencies@>
195
196@d append_to_name(#)== begin
197    cur_name[l_cur_name]:=#;
198    incr(l_cur_name);
199    end
200@d make_font_name_end(#)==
201  make_name
202@d make_font_name(#)==
203  l_cur_name:=0; make_font_name_end
204@z
205
206% [67] No conversion of filenames in lower case, and initialize and
207% terminate for C strings.  Eliminate now unused variable.
208@x
209@!c:char; {a character to be appended to |cur_name|}
210@y
211@z
212
213@x
214cur_loc:=pckt_start[n]; cur_limit:=pckt_start[n+1];
215@y
216cur_name := xmalloc_array (char, pckt_length (n) + pckt_length (e));
217cur_loc:=pckt_start[n]; cur_limit:=pckt_start[n+1];
218@z
219
220@x
221  if (b>="a")and(b<="z") then Decr(b)(("a"-"A")); {convert to upper case}
222@y
223@z
224
225@x
226cur_loc:=pckt_start[e]; cur_limit:=pckt_start[e+1];
227while cur_loc<cur_limit do
228  begin pckt_extract(b); append_res_to_name(xchr[b]);
229  end;
230while l_cur_name<name_length do
231  begin incr(l_cur_name); cur_name[l_cur_name]:=' ';
232  end;
233@y Skip copying in the extension, kpathsea knows what to do.
234  cur_name[l_cur_name] := 0;
235@z
236
237@x [91] Lower case file name extensions.
238id4(".")("T")("F")("M")(tfm_ext); {file name extension for \.{TFM} files}
239id4(".")("O")("F")("M")(ofm_ext); {file name extension for \.{OFM} files}
240@y
241id4(".")("t")("f")("m")(tfm_ext); {file name extension for \.{TFM} files}
242id4(".")("o")("f")("m")(ofm_ext); {file name extension for \.{OFM} files}
243@z
244
245@x [92] Set default directory name
246@ If no font directory has been specified, \.{\title} is supposed to use
247the default \.{TFM} directory, which is a system-dependent place where
248the \.{TFM} files for standard fonts are kept.
249The string variable |TFM_default_area| contains the name of this area.
250@^system dependencies@>
251
252@d TFM_default_area_name=='TeXfonts:' {change this to the correct name}
253@d OFM_default_area_name=='TeXfonts:' {change this to the correct name}
254@d TFM_default_area_name_length=9 {change this to the correct length}
255@d OFM_default_area_name_length=9 {change this to the correct length}
256
257@<Glob...@>=
258@!TFM_default_area:packed array[1..TFM_default_area_name_length] of char;
259@!OFM_default_area:packed array[1..OFM_default_area_name_length] of char;
260@y
261@ If no font directory has been specified, we search paths.
262@z
263
264@x [93] Remove initialization of now-defunct array
265@ @<Set init...@>=
266TFM_default_area:=TFM_default_area_name;
267OFM_default_area:=OFM_default_area_name;
268@y
269@ (No initialization to be done.  Keep this module to preserve numbering.)
270@z
271
272@x [94] Declare bad_tfm as noreturn
273procedure bad_tfm;
274@y
275noreturn procedure bad_tfm;
276@z
277
278@x [94] Declare bad_font as noreturn
279procedure bad_font;
280@y
281noreturn procedure bad_font;
282@z
283
284@x [95] Open TFM file
285@<TFM: Open |tfm_file|@>=
286make_font_name(TFM_default_area_name_length)(TFM_default_area)(tfm_ext);
287reset(tfm_file,cur_name);
288if eof(tfm_file) then begin
289  make_font_name(OFM_default_area_name_length)(OFM_default_area)(ofm_ext);
290  reset(tfm_file,cur_name);
291  if eof(tfm_file) then
292@^system dependencies@>
293    abort('---not loaded, TFM or OFM file can''t be opened!')
294@y
295|TFM_default_area_name_length| and |TFM_default_area| will not
296be used by |make_font_name|.
297
298@<TFM: Open |tfm_file|@>=
299make_font_name(TFM_default_area_name_length)(TFM_default_area)(tfm_ext);
300full_name := kpse_find_tfm (cur_name);
301if full_name then begin
302  resetbin (tfm_file, full_name);
303  free (cur_name);
304  free (full_name);
305  end
306else begin
307  make_font_name(OFM_default_area_name_length)(OFM_default_area)(ofm_ext);
308  full_name := kpse_find_ofm (cur_name);
309  if full_name then begin
310    resetbin (tfm_file, full_name);
311    free (cur_name);
312    free (full_name);
313    end
314  else abort('---not loaded, TFM or OFM file can''t be opened!')
315@z
316
317@x [99]
318close_in(tfm_file);
319@y
320xfclose(tfm_file, cur_name);
321@z
322
323@x [101] Avoid compiler warnings
324read_tfm_word; tfm_b01(first_two);
325@y
326nco:=0; extra_words:=0;
327read_tfm_word; tfm_b01(first_two);
328@z
329
330@x [108] Declare full_name.
331@!dvi_loc:int_32; {where we are about to look, in |dvi_file|}
332@y
333@!dvi_loc:int_32; {where we are about to look, in |dvi_file|}
334@!full_name: ^char;
335@z
336
337@x [109] Declare bad_dvi as noreturn
338procedure bad_dvi;
339@y
340noreturn procedure bad_dvi;
341@z
342
343@x [111] Fix up opening the binary files
344@ To prepare |dvi_file| for input, we |reset| it.
345
346@<Open input file(s)@>=
347reset(dvi_file); {prepares to read packed bytes from |dvi_file|}
348dvi_loc:=0;
349@y
350@ To prepare |dvi_file| for input, we |reset| it.
351
352@<Open input file(s)@>=
353dvi_loc:=0;
354@z
355
356@x [113] Make dvi_length() and dvi_move() work.
357@p function dvi_length:int_32;
358begin set_pos(dvi_file,-1); dvi_length:=cur_pos(dvi_file);
359end;
360@#
361procedure dvi_move(@!n:int_32);
362begin set_pos(dvi_file,n); dvi_loc:=n;
363end;
364@y
365@p function dvi_length:int_32;
366begin xfseek(dvi_file, 0, 2, dvi_name);
367dvi_loc:=xftell(dvi_file, dvi_name);
368dvi_length:=dvi_loc;
369end;
370@#
371procedure dvi_move(n:int_32);
372begin xfseek(dvi_file, n, 0, dvi_name);
373dvi_loc:=n;
374end;
375@z
376
377@x [135] Lower case file name extensions.
378id3(".")("V")("F")(vf_ext); {file name extension for \.{VF} files}
379id4(".")("O")("V")("F")(ovf_ext); {file name extension for \.{OVF} files}
380@y
381id3(".")("v")("f")(vf_ext); {file name extension for \.{VF} files}
382id4(".")("o")("v")("f")(ovf_ext); {file name extension for \.{OVF} files}
383@z
384
385@x [137/138] Set default directory name
386@ If no font directory has been specified, \.{\title} is supposed to use
387the default \.{VF} directory, which is a system-dependent place where
388the \.{VF} files for standard fonts are kept.
389The string variable |VF_default_area| contains the name of this area.
390@^system dependencies@>
391
392@d VF_default_area_name=='TeXvfonts:' {change this to the correct name}
393@d VF_default_area_name_length=10 {change this to the correct length}
394@d OVF_default_area_name=='TeXvfonts:' {change this to the correct name}
395@d OVF_default_area_name_length=10 {change this to the correct length}
396
397@<Glob...@>=
398@!VF_default_area:packed array[1..VF_default_area_name_length] of char;
399@!OVF_default_area:packed array[1..OVF_default_area_name_length] of char;
400
401@ @<Set init...@>=
402VF_default_area:=VF_default_area_name;
403OVF_default_area:=OVF_default_area_name;
404@y
405@ If no font directory has been specified, \.{\title} is supposed to use
406the default \.{VF} directory, which is a system-dependent place where
407the \.{VF} files for standard fonts are kept.
408
409Actually, under UNIX the standard area is defined in an external
410file \.{site.h}.  And the users have a path searched for fonts,
411by setting the \.{VFFONTS} environment variable.
412
413@ (No initialization to be done.  Keep this module to preserve numbering.)
414@z
415
416@x [139] Open VF file
417@<VF: Open |vf_file| or |goto not_found|@>=
418make_font_name(VF_default_area_name_length)(VF_default_area)(vf_ext);
419reset(vf_file,cur_name);
420if eof(vf_file) then begin
421  make_font_name(OVF_default_area_name_length)(OVF_default_area)(ovf_ext);
422  reset(vf_file,cur_name);
423  if eof(vf_file) then
424@^system dependencies@>
425    goto not_found
426  end;
427@y
428Do path searching. But the \.{VF} file may not exist.
429
430@<VF: Open |vf_file| or |goto not_found|@>=
431make_font_name(VF_default_area_name_length)(VF_default_area)(vf_ext);
432full_name := kpse_find_vf (cur_name);
433if full_name then begin
434  resetbin (vf_file, full_name);
435  free (cur_name);
436  free (full_name);
437  end
438else begin
439  make_font_name(OVF_default_area_name_length)(OVF_default_area)(ovf_ext);
440  full_name := kpse_find_ovf (cur_name);
441  if full_name then begin
442    resetbin (vf_file, full_name);
443    free (cur_name);
444    free (full_name);
445    end
446  else goto not_found
447  end;
448@z
449
450@x [151]
451close_in(vf_file);
452@y
453xfclose(vf_file,cur_name);
454@z
455
456@x [163] copy elements of array piece by piece
457@ @<VF: Start a new level@>=
458append_one(push);
459vf_move[vf_ptr]:=vf_move[vf_ptr-1];
460@y
461@ \.{web2c} does not like array assignments. So we need to do them
462through a macro replacement.
463
464@d do_vf_move(#) == vf_move[vf_ptr]# := vf_move[vf_ptr-1]#
465@d vf_move_assign == begin do_vf_move([0][0]); do_vf_move([0][1]);
466			   do_vf_move([1][0]); do_vf_move([1][1])
467		     end
468
469@<VF: Start a new level@>=
470append_one(push);
471vf_move_assign;
472@z
473
474@x [170] and again...
475  vf_move[vf_ptr]:=vf_move[vf_ptr-1];
476@y
477  vf_move_assign;
478@z
479
480@x [176] break is fflush.
481@d update_terminal == break(output) {empty the terminal output buffer}
482@y
483@d update_terminal == fflush(stdout) {empty the terminal output buffer}
484@z
485
486@x [176]
487procedure input_ln; {inputs a line from the terminal}
488var k:0..terminal_line_length;
489begin if n_opt=0 then
490  begin print('Enter option: '); update_terminal; reset(input);
491  if eoln(input) then read_ln(input);
492  k:=0; pckt_room(terminal_line_length);
493  while (k<terminal_line_length)and not eoln(input) do
494    begin append_byte(xord[input^]); incr(k); get(input);
495    end;
496  end
497else if k_opt<n_opt then
498  begin incr(k_opt);
499  {Copy command line option number |k_opt| into |byte_mem| array!}
500  end;
501end;
502@y
503procedure input_ln; {inputs a line from the terminal}
504var k:0..terminal_line_length;
505begin print('Enter option: '); update_terminal;
506{|if eoln(input) then read_ln(input);|}
507k:=0; pckt_room(terminal_line_length);
508while (k<terminal_line_length)and not eoln(input) do
509  begin append_byte(xord[getc(input)]); incr(k);
510  end;
511end;
512@z
513
514@x [241] No dialog, remove unused final label.
515dialog; {get options}
516@y
517@z
518@x
519final_end:end.
520@y
521end.
522@z
523
524@x [245] Do this later, to avoid creating empty files.
525@<Open output file(s)@>=
526rewrite(out_file); {prepares to write packed bytes to |out_file|}
527@y
528@<Open output file(s)@>=
529@z
530
531@x [247] Use external routine to output bytes.
532@d out_byte(#) == write(out_file,#) {write next \.{DVI} byte}
533@y
534@d out_byte(#) == put_byte(#,out_file) {write next \.{DVI} byte}
535@z
536
537@x [260] String declaration.
538@!comment:packed array[1..comm_length] of char; {preamble comment prefix}
539@y
540@!comment:const_c_string; {preamble comment prefix}
541@z
542
543@x [261] Output the string from 0 to len-1, not 1 to len.
544for k:=1 to comm_length do append_byte(xord[comment[k]]);
545@y
546for k:=0 to comm_length - 1 do append_byte(xord[ucharcast(comment[k])]);
547@z
548
549@x [293] System-dependent changes.
550This section should be replaced, if necessary, by changes to the program
551that are necessary to make \.{DVIcopy} work at a particular installation.
552It is usually best to design your change file so that all changes to
553previous sections preserve the section numbering; then everybody's version
554will be consistent with the printed program. More extensive changes,
555which introduce new sections, can be inserted here; then only the index
556itself will get a new section number.
557@^system dependencies@>
558@y
559Parse a Unix-style command line.
560
561This macro tests if its argument is the current option, as represented
562by the index variable |option_index|.
563
564@d argument_is (#) == (strcmp (long_options[option_index].name, #) = 0)
565
566@<Define |parse_arguments|@> =
567procedure parse_arguments;
568const n_options = 5; {Pascal won't count array lengths for us.}
569var @!long_options: array[0..n_options] of getopt_struct;
570    @!getopt_return_val: integer;
571    @!option_index: c_int_type;
572    @!current_option: 0..n_options;
573    @!k, @!m: c_int_type;
574    @!end_num: ^char;
575begin
576  @<Define the option table@>;
577  @<Initialize options@>;
578  repeat
579    getopt_return_val := getopt_long_only (argc, argv, '', long_options,
580                                           address_of (option_index));
581    if getopt_return_val = -1 then begin
582      {End of arguments; we exit the loop below.} ;
583
584    end else if getopt_return_val = "?" then begin
585      usage (my_name);
586
587    end else if argument_is ('help') then begin
588      usage_help (ODVICOPY_HELP, nil);
589
590    end else if argument_is ('version') then begin
591      print_version_and_exit
592        (banner, 'J. Plaice, Y. Haralambous, P. Breitenlohner', nil, nil);
593
594    end else if argument_is ('magnification') then begin
595      out_mag := atou (optarg);
596
597    end else if argument_is ('max-pages') then begin
598      max_pages := atou (optarg);
599      incr (cur_select);
600
601    end else if argument_is ('page-start') then begin
602      @<Determine the desired |start_count| values from |optarg|@>;
603
604    end; {Else it was a flag; |getopt| has already done the assignment.}
605  until getopt_return_val = -1;
606
607  {Now |optind| is the index of first non-option on the command line.
608   We can have zero, one, or two remaining arguments.}
609  if (optind > argc) or (optind + 2 < argc) then begin
610    write_ln (stderr, my_name, ': Need at most two file arguments.');
611    usage (my_name);
612  end;
613
614  if optind = argc then begin
615    dvi_name := '<stdin>';
616    dvi_file := make_binary_file (stdin);
617    random_reading := false;
618  end else begin
619    dvi_name := extend_filename (cmdline (optind), 'dvi');
620    resetbin (dvi_file, dvi_name);
621    random_reading := true;
622  end;
623
624  if optind + 2 = argc then begin
625    rewritebin (out_file, extend_filename (cmdline (optind + 1), 'dvi'));
626    term_out := stdout;
627  end else begin
628    out_file := make_binary_file (stdout);
629    term_out := stderr;
630  end;
631end;
632
633@ Here is the first of the options we allow.
634@.-help@>
635
636@<Define the option...@> =
637current_option := 0;
638long_options[0].name := 'help';
639long_options[0].has_arg := 0;
640long_options[0].flag := 0;
641long_options[0].val := 0;
642incr (current_option);
643
644@ Another of the standard options.
645@.-version@>
646
647@<Define the option...@> =
648long_options[current_option].name := 'version';
649long_options[current_option].has_arg := 0;
650long_options[current_option].flag := 0;
651long_options[current_option].val := 0;
652incr (current_option);
653
654@ Magnification to apply.
655@.-magnification@>
656
657@<Define the option...@> =
658long_options[current_option].name := 'magnification';
659long_options[current_option].has_arg := 1;
660long_options[current_option].flag := 0;
661long_options[current_option].val := 0;
662incr (current_option);
663
664@ How many pages to do.
665@.-max-pages@>
666
667@<Define the option...@> =
668long_options[current_option].name := 'max-pages';
669long_options[current_option].has_arg := 1;
670long_options[current_option].flag := 0;
671long_options[current_option].val := 0;
672incr (current_option);
673
674@ What page to start at.
675@.-page-start@>
676
677@<Define the option...@> =
678long_options[current_option].name := 'page-start';
679long_options[current_option].has_arg := 1;
680long_options[current_option].flag := 0;
681long_options[current_option].val := 0;
682incr (current_option);
683
684@ Parsing the starting page specification is a bit complicated.
685(This is the same as in \.{DVItype}.)
686
687@<Determine the desired |start_count|...@> =
688k := 0; {which \.{\\count} register we're on}
689m := 0; {position in |optarg|}
690while optarg[m] do begin
691  if optarg[m] = "*" then begin
692    start_there[k] := false;
693    incr (m);
694
695  end else if optarg[m] = "." then begin
696    incr (k);
697    if k >= 10 then begin
698      write_ln (stderr, my_name, ': More than ten count registers specified.');
699      uexit (1);
700    end;
701    incr (m);
702
703  end else begin
704    start_count[k] := strtol (optarg + m, address_of (end_num), 10);
705    if end_num = optarg + m then begin
706      write_ln (stderr, my_name, ': -page-start values must be numeric or *.');
707      uexit (1);
708    end;
709    start_there[k] := true;
710    m := m + end_num - (optarg + m);
711  end;
712end;
713start_vals := k;
714selected := false;
715
716@ An element with all zeros always ends the list.
717
718@<Define the option...@> =
719long_options[current_option].name := 0;
720long_options[current_option].has_arg := 0;
721long_options[current_option].flag := 0;
722long_options[current_option].val := 0;
723
724@ @<Glob...@> =
725@!term_out:text;
726@!dvi_name:const_c_string;
727@z
728