diff options
Diffstat (limited to 'macros/text1/texix/texix.web')
-rw-r--r-- | macros/text1/texix/texix.web | 1577 |
1 files changed, 1577 insertions, 0 deletions
diff --git a/macros/text1/texix/texix.web b/macros/text1/texix/texix.web new file mode 100644 index 0000000000..bbf577633e --- /dev/null +++ b/macros/text1/texix/texix.web @@ -0,0 +1,1577 @@ +% Version 1.3 makes it easier to create other changes files (6/89) +\font\twelvept=cmbx12 +\font\tentex=cmr10 +\def\topofcontents{\null\vfill\eject + \def\titlepage{T} + \centerline{{\twelvept The \TeX IX Index Program}} + \centerline{{\twelvept For IBM VM/CMS Pascal/VS}} + \vskip15pt + \centerline{Version 1.3, June 1989} + \hbox{\vbox{\hsize\the\hsize This work is + protected as an unpublished work under U.S. copyright laws. + Copyright $\copyright$ 1988 by WSUCSC. All rights Reserved.}} + \vskip18pt + \hbox{\vbox{\hsize\the\hsize This software is furnished under a + license for + use only on a single computer system and may be copied only + with the inclusion of the above copyright notice. + This software, or any other copies + thereof, may not be provided or otherwise made available to any + other person except for use on such system and to one who agrees to + these license terms. Title to and ownership of the software shall + at all times remain in WSUCSC.}} + \vfill} +\let\tentex=\tt +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}% +% +\def\}{\ifmmode \rbrace + \else $\rbrace$\fi}% +% +\def\{{\ifmmode \lbrace + \else $\lbrace$\fi}% +% +\def\us#1{$\underline{\smash{\hbox{#1}}}$}% +\def\lin#1{\par + \leftskip 0pt + \advance \leftskip by #1 + }% +\def\vs#1{\vskip #1\relax} +\catcode`*=11 +% labeled definition macro +% +\newdimen\la*w \la*w=1in % Label width +\newtoks\la*g \la*g={1em} % Label gutter +\newtoks\la*s \la*s={12pt} % Skip before label +\newtoks\la*f \la*f={\rm} % Label font +\newbox\tempbox +% +\long\def\label#1{\par\vskip\the\la*s + \setbox\tempbox=\vtop{\hsize=\la*w + \leftskip=0pt + \rightskip=0pt plus2em + \tolerance=1600 + \noindent + \the\la*f + #1}% + \hangindent=\la*w + \advance \hangindent by \the\la*g + \hangafter=1 + \noindent + \setbox0=\hbox{\rlap{\box\tempbox}}\ht0=0pt\dp0=0pt\box0% + \hskip\la*w + \hskip\the\la*g + \ignorespaces} +\let\la=\label +\catcode`*=12 +\let\nin=\noindent +\def\lbr{\null\hfil\break} +\def\PASCAL{{\sc PASCAL/VS}} +\def\hs#1{\hskip#1} +\def\text#1{{\it \TeX T#1}} +\def\9{\it} +\def\bs{$\backslash$} +% Version 1.0; Dean Guenther; 4/1/86 +% +@* Introduction. +This procedure was created to give \text1\ the ability to produce a sorted +index in the same one pass, instead of creating the index, sorting it, and +printing the index out in three separate steps. + +To accomplish this feat, a new control sequence, \bs{}sortindex, was added to +the basic \TeX\ program which gives the \text1\ user up to three sorted +index files per run. The format of this new control sequence is +\par{\tt\indent\bs{}sortindex\it n} +\par +\nin where {\it n} is the index file number: 1, 2, or 3. + +@ The @^TEXIX@> +program is written entirely in WEB, except for an external +procedure, {\it plsort}, which is written in @^PL/1@> PL/1. +This was necessary since +\PASCAL\ cannot call +@:plsort@> +Syncsort @^SYNCSORT@> +to do an internal sort, and PL/1 can. + +@ +Also, it should be pointed out early that I made use of \PASCAL' +nifty string handling capability, in particular, the |string|, +|index| and |substr| functions. If needed, these should not be too +difficult to translate into another \PASCAL\ +compiler (famous last words). + +@p +segment texix; +procedure texix(ix:char); external; +procedure texix; +const @<Global Constants@> +type @<Global Types@> +var @! m,k,i,j :integer;@/ +@<Global Variables@> + +@ The file {\it ix\_file} +is the file opened for output in the \text1\ session +itself. It will be closed in TEXIX, opened for input, closed again, and +finally opened for output where the final sorted index file will be +written to, complete with all \text1\ markup necessary for printing +the index. + +@<Global Var...@>= +sysprint:text; +@!ix_file :text; + +@ The {\it sort\_file} is used for the internal sort only. The \text1\ user +never has access to it. + +@<Global Var...@>= +@!sort_file :file of sort_type; + +@* Macros and definitions. +Here are some macros and definitions used throughout. + +@d incr(#) == # := # + 1 +@d decr(#) == # := # - 1 + +@d othercases == otherwise +@d endcases == end; + +@d dosubstr == substr +@d doindex == index + +@f othercases == else +@f endcases == end + +@d getout == return +@d messages == sysprint + +@d max_field = 300 +@d max_levels = 3 +@d max_lrecl = 2048 + +@d remove_characters(#) == if length(in_record) > # then +in_record := dosubstr(in_record,1 + #) +else in_record := '' + +@d do_nothing == begin end + +@d do_sort_as == begin remove_characters(6); +i := doindex(in_record,'{$}'); +write_sort_chars(i-1); +remove_characters(3); +end + +@d check_case == begin +if not respect_case then for j:= 1 to +sort_part[i].field_lngth do sort_part[i].field_level[j] := +upper_case(sort_part[i].field_level[j]); end + +@d string_type(#) == string(#) + +@d ccat_temp == @t\hs{2em}@>@=||@>@t\hs{2em}@> + + +@d add_comma(#) == # := ccat(#,',') +@d add_cmma_blnk(#) == # := ccat(#,', ') + +@d do_when_bold == begin +if length(bold_string) > 0 then add_comma(bold_string); +bold_string:= +ccat(ccat(ccat(bold_string,'{\bd '),curr_str_page),'}'); +@.\bs{}bd@> +end + +@d do_when_underscore == begin +if length(us_string) > 0 then add_comma(us_string); +us_string:= +ccat(ccat(ccat(us_string,'\us{'),curr_str_page),'}'); +@.\bs{}us@> +end + +@d do_when_italic == begin +if length(rm_string) > 0 then add_comma(rm_string); +rm_string:= +ccat(ccat(ccat(rm_string,'{\it '),curr_str_page),'}'); +@.\bs{}it@> +end + +@d do_when_roman == begin +if length(rm_string) > 0 then add_comma(rm_string); +rm_string:=ccat(rm_string,curr_str_page); +end + +@d do_write(#)==write(#) + +@d do_lnwrite(#)==writeln(#) + +@ This is arbitrary, but +there should never be more than 8 indicies. + +@d s_file_number == '9' + +@ This is used to print the subentry1 header if there are no page +numbers under its subentry and there are under subentry2. + +@d id2_missing_check== +curr_level:=2; +if sort_record.sort_part[3].field_lngth=0 +then do_nothing else begin +id2_is_missing:=true; +write_header(sort_record.print[2].field_lngth, +sort_record.print[2].field_level); +id2_is_missing:=false; +curr_level:=3;end + +@ This is used to print the primary header if there are no page +numbers under the primary header, and there are page numbers under +either subentry1 or subentry2. + +@d id1_missing_check==if sort_record.sort_part[2].field_lngth = 0 +then begin curr_level:=1; +if sort_record.sort_part[3].field_lngth = 0 +then do_nothing else begin +id1_is_missing:=true; +write_header(sort_record.print[1].field_lngth, +sort_record.print[1].field_level); +id1_is_missing:=false; +curr_level:=3;end;end +else begin curr_level:=1; +id1_is_missing:=true; +write_header(sort_record.print[1].field_lngth, +sort_record.print[1].field_level); +id1_is_missing:=false; +id2_missing_check; +end + +@ This is a little macro used to access {\it write\_header}. + +@d write_prev_header== +begin case curr_level of +1: write_header(prev_ln1,prev_pn1); +2: write_header(prev_ln2,prev_pn2); +3: write_header(prev_ln3,prev_pn3); +othercases do_nothing +endcases +end; + +@ The function ccat will concatenate two strings together. + +@^System dependent code@> +@p function ccat(x,y:string_pass):string_pass; +begin + ccat := x ccat_temp y; +end; + +@* Opening and Closing the files. +This is all very dependent on \PASCAL. + +@ The {\it reset\_file} procedure is used to open all files. +One time this is done when first entering TEXIX. +Note that the file name is ``{\tt IX\it n}'' where ``{\it n}'' is +1--3. This can easily be extended to 4--8 by chaning the \bs{}index +markup in TEXT1@@. +The other time the open is done is when opening the sort file, after it +has already been sorted. +This is system dependent. The following will work for \PASCAL. + +@^System dependent code@> +@p procedure reset_file(file_number:char); +begin +if file_number = '9' then reset(sort_file, +'NAME=TEXT1$$.OUTSORT.A,LRECL=1857,RECFM=V') +else reset(ix_file, +ccat(ccat('NAME=TEXT1$$.IX',str(file_number)),'.A')); +end; + +@ +The {\it sort\_file} is opened for output to write the sort records to. +The {\it ix\_file} is opened for output after the sort records have +been sorted and processed again. +This is system dependent. The following will work for \PASCAL. + +@^System dependent code@> +@p procedure file_rewrite(file_number:char); +begin +if file_number = '9' +then +rewrite(sort_file,'NAME=TEXT1$$.INSORT.A,LRECL=1857,RECFM=V') +else +rewrite(ix_file, +ccat(ccat('NAME=TEXT1$$.IX',str(file_number)), +'.A,LRECL=2048,RECFM=V')); +end; + +@* The Sort Record Description. The record type called +{\it sort\_type} is the record written to the {\it sort\_file}. +If consists of the following: +\la{\bf Bytes} +\la{1} +A one byte {\it record\_type} (0={\bf bold page number}; +2= roman page number (the default); 4=\us{underscored} \us{page} +\us{number}; +6={\it italic page number}; 9=blind entry). +\la{2--5} +The integer page number. If the page +number is in the preface part of the document, then the page number will +be negative. +\la{6--9} +Used in sorting decending. That means that -1 will be at the top. +If the page number is plus to begin with, then this is set to zero +for sorting, so it will be at the bottom of the list. +\la{10-29} This is the same as page number, unless the page number is +negative, in which case this field is a roman numeral. +\la{30--33\lbr34--333\lbr334--337\lbr338--637\lbr638--641\lbr642--941} +The sort field. There are three arrays in this field. Each array +consists of a 4 byte length, followed by the {\it field\_array} which is +the length of the sort entry or subentry. +It is these fields which will get sorted by @^Syncsort@> Syncsort. +If there was a {\it sort\_as} +used for a sort entry or subentry, that value passed in the {\it sort\_as} +is placed here. +\vs{24pt} +\la{942--945\lbr946--1245\lbr1246--1249\lbr +1250--1549\lbr1550--1553\lbr1554--1853} +The print field. +The description is the same as the sort field. +This is the way the index entry will print, but not necessarily how +it will sort. +\vs{96pt} + +@ @<Global Constants@>= +@!max_pn_alpha=20; +@!max_pnum=9; + +@ @<Global Types@>= +@!string_pass=string_type(max_lrecl); +@!pass_pn_alpha=string_type(max_pn_alpha); +@!pn_type=packed array[1..max_pnum] of char; +@!pn_alpha_type=packed array[1..max_pn_alpha] of char; +@!field_array = packed array[1..max_field] of char; +@!field_type = packed record@| +@!field_lngth :integer; +@!field_level :field_array; +end; +@!sort_type = packed record@/ +@!record_type :char; +@!page_number :integer; +@!abs_page_number :integer; +@!page_string :pn_alpha_type; +@!sort_part :packed array[1..3] of field_type; +@!print :packed array[1..3] of field_type; +end; + +@* Subroutines. For many of the following subroutines, the following +global variable, {\it current\_level} is needed to indicate what +index level we are presently processing. +0 = the primary index; 1 = subentry 1, and +2 = subentry 2. +{\it on\_a\_roll} is `true' if we have a series of consecutive page +numbers going. `false' otherwise. +In other places, {\it print\_style}=1 for the paragraph style; it is +2 for the dash style; and it is 3 for the indent style. + +@<Global Var...@>= +@!curr_level :integer; +@!on_a_roll:boolean; + +@ The {\it write\_header} procedure will write out the primary and +subentry level titles from {\it sort\_record.print}. + +@p procedure write_header(print_length:integer;print_field:field_array); +var i:integer; +begin +case curr_level of +1: begin + do_write(ix_file,'\goodbreak\hp '); +@.\bs{}leavevmode@> +@.\bs{}goodbreak@> +@.\bs{}hp@> + for i:=1 to print_length do do_write(ix_file,print_field[i]); + case print_style of + '1':begin + do_write(ix_file,', '); + end; + '2','3':begin + if id1_is_missing or dot_leadering + then do_lnwrite(ix_file,' ') + else do_lnwrite(ix_file,', '); + end; + othercases do_nothing + endcases; end; +2: begin case print_style of + '1':do_nothing; + '2':begin + do_write(ix_file,'\indentsubentry',ix,'1---'); +@.\bs{}indentsubentry@> + end; + '3':begin + do_write(ix_file,'\indentsubentry',ix,'1'); + end; + othercases do_nothing + endcases; + for i:=1 to print_length do do_write(ix_file,print_field[i]); + if (print_style <> '1') or id2_is_missing or dot_leadering + then do_lnwrite(ix_file,' ') + else do_lnwrite(ix_file,', '); + end; +3: begin case print_style of + '1':do_nothing; + '2':begin + do_write(ix_file,'\indentsubentry',ix,'2---'); + end; + '3':begin + do_write(ix_file,'\indentsubentry',ix,'2'); + end; + othercases do_nothing + endcases; + for i:=1 to print_length do do_write(ix_file,print_field[i]); + if dot_leadering + then do_lnwrite(ix_file,' ') + else do_lnwrite(ix_file,', '); + end; +othercases do_nothing +endcases +end; + +@ The {\it numeric} function will take a packed array of length +max\_pnum and convert +that array (which is really the page number) into an integer. + +@p function numeric(simple_array:pn_type):integer; +var @!i,j_mult,pn:integer; +begin pn := 0; +i := max_pnum;j_mult:=1; +repeat +if i = 1 then if simple_array[1] = '-' +then pn := -1 * pn +else pn := pn + ((ord(simple_array[1])-ord('0')) * j_mult) +else pn := pn + ((ord(simple_array[i])-ord('0')) * j_mult); +j_mult := j_mult * 10; +decr(i); +until i < 1; +numeric:=pn; +end; + +@ The {\it get\_numeric} +function will take a packed array of length max\_pn\_alpha and convert +that array (which is really the page number) into an integer. + +@p function get_numeric(x_string:string_type(max_pn_alpha)):integer; +var @!i:integer; +begin +readstr(x_string,i); +get_numeric:=i; +end; + +@ The {\it strvalue} function takes an integer and converts it into +a string. + +@^System dependent code@> +@p procedure strvalue(x:integer; var results:pass_pn_alpha); +var +temp:string_type(max_pn_alpha); +begin +writestr(temp,x); +results:=ltrim(temp); +end; + +@ The {\it strconv} function takes an array and converts it into +a string. + +@p function strconv(x:pn_alpha_type):string_type(max_pn_alpha); +var i:integer; +temp:string_type(max_pn_alpha); +begin +temp:='';i := 1; +with sort_record do begin +repeat +if x[i] <> ' ' then +temp := ccat(temp,str(x[i])); +incr(i); +until (i > max_pn_alpha) or (x[i] = ' '); +end; +strconv:=temp; +end; + +@ The procedure {\it write\_print\_chars} will write the number of +characters indicated +in the parm field to the appropriate print field. There are three levels of +print fields. Level 0 is the primary index, level 1 is the subentry 1 index, +and level 2 is the subentry 2 index. After writing the number of characters +to the print field, that number of characters is removed from the input record. +You might notice that this procedure is very similar to the +write\_sort\_chars +procedure. The only difference in the two is that this procedure deals +with how the index is +to be printed after sorting. The former deals with how the +index is to be sorted. +Also, this procedure is called by {\it write\_sort\_chars}. + +@^System dependent code@> +@p procedure write_print_chars(number_of_characters:integer); +var m:integer; +begin with sort_record.print[curr_level+1] do +for m := 1 to number_of_characters do begin +incr(field_lngth); +field_level[field_lngth] := in_record[m]; +end; +remove_characters(number_of_characters); +end; + +@ The procedure {\it write\_sort\_chars} +will write the number of characters indicated +in the parm field to the appropriate sort field. There are three levels of +sort fields. Level 0 is the primary index, level 1 is the subentry 1 index, +and level 2 is the subentry 2 index. After writing the characters to +the sort fields, they will be removed from the input string. + +@^System dependent code@> +@p procedure write_sort_chars(number_of_characters:integer); +var m:integer; +begin with sort_record.sort_part[curr_level+1] do +for m := 1 to number_of_characters do begin +incr(field_lngth); +field_level[field_lngth] := in_record[m]; +end; +remove_characters(number_of_characters); +end; + +@ +This procedure processes subentries within the \bs{}index command. For example, +the phrase ``Mt. St. Helens'' would be processed here for the entry created +by the markup: +\vs{12pt} +{\lin{.5in} +{\tt\bs{}index\{volcanos\bs{}subentry1\{Mt. St. Helens\}\}}\par} +\vs{12pt} +\nin Note +that there are two levels of subentries, \bs{}subentry1 and \bs{}subentry2. +You can +use \bs{}sortas within a \bs{}subentry. But you cannot use \bs{}subentry2 within +\bs{}subentry1 and vise versa. If you think it should be permitted, don't. +Also, \bs{}blindentry is not permitted within \bs{}subentry. +(I can't be flexible {\bf everywhere}.) + +@ First save the current level, then set the current level to the +subentry level. Process until the subentry is completely digested. + +@^System dependent code@> +@p procedure process_subentry(@!entry_level:integer); +var temp_level :integer; +digest :boolean; +begin remove_characters(1);{Throw away the `1' or `2'}@/ +temp_level := curr_level; +curr_level := entry_level; +digest := true; +repeat +@<Digest Subentry@> +until not digest; +curr_level := temp_level; +end; + +@ If the next character is a dollar sign, then we {\bf might} have a \bs{}sortas +If the next character is a left curly brace, then check to see if we've +reached the end of this subentry. If the character is not `\$' or `\{', +then write the character to the print file. + +@<Digest Subentry@>= +if in_record[1] = '$' +then @<Check for Sortas@> +else if in_record[1] = '{' +then @<Check for Subentry End@> +else write_print_chars(1); + +@ If the next two characters are `\$\}' then we are are the end of +the subentry. + +@<Check for Subentry End@>= +begin +if (in_record[2] = '$') and (in_record[3] = '}') +then begin +digest := false; +remove_characters(3); +end +else write_print_chars(1); +end + +@ If the next three are `\{\$\}' then we {\it might} have a sortas. +and check the next two +characters to see if they +are `{\tt sa}'. If so, we {\bf do} have a sortas. +Otherwise write those 6 characters out. In any case, if we don't have +a `\{\$\}' to begin with, then write the first character out +(which was a +`\$' if you remember from earlier.) + +@<Check for Sortas@>= +if (in_record[2] = '{') and +(in_record[3] = '$') and (in_record[4] = '}') +then begin +if (in_record[5] = 's') and (in_record[6] = 'a') +then do_sort_as +else write_print_chars(6); +end +else write_print_chars(1) + +@ +The {\it equal\_arrays} +function returns a true if the two arrays being passed are +identical. False if not. + +@p function equal_arrays(fieldy:field_array;fieldz:field_array):boolean; +var i :integer; +still_checking :boolean; +begin i := 1; +still_checking := true; +repeat +if fieldy[i] <> fieldz[i] {if arrays not equal} +then still_checking := false +else incr(i); +until (i>max_field) or not still_checking; +equal_arrays := still_checking; +end; + +@ The {\it plsort} procedure is written in PL/1 to call the CMS sort program +Syncsort. This was necessary since you cannot call Syncsort from PASCAL/VS. +The fields to be sorted are defined internally in the {\it plsort} +program. This should be the same as the three sort fields in {\it sort\_type}. +@:sort_type@> +@:plsort@> @^PL/1@> +@^Syncsort@> + +@p procedure plsort(var sort_rc:integer); fortran; + +@ This function converts to all uppercase. +Notice that this is an EBCIDIC conversion, not an ASCII conversion +to uppercase. + +@p function upper_case(x:char):char; +var temp:char; +begin + if (ord(x)>=129)and(ord(x)<=169) then + temp:=chr(ord(x)+64) + else temp:=x; +upper_case:=temp; +end; + + +@* Read Each Index Entry. +Each line in the {\it ix\_file} is a separate index entry generated with the +\bs{\it index markup}. This markup has the format +\par{\tt\bs{}index\it n\tt\{\it entry\rm/\it markup\tt\}} +\par +\nin where ``{\it entry}'' +is the textual material of the primary index. The +``{\it markup}'' may be one of the following submarkup +which may {\bf only} +appear within the \bs{\it index markup}. Never outside of it. +\item{1.} {\tt\bs{}subentry{\it n\/}}: where {\it n} is ``1'' or ``2'', +denoting the subentry level. +You would use this submarkup in the following fashion: +\par{\lin{+.5in}\tt\bs{}index1\{\rm entry +\bs\rm subentry1\tt\{\it submarkup\tt\}\}\par} +\indent where {\it submarkup} here can only be \bs{\it sortas}. +\item{2.}{\tt\bs{}sortas}: This markup is used to indicate text for either the +primary sort level, or one of the two subentry sort levels that is to be +sorted, but not printed in the resulting index. For example, someone may +want ``10 Downing Street'' +to sort as ``ten Downing Street''. This would be accomplished by entering +``{\tt\bs{}index1\{10 Downing Street\bs{}sortas\{ten Downing Street\}\}}''. +You can also use \bs{\it sortas} within the \bs{\it subentry} submarkup. +\item{3.} +{\tt\bs{}itpn}: This markup indicates this index number +is to be printed in italics in the sorted index. +To use it, enter: +\par{\lin{+.5in}\tt\bs{}index1\{\rm entry \tt +\bs{}itpn\}\par} +\item{4.} {\tt\bs{}bdpn}: This markup indicates this +index number is to be +printed in bold in the sorted index. +To use it, enter: +\par{\lin{+.5in}\tt\bs{}index1\{\rm entry \tt +\bs{}bdpn\}\par} +\item{5.} {\tt\bs{}uspn}: This markup indicates +this index number is to +be underscored in the sorted index. +To use it, enter: +\par{\lin{+.5in}\tt\bs{}index1\{\rm entry \tt +\bs{}uspn\}\par} +\item{6.} {\tt\bs{}blindentry}: This markup indicates this index is to be +a blind entry or ``cross reference''. It may appear inside of a +standard entry or subentry. There is no page number associated with +this submarkup. +\par + +@ @<Global Var...@>= +@!respect_case :boolean; +@!dot_leadering :boolean; +@!print_style:char; +@!sort_record :sort_type; +@!in_record :string_type(max_lrecl); +@!temp_strvalue:pass_pn_alpha; + +@^System dependent code@> +@ This procedure will read the {\it ix\_file} in until all index requests +have been read. + +@p procedure read_all_entries; +var @!i,j,k:integer; +begin +@<Get Default Index Values@> +while not eof(ix_file) do begin +@<Initialize Sort Records@>@/ +@<Read Next Record@>@/ +@<Move Sort Type to Sort Record@>@/ +@<Move Page Number to Sort Record@>@/ +@<Digest the Input Record@>@/ +@<Fill in Sort Fields@>@/ +@<Write Sort Record@>@/ +end;end; + +@ The first index default variable passed is ``case=". A ``yes" value will +respect the case in an index sort field. ``no" (the default) will convert +everything to uppercase before sorting. + +The second index default ``style=" will be one of ``1", ``2'', or ``3'' +depending on whether the style is ``paragraph'', ``dash'', or ``indented'' +(which is the default). + +The third default read in here is the ``leadering=". A ``yes'' here will give +dot leadering. Guess what ``no'' does. +Dot leadering in the paragraph style ({\it print\_style}=1). If that +has been requested, change {\it dot\_leadering} to false. + +@<Get Default Index Values@>= +readln(ix_file,in_record); +if dosubstr(in_record,doindex(in_record,'=')+1) = 'no' +then respect_case := false +else respect_case := true; +readln(ix_file,in_record);@/ +print_style:=in_record[doindex(in_record,'=')+1];@/ +readln(ix_file,in_record);@/ +if dosubstr(in_record,doindex(in_record,'=')+1) = 'no' +then dot_leadering := false +else dot_leadering := true;@/ +if dot_leadering and (print_style = '1') +then begin writeln(messages, +'<TEXT1> Error! Dot leadering not permitted with the paragraph style.'); +writeln(messages,' Dot leadering will be disabled.'); +dot_leadering := false; +end; + +@ The {\it all\_blanks} variable is filled with all blanks. Other arrays +of the same dimension of {\it all\_blanks} can be set to blank themselves +by saying $array\leftarrow all\_blanks$. + +@<Global Var...@>= +@!all_blanks:field_array; + +@ @<Initialize Sort Records@>= +with sort_record do +for i := 1 to max_levels do begin +sort_part[i].field_level:= all_blanks; +sort_part[i].field_lngth := 0; +print[i].field_level:= all_blanks; +print[i].field_lngth := 0; +end; +curr_level := 0; + +@ Read the next index request to be processed. +Get rid of trailing blanks. + +@<Read Next Record@>= +readln(ix_file,in_record); +in_record:=trim(in_record); + +@ The {\it sort\_type} is always in column 2. Column 1, 3 and 4 will always +be curly braces. (`\{{\it s}\}\{' where ``{\it s}'' is the sort type.) +After moving the {\it sort\_type} to the sort record, then +delete the {\it sort\_type} and the three curly braces. + +@<Move Sort Type to Sort Record@>= +sort_record.record_type := in_record[2]; +remove_characters(4); + +@ The end of the page number is the next right curly brace (`\}'). +Move all of the digits from the input record to the sort record, +starting with the last digit and going forward. If a minus sign (`-') +is in +the page number (preface material), then put a minus sign in +byte one of the sort record's page number. + +@<Global Var...@>= +@!in_page_number:pn_type; + +@ Find and move the page number to the sort record. If it is negative, +then its a roman numeral. In that case, move the page number to the +{\it abs\_page\_number} to be sorted descending, as negative numbers +should be. If its not negative, then move zero to {\it abs\_page\_number} +so it will move to the bottom of that sort field. +After it is moved, delete the appropriate number of characters to +finish digesting the entry. + +@<Move Page Number to Sort Record@>= +k := doindex(in_record,'}'); {find the end of the page number} +i := k - 1; +for j := 1 to max_pnum do in_page_number[j] := '0'; +j := max_pnum; +repeat +if in_record[i] = '-' +then begin +in_page_number[1] := '-'; +i := 0; +end +else begin +in_page_number[j] := in_record[i]; +decr(i); +decr(j); +end; +until i <= 0; +remove_characters(k+1);@/ +sort_record.page_number:=numeric(in_page_number);@/ +if sort_record.page_number < 0 +then sort_record.abs_page_number:=abs(sort_record.page_number) +else sort_record.abs_page_number:=0; +k := doindex(in_record,'}'); {find the end of the page number string} +for i := 1 to max_pn_alpha do sort_record.page_string[i] := ' '; +for i := 1 to k-1 do +sort_record.page_string[i] := in_record[i]; +remove_characters(k); + +@^System dependent code@> +@ Process the rest of the input record. Each time you see a dollar sign, +there could be a submarkup coming, so examine the next three characters. + +@<Digest the Input Record@>= +repeat +if (in_record[1] = '$') and (length(in_record) >= 4) +then @<Examine Next 3 Chars@> +else write_print_chars(1); +until length(in_record) < 1; + +@ Once the index request has been digested, each sort field is checked +to see if it is blank. If so, then {\it sort\_as} was not used, so copy the +{\it print} field to the {\it sort} field. + +@<Fill in Sort Fields@>= +with sort_record do begin +for i := 1 to max_levels do +if sort_part[i].field_lngth=0 +then begin +sort_part[i].field_level := print[i].field_level; +sort_part[i].field_lngth := print[i].field_lngth; +check_case; end +else check_case; +end; + +@^System dependent code@> +@ Ok, the record has been processed, so write it to the output file. + +@<Write Sort Record@>= +sort_file@@:=sort_record; +put(sort_file); + +@ Ok, a dollar sign signals the beginning of some sort of action code if the +next three characters are `\{\$\}'. So lets look at them and see. + +@<Examine Next 3 Chars@>= +begin if (in_record[2] = '{') and +(in_record[3] = '$') and (in_record[4] = '}') +then @<Examine Next 2 Chars@> +else write_print_chars(1);{Well then, the dollar sign must be part of the index} +end + +@ If a {\it blindentry} (`{\tt be}') or {\it subentry} (`{\tt se}'), +then perform the appropriate sections. + +@<Examine Next 2 Chars@>= +begin if (in_record[5] = 'b') and (in_record[6] = 'e') +then @<Do Blind Entry@> +else if (in_record[5] = 's') and (in_record[6] = 'e') +then @<Do Sub Entries@> +else if (in_record[5] = 's') and (in_record[6] = 'a') +then do_sort_as +else write_print_chars(6);{Might as well write all 6 characters examined} +end + +@ Everything up to the next `\{\$\}' is the blind entry. +The page number for a blind entry will always be 999999999. + +@<Do Blind Entry@>= +begin remove_characters(6);{Throw away the `\$\{\$\}be'}@/ +i := doindex(in_record,'{$}'); +curr_level:=2; +write_print_chars(i-1); +curr_level:=0; +remove_characters(3);{Throw away the `\{\$\}'} +sort_record.page_number := 999999999; +end + +@ Process the subentry, depending on whether or not it is +{\it subentry}1 or {\it subentry}2. If not, ignore the whole thing. + +@<Do Sub Entries@>= +begin remove_characters(6); {Throw away the `\$\{\$\}se'} +if in_record[1] = '1' +then process_subentry(1) +else if in_record[1] = '2' +then process_subentry(2) +else write_print_chars(1);{Perhaps someone entered \bs{}subentry3??} +end + +@* Write Formated Index. This section of code takes the sorted index +entries, merges them together, and writes them back out to the index file +to be read in by \bs{}printindex in the user's program. This section consists +of three procedures for accomplishing this feat: {\it add\_page\_number}, +{\it digest\_the\_line}, and {\it read\_sorted\_records}. +{\it numeric} is a function to convert the character string page number into +an integer. + +@^System dependent code@> +@ The procedure {\it add\_page\_number} is used to add the page number of the +current sorted record to the {\it string\_bold} if a +\bs{\it bdpn}, or to +the {\it string\_underscore} if a \bs{\it uspn}, +or otherwise to +the {\it str\_build}. + +@p procedure add_page_number; +var i:integer; + +@ @<Global Var...@>= +@!prev_page_number:integer; +@!prev_pg_string:string_type(max_pn_alpha); +@!prev_record_type:char; + +@ First check to see if we have a new page number. If so, then add the page +number to the string. Otherwise, only add the page number if the sort type +is new and is not equal to ``6'' (italic). + +@p +begin +with sort_record do if prev_page_number = page_number +then if (prev_record_type = record_type) and (record_type <> '9') + then getout +else if record_type = '6' then getout; +@<Add Page Number to the String@> +end; + +@ {\it str\_build} is used to accumulate all of the page numbers. +{\it str\_blind\_entry} is used to accumulate the blind entry information +(typically there should be no more than one, but allowance is made for more.) + +@<Global Var...@>= +@!str_build:string_type(max_lrecl); +@!str_blind_entry:string_type(max_lrecl); +{come on, who's going to have one that long?} + +@ This module will take the page number of the current sorted index +record and add it to the build string, unless the record type is +9, which is a blind entry, in which case it is added to the blind entry +string. Note that if the record type is 0 (bold), 4 (underscore) or +6 (italic), then the page number is prefaced with ``B'', ``U'' or +``I'' respectively. This identifies that the page number is to be +emphasized when the build string is processed through the +{\it digest\_the\_line} procedure. + +@<Add Page Number to the String@>= +if sort_record.record_type = '9' then @<Do Sorted Blind Entry@> +else begin @<Do Sorted Non Blind Entry@> +end; +prev_page_number := sort_record.page_number;@/ +prev_pg_string := strconv(sort_record.page_string);@/ +prev_record_type := sort_record.record_type; + +@ @<Do Sorted Blind Entry@>= +with sort_record.print[3] do begin +if length(str_blind_entry) > 0 then add_cmma_blnk(str_blind_entry); +for i := 1 to field_lngth do +str_blind_entry := ccat(str_blind_entry,str(field_level[i])); +end + +@ If the {\it page\_string[1]} is less than zero, its alphabetic and +roman numeral processing is necessary. + +@<Do Sorted Non Blind Entry@>= +with sort_record do begin +if ord(page_string[1]) < ord('0') +then @<Add Roman Page Number@> +else @<Add Arabic Page Number@>; +end; + +@ @<Add Roman Page Number@>= +begin +if length(str_build) >= 1 +then str_build:=ccat(',',str_build); +strvalue(page_number,temp_strvalue); +str_build := ccat(ccat(ccat(strconv(page_string), +','),temp_strvalue),str_build); +if record_type = '0' +then str_build := ccat('B',str_build) +else if record_type = '4' +then str_build := ccat('U',str_build) +else if record_type = '6' +then str_build := ccat('I',str_build) +end + +@ @<Add Arabic Page Number@>= +begin +if length(str_build) >= 1 +then add_comma(str_build); +if record_type = '0' +then str_build := ccat(str_build,'B') +else if record_type = '4' +then str_build := ccat(str_build,'U') +else if record_type = '6' +then str_build := ccat(str_build,'I'); +str_build := ccat(str_build,strconv(page_string)); +end + +@ {\it output\_string} is used to collect all of the page numbers +before writing them back out to the index file; +{\it bold\_string} collects the bold page numbers; +{\it us\_string} collects the underscored page numbers; +{\it rm\_string} collects everything not bold or underscored. +As you might expect, {\it italic\_last\_page} is true when the last +page number of a `roll' is to be italic. + +@<Global Var...@>= +@!output_string:string_type(max_lrecl); +@!bold_string:string_type(max_lrecl); +@!us_string:string_type(max_lrecl); +@!rm_string:string_type(max_lrecl); +@!italic_last_page:boolean; + +@^System dependent code@> +@ {\it finish\_the\_process} is a procedure that is used to +first check to see if we are {\it on\_a\_roll}, which means we are formatting +something like pages 1-3. +After doing that, if there were any bold page numbers, they are concatenated +to the front of the {\it output\_string}; underscored page numbers (if any) +are concatenated to the end of the {\it output\_string}. + +@p procedure finish_the_process; +begin +@<Concatenate Bold Pages to Output@>;@/ +@<Concatenate Roman Pages to Output@>;@/ +@<Concatenate Underscored Pages to Output@>; +end; + +@ If there were any bold page numbers, then add them to the {\it +output\_string}. + +@<Concatenate Bold...@>= +if length(bold_string) > 0 then begin +if length(output_string) > 0 then add_cmma_blnk(output_string); +output_string := ccat(output_string,bold_string); +end + +@ If we were on a roll (a consecutive series of page numbers) then finish +the roll. Then if there were any roman or italic page numbers, add them to +the {\it output\_string}. + +@<Concatenate Roman...@>= +if on_a_roll then if italic_last_page +then rm_string := +ccat(ccat(ccat(rm_string,'{\it '),trim(prev_pg_string)),'}') +else rm_string := ccat(rm_string,prev_pg_string); +@.\bs{}it@> +if length(rm_string) > 0 then begin if length(output_string) > 0 +then add_cmma_blnk(output_string); +output_string := ccat(output_string,rm_string); +end + +@ If there were any underscored page numbers, add them to the {\it +output\_string} here. + +@<Concatenate Under...@>= +if length(us_string) > 0 then begin if length(output_string) > 0 +then add_cmma_blnk(output_string); +output_string := ccat(output_string,us_string); +end + +@ The procedure {\it start\_digesting} will initialize a few variables, +then add the {\it current\_page} to the appropriate list. + +@p procedure start_digesting; +begin @<Initialize Some Global Variables@>;@/ +prev_pg_string := curr_str_page;@/ +@<Do Appropriate Highlighting@>; +end; + +@ @<Initialize Some Global Variables@>= +italic_last_page := false; +bold_string := ''; us_string :=''; rm_string:=''; +starting_to_process:=false; +on_a_roll:=false + +@ @<Get the Current Print Type of this Page Number@>= +print_type:= curr_str_page[1]; +if (print_type='B') or (print_type='I') or (print_type='U') +then curr_str_page:=dosubstr(curr_str_page,2) +else print_type := ' ' + +@ @<Do Appropriate Highlighting@>= +if print_type = 'B' then do_when_bold +else if print_type = 'I' then do_when_italic +else if print_type = 'U' then do_when_underscore +else do_when_roman + +@^System dependent code@> +@ The procedure {\it digest\_the\_line} will take the full {\it str\_build} +and add the dashes when there is a run of page numbers (i.e. ``{\tt 1,2,3}'' bec +``1-3''); add the bold page numbers in front of the string (i.e. +``{\tt 1,2,B3,3,4}'' +prints as ``{\bf 3},1-4''. Note that page 3 had to appear twice +``{\tt B3,3}''. If it had only appeard as a bold page number and not the +default, ``{\tt 1,2,B3,4}'', you would get ``1-2,{\bf 3},4''); +add the underscored +page numbers to the end of the string (similar to bold page numbers, +``1,2,U3,3,4'' prints as ``1-4,\us{3}''); and print in italics when +necessary. + +@p procedure digest_the_line; +var +i:integer; +@!temp_roman:string_type(max_pn_alpha); +@!no_page_numbers:boolean; +begin +@<Process Each Page Number@>;@/ +@<Write the Line Out@>; +end; + +@ @<Global Var...@>= +@!starting_to_process :boolean; +@!print_type:char; +@!curr_str_page :string_type(max_pn_alpha); +@!curr_num_page :integer; + +@ Initialize the variables, then read each page number until the whole +string is digested, then finish off the page number string before returning. +If {\it str\_build} is null, then we are doing a blind entry with no +page numbers associated. In that case, initialize the highlighting +strings. +@<Process Each Page Number@>= +output_string := ''; +starting_to_process := true; +no_page_numbers:=false; +if length(str_build) > 0 +then repeat @<Digesting Each Page Number@> + until length(str_build) < 1 +else if starting_to_process then begin +@<Initialize Some Global Variables@>; +no_page_numbers:=true; +end; +finish_the_process; + +@ First get the next page number. Then if we are starting, initialize +everything. If we have already started, then check to see if we have a +consecutive page number sequence (i.e. pages 1,2,3,4 etc.) which is called +a `roll'. +@<Digesting Each Page Number@>= +@<Get Next Page Number@>;@/ +if starting_to_process +then start_digesting +else @<Check for a Roll@>; +prev_page_number:=curr_num_page; + +@ @<Get Next Page Number@>= +i := doindex(str_build,','); +if i < 1 then begin curr_str_page:=str_build; str_build:='';end +else begin +curr_str_page:=dosubstr(str_build,1,i-1); +str_build := dosubstr(str_build,i+1); +end; +@<Get the Current Print Type of this Page Number@>;@/ +if ord(curr_str_page[1]) < ord('0') {Then its alphabetic} +then @<Get Numeric for Roman Page Number@> +else curr_num_page:=get_numeric(curr_str_page); + +@ @<Get Numeric for Roman Page Number@>= +begin +i := doindex(str_build,','); +if i < 1 then begin temp_roman:=str_build; str_build:='';end +else begin +temp_roman:=dosubstr(str_build,1,i-1); +str_build := dosubstr(str_build,i+1); +end; +curr_num_page:=get_numeric(temp_roman); +end + +@ If we are on a roll, then the previous page number will be one less than +the current page number. If this is not the case, then {\it +finish\_the\_process} +and {\it start\_digesting} all over again. + +@<Check for a Roll@>= +if ((prev_page_number = curr_num_page) and (print_type <> ' ')) or + ((prev_page_number>=0) and (prev_page_number = curr_num_page - 1)) or + ((prev_page_number<0) and (prev_page_number = curr_num_page + 1)) +then begin +@<Got a Roll Going@> +prev_pg_string:=curr_str_page; +end +else begin finish_the_process; start_digesting; end + +@ Ok, so we're on a roll, right? If the {\it print\_type} is ``B'' (bold) or +``U'' (underscored) then do those and return. Otherwise, check to se if we +were previously {\it on\_a\_roll}. If we weren't, then add the hyphen to the +starting page number. In either case, move the {\it current\_page} to the +{\it prev\_pg\_string}. Lastly, if the page number is italic, then set +{\it italic\_last\_page} to true, in case it ends up being the last page in +the string. + +@<Got a Roll Going@>= +if print_type = 'B' then do_when_bold +else if print_type = 'U' then do_when_underscore +else begin if not on_a_roll then begin on_a_roll := true; +rm_string:=ccat(rm_string,'--'); end; +if print_type = 'I' then italic_last_page := true +else italic_last_page := false; +end; + +@ Before the page numbers are actually written, we need to write out +the ID depending on which level we are formatting. Level 1 is the +primary level, level 2 is the subentry1, and level 3 is subentry2. +Then, we need to do a couple of things depending on whether there is +dot leadering going on or not. +Finally, write the output string to the formatted index file. + +@<Write the Line Out@>= +write_prev_header; +if dot_leadering then begin @<Do Dot Leadering@> end +else begin @<Do not do Dot Leadering@> end; +do_lnwrite(ix_file,output_string); + +@ If there is dot leadering, then add the blind entry first, before adding +the leadering. + +@<Do Dot Leadering@>= +if length(str_blind_entry) > 0 +then begin +if length(output_string) > 0 then add_cmma_blnk(output_string); +output_string := ccat(output_string,str_blind_entry); +end; +output_string := ccat(ccat('\leader{}',output_string),'\par'); +@.\bs{}leader@> +@.\bs{}par@> + +@ @<Global Var...@>= +@!new_level_1:boolean; + +@ If there is not dot leadering, then the blind entry goes at the end of the +page, except for +the paragraph style ({\it print\_style}=1). Also, if the paragraph style, +then do not add the {\tt \bs{}par} at the end. Instead, add a comma +if there is a new level 1 entry. + +@<Do not do Dot Leadering@>= +if (print_style <> '1') and (length(str_blind_entry) > 0)@/ +then begin +if length(output_string) > 0 then add_cmma_blnk(output_string); +output_string := ccat(output_string,str_blind_entry); +end; +if print_style = '1' +then if new_level_1 and ((length(str_blind_entry)=0) or no_page_numbers) +then do_nothing +else add_cmma_blnk(output_string) +else output_string := ccat(output_string,'\par'); +@.\bs{}par@> + +@ The {\it build\_sorted\_index} procedure is the driving force behind +formatting the index. The basic process is to read all of the sorted records in +and create a record called {\it str\_build}. There will be one of these for +each primary and subentry level index. After doing the {\it str\_build}, +this record is then read through again to add the {\it\TeX T1} markup +necessary to +print out the sorted index line. + +@p procedure build_sorted_index; +var @!first_time_through:boolean; + +@ @<Global Var...@>= +@!prev_sr1:field_array; +@!prev_sr2:field_array; +@!prev_sr3:field_array; +@!prev_pn1:field_array; +@!prev_ln1:integer;{the length of pn1} +@!prev_pn2:field_array; +@!prev_ln2:integer;{the length of pn2} +@!prev_pn3:field_array; +@!prev_ln3:integer;{the length of pn3} +@!id1_is_missing:boolean; +@!id2_is_missing:boolean; + +@ The first thing we need to do is read the next sorted record. If this is the +first time ever through this procedure, then do some quick initializing. Then, +once we come to a new ID, we should write out the previous index page numbers, +etc. If the ID has not changed from the previous record, then add the page +number given here on the sorted record to the {\it str\_build}. + +@p begin first_time_through:=true; +while not eof(sort_file) do begin +sort_record:=sort_file@@; +get(sort_file); +if first_time_through then begin @<Do First Time Inits@> end; +if not equal_arrays(prev_sr1,sort_record.sort_part[1].field_level) +then begin +@<Start a New Level 1@> end +else if not equal_arrays(prev_sr2,sort_record.sort_part[2].field_level) +then begin +@<Start a New Level 2@> end +else if not equal_arrays(prev_sr3,sort_record.sort_part[3].field_level) +and (sort_record.record_type <> '9') +then begin +@<Start a New Level 3@> end +else add_page_number; +end; +@<Digest and Print Level 1@> +end; + +@ First write out the {\it \bs{}everyindex} record at the beginning +of the index file. + +@<Do First Time Inits@>= +do_lnwrite(ix_file,'\everyindex{',ix,'}'); +@.\bs{}everyindex@> + +@ These initializations only get done at the beginning of the +first sort record. + +@<Do First Time Inits@>= +first_time_through:=false; +id1_is_missing:=false; +id2_is_missing:=false; +new_level_1:=false; +with sort_record do begin +prev_sr1:=sort_part[1].field_level; +prev_sr2:=sort_part[2].field_level; +prev_sr3:=sort_part[3].field_level; +prev_pn1:=print[1].field_level; +prev_ln1:=print[1].field_lngth; +prev_pn2:=print[2].field_level; +prev_ln2:=print[2].field_lngth; +prev_pn3:=print[3].field_level; +prev_ln3:=print[3].field_lngth; +end; +prev_page_number:=0; +str_blind_entry:='';@/ +str_build:='';@/ + +@ If this is not a blind entry, then check to see if sort records for +the first level id are missing. If they are, then the id name itself +will be printed in {\it id1\_missing\_check}. + +@<Do First Time Inits@>= +if sort_record.record_type <> '9' +then id1_missing_check; + +@ Only alpha (a--z and A--Z) and numeric (0--9) characters get an +{\it \bs{}everyletterbreak}. Punctuation, for example, will not get +an {\it \bs{}everyletterbreak}. + +@<Do First Time Inits@>= +with sort_record.sort_part[1] do begin +if ((field_level[1]>='a') and (field_level[1]<='i')) or @/ +((field_level[1]>='j') and (field_level[1]<='r')) or @/ +((field_level[1]>='s') and (field_level[1]<='z')) or @/ +((field_level[1]>='A') and (field_level[1]<='I')) or @/ +((field_level[1]>='J') and (field_level[1]<='R')) or @/ +((field_level[1]>='S') and (field_level[1]<='Z')) or @/ +((field_level[1]>='0') and (field_level[1]<='9')) + then +do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{',field_level[1],'}') + else +do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{}'); +end +@.\bs{}everyletterbreak@> + +@ +First we need to {\it digest\_the\_line} which is the current index's +entry. {\it digest\_the\_line} will write out the formatted index unless +we are in the paragraph +style of formatted index +({\it print\_style}=1). If we are in the paragraph style, +then we need to write out any {\it str\_blind\_entry} pending. + +@<Digest and Print Level 1@>= +new_level_1:=true; +digest_the_line; +if print_style = '1' then +do_lnwrite(ix_file,str_blind_entry,'\par'); +new_level_1:=false; +@.\bs{}par@> + +@ We have just found the start of a new primary index level. +First we need to process the previous index's +entry. +If there is a blind entry, and it is style `1', then add it now. +Next, if we are at a letter break (i.e., going from the sorted ``A'' +primary index letters to the ``B''s) then write the ``{\tt +\bs{}everyletterbreak}'' to the formatted index file. + +@<Start a New Level 1@>= +@<Digest and Print Level 1@> +with sort_record.sort_part[1] do begin +if (field_level[1] <> prev_sr1[1]) +then if +(((field_level[1]>='a') and (field_level[1]<='i')) or @/ +((field_level[1]>='j') and (field_level[1]<='r')) or @/ +((field_level[1]>='s') and (field_level[1]<='z')) or @/ +((field_level[1]>='A') and (field_level[1]<='I')) or @/ +((field_level[1]>='J') and (field_level[1]<='R')) or @/ +((field_level[1]>='S') and (field_level[1]<='Z')) or @/ +((field_level[1]>='0') and (field_level[1]<='9'))) @/ +then do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{',field_level[1],'}') + else +do_lnwrite(ix_file,'\everyletterbreak{',ix,'}{}'); +end; +@.\bs{}everyletterbreak@> + +@ The next thing to be done when starting a new primary index is to +check the subentries. If they exist, then you can assume that this +primary level index has no page numbers associated with it. The macro +{\it id1\_missing\_check} accomplishes this. + +@<Start a New Level 1@>= +curr_level:=1;@/ +if sort_record.record_type <> '9' +then id1_missing_check; + +@ The complicated stuff is done. So now we can actually do some simple +initializations to get this new level 1 (primary level) sort rolling. + +@<Start a New Level 1@>= +str_build:=''; +str_blind_entry:=''; +with sort_record do begin +prev_sr1:=sort_part[1].field_level; +prev_sr2:=sort_part[2].field_level; +prev_sr3:=sort_part[3].field_level; +prev_pn1:=print[1].field_level; +prev_ln1:=print[1].field_lngth; +prev_pn2:=print[2].field_level; +prev_ln2:=print[2].field_lngth; +prev_pn3:=print[3].field_level; +prev_ln3:=print[3].field_lngth; +prev_page_number:=0; +end; +add_page_number; + +@ We have just found the start of a new subentry1 index level. +These modules are similar to {\it Start a New Level 1}, but not as +detailed since it is dealing with fewer levels. +First we need to {\it digest\_the\_line} which is the previous index's +entry. {\it digest\_the\_line} will write out the formatted index unless +we are in the paragraph +style of formatted index +({\it print\_style}=1). + +@<Start a New Level 2@>= +digest_the_line; + +@ The next thing to be done when starting a new subentry1 index is to +check the subentry2. If it exists, then you can assume that this +subentry index has no page numbers associated with it. +This is done in {\it id2\_missing\_check}. + +@<Start a New Level 2@>= +id2_missing_check; + +@ The complicated stuff is done. So now we can actually do some simple +initializations to get this new level 2 (subentry2 level) sort rolling. + +@<Start a New Level 2@>= +str_build:=''; +if print_style <> '1' then str_blind_entry:=''; +with sort_record do begin +prev_sr2:=sort_part[2].field_level; +prev_sr3:=sort_part[3].field_level; +prev_pn2:=print[2].field_level; +prev_ln2:=print[2].field_lngth; +prev_pn3:=print[3].field_level; +prev_ln3:=print[3].field_lngth; +prev_page_number:=0; +end; +add_page_number; + +@ We have just found the start of a new subentry2 index level. +These modules are similar to {\it Start a New Level 2}, but not as +detailed since it is dealing with the lowest level. +First we need to {\it digest\_the\_line} which is the previous index's +entry. {\it digest\_the\_line} will write out the formatted index unless +we are in the paragraph +style of formatted index +({\it print\_style}=1). + +@<Start a New Level 3@>= +digest_the_line; +curr_level:=3; + +@ Do some +initializations to get this new level 3 (subentry2) sort rolling. + +@<Start a New Level 3@>= +str_build:=''; +if print_style <> '1' then str_blind_entry:=''; +with sort_record do begin +prev_sr3:=sort_part[3].field_level; +prev_pn3:=print[3].field_level; +prev_ln3:=print[3].field_lngth; +prev_page_number:=0; +end; +add_page_number; + +@* Main Program. +Ok, here is the main program. First we initialize (all\_blanks); then +set the ix\_file for input and the sort\_file for output; read all of the +entries, processing each one; close the files; sort; read the sorted file +in and build the entries, writing them back to the ix\_file to be read in +by the index markup. WHEW!! + +@p +begin @<Initialize Main@>@/ +termout(messages); +reset_file(ix);@/ +file_rewrite(s_file_number); {Should always be file 9}@/ +read_all_entries;@/ +close(ix_file);@/ +close(sort_file);@/ +@<Sort the Index@>@/ +reset_file(s_file_number);@/ +file_rewrite(ix);@/ +build_sorted_index;@/ +end; + +@ @<Initialize Main@>= +for i := 1 to max_field do all_blanks[i] := ' '; + +@ As mentioned earlier, {\it plsort} is an external PL/1 subroutine +@^PL/1@> +@^Syncsort@> +which is used to call Syncsort to sort the file. +The sort fields are as follows: +\halign{\hskip3em\hfill#\hfill&&\hskip3em\hfill#\hfill\cr +\bf Starting Column&\bf Length&\bf Field Description&\bf Order\cr +38&300&character&ascending\cr +342&300&character&ascending\cr +646&300&character&ascending\cr +10&4&binary&descending\cr +6&4&binary&ascending\cr} + +@<Global Var...@>= +sort_rc:integer; + +@ @<Sort the Index@>= +plsort(sort_rc); +if sort_rc = 0 + then writeln(messages,'Index Successfully Completed') + else writeln(messages,'Index Failed'); + +@* Index. +All modules in which an identifier is +used are listed with that identifier, except that reserved words are +indexed only when they appear in format definitions, and the appearances +of identifiers in module names are not indexed. Underlined entries +correspond to where the identifier was declared. Error messages, control +sequences put into the output, and a few +other things like ``Syncsort'' are indexed here too. |