fix default tfm reading
[mplib] / src / texk / web2c / mpdir / lib / mp.w
1 % $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $
2 % MetaPost, by John Hobby.  Public domain.
3
4 % Much of this program was copied with permission from MF.web Version 1.9
5 % It interprets a language very similar to D.E. Knuth's METAFONT, but with
6 % changes designed to make it more suitable for PostScript output.
7
8 % TeX is a trademark of the American Mathematical Society.
9 % METAFONT is a trademark of Addison-Wesley Publishing Company.
10 % PostScript is a trademark of Adobe Systems Incorporated.
11
12 % Here is TeX material that gets inserted after \input webmac
13 \def\hang{\hangindent 3em\noindent\ignorespaces}
14 \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
15 \def\PASCAL{Pascal}
16 \def\ps{PostScript}
17 \def\ph{\hbox{Pascal-H}}
18 \def\psqrt#1{\sqrt{\mathstrut#1}}
19 \def\k{_{k+1}}
20 \def\pct!{{\char`\%}} % percent sign in ordinary text
21 \font\tenlogo=logo10 % font used for the METAFONT logo
22 \font\logos=logosl10
23 \def\MF{{\tenlogo META}\-{\tenlogo FONT}}
24 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
25 \def\[#1]{#1.} % from pascal web
26 \def\<#1>{$\langle#1\rangle$}
27 \def\section{\mathhexbox278}
28 \let\swap=\leftrightarrow
29 \def\round{\mathop{\rm round}\nolimits}
30 \mathchardef\vb="026A % synonym for `\|'
31
32 \def\(#1){} % this is used to make section names sort themselves better
33 \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
34 \def\title{MetaPost}
35 \def\glob{15} % this should be the section number of "<Global...>"
36 \def\gglob{23, 28} % this should be the next two sections of "<Global...>"
37 \pdfoutput=1
38 \pageno=3
39
40 @* \[1] Introduction.
41 This is \MP, a graphics-language processor based on D. E. Knuth's \MF.
42
43 The main purpose of the following program is to explain the algorithms of \MP\
44 as clearly as possible. As a result, the program will not necessarily be very
45 efficient when a particular \PASCAL\ compiler has translated it into a
46 particular machine language. However, the program has been written so that it
47 can be tuned to run efficiently in a wide variety of operating environments
48 by making comparatively few changes. Such flexibility is possible because
49 the documentation that follows is written in the \.{WEB} language, which is
50 at a higher level than \PASCAL; the preprocessing step that converts \.{WEB}
51 to \PASCAL\ is able to introduce most of the necessary refinements.
52 Semi-automatic translation to other languages is also feasible, because the
53 program below does not make extensive use of features that are peculiar to
54 \PASCAL.
55
56 A large piece of software like \MP\ has inherent complexity that cannot
57 be reduced below a certain level of difficulty, although each individual
58 part is fairly simple by itself. The \.{WEB} language is intended to make
59 the algorithms as readable as possible, by reflecting the way the
60 individual program pieces fit together and by providing the
61 cross-references that connect different parts. Detailed comments about
62 what is going on, and about why things were done in certain ways, have
63 been liberally sprinkled throughout the program.  These comments explain
64 features of the implementation, but they rarely attempt to explain the
65 \MP\ language itself, since the reader is supposed to be familiar with
66 {\sl The {\logos METAFONT\/}book} as well as the manual
67 @.WEB@>
68 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
69 {\sl A User's Manual for MetaPost}, Computing Science Technical Report 162,
70 AT\AM T Bell Laboratories.
71
72 @ The present implementation is a preliminary version, but the possibilities
73 for new features are limited by the desire to remain as nearly compatible
74 with \MF\ as possible.
75
76 On the other hand, the \.{WEB} description can be extended without changing
77 the core of the program, and it has been designed so that such
78 extensions are not extremely difficult to make.
79 The |banner| string defined here should be changed whenever \MP\
80 undergoes any modifications, so that it will be clear which version of
81 \MP\ might be the guilty party when a problem arises.
82 @^extensions to \MP@>
83 @^system dependencies@>
84
85 @d banner "This is MetaPost, Version 1.002" /* printed when \MP\ starts */
86 @d metapost_version "1.002"
87 @d mplib_version "0.10"
88 @d version_string " (Cweb version 0.10)"
89
90 @ Different \PASCAL s have slightly different conventions, and the present
91 @:PASCAL H}{\ph@>
92 program is expressed in a version of \PASCAL\ that D. E. Knuth used for \MF.
93 Constructions that apply to
94 this particular compiler, which we shall call \ph, should help the
95 reader see how to make an appropriate interface for other systems
96 if necessary. (\ph\ is Charles Hedrick's modification of a compiler
97 @^Hedrick, Charles Locke@>
98 for the DECsystem-10 that was originally developed at the University of
99 Hamburg; cf.\ {\sl SOFTWARE---Practice \AM\ Experience \bf6} (1976),
100 29--42. The \MP\ program below is intended to be adaptable, without
101 extensive changes, to most other versions of \PASCAL\ and commonly used
102 \PASCAL-to-C translators, so it does not fully
103 @:C@>
104 use the admirable features of \ph. Indeed, a conscious effort has been
105 made here to avoid using several idiosyncratic features of standard
106 \PASCAL\ itself, so that most of the code can be translated mechanically
107 into other high-level languages. For example, the `\&{with}' and `\\{new}'
108 features are not used, nor are pointer types, set types, or enumerated
109 scalar types; there are no `\&{var}' parameters, except in the case of files;
110 there are no tag fields on variant records; there are no |real| variables;
111 no procedures are declared local to other procedures.)
112
113 The portions of this program that involve system-dependent code, where
114 changes might be necessary because of differences between \PASCAL\ compilers
115 and/or differences between
116 operating systems, can be identified by looking at the sections whose
117 numbers are listed under `system dependencies' in the index. Furthermore,
118 the index entries for `dirty \PASCAL' list all places where the restrictions
119 of \PASCAL\ have not been followed perfectly, for one reason or another.
120 @^system dependencies@>
121 @^dirty \PASCAL@>
122
123 @ The program begins with a normal \PASCAL\ program heading, whose
124 components will be filled in later, using the conventions of \.{WEB}.
125 @.WEB@>
126 For example, the portion of the program called `\X\glob:Global
127 variables\X' below will be replaced by a sequence of variable declarations
128 that starts in $\section\glob$ of this documentation. In this way, we are able
129 to define each individual global variable when we are prepared to
130 understand what it means; we do not have to define all of the globals at
131 once.  Cross references in $\section\glob$, where it says ``See also
132 sections \gglob, \dots,'' also make it possible to look at the set of
133 all global variables, if desired.  Similar remarks apply to the other
134 portions of the program heading.
135
136 Actually the heading shown here is not quite normal: The |program| line
137 does not mention any |output| file, because \ph\ would ask the \MP\ user
138 to specify a file name if |output| were specified here.
139 @^system dependencies@>
140
141 @d true 1
142 @d false 0
143  
144 @(mplib.h@>=
145 #  ifndef LIBAVL_ALLOCATOR
146 #    define LIBAVL_ALLOCATOR
147     struct libavl_allocator {
148         void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
149         void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
150     };
151 #  endif
152 typedef struct psout_data_struct * psout_data;
153 typedef struct MP_instance * MP;
154 typedef int boolean;
155 typedef signed int integer;
156 @<Types in the outer block@>
157 typedef struct MP_options {
158   @<Option variables@>
159 } MP_options;
160 @<Declare helpers@>;
161 @<Exported function headers@>
162
163 @ @(mpmp.h@>=
164 @<Constants in the outer block@>
165 typedef struct MP_instance {
166   @<Global variables@>
167 } MP_instance;
168
169 @ @c 
170 #include <stdio.h>
171 #include <stdlib.h>
172 #include <string.h>
173 #include <stdarg.h>
174 #include <assert.h>
175 #include <unistd.h> /* for access() */
176 #include <time.h> /* for struct tm \& co */
177 #include "mplib.h"
178 #include "mpmp.h" /* internal header */
179 #include "mppsout.h" /* internal header */
180 @h
181 @<Declarations@>
182 @<Basic printing procedures@>
183 @<Error handling procedures@>
184
185 @ Here are the functions that set up the \MP\ instance.
186
187 @<Declarations@> =
188 @<Declare |mp_reallocate| functions@>;
189 struct MP_options *mp_options (void) {
190   struct MP_options *opt;
191   opt = xmalloc(1,sizeof(MP_options));
192   memset (opt,0,sizeof(MP_options));
193   return opt;
194
195 MP mp_new (struct MP_options *opt) {
196   MP mp;
197   mp = xmalloc(1,sizeof(MP_instance));
198   @<Set |ini_version|@>;
199   @<Allocate or initialize variables@>
200   if (opt->main_memory>mp->mem_max)
201     mp_reallocate_memory(mp,opt->main_memory);
202   mp_reallocate_paths(mp,1000);
203   mp_reallocate_fonts(mp,8);
204   mp->term_in = stdin;
205   mp->term_out = stdout;
206   return mp;
207 }
208 void mp_free (MP mp) {
209   int k; /* loop variable */
210   @<Dealloc variables@>
211   xfree(mp);
212 }
213
214 @ @c
215 boolean mp_initialize (MP mp) { /* this procedure gets things started properly */
216   @<Local variables for initialization@>
217   mp->history=fatal_error_stop; /* in case we quit during initialization */
218   t_open_out; /* open the terminal for output */
219   @<Check the ``constant'' values...@>;
220   if ( mp->bad>0 ) {
221     fprintf(stdout,"Ouch---my internal constants have been clobbered!\n"
222                    "---case %i",(int)mp->bad);
223 @.Ouch...clobbered@>
224     return false;
225   }
226   @<Set initial values of key variables@>
227   if (mp->ini_version) {
228     @<Run inimpost commands@>;
229   }
230   @<Initialize the output routines@>;
231   @<Get the first line of input and prepare to start@>;
232   mp_set_job_id(mp,mp->internal[year],mp->internal[month],
233                        mp->internal[day],mp->internal[mp_time]);
234   mp_init_map_file(mp, mp->troff_mode);
235   mp->history=spotless; /* ready to go! */
236   if (mp->troff_mode) {
237     mp->internal[gtroffmode]=unity; 
238     mp->internal[prologues]=unity; 
239   }
240   if ( mp->start_sym>0 ) { /* insert the `\&{everyjob}' symbol */
241     mp->cur_sym=mp->start_sym; mp_back_input(mp);
242   }
243   return true;
244 }
245
246
247 @<Exported function headers@>=
248 extern struct MP_options *mp_options (void);
249 extern MP mp_new (struct MP_options *opt) ;
250 extern void mp_free (MP mp);
251 extern boolean mp_initialize (MP mp);
252
253
254 @ The overall \MP\ program begins with the heading just shown, after which
255 comes a bunch of procedure declarations and function declarations.
256 Finally we will get to the main program, which begins with the
257 comment `|start_here|'. If you want to skip down to the
258 main program now, you can look up `|start_here|' in the index.
259 But the author suggests that the best way to understand this program
260 is to follow pretty much the order of \MP's components as they appear in the
261 \.{WEB} description you are now reading, since the present ordering is
262 intended to combine the advantages of the ``bottom up'' and ``top down''
263 approaches to the problem of understanding a somewhat complicated system.
264
265 @ Some of the code below is intended to be used only when diagnosing the
266 strange behavior that sometimes occurs when \MP\ is being installed or
267 when system wizards are fooling around with \MP\ without quite knowing
268 what they are doing. Such code will not normally be compiled; it is
269 delimited by the preprocessor test `|#ifdef DEBUG .. #endif|'.
270
271 @ This program has two important variations: (1) There is a long and slow
272 version called \.{INIMP}, which does the extra calculations needed to
273 @.INIMP@>
274 initialize \MP's internal tables; and (2)~there is a shorter and faster
275 production version, which cuts the initialization to a bare minimum.
276
277 Which is which is decided at runtime.
278
279 @ The following parameters can be changed at compile time to extend or
280 reduce \MP's capacity. They may have different values in \.{INIMP} and
281 in production versions of \MP.
282 @.INIMP@>
283 @^system dependencies@>
284
285 @<Constants...@>=
286 #define file_name_size 255 /* file names shouldn't be longer than this */
287 #define bistack_size 1500 /* size of stack for bisection algorithms;
288   should probably be left at this value */
289
290 @ Like the preceding parameters, the following quantities can be changed
291 at compile time to extend or reduce \MP's capacity. But if they are changed,
292 it is necessary to rerun the initialization program \.{INIMP}
293 @.INIMP@>
294 to generate new tables for the production \MP\ program.
295 One can't simply make helter-skelter changes to the following constants,
296 since certain rather complex initialization
297 numbers are computed from them. 
298
299 @ @<Glob...@>=
300 int max_strings; /* maximum number of strings; must not exceed |max_halfword| */
301 int pool_size; /* maximum number of characters in strings, including all
302   error messages and help texts, and the names of all identifiers */
303 int error_line; /* width of context lines on terminal error messages */
304 int half_error_line; /* width of first lines of contexts in terminal
305   error messages; should be between 30 and |error_line-15| */
306 int max_print_line; /* width of longest text lines output; should be at least 60 */
307 int mem_max; /* greatest index in \MP's internal |mem| array;
308   must be strictly less than |max_halfword|;
309   must be equal to |mem_top| in \.{INIMP}, otherwise |>=mem_top| */
310 int mem_top; /* largest index in the |mem| array dumped by \.{INIMP};
311   must not be greater than |mem_max| */
312 int hash_size; /* maximum number of symbolic tokens,
313   must be less than |max_halfword-3*param_size| */
314 int hash_prime; /* a prime number equal to about 85\pct! of |hash_size| */
315 int param_size; /* maximum number of simultaneous macro parameters */
316 int max_in_open; /* maximum number of input files and error insertions that
317   can be going on simultaneously */
318
319 @ @<Option variables@>=
320 int error_line;
321 int half_error_line;
322 int max_print_line;
323 int main_memory;
324 int hash_size; 
325 int hash_prime; 
326 int param_size; 
327 int max_in_open; 
328
329
330 @d set_value(a,b,c) do { a=c; if (b>c) a=b; } while (0)
331
332 @<Allocate or ...@>=
333 mp->max_strings=500;
334 mp->pool_size=10000;
335 set_value(mp->error_line,opt->error_line,79);
336 set_value(mp->half_error_line,opt->half_error_line,50);
337 set_value(mp->max_print_line,opt->max_print_line,79);
338 mp->mem_max=5000;
339 mp->mem_top=5000;
340 set_value(mp->hash_size,opt->hash_size,9500);
341 set_value(mp->hash_prime,opt->hash_prime,7919);
342 set_value(mp->param_size,opt->param_size,150);
343 set_value(mp->max_in_open,opt->max_in_open,10);
344
345
346 @ In case somebody has inadvertently made bad settings of the ``constants,''
347 \MP\ checks them using a global variable called |bad|.
348
349 This is the first of many sections of \MP\ where global variables are
350 defined.
351
352 @<Glob...@>=
353 integer bad; /* is some ``constant'' wrong? */
354
355 @ Later on we will say `\ignorespaces|if (mem_max>=max_halfword) bad=10;|',
356 or something similar. (We can't do that until |max_halfword| has been defined.)
357
358 @<Check the ``constant'' values for consistency@>=
359 mp->bad=0;
360 if ( (mp->half_error_line<30)||(mp->half_error_line>mp->error_line-15) ) mp->bad=1;
361 if ( mp->max_print_line<60 ) mp->bad=2;
362 if ( mp->mem_top<=1100 ) mp->bad=4;
363 if (mp->hash_prime>mp->hash_size ) mp->bad=5;
364
365 @ Labels are given symbolic names by the following definitions, so that
366 occasional |goto| statements will be meaningful. We insert the label
367 `|exit|:' just before the `\ignorespaces|end|\unskip' of a procedure in
368 which we have used the `|return|' statement defined below; the label
369 `|restart|' is occasionally used at the very beginning of a procedure; and
370 the label `|reswitch|' is occasionally used just prior to a |case|
371 statement in which some cases change the conditions and we wish to branch
372 to the newly applicable case.  Loops that are set up with the |loop|
373 construction defined below are commonly exited by going to `|done|' or to
374 `|found|' or to `|not_found|', and they are sometimes repeated by going to
375 `|continue|'.  If two or more parts of a subroutine start differently but
376 end up the same, the shared code may be gathered together at
377 `|common_ending|'.
378
379 Incidentally, this program never declares a label that isn't actually used,
380 because some fussy \PASCAL\ compilers will complain about redundant labels.
381
382 @d label_exit 10 /* go here to leave a procedure */
383 @d restart 20 /* go here to start a procedure again */
384 @d reswitch 21 /* go here to start a case statement again */
385 @d continue 22 /* go here to resume a loop */
386 @d done 30 /* go here to exit a loop */
387 @d done1 31 /* like |done|, when there is more than one loop */
388 @d done2 32 /* for exiting the second loop in a long block */
389 @d done3 33 /* for exiting the third loop in a very long block */
390 @d done4 34 /* for exiting the fourth loop in an extremely long block */
391 @d done5 35 /* for exiting the fifth loop in an immense block */
392 @d done6 36 /* for exiting the sixth loop in a block */
393 @d found 40 /* go here when you've found it */
394 @d found1 41 /* like |found|, when there's more than one per routine */
395 @d found2 42 /* like |found|, when there's more than two per routine */
396 @d found3 43 /* like |found|, when there's more than three per routine */
397 @d not_found 45 /* go here when you've found nothing */
398 @d common_ending 50 /* go here when you want to merge with another branch */
399
400 @ Here are some macros for common programming idioms.
401
402 @d incr(A)   (A)=(A)+1 /* increase a variable by unity */
403 @d decr(A)   (A)=(A)-1 /* decrease a variable by unity */
404 @d negate(A)   (A)=-(A) /* change the sign of a variable */
405 @d odd(A)   ((A)%2==1)
406 @d chr(A)   (A)
407 @d do_nothing   /* empty statement */
408 @d Return   goto exit /* terminate a procedure call */
409 @f return   nil /* \.{WEB} will henceforth say |return| instead of \\{return} */
410
411 @* \[2] The character set.
412 In order to make \MP\ readily portable to a wide variety of
413 computers, all of its input text is converted to an internal eight-bit
414 code that includes standard ASCII, the ``American Standard Code for
415 Information Interchange.''  This conversion is done immediately when each
416 character is read in. Conversely, characters are converted from ASCII to
417 the user's external representation just before they are output to a
418 text file.
419 @^ASCII code@>
420
421 Such an internal code is relevant to users of \MP\ only with respect to
422 the \&{char} and \&{ASCII} operations, and the comparison of strings.
423
424 @ Characters of text that have been converted to \MP's internal form
425 are said to be of type |ASCII_code|, which is a subrange of the integers.
426
427 @<Types...@>=
428 typedef unsigned char ASCII_code; /* eight-bit numbers */
429
430 @ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
431 character sets were common, so it did not make provision for lowercase
432 letters. Nowadays, of course, we need to deal with both capital and small
433 letters in a convenient way, especially in a program for font design;
434 so the present specification of \MP\ has been written under the assumption
435 that the \PASCAL\ compiler and run-time system permit the use of text files
436 with more than 64 distinguishable characters. More precisely, we assume that
437 the character set contains at least the letters and symbols associated
438 with ASCII codes 040 through 0176; all of these characters are now
439 available on most computer terminals.
440
441 Since we are dealing with more characters than were present in the first
442 \PASCAL\ compilers, we have to decide what to call the associated data
443 type. Some \PASCAL s use the original name |char| for the
444 characters in text files, even though there now are more than 64 such
445 characters, while other \PASCAL s consider |char| to be a 64-element
446 subrange of a larger data type that has some other name.
447
448 In order to accommodate this difference, we shall use the name |text_char|
449 to stand for the data type of the characters that are converted to and
450 from |ASCII_code| when they are input and output. We shall also assume
451 that |text_char| consists of the elements |chr(first_text_char)| through
452 |chr(last_text_char)|, inclusive. The following definitions should be
453 adjusted if necessary.
454 @^system dependencies@>
455
456 @d first_text_char 0 /* ordinal number of the smallest element of |text_char| */
457 @d last_text_char 255 /* ordinal number of the largest element of |text_char| */
458
459 @<Types...@>=
460 typedef unsigned char text_char; /* the data type of characters in text files */
461
462 @ @<Local variables for init...@>=
463 integer i;
464
465 @ The \MP\ processor converts between ASCII code and
466 the user's external character set by means of arrays |xord| and |xchr|
467 that are analogous to \PASCAL's |ord| and |chr| functions.
468
469 @d xchr(A) mp->xchr[(A)]
470 @d xord(A) mp->xord[(A)]
471
472 @<Glob...@>=
473 ASCII_code xord[256];  /* specifies conversion of input characters */
474 text_char xchr[256];  /* specifies conversion of output characters */
475
476 @ The core system assumes all 8-bit is acceptable.  If it is not,
477 a change file has to alter the below section.
478 @^system dependencies@>
479
480 Additionally, people with extended character sets can
481 assign codes arbitrarily, giving an |xchr| equivalent to whatever
482 characters the users of \MP\ are allowed to have in their input files.
483 Appropriate changes to \MP's |char_class| table should then be made.
484 (Unlike \TeX, each installation of \MP\ has a fixed assignment of category
485 codes, called the |char_class|.) Such changes make portability of programs
486 more difficult, so they should be introduced cautiously if at all.
487 @^character set dependencies@>
488 @^system dependencies@>
489
490 @<Set initial ...@>=
491 for (i=0;i<=0377;i++) { xchr(i)=i; }
492
493 @ The following system-independent code makes the |xord| array contain a
494 suitable inverse to the information in |xchr|. Note that if |xchr[i]=xchr[j]|
495 where |i<j<0177|, the value of |xord[xchr[i]]| will turn out to be
496 |j| or more; hence, standard ASCII code numbers will be used instead of
497 codes below 040 in case there is a coincidence.
498
499 @<Set initial ...@>=
500 for (i=first_text_char;i<=last_text_char;i++) { 
501    xord(chr(i))=0177;
502 }
503 for (i=0200;i<=0377;i++) { xord(xchr(i))=i;}
504 for (i=0;i<=0176;i++) { xord(xchr(i))=i;}
505
506 @* \[3] Input and output.
507 The bane of portability is the fact that different operating systems treat
508 input and output quite differently, perhaps because computer scientists
509 have not given sufficient attention to this problem. People have felt somehow
510 that input and output are not part of ``real'' programming. Well, it is true
511 that some kinds of programming are more fun than others. With existing
512 input/output conventions being so diverse and so messy, the only sources of
513 joy in such parts of the code are the rare occasions when one can find a
514 way to make the program a little less bad than it might have been. We have
515 two choices, either to attack I/O now and get it over with, or to postpone
516 I/O until near the end. Neither prospect is very attractive, so let's
517 get it over with.
518
519 The basic operations we need to do are (1)~inputting and outputting of
520 text, to or from a file or the user's terminal; (2)~inputting and
521 outputting of eight-bit bytes, to or from a file; (3)~instructing the
522 operating system to initiate (``open'') or to terminate (``close'') input or
523 output from a specified file; (4)~testing whether the end of an input
524 file has been reached; (5)~display of bits on the user's screen.
525 The bit-display operation will be discussed in a later section; we shall
526 deal here only with more traditional kinds of I/O.
527
528 @ Finding files happens in a slightly roundabout fashion: the \MP\
529 instance object contains a field that holds a function pointer that finds a
530 file, and returns its name, or NULL. For this, it receives three
531 parameters: the non-qualified name |fname|, the intended |fopen|
532 operation type |fmode|, and the type of the file |ftype|.
533
534 The file types that are passed on in |ftype| can be  used to 
535 differentiate file searches if a library like kpathsea is used,
536 the fopen mode is passed along for the same reason.
537
538 @<Types...@>=
539 typedef unsigned char eight_bits ; /* unsigned one-byte quantity */
540 enum {
541   mp_filetype_program = 1, /* \MP\ language input */
542   mp_filetype_log,  /* the log file */
543   mp_filetype_postscript, /* the postscript output */
544   mp_filetype_text,  /* text files for readfrom and writeto primitives */
545   mp_filetype_memfile, /* memory dumps */
546   mp_filetype_metrics, /* TeX font metric files */
547   mp_filetype_fontmap, /* PostScript font mapping files */
548   mp_filetype_font, /*  PostScript type1 font programs */
549   mp_filetype_encoding, /*  PostScript font encoding files */
550 };
551 typedef char *(*file_finder)(char *, char *, int);
552
553 @ @<Glob...@>=
554 file_finder find_file;
555
556 @ @<Option variables@>=
557 file_finder find_file;
558
559 @ The default function for finding files is |mp_find_file|. It is 
560 pretty stupid: it will only find files in the current directory.
561
562 @c
563 char *mp_find_file (char *fname, char *fmode, int ftype)  {
564   if (fmode[0] != 'r' || access (fname,R_OK) || ftype)  
565      return xstrdup(fname);
566   return NULL;
567 }
568
569 @ This has to be done very early on, so it is best to put it in with
570 the |mp_new| allocations
571
572 @d set_callback_option(A) do { mp->A = mp_##A;
573   if (opt->A!=NULL) mp->A = opt->A;
574 } while (0)
575
576 @<Allocate or initialize ...@>=
577 set_callback_option(find_file);
578
579 @ Because |mp_find_file| is used so early, it has to be in the helpers
580 section.
581
582 @<Declare helpers@>=
583 char *mp_find_file (char *fname, char *fmode, int ftype) ;
584
585 @ The function to open files can now be very short.
586
587 @c
588 FILE *mp_open_file(MP mp, char *fname, char *fmode, int ftype)  {
589   char *s = (mp->find_file)(fname,fmode,ftype);
590   if (s!=NULL) {
591     FILE *f = fopen(s, fmode);
592     xfree(s);
593     return f;   
594   }
595   return NULL;
596 }
597
598 @ This is a legacy interface: (almost) all file names pass through |name_of_file|.
599
600 @<Glob...@>=
601 char name_of_file[file_name_size+1]; /* the name of a system file */
602 int name_length;/* this many characters are actually
603   relevant in |name_of_file| (the rest are blank) */
604 boolean print_found_names; /* configuration parameter */
605
606 @ @<Option variables@>=
607 boolean print_found_names; /* configuration parameter */
608
609 @ If this parameter is true, the terminal and log will report the found
610 file names for input files instead of the requested ones. 
611 It is off by default because it creates an extra filename lookup.
612
613 @<Allocate or initialize ...@>=
614 mp->print_found_names = (opt->print_found_names>0 ? true : false);
615
616 @ \MP's file-opening procedures return |false| if no file identified by
617 |name_of_file| could be opened.
618
619 The |OPEN_FILE| macro takes care of the |print_found_names| parameter.
620 It is not used for opening a mem file for read, because that file name 
621 is never printed.
622
623 @d OPEN_FILE(A) do {
624   if (mp->print_found_names) {
625     char *s = (mp->find_file)(mp->name_of_file,A,ftype);
626     if (s!=NULL) {
627       *f = mp_open_file(mp,mp->name_of_file,A, ftype); 
628       strncpy(mp->name_of_file,s,file_name_size);
629       xfree(s);
630     } else {
631       *f = NULL;
632     }
633   } else {
634     *f = mp_open_file(mp,mp->name_of_file,A, ftype); 
635   }
636 } while (0);
637 return (*f ? true : false)
638
639 @c 
640 boolean mp_a_open_in (MP mp, FILE **f, int ftype) {
641   /* open a text file for input */
642   OPEN_FILE("r");
643 }
644 @#
645 boolean mp_w_open_in (MP mp, FILE **f) {
646   /* open a word file for input */
647   *f = mp_open_file(mp,mp->name_of_file,"rb",mp_filetype_memfile); 
648   return (*f ? true : false);
649 }
650 @#
651 boolean mp_a_open_out (MP mp, FILE **f, int ftype) {
652   /* open a text file for output */
653   OPEN_FILE("w");
654 }
655 @#
656 boolean mp_b_open_out (MP mp, FILE **f, int ftype) {
657   /* open a binary file for output */
658   OPEN_FILE("wb");
659 }
660 @#
661 boolean mp_w_open_out (MP mp, FILE**f) {
662   /* open a word file for output */
663   int ftype = mp_filetype_memfile;
664   OPEN_FILE("wb");
665 }
666
667 @ @<Exported...@>=
668 FILE *mp_open_file(MP mp, char *fname, char *fmode, int ftype);
669
670 @ Binary input and output are done with \PASCAL's ordinary |get| and |put|
671 procedures, so we don't have to make any other special arrangements for
672 binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
673 The treatment of text input is more difficult, however, because
674 of the necessary translation to |ASCII_code| values.
675 \MP's conventions should be efficient, and they should
676 blend nicely with the user's operating environment.
677
678 @ Input from text files is read one line at a time, using a routine called
679 |input_ln|. This function is defined in terms of global variables called
680 |buffer|, |first|, and |last| that will be described in detail later; for
681 now, it suffices for us to know that |buffer| is an array of |ASCII_code|
682 values, and that |first| and |last| are indices into this array
683 representing the beginning and ending of a line of text.
684
685 @<Glob...@>=
686 size_t buf_size; /* maximum number of characters simultaneously present in
687                     current lines of open files */
688 ASCII_code *buffer; /* lines of characters being read */
689 size_t first; /* the first unused position in |buffer| */
690 size_t last; /* end of the line just input to |buffer| */
691 size_t max_buf_stack; /* largest index used in |buffer| */
692
693 @ @<Allocate or initialize ...@>=
694 mp->buf_size = 200;
695 mp->buffer = xmalloc((mp->buf_size+1),sizeof(ASCII_code));
696
697 @ @<Dealloc variables@>=
698 xfree(mp->buffer);
699
700 @ @c
701 void mp_reallocate_buffer(MP mp, size_t l) {
702   ASCII_code *buffer;
703   if (l>max_halfword) {
704     mp_confusion(mp,"buffer size"); /* can't happen (I hope) */
705   }
706   buffer = xmalloc((l+1),sizeof(ASCII_code));
707   memcpy(buffer,mp->buffer,(mp->buf_size+1));
708   xfree(mp->buffer);
709   mp->buffer = buffer ;
710   mp->buf_size = l;
711 }
712
713 @ The |input_ln| function brings the next line of input from the specified
714 field into available positions of the buffer array and returns the value
715 |true|, unless the file has already been entirely read, in which case it
716 returns |false| and sets |last:=first|.  In general, the |ASCII_code|
717 numbers that represent the next line of the file are input into
718 |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
719 global variable |last| is set equal to |first| plus the length of the
720 line. Trailing blanks are removed from the line; thus, either |last=first|
721 (in which case the line was entirely blank) or |buffer[last-1]<>" "|.
722 @^inner loop@>
723
724 An overflow error is given, however, if the normal actions of |input_ln|
725 would make |last>=buf_size|; this is done so that other parts of \MP\
726 can safely look at the contents of |buffer[last+1]| without overstepping
727 the bounds of the |buffer| array. Upon entry to |input_ln|, the condition
728 |first<buf_size| will always hold, so that there is always room for an
729 ``empty'' line.
730
731 The variable |max_buf_stack|, which is used to keep track of how large
732 the |buf_size| parameter must be to accommodate the present job, is
733 also kept up to date by |input_ln|.
734
735 If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get|
736 before looking at the first character of the line; this skips over
737 an |eoln| that was in |f^|. The procedure does not do a |get| when it
738 reaches the end of the line; therefore it can be used to acquire input
739 from the user's terminal as well as from ordinary text files.
740
741 Standard \PASCAL\ says that a file should have |eoln| immediately
742 before |eof|, but \MP\ needs only a weaker restriction: If |eof|
743 occurs in the middle of a line, the system function |eoln| should return
744 a |true| result (even though |f^| will be undefined).
745
746 @c 
747 boolean mp_input_ln (MP mp,FILE *  f, boolean bypass_eoln) {
748   /* inputs the next line or returns |false| */
749   int last_nonblank; /* |last| with trailing blanks removed */
750   int c;
751   if ( bypass_eoln ) {
752     c = fgetc(f);
753     if (c==EOF)
754       return false;
755     if (c!='\n' && c!='\r') {
756       ungetc(c,f);
757     }
758   }
759   /* input the first character of the line into |f^| */
760   mp->last=mp->first; /* cf.\ Matthew 19\thinspace:\thinspace30 */
761   c = fgetc(f);
762   if (c==EOF)
763         return false;
764   last_nonblank=mp->first;
765   while (c!=EOF && c!='\n' && c!='\r') { 
766     if ( mp->last>=mp->max_buf_stack ) { 
767       mp->max_buf_stack=mp->last+1;
768       if ( mp->max_buf_stack==mp->buf_size ) {
769         mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
770       }
771     }
772     mp->buffer[mp->last]=xord(c); 
773     incr(mp->last);
774     if ( mp->buffer[mp->last-1]!=' ' ) 
775       last_nonblank=mp->last;
776     c = fgetc(f); 
777   } 
778   if (c!=EOF) {
779     ungetc(c,f);
780   }
781   mp->last=last_nonblank; 
782   return true;
783 }
784
785 @ The user's terminal acts essentially like other files of text, except
786 that it is used both for input and for output. When the terminal is
787 considered an input file, the file variable is called |term_in|, and when it
788 is considered an output file the file variable is |term_out|.
789 @^system dependencies@>
790
791 @<Glob...@>=
792 FILE * term_in; /* the terminal as an input file */
793 FILE * term_out; /* the terminal as an output file */
794
795 @ Here is how to open the terminal files. In the default configuration,
796 nothing happens except that the command line (if there is one) is copied
797 to the input buffer.  The variable |command_line| will be filled by the 
798 |main| procedure. The copying can not be done earlier in the program 
799 logic because in the |INI| version, the |buffer| is also used for primitive 
800 initialization.
801
802 @^system dependencies@>
803
804 @d t_open_out  /* open the terminal for text output */
805 @d t_open_in  do { /* open the terminal for text input */
806     if (mp->command_line!=NULL) {
807       mp->last = strlen(mp->command_line);
808       strncpy((char *)mp->buffer,mp->command_line,mp->last);
809       xfree(mp->command_line);
810     }
811 } while (0)
812
813 @<Glob...@>=
814 char *command_line;
815
816 @ @<Option variables@>=
817 char *command_line;
818
819 @ @<Allocate or initialize ...@>=
820 mp->command_line = opt->command_line;
821
822 @ Sometimes it is necessary to synchronize the input/output mixture that
823 happens on the user's terminal, and three system-dependent
824 procedures are used for this
825 purpose. The first of these, |update_terminal|, is called when we want
826 to make sure that everything we have output to the terminal so far has
827 actually left the computer's internal buffers and been sent.
828 The second, |clear_terminal|, is called when we wish to cancel any
829 input that the user may have typed ahead (since we are about to
830 issue an unexpected error message). The third, |wake_up_terminal|,
831 is supposed to revive the terminal if the user has disabled it by
832 some instruction to the operating system.  The following macros show how
833 these operations can be specified in \ph:
834 @^system dependencies@>
835
836 @d update_terminal   fflush(mp->term_out) /* empty the terminal output buffer */
837 @d clear_terminal   do_nothing /* clear the terminal input buffer */
838 @d wake_up_terminal  fflush(mp->term_out) /* cancel the user's cancellation of output */
839
840 @ We need a special routine to read the first line of \MP\ input from
841 the user's terminal. This line is different because it is read before we
842 have opened the transcript file; there is sort of a ``chicken and
843 egg'' problem here. If the user types `\.{input cmr10}' on the first
844 line, or if some macro invoked by that line does such an \.{input},
845 the transcript file will be named `\.{cmr10.log}'; but if no \.{input}
846 commands are performed during the first line of terminal input, the transcript
847 file will acquire its default name `\.{mpout.log}'. (The transcript file
848 will not contain error messages generated by the first line before the
849 first \.{input} command.)
850
851 The first line is even more special if we are lucky enough to have an operating
852 system that treats \MP\ differently from a run-of-the-mill \PASCAL\ object
853 program. It's nice to let the user start running a \MP\ job by typing
854 a command line like `\.{MP cmr10}'; in such a case, \MP\ will operate
855 as if the first line of input were `\.{cmr10}', i.e., the first line will
856 consist of the remainder of the command line, after the part that invoked \MP.
857
858 @ Different systems have different ways to get started. But regardless of
859 what conventions are adopted, the routine that initializes the terminal
860 should satisfy the following specifications:
861
862 \yskip\textindent{1)}It should open file |term_in| for input from the
863   terminal. (The file |term_out| will already be open for output to the
864   terminal.)
865
866 \textindent{2)}If the user has given a command line, this line should be
867   considered the first line of terminal input. Otherwise the
868   user should be prompted with `\.{**}', and the first line of input
869   should be whatever is typed in response.
870
871 \textindent{3)}The first line of input, which might or might not be a
872   command line, should appear in locations |first| to |last-1| of the
873   |buffer| array.
874
875 \textindent{4)}The global variable |loc| should be set so that the
876   character to be read next by \MP\ is in |buffer[loc]|. This
877   character should not be blank, and we should have |loc<last|.
878
879 \yskip\noindent(It may be necessary to prompt the user several times
880 before a non-blank line comes in. The prompt is `\.{**}' instead of the
881 later `\.*' because the meaning is slightly different: `\.{input}' need
882 not be typed immediately after~`\.{**}'.)
883
884 @d loc mp->cur_input.loc_field /* location of first unread character in |buffer| */
885
886 @ The following program does the required initialization
887 without retrieving a possible command line.
888 It should be clear how to modify this routine to deal with command lines,
889 if the system permits them.
890 @^system dependencies@>
891
892 @c 
893 boolean mp_init_terminal (MP mp) { /* gets the terminal input started */
894   t_open_in; 
895   if (mp->last!=0) {
896     loc = mp->first = 0;
897         return true;
898   }
899   while (1) { 
900     wake_up_terminal; fprintf(mp->term_out,"**"); update_terminal;
901 @.**@>
902     if ( ! mp_input_ln(mp, mp->term_in,true) ) { /* this shouldn't happen */
903       fprintf(mp->term_out,"\n! End of file on the terminal... why?");
904 @.End of file on the terminal@>
905       return false;
906     }
907     loc=mp->first;
908     while ( (loc<(int)mp->last)&&(mp->buffer[loc]==' ') ) 
909       incr(loc);
910     if ( loc<(int)mp->last ) { 
911       return true; /* return unless the line was all blank */
912     };
913     fprintf(mp->term_out,"Please type the name of your input file.\n");
914   }
915 }
916
917 @ @<Declarations@>=
918 boolean mp_init_terminal (MP mp) ;
919
920
921 @* \[4] String handling.
922 Symbolic token names and diagnostic messages are variable-length strings
923 of eight-bit characters. Since \PASCAL\ does not have a well-developed string
924 mechanism, \MP\ does all of its string processing by homegrown methods.
925
926 \MP\ uses strings more extensively than \MF\ does, but the necessary
927 operations can still be handled with a fairly simple data structure.
928 The array |str_pool| contains all of the (eight-bit) ASCII codes in all
929 of the strings, and the array |str_start| contains indices of the starting
930 points of each string. Strings are referred to by integer numbers, so that
931 string number |s| comprises the characters |str_pool[j]| for
932 |str_start[s]<=j<str_start[ss]| where |ss=next_str[s]|.  The string pool
933 is allocated sequentially and |str_pool[pool_ptr]| is the next unused
934 location.  The first string number not currently in use is |str_ptr|
935 and |next_str[str_ptr]| begins a list of free string numbers.  String
936 pool entries |str_start[str_ptr]| up to |pool_ptr| are reserved for a
937 string currently being constructed.
938
939 String numbers 0 to 255 are reserved for strings that correspond to single
940 ASCII characters. This is in accordance with the conventions of \.{WEB},
941 @.WEB@>
942 which converts single-character strings into the ASCII code number of the
943 single character involved, while it converts other strings into integers
944 and builds a string pool file. Thus, when the string constant \.{"."} appears
945 in the program below, \.{WEB} converts it into the integer 46, which is the
946 ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
947 into some integer greater than~255. String number 46 will presumably be the
948 single character `\..'\thinspace; but some ASCII codes have no standard visible
949 representation, and \MP\ may need to be able to print an arbitrary
950 ASCII character, so the first 256 strings are used to specify exactly what
951 should be printed for each of the 256 possibilities.
952
953 @<Types...@>=
954 typedef int pool_pointer; /* for variables that point into |str_pool| */
955 typedef int str_number; /* for variables that point into |str_start| */
956
957 @ @<Glob...@>=
958 ASCII_code *str_pool; /* the characters */
959 pool_pointer *str_start; /* the starting pointers */
960 str_number *next_str; /* for linking strings in order */
961 pool_pointer pool_ptr; /* first unused position in |str_pool| */
962 str_number str_ptr; /* number of the current string being created */
963 pool_pointer init_pool_ptr; /* the starting value of |pool_ptr| */
964 str_number init_str_use; /* the initial number of strings in use */
965 pool_pointer max_pool_ptr; /* the maximum so far of |pool_ptr| */
966 str_number max_str_ptr; /* the maximum so far of |str_ptr| */
967
968 @ @<Allocate or initialize ...@>=
969 mp->str_pool  = xmalloc ((mp->pool_size +1),sizeof(ASCII_code));
970 mp->str_start = xmalloc ((mp->max_strings+1),sizeof(pool_pointer));
971 mp->next_str  = xmalloc ((mp->max_strings+1),sizeof(str_number));
972
973 @ @<Dealloc variables@>=
974 xfree(mp->str_pool);
975 xfree(mp->str_start);
976 xfree(mp->next_str);
977
978 @ Most printing is done from |char *|s, but sometimes not. Here are
979 functions that convert an internal string into a |char *| for use
980 by the printing routines, and vice versa.
981
982 @d str(A) mp_str(mp,A)
983 @d rts(A) mp_rts(mp,A)
984
985 @<Exported function headers@>=
986 int mp_xstrcmp (const char *a, const char *b);
987 char * mp_str (MP mp, str_number s);
988
989 @ @<Declarations@>=
990 str_number mp_rts (MP mp, char *s);
991 str_number mp_make_string (MP mp);
992
993 @ The attempt to catch interrupted strings that is in |mp_rts|, is not 
994 very good: it does not handle nesting over more than one level.
995
996 @c 
997 int mp_xstrcmp (const char *a, const char *b) {
998         if (a==NULL && b==NULL) 
999           return 0;
1000     if (a==NULL)
1001       return -1;
1002     if (b==NULL)
1003       return 1;
1004     return strcmp(a,b);
1005 }
1006
1007 @ @c
1008 char * mp_str (MP mp, str_number ss) {
1009   char *s;
1010   int len;
1011   if (ss==mp->str_ptr) {
1012     return NULL;
1013   } else {
1014     len = length(ss);
1015     s = xmalloc(len+1,sizeof(char));
1016     strncpy(s,(char *)(mp->str_pool+(mp->str_start[ss])),len);
1017     s[len] = 0;
1018     return (char *)s;
1019   }
1020 }
1021 str_number mp_rts (MP mp, char *s) {
1022   int r; /* the new string */ 
1023   int old; /* a possible string in progress */
1024   int i=0;
1025   if (strlen(s)==0) {
1026     return 256;
1027   } else if (strlen(s)==1) {
1028     return s[0];
1029   } else {
1030    old=0;
1031    str_room((integer)strlen(s));
1032    if (mp->str_start[mp->str_ptr]<mp->pool_ptr)
1033      old = mp_make_string(mp);
1034    while (*s) {
1035      append_char(*s);
1036      s++;
1037    }
1038    r = mp_make_string(mp);
1039    if (old!=0) {
1040       str_room(length(old));
1041       while (i<length(old)) {
1042         append_char((mp->str_start[old]+i));
1043       } 
1044       mp_flush_string(mp,old);
1045     }
1046     return r;
1047   }
1048 }
1049
1050 @ Except for |strs_used_up|, the following string statistics are only
1051 maintained when code between |stat| $\ldots$ |tats| delimiters is not
1052 commented out:
1053
1054 @<Glob...@>=
1055 integer strs_used_up; /* strings in use or unused but not reclaimed */
1056 integer pool_in_use; /* total number of cells of |str_pool| actually in use */
1057 integer strs_in_use; /* total number of strings actually in use */
1058 integer max_pl_used; /* maximum |pool_in_use| so far */
1059 integer max_strs_used; /* maximum |strs_in_use| so far */
1060
1061 @ Several of the elementary string operations are performed using \.{WEB}
1062 macros instead of \PASCAL\ procedures, because many of the
1063 operations are done quite frequently and we want to avoid the
1064 overhead of procedure calls. For example, here is
1065 a simple macro that computes the length of a string.
1066 @.WEB@>
1067
1068 @d str_stop(A) mp->str_start[mp->next_str[(A)]] /* one cell past the end of string
1069   number \# */
1070 @d length(A) (str_stop((A))-mp->str_start[(A)]) /* the number of characters in string \# */
1071
1072 @ The length of the current string is called |cur_length|.  If we decide that
1073 the current string is not needed, |flush_cur_string| resets |pool_ptr| so that
1074 |cur_length| becomes zero.
1075
1076 @d cur_length   (mp->pool_ptr - mp->str_start[mp->str_ptr])
1077 @d flush_cur_string   mp->pool_ptr=mp->str_start[mp->str_ptr]
1078
1079 @ Strings are created by appending character codes to |str_pool|.
1080 The |append_char| macro, defined here, does not check to see if the
1081 value of |pool_ptr| has gotten too high; this test is supposed to be
1082 made before |append_char| is used.
1083
1084 To test if there is room to append |l| more characters to |str_pool|,
1085 we shall write |str_room(l)|, which tries to make sure there is enough room
1086 by compacting the string pool if necessary.  If this does not work,
1087 |do_compaction| aborts \MP\ and gives an apologetic error message.
1088
1089 @d append_char(A)   /* put |ASCII_code| \# at the end of |str_pool| */
1090 { mp->str_pool[mp->pool_ptr]=(A); incr(mp->pool_ptr);
1091 }
1092 @d str_room(A)   /* make sure that the pool hasn't overflowed */
1093   { if ( mp->pool_ptr+(A) > mp->max_pool_ptr ) {
1094     if ( mp->pool_ptr+(A) > mp->pool_size ) mp_do_compaction(mp, (A));
1095     else mp->max_pool_ptr=mp->pool_ptr+(A); }
1096   }
1097
1098 @ The following routine is similar to |str_room(1)| but it uses the
1099 argument |mp->pool_size| to prevent |do_compaction| from aborting when
1100 string space is exhausted.
1101
1102 @<Declare the procedure called |unit_str_room|@>=
1103 void mp_unit_str_room (MP mp);
1104
1105 @ @c
1106 void mp_unit_str_room (MP mp) { 
1107   if ( mp->pool_ptr>=mp->pool_size ) mp_do_compaction(mp, mp->pool_size);
1108   if ( mp->pool_ptr>=mp->max_pool_ptr ) mp->max_pool_ptr=mp->pool_ptr+1;
1109 }
1110
1111 @ \MP's string expressions are implemented in a brute-force way: Every
1112 new string or substring that is needed is simply copied into the string pool.
1113 Space is eventually reclaimed by a procedure called |do_compaction| with
1114 the aid of a simple system system of reference counts.
1115 @^reference counts@>
1116
1117 The number of references to string number |s| will be |str_ref[s]|. The
1118 special value |str_ref[s]=max_str_ref=127| is used to denote an unknown
1119 positive number of references; such strings will never be recycled. If
1120 a string is ever referred to more than 126 times, simultaneously, we
1121 put it in this category. Hence a single byte suffices to store each |str_ref|.
1122
1123 @d max_str_ref 127 /* ``infinite'' number of references */
1124 @d add_str_ref(A) { if ( mp->str_ref[(A)]<max_str_ref ) incr(mp->str_ref[(A)]);
1125   }
1126
1127 @<Glob...@>=
1128 int *str_ref;
1129
1130 @ @<Allocate or initialize ...@>=
1131 mp->str_ref = xmalloc ((mp->max_strings+1),sizeof(int));
1132
1133 @ @<Dealloc variables@>=
1134 xfree(mp->str_ref);
1135
1136 @ Here's what we do when a string reference disappears:
1137
1138 @d delete_str_ref(A)  { 
1139     if ( mp->str_ref[(A)]<max_str_ref ) {
1140        if ( mp->str_ref[(A)]>1 ) decr(mp->str_ref[(A)]); 
1141        else mp_flush_string(mp, (A));
1142     }
1143   }
1144
1145 @<Declare the procedure called |flush_string|@>=
1146 void mp_flush_string (MP mp,str_number s) ;
1147
1148
1149 @ We can't flush the first set of static strings at all, so there 
1150 is no point in trying
1151
1152 @c
1153 void mp_flush_string (MP mp,str_number s) { 
1154   if (length(s)>1) {
1155     mp->pool_in_use=mp->pool_in_use-length(s);
1156     decr(mp->strs_in_use);
1157     if ( mp->next_str[s]!=mp->str_ptr ) {
1158       mp->str_ref[s]=0;
1159     } else { 
1160       mp->str_ptr=s;
1161       decr(mp->strs_used_up);
1162     }
1163     mp->pool_ptr=mp->str_start[mp->str_ptr];
1164   }
1165 }
1166
1167 @ C literals cannot be simply added, they need to be set so they can't
1168 be flushed.
1169
1170 @d intern(A) mp_intern(mp,(A))
1171
1172 @c
1173 str_number mp_intern (MP mp, char *s) {
1174   str_number r ;
1175   r = rts(s);
1176   mp->str_ref[r] = max_str_ref;
1177   return r;
1178 }
1179
1180 @ @<Declarations@>=
1181 str_number mp_intern (MP mp, char *s);
1182
1183
1184 @ Once a sequence of characters has been appended to |str_pool|, it
1185 officially becomes a string when the function |make_string| is called.
1186 This function returns the identification number of the new string as its
1187 value.
1188
1189 When getting the next unused string number from the linked list, we pretend
1190 that
1191 $$ \hbox{|max_str_ptr+1|, |max_str_ptr+2|, $\ldots$, |mp->max_strings|} $$
1192 are linked sequentially even though the |next_str| entries have not been
1193 initialized yet.  We never allow |str_ptr| to reach |mp->max_strings|;
1194 |do_compaction| is responsible for making sure of this.
1195
1196 @<Declarations@>=
1197 @<Declare the procedure called |do_compaction|@>;
1198 @<Declare the procedure called |unit_str_room|@>;
1199 str_number mp_make_string (MP mp);
1200
1201 @ @c 
1202 str_number mp_make_string (MP mp) { /* current string enters the pool */
1203   str_number s; /* the new string */
1204 RESTART: 
1205   s=mp->str_ptr;
1206   mp->str_ptr=mp->next_str[s];
1207   if ( mp->str_ptr>mp->max_str_ptr ) {
1208     if ( mp->str_ptr==mp->max_strings ) { 
1209       mp->str_ptr=s;
1210       mp_do_compaction(mp, 0);
1211       goto RESTART;
1212     } else {
1213 #ifdef DEBUG 
1214       if ( mp->strs_used_up!=mp->max_str_ptr ) mp_confusion(mp, "s");
1215 @:this can't happen s}{\quad \.s@>
1216 #endif
1217       mp->max_str_ptr=mp->str_ptr;
1218       mp->next_str[mp->str_ptr]=mp->max_str_ptr+1;
1219     }
1220   }
1221   mp->str_ref[s]=1;
1222   mp->str_start[mp->str_ptr]=mp->pool_ptr;
1223   incr(mp->strs_used_up);
1224   incr(mp->strs_in_use);
1225   mp->pool_in_use=mp->pool_in_use+length(s);
1226   if ( mp->pool_in_use>mp->max_pl_used ) 
1227     mp->max_pl_used=mp->pool_in_use;
1228   if ( mp->strs_in_use>mp->max_strs_used ) 
1229     mp->max_strs_used=mp->strs_in_use;
1230   return s;
1231 }
1232
1233 @ The most interesting string operation is string pool compaction.  The idea
1234 is to recover unused space in the |str_pool| array by recopying the strings
1235 to close the gaps created when some strings become unused.  All string
1236 numbers~$k$ where |str_ref[k]=0| are to be linked into the list of free string
1237 numbers after |str_ptr|.  If this fails to free enough pool space we issue an
1238 |overflow| error unless |needed=mp->pool_size|.  Calling |do_compaction|
1239 with |needed=mp->pool_size| supresses all overflow tests.
1240
1241 The compaction process starts with |last_fixed_str| because all lower numbered
1242 strings are permanently allocated with |max_str_ref| in their |str_ref| entries.
1243
1244 @<Glob...@>=
1245 str_number last_fixed_str; /* last permanently allocated string */
1246 str_number fixed_str_use; /* number of permanently allocated strings */
1247
1248 @ @<Declare the procedure called |do_compaction|@>=
1249 void mp_do_compaction (MP mp, pool_pointer needed) ;
1250
1251 @ @c
1252 void mp_do_compaction (MP mp, pool_pointer needed) {
1253   str_number str_use; /* a count of strings in use */
1254   str_number r,s,t; /* strings being manipulated */
1255   pool_pointer p,q; /* destination and source for copying string characters */
1256   @<Advance |last_fixed_str| as far as possible and set |str_use|@>;
1257   r=mp->last_fixed_str;
1258   s=mp->next_str[r];
1259   p=mp->str_start[s];
1260   while ( s!=mp->str_ptr ) { 
1261     while ( mp->str_ref[s]==0 ) {
1262       @<Advance |s| and add the old |s| to the list of free string numbers;
1263         then |break| if |s=str_ptr|@>;
1264     }
1265     r=s; s=mp->next_str[s];
1266     incr(str_use);
1267     @<Move string |r| back so that |str_start[r]=p|; make |p| the location
1268      after the end of the string@>;
1269   }
1270   @<Move the current string back so that it starts at |p|@>;
1271   if ( needed<mp->pool_size ) {
1272     @<Make sure that there is room for another string with |needed| characters@>;
1273   }
1274   @<Account for the compaction and make sure the statistics agree with the
1275      global versions@>;
1276   mp->strs_used_up=str_use;
1277 }
1278
1279 @ @<Advance |last_fixed_str| as far as possible and set |str_use|@>=
1280 t=mp->next_str[mp->last_fixed_str];
1281 while (t!=mp->str_ptr && mp->str_ref[t]==max_str_ref) {
1282   incr(mp->fixed_str_use);
1283   mp->last_fixed_str=t;
1284   t=mp->next_str[t];
1285 }
1286 str_use=mp->fixed_str_use
1287
1288 @ Because of the way |flush_string| has been written, it should never be
1289 necessary to |break| here.  The extra line of code seems worthwhile to
1290 preserve the generality of |do_compaction|.
1291
1292 @<Advance |s| and add the old |s| to the list of free string numbers;...@>=
1293 {
1294 t=s;
1295 s=mp->next_str[s];
1296 mp->next_str[r]=s;
1297 mp->next_str[t]=mp->next_str[mp->str_ptr];
1298 mp->next_str[mp->str_ptr]=t;
1299 if ( s==mp->str_ptr ) break;
1300 }
1301
1302 @ The string currently starts at |str_start[r]| and ends just before
1303 |str_start[s]|.  We don't change |str_start[s]| because it might be needed
1304 to locate the next string.
1305
1306 @<Move string |r| back so that |str_start[r]=p|; make |p| the location...@>=
1307 q=mp->str_start[r];
1308 mp->str_start[r]=p;
1309 while ( q<mp->str_start[s] ) { 
1310   mp->str_pool[p]=mp->str_pool[q];
1311   incr(p); incr(q);
1312 }
1313
1314 @ Pointers |str_start[str_ptr]| and |pool_ptr| have not been updated.  When
1315 we do this, anything between them should be moved.
1316
1317 @ @<Move the current string back so that it starts at |p|@>=
1318 q=mp->str_start[mp->str_ptr];
1319 mp->str_start[mp->str_ptr]=p;
1320 while ( q<mp->pool_ptr ) { 
1321   mp->str_pool[p]=mp->str_pool[q];
1322   incr(p); incr(q);
1323 }
1324 mp->pool_ptr=p
1325
1326 @ We must remember that |str_ptr| is not allowed to reach |mp->max_strings|.
1327
1328 @<Make sure that there is room for another string with |needed| char...@>=
1329 if ( str_use>=mp->max_strings-1 )
1330   mp_reallocate_strings (mp,str_use);
1331 if ( mp->pool_ptr+needed>mp->max_pool_ptr ) {
1332   mp_reallocate_pool(mp, mp->pool_ptr+needed);
1333   mp->max_pool_ptr=mp->pool_ptr+needed;
1334 }
1335
1336 @ @<Declarations@>=
1337 void mp_reallocate_strings (MP mp, str_number str_use) ;
1338 void mp_reallocate_pool(MP mp, pool_pointer needed) ;
1339
1340 @ @c 
1341 void mp_reallocate_strings (MP mp, str_number str_use) { 
1342   while ( str_use>=mp->max_strings-1 ) {
1343     int l = mp->max_strings + (mp->max_strings>>2);
1344     XREALLOC (mp->str_ref,   l, int);
1345     XREALLOC (mp->str_start, l, pool_pointer);
1346     XREALLOC (mp->next_str,  l, str_number);
1347     mp->max_strings = l;
1348   }
1349 }
1350 void mp_reallocate_pool(MP mp, pool_pointer needed) {
1351   while ( needed>mp->pool_size ) {
1352     int l = mp->pool_size + (mp->pool_size>>2);
1353         XREALLOC (mp->str_pool, l, ASCII_code);
1354     mp->pool_size = l;
1355   }
1356 }
1357
1358 @ @<Account for the compaction and make sure the statistics agree with...@>=
1359 if ( (mp->str_start[mp->str_ptr]!=mp->pool_in_use)||(str_use!=mp->strs_in_use) )
1360   mp_confusion(mp, "string");
1361 @:this can't happen string}{\quad string@>
1362 incr(mp->pact_count);
1363 mp->pact_chars=mp->pact_chars+mp->pool_ptr-str_stop(mp->last_fixed_str);
1364 mp->pact_strs=mp->pact_strs+str_use-mp->fixed_str_use;
1365 #ifdef DEBUG
1366 s=mp->str_ptr; t=str_use;
1367 while ( s<=mp->max_str_ptr ){
1368   if ( t>mp->max_str_ptr ) mp_confusion(mp, "\"");
1369   incr(t); s=mp->next_str[s];
1370 };
1371 if ( t<=mp->max_str_ptr ) mp_confusion(mp, "\"");
1372 #endif
1373
1374 @ A few more global variables are needed to keep track of statistics when
1375 |stat| $\ldots$ |tats| blocks are not commented out.
1376
1377 @<Glob...@>=
1378 integer pact_count; /* number of string pool compactions so far */
1379 integer pact_chars; /* total number of characters moved during compactions */
1380 integer pact_strs; /* total number of strings moved during compactions */
1381
1382 @ @<Initialize compaction statistics@>=
1383 mp->pact_count=0;
1384 mp->pact_chars=0;
1385 mp->pact_strs=0;
1386
1387 @ The following subroutine compares string |s| with another string of the
1388 same length that appears in |buffer| starting at position |k|;
1389 the result is |true| if and only if the strings are equal.
1390
1391 @c 
1392 boolean mp_str_eq_buf (MP mp,str_number s, integer k) {
1393   /* test equality of strings */
1394   pool_pointer j; /* running index */
1395   j=mp->str_start[s];
1396   while ( j<str_stop(s) ) { 
1397     if ( mp->str_pool[j++]!=mp->buffer[k++] ) 
1398       return false;
1399   }
1400   return true;
1401 }
1402
1403 @ Here is a similar routine, but it compares two strings in the string pool,
1404 and it does not assume that they have the same length. If the first string
1405 is lexicographically greater than, less than, or equal to the second,
1406 the result is respectively positive, negative, or zero.
1407
1408 @c 
1409 integer mp_str_vs_str (MP mp, str_number s, str_number t) {
1410   /* test equality of strings */
1411   pool_pointer j,k; /* running indices */
1412   integer ls,lt; /* lengths */
1413   integer l; /* length remaining to test */
1414   ls=length(s); lt=length(t);
1415   if ( ls<=lt ) l=ls; else l=lt;
1416   j=mp->str_start[s]; k=mp->str_start[t];
1417   while ( l-->0 ) { 
1418     if ( mp->str_pool[j]!=mp->str_pool[k] ) {
1419        return (mp->str_pool[j]-mp->str_pool[k]); 
1420     }
1421     incr(j); incr(k);
1422   }
1423   return (ls-lt);
1424 }
1425
1426 @ The initial values of |str_pool|, |str_start|, |pool_ptr|,
1427 and |str_ptr| are computed by the \.{INIMP} program, based in part
1428 on the information that \.{WEB} has output while processing \MP.
1429 @.INIMP@>
1430 @^string pool@>
1431
1432 @c 
1433 void mp_get_strings_started (MP mp) { 
1434   /* initializes the string pool,
1435     but returns |false| if something goes wrong */
1436   int k; /* small indices or counters */
1437   str_number g; /* a new string */
1438   mp->pool_ptr=0; mp->str_ptr=0; mp->max_pool_ptr=0; mp->max_str_ptr=0;
1439   mp->str_start[0]=0;
1440   mp->next_str[0]=1;
1441   mp->pool_in_use=0; mp->strs_in_use=0;
1442   mp->max_pl_used=0; mp->max_strs_used=0;
1443   @<Initialize compaction statistics@>;
1444   mp->strs_used_up=0;
1445   @<Make the first 256 strings@>;
1446   g=mp_make_string(mp); /* string 256 == "" */
1447   mp->str_ref[g]=max_str_ref;
1448   mp->last_fixed_str=mp->str_ptr-1;
1449   mp->fixed_str_use=mp->str_ptr;
1450   return;
1451 }
1452
1453 @ @<Declarations@>=
1454 void mp_get_strings_started (MP mp);
1455
1456 @ The first 256 strings will consist of a single character only.
1457
1458 @<Make the first 256...@>=
1459 for (k=0;k<=255;k++) { 
1460   append_char(k);
1461   g=mp_make_string(mp); 
1462   mp->str_ref[g]=max_str_ref;
1463 }
1464
1465 @ The first 128 strings will contain 95 standard ASCII characters, and the
1466 other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
1467 unless a system-dependent change is made here. Installations that have
1468 an extended character set, where for example |xchr[032]=@t\.{'^^Z'}@>|,
1469 would like string 032 to be printed as the single character 032 instead
1470 of the three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand,
1471 even people with an extended character set will want to represent string
1472 015 by \.{\^\^M}, since 015 is ASCII's ``carriage return'' code; the idea is
1473 to produce visible strings instead of tabs or line-feeds or carriage-returns
1474 or bell-rings or characters that are treated anomalously in text files.
1475
1476 Unprintable characters of codes 128--255 are, similarly, rendered
1477 \.{\^\^80}--\.{\^\^ff}.
1478
1479 The boolean expression defined here should be |true| unless \MP\ internal
1480 code number~|k| corresponds to a non-troublesome visible symbol in the
1481 local character set.
1482 If character |k| cannot be printed, and |k<0200|, then character |k+0100| or
1483 |k-0100| must be printable; moreover, ASCII codes |[060..071, 0141..0146]|
1484 must be printable.
1485 @^character set dependencies@>
1486 @^system dependencies@>
1487
1488 @<Character |k| cannot be printed@>=
1489   (k<' ')||(k>'~')
1490
1491 @* \[5] On-line and off-line printing.
1492 Messages that are sent to a user's terminal and to the transcript-log file
1493 are produced by several `|print|' procedures. These procedures will
1494 direct their output to a variety of places, based on the setting of
1495 the global variable |selector|, which has the following possible
1496 values:
1497
1498 \yskip
1499 \hang |term_and_log|, the normal setting, prints on the terminal and on the
1500   transcript file.
1501
1502 \hang |log_only|, prints only on the transcript file.
1503
1504 \hang |term_only|, prints only on the terminal.
1505
1506 \hang |no_print|, doesn't print at all. This is used only in rare cases
1507   before the transcript file is open.
1508
1509 \hang |ps_file_only| prints only on the \ps\ output file.
1510
1511 \hang |pseudo|, puts output into a cyclic buffer that is used
1512   by the |show_context| routine; when we get to that routine we shall discuss
1513   the reasoning behind this curious mode.
1514
1515 \hang |new_string|, appends the output to the current string in the
1516   string pool.
1517
1518 \hang |>=write_file| prints on one of the files used for the \&{write}
1519 @:write_}{\&{write} primitive@>
1520   command.
1521
1522 \yskip
1523 \noindent The symbolic names `|term_and_log|', etc., have been assigned
1524 numeric codes that satisfy the convenient relations |no_print+1=term_only|,
1525 |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.  These
1526 relations are not used when |selector| could be |pseudo|, |new_string|,
1527 or |ps_file_only|.  We need not check for unprintable characters when
1528 |selector<pseudo|.
1529
1530 Four additional global variables, |tally|, |term_offset|, |file_offset|,
1531 and |ps_offset| record the number of characters that have been printed
1532 since they were most recently cleared to zero. We use |tally| to record
1533 the length of (possibly very long) stretches of printing; |term_offset|,
1534 |file_offset|, and |ps_offset|, on the other hand, keep track of how many
1535 characters have appeared so far on the current line that has been output
1536 to the terminal, the transcript file, or the \ps\ output file, respectively.
1537
1538 @d new_string 0 /* printing is deflected to the string pool */
1539 @d ps_file_only 1 /* printing goes to the \ps\ output file */
1540 @d pseudo 2 /* special |selector| setting for |show_context| */
1541 @d no_print 3 /* |selector| setting that makes data disappear */
1542 @d term_only 4 /* printing is destined for the terminal only */
1543 @d log_only 5 /* printing is destined for the transcript file only */
1544 @d term_and_log 6 /* normal |selector| setting */
1545 @d write_file 7 /* first write file selector */
1546
1547 @<Glob...@>=
1548 FILE * log_file; /* transcript of \MP\ session */
1549 FILE * ps_file; /* the generic font output goes here */
1550 unsigned int selector; /* where to print a message */
1551 unsigned char dig[23]; /* digits in a number being output */
1552 integer tally; /* the number of characters recently printed */
1553 unsigned int term_offset;
1554   /* the number of characters on the current terminal line */
1555 unsigned int file_offset;
1556   /* the number of characters on the current file line */
1557 integer ps_offset;
1558   /* the number of characters on the current \ps\ file line */
1559 ASCII_code *trick_buf; /* circular buffer for pseudoprinting */
1560 integer trick_count; /* threshold for pseudoprinting, explained later */
1561 integer first_count; /* another variable for pseudoprinting */
1562
1563 @ @<Allocate or initialize ...@>=
1564 memset(mp->dig,0,23);
1565 mp->trick_buf = xmalloc((mp->error_line+1),sizeof(ASCII_code));
1566
1567 @ @<Dealloc variables@>=
1568 xfree(mp->trick_buf);
1569
1570 @ @<Initialize the output routines@>=
1571 mp->selector=term_only; mp->tally=0; mp->term_offset=0; mp->file_offset=0; mp->ps_offset=0;
1572
1573 @ Macro abbreviations for output to the terminal and to the log file are
1574 defined here for convenience. Some systems need special conventions
1575 for terminal output, and it is possible to adhere to those conventions
1576 by changing |wterm|, |wterm_ln|, and |wterm_cr| here.
1577 @^system dependencies@>
1578
1579 @d wterm(A)    fprintf(mp->term_out,"%s",(A))
1580 @d wterm_chr(A)fprintf(mp->term_out,"%c",(A))
1581 @d wterm_ln(A) fprintf(mp->term_out,"\n%s",(A))
1582 @d wterm_cr    fprintf(mp->term_out,"\n")
1583 @d wlog(A)     fprintf(mp->log_file,"%s",(A))
1584 @d wlog_chr(A) fprintf(mp->log_file,"%c",(A))
1585 @d wlog_ln(A)  fprintf(mp->log_file,"\n%s",(A))
1586 @d wlog_cr     fprintf(mp->log_file, "\n")
1587 @d wps(A)      fprintf(mp->ps_file,"%s",(A))
1588 @d wps_chr(A)  fprintf(mp->ps_file,"%c",(A))
1589 @d wps_ln(A)   fprintf(mp->ps_file,,"\n%s",(A))
1590 @d wps_cr      fprintf(mp->ps_file,"\n")
1591
1592 @ To end a line of text output, we call |print_ln|.  Cases |0..max_write_files|
1593 use an array |wr_file| that will be declared later.
1594
1595 @d mp_print_text(A) mp_print_str(mp,text((A)))
1596
1597 @<Exported...@>=
1598 void mp_print_ln (MP mp);
1599 void mp_print_visible_char (MP mp, ASCII_code s); 
1600 void mp_print_char (MP mp, ASCII_code k);
1601 void mp_print (MP mp, char *s);
1602 void mp_print_str (MP mp, str_number s);
1603 void mp_print_nl (MP mp, char *s);
1604 void mp_print_two (MP mp,scaled x, scaled y) ;
1605 void mp_print_scaled (MP mp,scaled s);
1606
1607 @ @<Basic print...@>=
1608 void mp_print_ln (MP mp) { /* prints an end-of-line */
1609  switch (mp->selector) {
1610   case term_and_log: 
1611     wterm_cr; wlog_cr;
1612     mp->term_offset=0;  mp->file_offset=0;
1613     break;
1614   case log_only: 
1615     wlog_cr; mp->file_offset=0;
1616     break;
1617   case term_only: 
1618     wterm_cr; mp->term_offset=0;
1619     break;
1620   case ps_file_only: 
1621     wps_cr; mp->ps_offset=0;
1622     break;
1623   case no_print:
1624   case pseudo: 
1625   case new_string: 
1626     break;
1627   default: 
1628     fprintf(mp->wr_file[(mp->selector-write_file)],"\n");
1629   }
1630 } /* note that |tally| is not affected */
1631
1632 @ The |print_visible_char| procedure sends one character to the desired
1633 destination, using the |xchr| array to map it into an external character
1634 compatible with |input_ln|.  (It assumes that it is always called with
1635 a visible ASCII character.)  All printing comes through |print_ln| or
1636 |print_char|, which ultimately calls |print_visible_char|, hence these
1637 routines are the ones that limit lines to at most |max_print_line| characters.
1638 But we must make an exception for the \ps\ output file since it is not safe
1639 to cut up lines arbitrarily in \ps.
1640
1641 Procedure |unit_str_room| needs to be declared |forward| here because it calls
1642 |do_compaction| and |do_compaction| can call the error routines.  Actually,
1643 |unit_str_room| avoids |overflow| errors but it can call |confusion|.
1644
1645 @<Basic printing...@>=
1646 void mp_print_visible_char (MP mp, ASCII_code s) { /* prints a single character */
1647   switch (mp->selector) {
1648   case term_and_log: 
1649     wterm_chr(xchr(s)); wlog_chr(xchr(s));
1650     incr(mp->term_offset); incr(mp->file_offset);
1651     if ( mp->term_offset==(unsigned)mp->max_print_line ) { 
1652        wterm_cr; mp->term_offset=0;
1653     };
1654     if ( mp->file_offset==(unsigned)mp->max_print_line ) { 
1655        wlog_cr; mp->file_offset=0;
1656     };
1657     break;
1658   case log_only: 
1659     wlog_chr(xchr(s)); incr(mp->file_offset);
1660     if ( mp->file_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1661     break;
1662   case term_only: 
1663     wterm_chr(xchr(s)); incr(mp->term_offset);
1664     if ( mp->term_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1665     break;
1666   case ps_file_only: 
1667     if ( s==13 ) {
1668       wps_cr; mp->ps_offset=0;
1669     } else {
1670       wps_chr(xchr(s)); incr(mp->ps_offset);
1671     };
1672     break;
1673   case no_print: 
1674     break;
1675   case pseudo: 
1676     if ( mp->tally<mp->trick_count ) 
1677       mp->trick_buf[mp->tally % mp->error_line]=s;
1678     break;
1679   case new_string: 
1680     if ( mp->pool_ptr>=mp->max_pool_ptr ) { 
1681       mp_unit_str_room(mp);
1682       if ( mp->pool_ptr>=mp->pool_size ) 
1683         goto DONE; /* drop characters if string space is full */
1684     };
1685     append_char(s);
1686     break;
1687   default:
1688     fprintf(mp->wr_file[(mp->selector-write_file)],"%c",xchr(s));
1689   }
1690 DONE:
1691   incr(mp->tally);
1692 }
1693
1694 @ The |print_char| procedure sends one character to the desired destination.
1695 File names and string expressions might contain |ASCII_code| values that
1696 can't be printed using |print_visible_char|.  These characters will be
1697 printed in three- or four-symbol form like `\.{\^\^A}' or `\.{\^\^e4}'.
1698 (This procedure assumes that it is safe to bypass all checks for unprintable
1699 characters when |selector| is in the range |0..max_write_files-1| or when
1700 |selector=ps_file_only|.  In the former case the user might want to write
1701 unprintable characters, and in the latter case the \ps\ printing routines
1702 check their arguments themselves before calling |print_char| or |print|.)
1703
1704 @d print_lc_hex(A) do { l=(A);
1705     mp_print_visible_char(mp, (l<10 ? l+'0' : l-10+'a'));
1706   } while (0)
1707
1708 @<Basic printing...@>=
1709 void mp_print_char (MP mp, ASCII_code k) { /* prints a single character */
1710   int l; /* small index or counter */
1711   if ( mp->selector<pseudo || mp->selector>=write_file) {
1712     mp_print_visible_char(mp, k);
1713   } else if ( @<Character |k| cannot be printed@> ) { 
1714     mp_print(mp, "^^"); 
1715     if ( k<0100 ) { 
1716       mp_print_visible_char(mp, k+0100); 
1717     } else if ( k<0200 ) { 
1718       mp_print_visible_char(mp, k-0100); 
1719     } else { 
1720       print_lc_hex(k / 16);  
1721       print_lc_hex(k % 16); 
1722     }
1723   } else {
1724     mp_print_visible_char(mp, k);
1725   }
1726 };
1727
1728 @ An entire string is output by calling |print|. Note that if we are outputting
1729 the single standard ASCII character \.c, we could call |print("c")|, since
1730 |"c"=99| is the number of a single-character string, as explained above. But
1731 |print_char("c")| is quicker, so \MP\ goes directly to the |print_char|
1732 routine when it knows that this is safe. (The present implementation
1733 assumes that it is always safe to print a visible ASCII character.)
1734 @^system dependencies@>
1735
1736 @<Basic print...@>=
1737 void mp_do_print (MP mp, char *ss, unsigned int len) { /* prints string |s| */
1738   unsigned int j = 0;
1739   while ( j<len ){ 
1740     mp_print_char(mp, ss[j]); incr(j);
1741   }
1742 }
1743
1744
1745 @<Basic print...@>=
1746 void mp_print (MP mp, char *ss) {
1747   mp_do_print(mp, ss, strlen(ss));
1748 }
1749 void mp_print_str (MP mp, str_number s) {
1750   pool_pointer j; /* current character code position */
1751   if ( (s<0)||(s>mp->max_str_ptr) ) {
1752      mp_do_print(mp,"???",3); /* this can't happen */
1753 @.???@>
1754   }
1755   j=mp->str_start[s];
1756   mp_do_print(mp, (char *)(mp->str_pool+j), (str_stop(s)-j));
1757 }
1758
1759
1760 @ Here is the very first thing that \MP\ prints: a headline that identifies
1761 the version number and base name. The |term_offset| variable is temporarily
1762 incorrect, but the discrepancy is not serious since we assume that the banner
1763 and mem identifier together will occupy at most |max_print_line|
1764 character positions.
1765
1766 @<Initialize the output...@>=
1767 wterm (banner);
1768 wterm (version_string);
1769 if (mp->mem_ident!=NULL) 
1770   mp_print(mp,mp->mem_ident); 
1771 mp_print_ln(mp);
1772 update_terminal;
1773
1774 @ The procedure |print_nl| is like |print|, but it makes sure that the
1775 string appears at the beginning of a new line.
1776
1777 @<Basic print...@>=
1778 void mp_print_nl (MP mp, char *s) { /* prints string |s| at beginning of line */
1779   switch(mp->selector) {
1780   case term_and_log: 
1781     if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_ln(mp);
1782     break;
1783   case log_only: 
1784     if ( mp->file_offset>0 ) mp_print_ln(mp);
1785     break;
1786   case term_only: 
1787     if ( mp->term_offset>0 ) mp_print_ln(mp);
1788     break;
1789   case ps_file_only: 
1790     if ( mp->ps_offset>0 ) mp_print_ln(mp);
1791     break;
1792   case no_print:
1793   case pseudo:
1794   case new_string: 
1795         break;
1796   } /* there are no other cases */
1797   mp_print(mp, s);
1798 }
1799
1800 @ An array of digits in the range |0..9| is printed by |print_the_digs|.
1801
1802 @<Basic print...@>=
1803 void mp_print_the_digs (MP mp, eight_bits k) {
1804   /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
1805   while ( k>0 ){ 
1806     decr(k); mp_print_char(mp, '0'+mp->dig[k]);
1807   }
1808 };
1809
1810 @ The following procedure, which prints out the decimal representation of a
1811 given integer |n|, has been written carefully so that it works properly
1812 if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div|
1813 to negative arguments, since such operations are not implemented consistently
1814 by all \PASCAL\ compilers.
1815
1816 @<Basic print...@>=
1817 void mp_print_int (MP mp,integer n) { /* prints an integer in decimal form */
1818   integer m; /* used to negate |n| in possibly dangerous cases */
1819   int k = 0; /* index to current digit; we assume that $|n|<10^{23}$ */
1820   if ( n<0 ) { 
1821     mp_print_char(mp, '-');
1822     if ( n>-100000000 ) {
1823           negate(n);
1824     } else  { 
1825           m=-1-n; n=m / 10; m=(m % 10)+1; k=1;
1826       if ( m<10 ) {
1827         mp->dig[0]=m;
1828       } else { 
1829         mp->dig[0]=0; incr(n);
1830       }
1831     }
1832   }
1833   do {  
1834     mp->dig[k]=n % 10; n=n / 10; incr(k);
1835   } while (n!=0);
1836   mp_print_the_digs(mp, k);
1837 };
1838
1839 @ @<Exported...@>=
1840 void mp_print_int (MP mp,integer n);
1841
1842 @ \MP\ also makes use of a trivial procedure to print two digits. The
1843 following subroutine is usually called with a parameter in the range |0<=n<=99|.
1844
1845 @c 
1846 void mp_print_dd (MP mp,integer n) { /* prints two least significant digits */
1847   n=abs(n) % 100; 
1848   mp_print_char(mp, '0'+(n / 10));
1849   mp_print_char(mp, '0'+(n % 10));
1850 }
1851
1852 @ Here is a procedure that asks the user to type a line of input,
1853 assuming that the |selector| setting is either |term_only| or |term_and_log|.
1854 The input is placed into locations |first| through |last-1| of the
1855 |buffer| array, and echoed on the transcript file if appropriate.
1856
1857 This procedure is never called when |interaction<mp_scroll_mode|.
1858
1859 @d prompt_input(A) do { 
1860     wake_up_terminal; mp_print(mp, (A)); mp_term_input(mp);
1861   } while (0) /* prints a string and gets a line of input */
1862
1863 @c 
1864 void mp_term_input (MP mp) { /* gets a line from the terminal */
1865   size_t k; /* index into |buffer| */
1866   update_terminal; /* Now the user sees the prompt for sure */
1867   if (!mp_input_ln(mp, mp->term_in,true)) 
1868     mp_fatal_error(mp, "End of file on the terminal!");
1869 @.End of file on the terminal@>
1870   mp->term_offset=0; /* the user's line ended with \<\rm return> */
1871   decr(mp->selector); /* prepare to echo the input */
1872   if ( mp->last!=mp->first ) {
1873     for (k=mp->first;k<=mp->last-1;k++) {
1874       mp_print_char(mp, mp->buffer[k]);
1875     }
1876   }
1877   mp_print_ln(mp); 
1878   mp->buffer[mp->last]='%'; 
1879   incr(mp->selector); /* restore previous status */
1880 };
1881
1882 @* \[6] Reporting errors.
1883 When something anomalous is detected, \MP\ typically does something like this:
1884 $$\vbox{\halign{#\hfil\cr
1885 |print_err("Something anomalous has been detected");|\cr
1886 |help3("This is the first line of my offer to help.")|\cr
1887 |("This is the second line. I'm trying to")|\cr
1888 |("explain the best way for you to proceed.");|\cr
1889 |error;|\cr}}$$
1890 A two-line help message would be given using |help2|, etc.; these informal
1891 helps should use simple vocabulary that complements the words used in the
1892 official error message that was printed. (Outside the U.S.A., the help
1893 messages should preferably be translated into the local vernacular. Each
1894 line of help is at most 60 characters long, in the present implementation,
1895 so that |max_print_line| will not be exceeded.)
1896
1897 The |print_err| procedure supplies a `\.!' before the official message,
1898 and makes sure that the terminal is awake if a stop is going to occur.
1899 The |error| procedure supplies a `\..' after the official message, then it
1900 shows the location of the error; and if |interaction=error_stop_mode|,
1901 it also enters into a dialog with the user, during which time the help
1902 message may be printed.
1903 @^system dependencies@>
1904
1905 @ The global variable |interaction| has four settings, representing increasing
1906 amounts of user interaction:
1907
1908 @<Types...@>=
1909 enum { 
1910  mp_unspecified_mode=0, /* extra value for command-line switch */
1911  mp_batch_mode, /* omits all stops and omits terminal output */
1912  mp_nonstop_mode, /* omits all stops */
1913  mp_scroll_mode, /* omits error stops */
1914  mp_error_stop_mode, /* stops at every opportunity to interact */
1915 };
1916
1917 @ @<Glob...@>=
1918 int interaction; /* current level of interaction */
1919
1920 @ @<Option variables@>=
1921 int interaction; /* current level of interaction */
1922
1923 @ Set it here so it can be overwritten by the commandline
1924
1925 @<Allocate or initialize ...@>=
1926 mp->interaction=opt->interaction;
1927 if (mp->interaction==mp_unspecified_mode || mp->interaction>mp_error_stop_mode) 
1928   mp->interaction=mp_error_stop_mode;
1929 if (mp->interaction<mp_unspecified_mode) 
1930   mp->interaction=mp_batch_mode;
1931
1932
1933
1934 @d print_err(A) mp_print_err(mp,(A))
1935
1936 @<Exported...@>=
1937 void mp_print_err(MP mp, char * A);
1938
1939 @ @c
1940 void mp_print_err(MP mp, char * A) { 
1941   if ( mp->interaction==mp_error_stop_mode ) 
1942     wake_up_terminal;
1943   mp_print_nl(mp, "! "); 
1944   mp_print(mp, A);
1945 @.!\relax@>
1946 }
1947
1948
1949 @ \MP\ is careful not to call |error| when the print |selector| setting
1950 might be unusual. The only possible values of |selector| at the time of
1951 error messages are
1952
1953 \yskip\hang|no_print| (when |interaction=mp_batch_mode|
1954   and |log_file| not yet open);
1955
1956 \hang|term_only| (when |interaction>mp_batch_mode| and |log_file| not yet open);
1957
1958 \hang|log_only| (when |interaction=mp_batch_mode| and |log_file| is open);
1959
1960 \hang|term_and_log| (when |interaction>mp_batch_mode| and |log_file| is open).
1961
1962 @<Initialize the print |selector| based on |interaction|@>=
1963 if ( mp->interaction==mp_batch_mode ) mp->selector=no_print; else mp->selector=term_only
1964
1965 @ A global variable |deletions_allowed| is set |false| if the |get_next|
1966 routine is active when |error| is called; this ensures that |get_next|
1967 will never be called recursively.
1968 @^recursion@>
1969
1970 The global variable |history| records the worst level of error that
1971 has been detected. It has four possible values: |spotless|, |warning_issued|,
1972 |error_message_issued|, and |fatal_error_stop|.
1973
1974 Another global variable, |error_count|, is increased by one when an
1975 |error| occurs without an interactive dialog, and it is reset to zero at
1976 the end of every statement.  If |error_count| reaches 100, \MP\ decides
1977 that there is no point in continuing further.
1978
1979 @d spotless 0 /* |history| value when nothing has been amiss yet */
1980 @d warning_issued 1 /* |history| value when |begin_diagnostic| has been called */
1981 @d error_message_issued 2 /* |history| value when |error| has been called */
1982 @d fatal_error_stop 3 /* |history| value when termination was premature */
1983
1984 @<Glob...@>=
1985 boolean deletions_allowed; /* is it safe for |error| to call |get_next|? */
1986 int history; /* has the source input been clean so far? */
1987 int error_count; /* the number of scrolled errors since the last statement ended */
1988
1989 @ The value of |history| is initially |fatal_error_stop|, but it will
1990 be changed to |spotless| if \MP\ survives the initialization process.
1991
1992 @<Allocate or ...@>=
1993 mp->deletions_allowed=true; mp->error_count=0; /* |history| is initialized elsewhere */
1994
1995 @ Since errors can be detected almost anywhere in \MP, we want to declare the
1996 error procedures near the beginning of the program. But the error procedures
1997 in turn use some other procedures, which need to be declared |forward|
1998 before we get to |error| itself.
1999
2000 It is possible for |error| to be called recursively if some error arises
2001 when |get_next| is being used to delete a token, and/or if some fatal error
2002 occurs while \MP\ is trying to fix a non-fatal one. But such recursion
2003 @^recursion@>
2004 is never more than two levels deep.
2005
2006 @<Declarations@>=
2007 void mp_get_next (MP mp);
2008 void mp_term_input (MP mp);
2009 void mp_show_context (MP mp);
2010 void mp_begin_file_reading (MP mp);
2011 void mp_open_log_file (MP mp);
2012 void mp_clear_for_error_prompt (MP mp);
2013 void mp_debug_help (MP mp);
2014 @<Declare the procedure called |flush_string|@>
2015
2016 @ @<Exported...@>=
2017 void mp_normalize_selector (MP mp);
2018
2019 @ Individual lines of help are recorded in the array |help_line|, which
2020 contains entries in positions |0..(help_ptr-1)|. They should be printed
2021 in reverse order, i.e., with |help_line[0]| appearing last.
2022
2023 @d hlp1(A) mp->help_line[0]=(A); }
2024 @d hlp2(A) mp->help_line[1]=(A); hlp1
2025 @d hlp3(A) mp->help_line[2]=(A); hlp2
2026 @d hlp4(A) mp->help_line[3]=(A); hlp3
2027 @d hlp5(A) mp->help_line[4]=(A); hlp4
2028 @d hlp6(A) mp->help_line[5]=(A); hlp5
2029 @d help0 mp->help_ptr=0 /* sometimes there might be no help */
2030 @d help1  { mp->help_ptr=1; hlp1 /* use this with one help line */
2031 @d help2  { mp->help_ptr=2; hlp2 /* use this with two help lines */
2032 @d help3  { mp->help_ptr=3; hlp3 /* use this with three help lines */
2033 @d help4  { mp->help_ptr=4; hlp4 /* use this with four help lines */
2034 @d help5  { mp->help_ptr=5; hlp5 /* use this with five help lines */
2035 @d help6  { mp->help_ptr=6; hlp6 /* use this with six help lines */
2036
2037 @<Glob...@>=
2038 char * help_line[6]; /* helps for the next |error| */
2039 unsigned int help_ptr; /* the number of help lines present */
2040 boolean use_err_help; /* should the |err_help| string be shown? */
2041 str_number err_help; /* a string set up by \&{errhelp} */
2042 str_number filename_template; /* a string set up by \&{filenametemplate} */
2043
2044 @ @<Allocate or ...@>=
2045 mp->help_ptr=0; mp->use_err_help=false; mp->err_help=0; mp->filename_template=0;
2046
2047 @ The |jump_out| procedure just cuts across all active procedure levels and
2048 goes to |end_of_MP|. This is the only nonlocal |goto| statement in the
2049 whole program. It is used when there is no recovery from a particular error.
2050
2051 Some \PASCAL\ compilers do not implement non-local |goto| statements.
2052 @^system dependencies@>
2053 In such cases the body of |jump_out| should simply be
2054 `|close_files_and_terminate|;\thinspace' followed by a call on some system
2055 procedure that quietly terminates the program.
2056
2057 @<Error hand...@>=
2058 void mp_jump_out (MP mp) { 
2059  exit(mp->history);
2060 };
2061
2062 @ Here now is the general |error| routine.
2063
2064 @<Error hand...@>=
2065 void mp_error (MP mp) { /* completes the job of error reporting */
2066   ASCII_code c; /* what the user types */
2067   integer s1,s2,s3; /* used to save global variables when deleting tokens */
2068   pool_pointer j; /* character position being printed */
2069   if ( mp->history<error_message_issued ) mp->history=error_message_issued;
2070   mp_print_char(mp, '.'); mp_show_context(mp);
2071   if ( mp->interaction==mp_error_stop_mode ) {
2072     @<Get user's advice and |return|@>;
2073   }
2074   incr(mp->error_count);
2075   if ( mp->error_count==100 ) { 
2076     mp_print_nl(mp,"(That makes 100 errors; please try again.)");
2077 @.That makes 100 errors...@>
2078     mp->history=fatal_error_stop; mp_jump_out(mp);
2079   }
2080   @<Put help message on the transcript file@>;
2081 }
2082 void mp_warn (MP mp, char *msg) {
2083   int saved_selector = mp->selector;
2084   mp_normalize_selector(mp);
2085   mp_print_nl(mp,"Warning: ");
2086   mp_print(mp,msg);
2087   mp->selector = saved_selector;
2088 }
2089
2090 @ @<Exported...@>=
2091 void mp_error (MP mp);
2092 void mp_warn (MP mp, char *msg);
2093
2094
2095 @ @<Get user's advice...@>=
2096 while (1) { 
2097 CONTINUE:
2098   mp_clear_for_error_prompt(mp); prompt_input("? ");
2099 @.?\relax@>
2100   if ( mp->last==mp->first ) return;
2101   c=mp->buffer[mp->first];
2102   if ( c>='a' ) c=c+'A'-'a'; /* convert to uppercase */
2103   @<Interpret code |c| and |return| if done@>;
2104 }
2105
2106 @ It is desirable to provide an `\.E' option here that gives the user
2107 an easy way to return from \MP\ to the system editor, with the offending
2108 line ready to be edited. But such an extension requires some system
2109 wizardry, so the present implementation simply types out the name of the
2110 file that should be
2111 edited and the relevant line number.
2112 @^system dependencies@>
2113
2114 @<Types...@>=
2115 typedef void (*run_editor_command)(MP, char *, int);
2116
2117 @ @<Glob...@>=
2118 run_editor_command run_editor;
2119
2120 @ @<Option variables@>=
2121 run_editor_command run_editor;
2122
2123 @ @<Allocate or initialize ...@>=
2124 set_callback_option(run_editor);
2125
2126 @ @<Exported function headers@>=
2127 void mp_run_editor (MP mp, char *fname, int fline);
2128
2129 @ @c void mp_run_editor (MP mp, char *fname, int fline) {
2130     mp_print_nl(mp, "You want to edit file ");
2131 @.You want to edit file x@>
2132     mp_print(mp, fname);
2133     mp_print(mp, " at line "); 
2134     mp_print_int(mp, fline);
2135     mp->interaction=mp_scroll_mode; 
2136     mp_jump_out(mp);
2137 }
2138
2139
2140 There is a secret `\.D' option available when the debugging routines haven't
2141 been commented~out.
2142 @^debugging@>
2143
2144 @<Interpret code |c| and |return| if done@>=
2145 switch (c) {
2146 case '0': case '1': case '2': case '3': case '4':
2147 case '5': case '6': case '7': case '8': case '9': 
2148   if ( mp->deletions_allowed ) {
2149     @<Delete |c-"0"| tokens and |continue|@>;
2150   }
2151   break;
2152 #ifdef DEBUG
2153 case 'D': 
2154   mp_debug_help(mp); continue; 
2155   break;
2156 #endif
2157 case 'E': 
2158   if ( mp->file_ptr>0 ){ 
2159     (mp->run_editor)(mp, 
2160                      str(mp->input_stack[mp->file_ptr].name_field), 
2161                      mp_true_line(mp));
2162   }
2163   break;
2164 case 'H': 
2165   @<Print the help information and |continue|@>;
2166   break;
2167 case 'I':
2168   @<Introduce new material from the terminal and |return|@>;
2169   break;
2170 case 'Q': case 'R': case 'S':
2171   @<Change the interaction level and |return|@>;
2172   break;
2173 case 'X':
2174   mp->interaction=mp_scroll_mode; mp_jump_out(mp);
2175   break;
2176 default:
2177   break;
2178 }
2179 @<Print the menu of available options@>
2180
2181 @ @<Print the menu...@>=
2182
2183   mp_print(mp, "Type <return> to proceed, S to scroll future error messages,");
2184 @.Type <return> to proceed...@>
2185   mp_print_nl(mp, "R to run without stopping, Q to run quietly,");
2186   mp_print_nl(mp, "I to insert something, ");
2187   if ( mp->file_ptr>0 ) 
2188     mp_print(mp, "E to edit your file,");
2189   if ( mp->deletions_allowed )
2190     mp_print_nl(mp, "1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
2191   mp_print_nl(mp, "H for help, X to quit.");
2192 }
2193
2194 @ Here the author of \MP\ apologizes for making use of the numerical
2195 relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
2196 |mp_batch_mode|, |mp_nonstop_mode|, |mp_scroll_mode|.
2197 @^Knuth, Donald Ervin@>
2198
2199 @<Change the interaction...@>=
2200
2201   mp->error_count=0; mp->interaction=mp_batch_mode+c-'Q';
2202   mp_print(mp, "OK, entering ");
2203   switch (c) {
2204   case 'Q': mp_print(mp, "batchmode"); decr(mp->selector); break;
2205   case 'R': mp_print(mp, "nonstopmode"); break;
2206   case 'S': mp_print(mp, "scrollmode"); break;
2207   } /* there are no other cases */
2208   mp_print(mp, "..."); mp_print_ln(mp); update_terminal; return;
2209 }
2210
2211 @ When the following code is executed, |buffer[(first+1)..(last-1)]| may
2212 contain the material inserted by the user; otherwise another prompt will
2213 be given. In order to understand this part of the program fully, you need
2214 to be familiar with \MP's input stacks.
2215
2216 @<Introduce new material...@>=
2217
2218   mp_begin_file_reading(mp); /* enter a new syntactic level for terminal input */
2219   if ( mp->last>mp->first+1 ) { 
2220     loc=mp->first+1; mp->buffer[mp->first]=' ';
2221   } else { 
2222    prompt_input("insert>"); loc=mp->first;
2223 @.insert>@>
2224   };
2225   mp->first=mp->last+1; mp->cur_input.limit_field=mp->last; return;
2226 }
2227
2228 @ We allow deletion of up to 99 tokens at a time.
2229
2230 @<Delete |c-"0"| tokens...@>=
2231
2232   s1=mp->cur_cmd; s2=mp->cur_mod; s3=mp->cur_sym; mp->OK_to_interrupt=false;
2233   if ( (mp->last>mp->first+1) && (mp->buffer[mp->first+1]>='0')&&(mp->buffer[mp->first+1]<='9') )
2234     c=c*10+mp->buffer[mp->first+1]-'0'*11;
2235   else 
2236     c=c-'0';
2237   while ( c>0 ) { 
2238     mp_get_next(mp); /* one-level recursive call of |error| is possible */
2239     @<Decrease the string reference count, if the current token is a string@>;
2240     decr(c);
2241   };
2242   mp->cur_cmd=s1; mp->cur_mod=s2; mp->cur_sym=s3; mp->OK_to_interrupt=true;
2243   help2("I have just deleted some text, as you asked.")
2244        ("You can now delete more, or insert, or whatever.");
2245   mp_show_context(mp); 
2246   goto CONTINUE;
2247 }
2248
2249 @ @<Print the help info...@>=
2250
2251   if ( mp->use_err_help ) { 
2252     @<Print the string |err_help|, possibly on several lines@>;
2253     mp->use_err_help=false;
2254   } else { 
2255     if ( mp->help_ptr==0 ) {
2256       help2("Sorry, I don't know how to help in this situation.")
2257            ("Maybe you should try asking a human?");
2258      }
2259     do { 
2260       decr(mp->help_ptr); mp_print(mp, mp->help_line[mp->help_ptr]); mp_print_ln(mp);
2261     } while (mp->help_ptr!=0);
2262   };
2263   help4("Sorry, I already gave what help I could...")
2264        ("Maybe you should try asking a human?")
2265        ("An error might have occurred before I noticed any problems.")
2266        ("``If all else fails, read the instructions.''");
2267   goto CONTINUE;
2268 }
2269
2270 @ @<Print the string |err_help|, possibly on several lines@>=
2271 j=mp->str_start[mp->err_help];
2272 while ( j<str_stop(mp->err_help) ) { 
2273   if ( mp->str_pool[j]!='%' ) mp_print_str(mp, mp->str_pool[j]);
2274   else if ( j+1==str_stop(mp->err_help) ) mp_print_ln(mp);
2275   else if ( mp->str_pool[j+1]!='%' ) mp_print_ln(mp);
2276   else  { incr(j); mp_print_char(mp, '%'); };
2277   incr(j);
2278 }
2279
2280 @ @<Put help message on the transcript file@>=
2281 if ( mp->interaction>mp_batch_mode ) decr(mp->selector); /* avoid terminal output */
2282 if ( mp->use_err_help ) { 
2283   mp_print_nl(mp, "");
2284   @<Print the string |err_help|, possibly on several lines@>;
2285 } else { 
2286   while ( mp->help_ptr>0 ){ 
2287     decr(mp->help_ptr); mp_print_nl(mp, mp->help_line[mp->help_ptr]);
2288   };
2289 }
2290 mp_print_ln(mp);
2291 if ( mp->interaction>mp_batch_mode ) incr(mp->selector); /* re-enable terminal output */
2292 mp_print_ln(mp)
2293
2294 @ In anomalous cases, the print selector might be in an unknown state;
2295 the following subroutine is called to fix things just enough to keep
2296 running a bit longer.
2297
2298 @c 
2299 void mp_normalize_selector (MP mp) { 
2300   if ( mp->log_opened ) mp->selector=term_and_log;
2301   else mp->selector=term_only;
2302   if ( mp->job_name==NULL ) mp_open_log_file(mp);
2303   if ( mp->interaction==mp_batch_mode ) decr(mp->selector);
2304 }
2305
2306 @ The following procedure prints \MP's last words before dying.
2307
2308 @d succumb { if ( mp->interaction==mp_error_stop_mode )
2309     mp->interaction=mp_scroll_mode; /* no more interaction */
2310   if ( mp->log_opened ) mp_error(mp);
2311   /* if ( mp->interaction>mp_batch_mode ) mp_debug_help(mp); */
2312   mp->history=fatal_error_stop; mp_jump_out(mp); /* irrecoverable error */
2313   }
2314
2315 @<Error hand...@>=
2316 void mp_fatal_error (MP mp, char *s) { /* prints |s|, and that's it */
2317   mp_normalize_selector(mp);
2318   print_err("Emergency stop"); help1(s); succumb;
2319 @.Emergency stop@>
2320 }
2321
2322 @ @<Exported...@>=
2323 void mp_fatal_error (MP mp, char *s);
2324
2325
2326 @ Here is the most dreaded error message.
2327
2328 @<Error hand...@>=
2329 void mp_overflow (MP mp, char *s, integer n) { /* stop due to finiteness */
2330   mp_normalize_selector(mp);
2331   print_err("MetaPost capacity exceeded, sorry [");
2332 @.MetaPost capacity exceeded ...@>
2333   mp_print(mp, s); mp_print_char(mp, '='); mp_print_int(mp, n); mp_print_char(mp, ']');
2334   help2("If you really absolutely need more capacity,")
2335        ("you can ask a wizard to enlarge me.");
2336   succumb;
2337 }
2338
2339 @ @<Declarations@>=
2340 void mp_overflow (MP mp, char *s, integer n);
2341
2342 @ The program might sometime run completely amok, at which point there is
2343 no choice but to stop. If no previous error has been detected, that's bad
2344 news; a message is printed that is really intended for the \MP\
2345 maintenance person instead of the user (unless the user has been
2346 particularly diabolical).  The index entries for `this can't happen' may
2347 help to pinpoint the problem.
2348 @^dry rot@>
2349
2350 @<Declarations@>=
2351 void mp_confusion (MP mp,char *s);
2352
2353 @ @<Error hand...@>=
2354 void mp_confusion (MP mp,char *s) {
2355   /* consistency check violated; |s| tells where */
2356   mp_normalize_selector(mp);
2357   if ( mp->history<error_message_issued ) { 
2358     print_err("This can't happen ("); mp_print(mp, s); mp_print_char(mp, ')');
2359 @.This can't happen@>
2360     help1("I'm broken. Please show this to someone who can fix can fix");
2361   } else { 
2362     print_err("I can\'t go on meeting you like this");
2363 @.I can't go on...@>
2364     help2("One of your faux pas seems to have wounded me deeply...")
2365          ("in fact, I'm barely conscious. Please fix it and try again.");
2366   }
2367   succumb;
2368 }
2369
2370 @ Users occasionally want to interrupt \MP\ while it's running.
2371 If the \PASCAL\ runtime system allows this, one can implement
2372 a routine that sets the global variable |interrupt| to some nonzero value
2373 when such an interrupt is signaled. Otherwise there is probably at least
2374 a way to make |interrupt| nonzero using the \PASCAL\ debugger.
2375 @^system dependencies@>
2376 @^debugging@>
2377
2378 @d check_interrupt { if ( mp->interrupt!=0 )
2379    mp_pause_for_instructions(mp); }
2380
2381 @<Global...@>=
2382 integer interrupt; /* should \MP\ pause for instructions? */
2383 boolean OK_to_interrupt; /* should interrupts be observed? */
2384
2385 @ @<Allocate or ...@>=
2386 mp->interrupt=0; mp->OK_to_interrupt=true;
2387
2388 @ When an interrupt has been detected, the program goes into its
2389 highest interaction level and lets the user have the full flexibility of
2390 the |error| routine.  \MP\ checks for interrupts only at times when it is
2391 safe to do this.
2392
2393 @c 
2394 void mp_pause_for_instructions (MP mp) { 
2395   if ( mp->OK_to_interrupt ) { 
2396     mp->interaction=mp_error_stop_mode;
2397     if ( (mp->selector==log_only)||(mp->selector==no_print) )
2398       incr(mp->selector);
2399     print_err("Interruption");
2400 @.Interruption@>
2401     help3("You rang?")
2402          ("Try to insert some instructions for me (e.g.,`I show x'),")
2403          ("unless you just want to quit by typing `X'.");
2404     mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
2405     mp->interrupt=0;
2406   }
2407 }
2408
2409 @ Many of \MP's error messages state that a missing token has been
2410 inserted behind the scenes. We can save string space and program space
2411 by putting this common code into a subroutine.
2412
2413 @c 
2414 void mp_missing_err (MP mp, char *s) { 
2415   print_err("Missing `"); mp_print(mp, s); mp_print(mp, "' has been inserted");
2416 @.Missing...inserted@>
2417 }
2418
2419 @* \[7] Arithmetic with scaled numbers.
2420 The principal computations performed by \MP\ are done entirely in terms of
2421 integers less than $2^{31}$ in magnitude; thus, the arithmetic specified in this
2422 program can be carried out in exactly the same way on a wide variety of
2423 computers, including some small ones.
2424 @^small computers@>
2425
2426 But \PASCAL\ does not define the |div|
2427 operation in the case of negative dividends; for example, the result of
2428 |(-2*n-1) div 2| is |-(n+1)| on some computers and |-n| on others.
2429 There are two principal types of arithmetic: ``translation-preserving,''
2430 in which the identity |(a+q*b)div b=(a div b)+q| is valid; and
2431 ``negation-preserving,'' in which |(-a)div b=-(a div b)|. This leads to
2432 two \MP s, which can produce different results, although the differences
2433 should be negligible when the language is being used properly.
2434 The \TeX\ processor has been defined carefully so that both varieties
2435 of arithmetic will produce identical output, but it would be too
2436 inefficient to constrain \MP\ in a similar way.
2437
2438 @d el_gordo   017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */
2439
2440 @ One of \MP's most common operations is the calculation of
2441 $\lfloor{a+b\over2}\rfloor$,
2442 the midpoint of two given integers |a| and~|b|. The only decent way to do
2443 this in \PASCAL\ is to write `|(a+b) div 2|'; but on most machines it is
2444 far more efficient to calculate `|(a+b)| right shifted one bit'.
2445
2446 Therefore the midpoint operation will always be denoted by `|half(a+b)|'
2447 in this program. If \MP\ is being implemented with languages that permit
2448 binary shifting, the |half| macro should be changed to make this operation
2449 as efficient as possible.  Since some languages have shift operators that can
2450 only be trusted to work on positive numbers, there is also a macro |halfp|
2451 that is used only when the quantity being halved is known to be positive
2452 or zero.
2453
2454 @d half(A) ((A)) / 2
2455 @d halfp(A) ((A)) / 2
2456
2457 @ A single computation might use several subroutine calls, and it is
2458 desirable to avoid producing multiple error messages in case of arithmetic
2459 overflow. So the routines below set the global variable |arith_error| to |true|
2460 instead of reporting errors directly to the user.
2461
2462 @<Glob...@>=
2463 boolean arith_error; /* has arithmetic overflow occurred recently? */
2464
2465 @ @<Allocate or ...@>=
2466 mp->arith_error=false;
2467
2468 @ At crucial points the program will say |check_arith|, to test if
2469 an arithmetic error has been detected.
2470
2471 @d check_arith { if ( mp->arith_error ) mp_clear_arith(mp); }
2472
2473 @c 
2474 void mp_clear_arith (MP mp) { 
2475   print_err("Arithmetic overflow");
2476 @.Arithmetic overflow@>
2477   help4("Uh, oh. A little while ago one of the quantities that I was")
2478        ("computing got too large, so I'm afraid your answers will be")
2479        ("somewhat askew. You'll probably have to adopt different")
2480        ("tactics next time. But I shall try to carry on anyway.");
2481   mp_error(mp); 
2482   mp->arith_error=false;
2483 }
2484
2485 @ Addition is not always checked to make sure that it doesn't overflow,
2486 but in places where overflow isn't too unlikely the |slow_add| routine
2487 is used.
2488
2489 @c integer mp_slow_add (MP mp,integer x, integer y) { 
2490   if ( x>=0 )  {
2491     if ( y<=el_gordo-x ) { 
2492       return x+y;
2493     } else  { 
2494       mp->arith_error=true; 
2495           return el_gordo;
2496     }
2497   } else  if ( -y<=el_gordo+x ) {
2498     return x+y;
2499   } else { 
2500     mp->arith_error=true; 
2501         return -el_gordo;
2502   }
2503 }
2504
2505 @ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
2506 of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
2507 positions from the right end of a binary computer word.
2508
2509 @d quarter_unit   040000 /* $2^{14}$, represents 0.250000 */
2510 @d half_unit   0100000 /* $2^{15}$, represents 0.50000 */
2511 @d three_quarter_unit   0140000 /* $3\cdot2^{14}$, represents 0.75000 */
2512 @d unity   0200000 /* $2^{16}$, represents 1.00000 */
2513 @d two   0400000 /* $2^{17}$, represents 2.00000 */
2514 @d three   0600000 /* $2^{17}+2^{16}$, represents 3.00000 */
2515
2516 @<Types...@>=
2517 typedef integer scaled; /* this type is used for scaled integers */
2518 typedef unsigned char small_number; /* this type is self-explanatory */
2519
2520 @ The following function is used to create a scaled integer from a given decimal
2521 fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
2522 given in |dig[i]|, and the calculation produces a correctly rounded result.
2523
2524 @c 
2525 scaled mp_round_decimals (MP mp,small_number k) {
2526   /* converts a decimal fraction */
2527  integer a = 0; /* the accumulator */
2528  while ( k-->0 ) { 
2529     a=(a+mp->dig[k]*two) / 10;
2530   }
2531   return halfp(a+1);
2532 }
2533
2534 @ Conversely, here is a procedure analogous to |print_int|. If the output
2535 of this procedure is subsequently read by \MP\ and converted by the
2536 |round_decimals| routine above, it turns out that the original value will
2537 be reproduced exactly. A decimal point is printed only if the value is
2538 not an integer. If there is more than one way to print the result with
2539 the optimum number of digits following the decimal point, the closest
2540 possible value is given.
2541
2542 The invariant relation in the \&{repeat} loop is that a sequence of
2543 decimal digits yet to be printed will yield the original number if and only if
2544 they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
2545 We can stop if and only if $f=0$ satisfies this condition; the loop will
2546 terminate before $s$ can possibly become zero.
2547
2548 @<Basic printing...@>=
2549 void mp_print_scaled (MP mp,scaled s) { /* prints scaled real, rounded to five  digits */
2550   scaled delta; /* amount of allowable inaccuracy */
2551   if ( s<0 ) { 
2552         mp_print_char(mp, '-'); 
2553     negate(s); /* print the sign, if negative */
2554   }
2555   mp_print_int(mp, s / unity); /* print the integer part */
2556   s=10*(s % unity)+5;
2557   if ( s!=5 ) { 
2558     delta=10; 
2559     mp_print_char(mp, '.');
2560     do {  
2561       if ( delta>unity )
2562         s=s+0100000-(delta / 2); /* round the final digit */
2563       mp_print_char(mp, '0'+(s / unity)); 
2564       s=10*(s % unity); 
2565       delta=delta*10;
2566     } while (s>delta);
2567   }
2568 }
2569
2570 @ We often want to print two scaled quantities in parentheses,
2571 separated by a comma.
2572
2573 @<Basic printing...@>=
2574 void mp_print_two (MP mp,scaled x, scaled y) { /* prints `|(x,y)|' */
2575   mp_print_char(mp, '('); 
2576   mp_print_scaled(mp, x); 
2577   mp_print_char(mp, ','); 
2578   mp_print_scaled(mp, y);
2579   mp_print_char(mp, ')');
2580 }
2581
2582 @ The |scaled| quantities in \MP\ programs are generally supposed to be
2583 less than $2^{12}$ in absolute value, so \MP\ does much of its internal
2584 arithmetic with 28~significant bits of precision. A |fraction| denotes
2585 a scaled integer whose binary point is assumed to be 28 bit positions
2586 from the right.
2587
2588 @d fraction_half 01000000000 /* $2^{27}$, represents 0.50000000 */
2589 @d fraction_one 02000000000 /* $2^{28}$, represents 1.00000000 */
2590 @d fraction_two 04000000000 /* $2^{29}$, represents 2.00000000 */
2591 @d fraction_three 06000000000 /* $3\cdot2^{28}$, represents 3.00000000 */
2592 @d fraction_four 010000000000 /* $2^{30}$, represents 4.00000000 */
2593
2594 @<Types...@>=
2595 typedef integer fraction; /* this type is used for scaled fractions */
2596
2597 @ In fact, the two sorts of scaling discussed above aren't quite
2598 sufficient; \MP\ has yet another, used internally to keep track of angles
2599 in units of $2^{-20}$ degrees.
2600
2601 @d forty_five_deg 0264000000 /* $45\cdot2^{20}$, represents $45^\circ$ */
2602 @d ninety_deg 0550000000 /* $90\cdot2^{20}$, represents $90^\circ$ */
2603 @d one_eighty_deg 01320000000 /* $180\cdot2^{20}$, represents $180^\circ$ */
2604 @d three_sixty_deg 02640000000 /* $360\cdot2^{20}$, represents $360^\circ$ */
2605
2606 @<Types...@>=
2607 typedef integer angle; /* this type is used for scaled angles */
2608
2609 @ The |make_fraction| routine produces the |fraction| equivalent of
2610 |p/q|, given integers |p| and~|q|; it computes the integer
2611 $f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
2612 positive. If |p| and |q| are both of the same scaled type |t|,
2613 the ``type relation'' |make_fraction(t,t)=fraction| is valid;
2614 and it's also possible to use the subroutine ``backwards,'' using
2615 the relation |make_fraction(t,fraction)=t| between scaled types.
2616
2617 If the result would have magnitude $2^{31}$ or more, |make_fraction|
2618 sets |arith_error:=true|. Most of \MP's internal computations have
2619 been designed to avoid this sort of error.
2620
2621 If this subroutine were programmed in assembly language on a typical
2622 machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
2623 double-precision product can often be input to a fixed-point division
2624 instruction. But when we are restricted to \PASCAL\ arithmetic it
2625 is necessary either to resort to multiple-precision maneuvering
2626 or to use a simple but slow iteration. The multiple-precision technique
2627 would be about three times faster than the code adopted here, but it
2628 would be comparatively long and tricky, involving about sixteen
2629 additional multiplications and divisions.
2630
2631 This operation is part of \MP's ``inner loop''; indeed, it will
2632 consume nearly 10\pct! of the running time (exclusive of input and output)
2633 if the code below is left unchanged. A machine-dependent recoding
2634 will therefore make \MP\ run faster. The present implementation
2635 is highly portable, but slow; it avoids multiplication and division
2636 except in the initial stage. System wizards should be careful to
2637 replace it with a routine that is guaranteed to produce identical
2638 results in all cases.
2639 @^system dependencies@>
2640
2641 As noted below, a few more routines should also be replaced by machine-dependent
2642 code, for efficiency. But when a procedure is not part of the ``inner loop,''
2643 such changes aren't advisable; simplicity and robustness are
2644 preferable to trickery, unless the cost is too high.
2645 @^inner loop@>
2646
2647 @<Exported...@>=
2648 fraction mp_make_fraction (MP mp,integer p, integer q);
2649 integer mp_take_scaled (MP mp,integer q, scaled f) ;
2650
2651 @ If FIXPT is not defined, we need these preprocessor values
2652
2653 @d ELGORDO  0x7fffffff
2654 @d TWEXP31  2147483648.0
2655 @d TWEXP28  268435456.0
2656 @d TWEXP16 65536.0
2657 @d TWEXP_16 (1.0/65536.0)
2658 @d TWEXP_28 (1.0/268435456.0)
2659
2660
2661 @c 
2662 fraction mp_make_fraction (MP mp,integer p, integer q) {
2663 #ifdef FIXPT
2664   integer f; /* the fraction bits, with a leading 1 bit */
2665   integer n; /* the integer part of $\vert p/q\vert$ */
2666   integer be_careful; /* disables certain compiler optimizations */
2667   boolean negative = false; /* should the result be negated? */
2668   if ( p<0 ) {
2669     negate(p); negative=true;
2670   }
2671   if ( q<=0 ) { 
2672 #ifdef DEBUG
2673     if ( q==0 ) mp_confusion(mp, '/');
2674 #endif
2675 @:this can't happen /}{\quad \./@>
2676     negate(q); negative = ! negative;
2677   };
2678   n=p / q; p=p % q;
2679   if ( n>=8 ){ 
2680     mp->arith_error=true;
2681     return ( negative ? -el_gordo : el_gordo);
2682   } else { 
2683     n=(n-1)*fraction_one;
2684     @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>;
2685     return (negative ? (-(f+n)) : (f+n));
2686   }
2687 #else /* FIXPT */
2688     register double d;
2689         register integer i;
2690 #ifdef DEBUG
2691         if (q==0) mp_confusion(mp,'/'); 
2692 #endif /* DEBUG */
2693         d = TWEXP28 * (double)p /(double)q;
2694         if ((p^q) >= 0) {
2695                 d += 0.5;
2696                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
2697                 i = (integer) d;
2698                 if (d==i && ( ((q>0 ? -q : q)&077777)
2699                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2700         } else {
2701                 d -= 0.5;
2702                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
2703                 i = (integer) d;
2704                 if (d==i && ( ((q>0 ? q : -q)&077777)
2705                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2706         }
2707         return i;
2708 #endif /* FIXPT */
2709 }
2710
2711 @ The |repeat| loop here preserves the following invariant relations
2712 between |f|, |p|, and~|q|:
2713 (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
2714 $p_0$ is the original value of~$p$.
2715
2716 Notice that the computation specifies
2717 |(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
2718 Let us hope that optimizing compilers do not miss this point; a
2719 special variable |be_careful| is used to emphasize the necessary
2720 order of computation. Optimizing compilers should keep |be_careful|
2721 in a register, not store it in memory.
2722 @^inner loop@>
2723
2724 @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>=
2725 {
2726   f=1;
2727   do {  
2728     be_careful=p-q; p=be_careful+p;
2729     if ( p>=0 ) { 
2730       f=f+f+1;
2731     } else  { 
2732       f+=f; p=p+q;
2733     }
2734   } while (f<fraction_one);
2735   be_careful=p-q;
2736   if ( be_careful+p>=0 ) incr(f);
2737 }
2738
2739 @ The dual of |make_fraction| is |take_fraction|, which multiplies a
2740 given integer~|q| by a fraction~|f|. When the operands are positive, it
2741 computes $p=\lfloor qf/2^{28}+{1\over2}\rfloor$, a symmetric function
2742 of |q| and~|f|.
2743
2744 This routine is even more ``inner loopy'' than |make_fraction|;
2745 the present implementation consumes almost 20\pct! of \MP's computation
2746 time during typical jobs, so a machine-language substitute is advisable.
2747 @^inner loop@> @^system dependencies@>
2748
2749 @<Declarations@>=
2750 integer mp_take_fraction (MP mp,integer q, fraction f) ;
2751
2752 @ @c 
2753 #ifdef FIXPT
2754 integer mp_take_fraction (MP mp,integer q, fraction f) {
2755   integer p; /* the fraction so far */
2756   boolean negative; /* should the result be negated? */
2757   integer n; /* additional multiple of $q$ */
2758   integer be_careful; /* disables certain compiler optimizations */
2759   @<Reduce to the case that |f>=0| and |q>0|@>;
2760   if ( f<fraction_one ) { 
2761     n=0;
2762   } else { 
2763     n=f / fraction_one; f=f % fraction_one;
2764     if ( q<=el_gordo / n ) { 
2765       n=n*q ; 
2766     } else { 
2767       mp->arith_error=true; n=el_gordo;
2768     }
2769   }
2770   f=f+fraction_one;
2771   @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>;
2772   be_careful=n-el_gordo;
2773   if ( be_careful+p>0 ){ 
2774     mp->arith_error=true; n=el_gordo-p;
2775   }
2776   if ( negative ) 
2777         return (-(n+p));
2778   else 
2779     return (n+p);
2780 #else /* FIXPT */
2781 integer mp_take_fraction (MP mp,integer p, fraction q) {
2782     register double d;
2783         register integer i;
2784         d = (double)p * (double)q * TWEXP_28;
2785         if ((p^q) >= 0) {
2786                 d += 0.5;
2787                 if (d>=TWEXP31) {
2788                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2789                                 mp->arith_error = true;
2790                         return ELGORDO;
2791                 }
2792                 i = (integer) d;
2793                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2794         } else {
2795                 d -= 0.5;
2796                 if (d<= -TWEXP31) {
2797                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2798                                 mp->arith_error = true;
2799                         return -ELGORDO;
2800                 }
2801                 i = (integer) d;
2802                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2803         }
2804         return i;
2805 #endif /* FIXPT */
2806 }
2807
2808 @ @<Reduce to the case that |f>=0| and |q>0|@>=
2809 if ( f>=0 ) {
2810   negative=false;
2811 } else { 
2812   negate( f); negative=true;
2813 }
2814 if ( q<0 ) { 
2815   negate(q); negative=! negative;
2816 }
2817
2818 @ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
2819 =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
2820 $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
2821 @^inner loop@>
2822
2823 @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>=
2824 p=fraction_half; /* that's $2^{27}$; the invariants hold now with $k=28$ */
2825 if ( q<fraction_four ) {
2826   do {  
2827     if ( odd(f) ) p=halfp(p+q); else p=halfp(p);
2828     f=halfp(f);
2829   } while (f!=1);
2830 } else  {
2831   do {  
2832     if ( odd(f) ) p=p+halfp(q-p); else p=halfp(p);
2833     f=halfp(f);
2834   } while (f!=1);
2835 }
2836
2837
2838 @ When we want to multiply something by a |scaled| quantity, we use a scheme
2839 analogous to |take_fraction| but with a different scaling.
2840 Given positive operands, |take_scaled|
2841 computes the quantity $p=\lfloor qf/2^{16}+{1\over2}\rfloor$.
2842
2843 Once again it is a good idea to use a machine-language replacement if
2844 possible; otherwise |take_scaled| will use more than 2\pct! of the running time
2845 when the Computer Modern fonts are being generated.
2846 @^inner loop@>
2847
2848 @c 
2849 #ifdef FIXPT
2850 integer mp_take_scaled (MP mp,integer q, scaled f) {
2851   integer p; /* the fraction so far */
2852   boolean negative; /* should the result be negated? */
2853   integer n; /* additional multiple of $q$ */
2854   integer be_careful; /* disables certain compiler optimizations */
2855   @<Reduce to the case that |f>=0| and |q>0|@>;
2856   if ( f<unity ) { 
2857     n=0;
2858   } else  { 
2859     n=f / unity; f=f % unity;
2860     if ( q<=el_gordo / n ) {
2861       n=n*q;
2862     } else  { 
2863       mp->arith_error=true; n=el_gordo;
2864     }
2865   }
2866   f=f+unity;
2867   @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>;
2868   be_careful=n-el_gordo;
2869   if ( be_careful+p>0 ) { 
2870     mp->arith_error=true; n=el_gordo-p;
2871   }
2872   return ( negative ?(-(n+p)) :(n+p));
2873 #else /* FIXPT */
2874 integer mp_take_scaled (MP mp,integer p, scaled q) {
2875     register double d;
2876         register integer i;
2877         d = (double)p * (double)q * TWEXP_16;
2878         if ((p^q) >= 0) {
2879                 d += 0.5;
2880                 if (d>=TWEXP31) {
2881                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2882                                 mp->arith_error = true;
2883                         return ELGORDO;
2884                 }
2885                 i = (integer) d;
2886                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2887         } else {
2888                 d -= 0.5;
2889                 if (d<= -TWEXP31) {
2890                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2891                                 mp->arith_error = true;
2892                         return -ELGORDO;
2893                 }
2894                 i = (integer) d;
2895                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2896         }
2897         return i;
2898 #endif /* FIXPT */
2899 }
2900
2901 @ @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>=
2902 p=half_unit; /* that's $2^{15}$; the invariants hold now with $k=16$ */
2903 @^inner loop@>
2904 if ( q<fraction_four ) {
2905   do {  
2906     p = (odd(f) ? halfp(p+q) : halfp(p));
2907     f=halfp(f);
2908   } while (f!=1);
2909 } else {
2910   do {  
2911     p = (odd(f) ? p+halfp(q-p) : halfp(p));
2912     f=halfp(f);
2913   } while (f!=1);
2914 }
2915
2916 @ For completeness, there's also |make_scaled|, which computes a
2917 quotient as a |scaled| number instead of as a |fraction|.
2918 In other words, the result is $\lfloor2^{16}p/q+{1\over2}\rfloor$, if the
2919 operands are positive. \ (This procedure is not used especially often,
2920 so it is not part of \MP's inner loop.)
2921
2922 @c 
2923 scaled mp_make_scaled (MP mp,integer p, integer q) {
2924 #ifdef FIXPT 
2925   integer f; /* the fraction bits, with a leading 1 bit */
2926   integer n; /* the integer part of $\vert p/q\vert$ */
2927   boolean negative; /* should the result be negated? */
2928   integer be_careful; /* disables certain compiler optimizations */
2929   if ( p>=0 ) negative=false;
2930   else  { negate(p); negative=true; };
2931   if ( q<=0 ) { 
2932 #ifdef DEBUG 
2933     if ( q==0 ) mp_confusion(mp, "/");
2934 @:this can't happen /}{\quad \./@>
2935 #endif
2936     negate(q); negative=! negative;
2937   }
2938   n=p / q; p=p % q;
2939   if ( n>=0100000 ) { 
2940     mp->arith_error=true;
2941     return (negative ? (-el_gordo) : el_gordo);
2942   } else  { 
2943     n=(n-1)*unity;
2944     @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>;
2945     return ( negative ? (-(f+n)) :(f+n));
2946   }
2947 #else /* FIXPT */
2948     register double d;
2949         register integer i;
2950 #ifdef DEBUG
2951         if (q==0) mp_confusion(mp,"/"); 
2952 #endif /* DEBUG */
2953         d = TWEXP16 * (double)p /(double)q;
2954         if ((p^q) >= 0) {
2955                 d += 0.5;
2956                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
2957                 i = (integer) d;
2958                 if (d==i && ( ((q>0 ? -q : q)&077777)
2959                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2960         } else {
2961                 d -= 0.5;
2962                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
2963                 i = (integer) d;
2964                 if (d==i && ( ((q>0 ? q : -q)&077777)
2965                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2966         }
2967         return i;
2968 #endif /* FIXPT */
2969 }
2970
2971 @ @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>=
2972 f=1;
2973 do {  
2974   be_careful=p-q; p=be_careful+p;
2975   if ( p>=0 ) f=f+f+1;
2976   else  { f+=f; p=p+q; };
2977 } while (f<unity);
2978 be_careful=p-q;
2979 if ( be_careful+p>=0 ) incr(f)
2980
2981 @ Here is a typical example of how the routines above can be used.
2982 It computes the function
2983 $${1\over3\tau}f(\theta,\phi)=
2984 {\tau^{-1}\bigl(2+\sqrt2\,(\sin\theta-{1\over16}\sin\phi)
2985  (\sin\phi-{1\over16}\sin\theta)(\cos\theta-\cos\phi)\bigr)\over
2986 3\,\bigl(1+{1\over2}(\sqrt5-1)\cos\theta+{1\over2}(3-\sqrt5\,)\cos\phi\bigr)},$$
2987 where $\tau$ is a |scaled| ``tension'' parameter. This is \MP's magic
2988 fudge factor for placing the first control point of a curve that starts
2989 at an angle $\theta$ and ends at an angle $\phi$ from the straight path.
2990 (Actually, if the stated quantity exceeds 4, \MP\ reduces it to~4.)
2991
2992 The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$.
2993 (It's a sum of eight terms whose absolute values can be bounded using
2994 relations such as $\sin\theta\cos\theta\L{1\over2}$.) Thus the numerator
2995 is positive; and since the tension $\tau$ is constrained to be at least
2996 $3\over4$, the numerator is less than $16\over3$. The denominator is
2997 nonnegative and at most~6.  Hence the fixed-point calculations below
2998 are guaranteed to stay within the bounds of a 32-bit computer word.
2999
3000 The angles $\theta$ and $\phi$ are given implicitly in terms of |fraction|
3001 arguments |st|, |ct|, |sf|, and |cf|, representing $\sin\theta$, $\cos\theta$,
3002 $\sin\phi$, and $\cos\phi$, respectively.
3003
3004 @c 
3005 fraction mp_velocity (MP mp,fraction st, fraction ct, fraction sf,
3006                       fraction cf, scaled t) {
3007   integer acc,num,denom; /* registers for intermediate calculations */
3008   acc=mp_take_fraction(mp, st-(sf / 16), sf-(st / 16));
3009   acc=mp_take_fraction(mp, acc,ct-cf);
3010   num=fraction_two+mp_take_fraction(mp, acc,379625062);
3011                    /* $2^{28}\sqrt2\approx379625062.497$ */
3012   denom=fraction_three+mp_take_fraction(mp, ct,497706707)+mp_take_fraction(mp, cf,307599661);
3013                       /* $3\cdot2^{27}\cdot(\sqrt5-1)\approx497706706.78$ and
3014                          $3\cdot2^{27}\cdot(3-\sqrt5\,)\approx307599661.22$ */
3015   if ( t!=unity ) num=mp_make_scaled(mp, num,t);
3016   /* |make_scaled(fraction,scaled)=fraction| */
3017   if ( num / 4>=denom ) 
3018     return fraction_four;
3019   else 
3020     return mp_make_fraction(mp, num, denom);
3021 }
3022
3023 @ The following somewhat different subroutine tests rigorously if $ab$ is
3024 greater than, equal to, or less than~$cd$,
3025 given integers $(a,b,c,d)$. In most cases a quick decision is reached.
3026 The result is $+1$, 0, or~$-1$ in the three respective cases.
3027
3028 @d mp_ab_vs_cd(M,A,B,C,D) mp_do_ab_vs_cd(A,B,C,D)
3029
3030 @c 
3031 integer mp_do_ab_vs_cd (integer a,integer b, integer c, integer d) {
3032   integer q,r; /* temporary registers */
3033   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
3034   while (1) { 
3035     q = a / d; r = c / b;
3036     if ( q!=r )
3037       return ( q>r ? 1 : -1);
3038     q = a % d; r = c % b;
3039     if ( r==0 )
3040       return (q ? 1 : 0);
3041     if ( q==0 ) return -1;
3042     a=b; b=q; c=d; d=r;
3043   } /* now |a>d>0| and |c>b>0| */
3044 }
3045
3046 @ @<Reduce to the case that |a...@>=
3047 if ( a<0 ) { negate(a); negate(b);  };
3048 if ( c<0 ) { negate(c); negate(d);  };
3049 if ( d<=0 ) { 
3050   if ( b>=0 ) {
3051     if ( (a==0||b==0)&&(c==0||d==0) ) return 0;
3052     else return 1;
3053   }
3054   if ( d==0 )
3055     return ( a==0 ? 0 : -1);
3056   q=a; a=c; c=q; q=-b; b=-d; d=q;
3057 } else if ( b<=0 ) { 
3058   if ( b<0 ) if ( a>0 ) return -1;
3059   return (c==0 ? 0 : -1);
3060 }
3061
3062 @ We conclude this set of elementary routines with some simple rounding
3063 and truncation operations that are coded in a machine-independent fashion.
3064 The routines are slightly complicated because we want them to work
3065 without overflow whenever $-2^{31}\L x<2^{31}$.
3066
3067 @<Declarations@>=
3068 #define mp_floor_scaled(M,i) ((i)&(-65536))
3069 #define mp_round_unscaled(M,i) (((i>>15)+1)>>1)
3070 #define mp_round_fraction(M,i) (((i>>11)+1)>>1)
3071
3072
3073 @* \[8] Algebraic and transcendental functions.
3074 \MP\ computes all of the necessary special functions from scratch, without
3075 relying on |real| arithmetic or system subroutines for sines, cosines, etc.
3076
3077 @ To get the square root of a |scaled| number |x|, we want to calculate
3078 $s=\lfloor 2^8\!\sqrt x +{1\over2}\rfloor$. If $x>0$, this is the unique
3079 integer such that $2^{16}x-s\L s^2<2^{16}x+s$. The following subroutine
3080 determines $s$ by an iterative method that maintains the invariant
3081 relations $x=2^{46-2k}x_0\bmod 2^{30}$, $0<y=\lfloor 2^{16-2k}x_0\rfloor
3082 -s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$
3083 might, however, be zero at the start of the first iteration.
3084
3085 @<Declarations@>=
3086 scaled mp_square_rt (MP mp,scaled x) ;
3087
3088 @ @c 
3089 scaled mp_square_rt (MP mp,scaled x) {
3090   small_number k; /* iteration control counter */
3091   integer y,q; /* registers for intermediate calculations */
3092   if ( x<=0 ) { 
3093     @<Handle square root of zero or negative argument@>;
3094   } else { 
3095     k=23; q=2;
3096     while ( x<fraction_two ) { /* i.e., |while x<@t$2^{29}$@>|\unskip */
3097       decr(k); x=x+x+x+x;
3098     }
3099     if ( x<fraction_four ) y=0;
3100     else  { x=x-fraction_four; y=1; };
3101     do {  
3102       @<Decrease |k| by 1, maintaining the invariant
3103       relations between |x|, |y|, and~|q|@>;
3104     } while (k!=0);
3105     return (halfp(q));
3106   }
3107 }
3108
3109 @ @<Handle square root of zero...@>=
3110
3111   if ( x<0 ) { 
3112     print_err("Square root of ");
3113 @.Square root...replaced by 0@>
3114     mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3115     help2("Since I don't take square roots of negative numbers,")
3116          ("I'm zeroing this one. Proceed, with fingers crossed.");
3117     mp_error(mp);
3118   };
3119   return 0;
3120 }
3121
3122 @ @<Decrease |k| by 1, maintaining...@>=
3123 x+=x; y+=y;
3124 if ( x>=fraction_four ) { /* note that |fraction_four=@t$2^{30}$@>| */
3125   x=x-fraction_four; incr(y);
3126 };
3127 x+=x; y=y+y-q; q+=q;
3128 if ( x>=fraction_four ) { x=x-fraction_four; incr(y); };
3129 if ( y>q ){ y=y-q; q=q+2; }
3130 else if ( y<=0 )  { q=q-2; y=y+q;  };
3131 decr(k)
3132
3133 @ Pythagorean addition $\psqrt{a^2+b^2}$ is implemented by an elegant
3134 iterative scheme due to Cleve Moler and Donald Morrison [{\sl IBM Journal
3135 @^Moler, Cleve Barry@>
3136 @^Morrison, Donald Ross@>
3137 of Research and Development\/ \bf27} (1983), 577--581]. It modifies |a| and~|b|
3138 in such a way that their Pythagorean sum remains invariant, while the
3139 smaller argument decreases.
3140
3141 @c 
3142 integer mp_pyth_add (MP mp,integer a, integer b) {
3143   fraction r; /* register used to transform |a| and |b| */
3144   boolean big; /* is the result dangerously near $2^{31}$? */
3145   a=abs(a); b=abs(b);
3146   if ( a<b ) { r=b; b=a; a=r; }; /* now |0<=b<=a| */
3147   if ( b>0 ) {
3148     if ( a<fraction_two ) {
3149       big=false;
3150     } else { 
3151       a=a / 4; b=b / 4; big=true;
3152     }; /* we reduced the precision to avoid arithmetic overflow */
3153     @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>;
3154     if ( big ) {
3155       if ( a<fraction_two ) {
3156         a=a+a+a+a;
3157       } else  { 
3158         mp->arith_error=true; a=el_gordo;
3159       };
3160     }
3161   }
3162   return a;
3163 }
3164
3165 @ The key idea here is to reflect the vector $(a,b)$ about the
3166 line through $(a,b/2)$.
3167
3168 @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>=
3169 while (1) {  
3170   r=mp_make_fraction(mp, b,a);
3171   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3172   if ( r==0 ) break;
3173   r=mp_make_fraction(mp, r,fraction_four+r);
3174   a=a+mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3175 }
3176
3177
3178 @ Here is a similar algorithm for $\psqrt{a^2-b^2}$.
3179 It converges slowly when $b$ is near $a$, but otherwise it works fine.
3180
3181 @c 
3182 integer mp_pyth_sub (MP mp,integer a, integer b) {
3183   fraction r; /* register used to transform |a| and |b| */
3184   boolean big; /* is the input dangerously near $2^{31}$? */
3185   a=abs(a); b=abs(b);
3186   if ( a<=b ) {
3187     @<Handle erroneous |pyth_sub| and set |a:=0|@>;
3188   } else { 
3189     if ( a<fraction_four ) {
3190       big=false;
3191     } else  { 
3192       a=halfp(a); b=halfp(b); big=true;
3193     }
3194     @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>;
3195     if ( big ) a=a+a;
3196   }
3197   return a;
3198 }
3199
3200 @ @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>=
3201 while (1) { 
3202   r=mp_make_fraction(mp, b,a);
3203   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3204   if ( r==0 ) break;
3205   r=mp_make_fraction(mp, r,fraction_four-r);
3206   a=a-mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3207 }
3208
3209 @ @<Handle erroneous |pyth_sub| and set |a:=0|@>=
3210
3211   if ( a<b ){ 
3212     print_err("Pythagorean subtraction "); mp_print_scaled(mp, a);
3213     mp_print(mp, "+-+"); mp_print_scaled(mp, b); 
3214     mp_print(mp, " has been replaced by 0");
3215 @.Pythagorean...@>
3216     help2("Since I don't take square roots of negative numbers,")
3217          ("I'm zeroing this one. Proceed, with fingers crossed.");
3218     mp_error(mp);
3219   }
3220   a=0;
3221 }
3222
3223 @ The subroutines for logarithm and exponential involve two tables.
3224 The first is simple: |two_to_the[k]| equals $2^k$. The second involves
3225 a bit more calculation, which the author claims to have done correctly:
3226 |spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
3227 2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
3228 nearest integer.
3229
3230 @d two_to_the(A) (1<<(A))
3231
3232 @<Constants ...@>=
3233 static const integer spec_log[29] = { 0, /* special logarithms */
3234 93032640, 38612034, 17922280, 8662214, 4261238, 2113709,
3235 1052693, 525315, 262400, 131136, 65552, 32772, 16385,
3236 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 1 };
3237
3238 @ @<Local variables for initialization@>=
3239 integer k; /* all-purpose loop index */
3240
3241
3242 @ Here is the routine that calculates $2^8$ times the natural logarithm
3243 of a |scaled| quantity; it is an integer approximation to $2^{24}\ln(x/2^{16})$,
3244 when |x| is a given positive integer.
3245
3246 The method is based on exercise 1.2.2--25 in {\sl The Art of Computer
3247 Programming\/}: During the main iteration we have $1\L 2^{-30}x<1/(1-2^{1-k})$,
3248 and the logarithm of $2^{30}x$ remains to be added to an accumulator
3249 register called~$y$. Three auxiliary bits of accuracy are retained in~$y$
3250 during the calculation, and sixteen auxiliary bits to extend |y| are
3251 kept in~|z| during the initial argument reduction. (We add
3252 $100\cdot2^{16}=6553600$ to~|z| and subtract 100 from~|y| so that |z| will
3253 not become negative; also, the actual amount subtracted from~|y| is~96,
3254 not~100, because we want to add~4 for rounding before the final division by~8.)
3255
3256 @c 
3257 scaled mp_m_log (MP mp,scaled x) {
3258   integer y,z; /* auxiliary registers */
3259   integer k; /* iteration counter */
3260   if ( x<=0 ) {
3261      @<Handle non-positive logarithm@>;
3262   } else  { 
3263     y=1302456956+4-100; /* $14\times2^{27}\ln2\approx1302456956.421063$ */
3264     z=27595+6553600; /* and $2^{16}\times .421063\approx 27595$ */
3265     while ( x<fraction_four ) {
3266        x+=x; y=y-93032639; z=z-48782;
3267     } /* $2^{27}\ln2\approx 93032639.74436163$ and $2^{16}\times.74436163\approx 48782$ */
3268     y=y+(z / unity); k=2;
3269     while ( x>fraction_four+4 ) {
3270       @<Increase |k| until |x| can be multiplied by a
3271         factor of $2^{-k}$, and adjust $y$ accordingly@>;
3272     }
3273     return (y / 8);
3274   }
3275 }
3276
3277 @ @<Increase |k| until |x| can...@>=
3278
3279   z=((x-1) / two_to_the(k))+1; /* $z=\lceil x/2^k\rceil$ */
3280   while ( x<fraction_four+z ) { z=halfp(z+1); k=k+1; };
3281   y=y+spec_log[k]; x=x-z;
3282 }
3283
3284 @ @<Handle non-positive logarithm@>=
3285
3286   print_err("Logarithm of ");
3287 @.Logarithm...replaced by 0@>
3288   mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3289   help2("Since I don't take logs of non-positive numbers,")
3290        ("I'm zeroing this one. Proceed, with fingers crossed.");
3291   mp_error(mp); 
3292   return 0;
3293 }
3294
3295 @ Conversely, the exponential routine calculates $\exp(x/2^8)$,
3296 when |x| is |scaled|. The result is an integer approximation to
3297 $2^{16}\exp(x/2^{24})$, when |x| is regarded as an integer.
3298
3299 @c 
3300 scaled mp_m_exp (MP mp,scaled x) {
3301   small_number k; /* loop control index */
3302   integer y,z; /* auxiliary registers */
3303   if ( x>174436200 ) {
3304     /* $2^{24}\ln((2^{31}-1)/2^{16})\approx 174436199.51$ */
3305     mp->arith_error=true; 
3306     return el_gordo;
3307   } else if ( x<-197694359 ) {
3308         /* $2^{24}\ln(2^{-1}/2^{16})\approx-197694359.45$ */
3309     return 0;
3310   } else { 
3311     if ( x<=0 ) { 
3312        z=-8*x; y=04000000; /* $y=2^{20}$ */
3313     } else { 
3314       if ( x<=127919879 ) { 
3315         z=1023359037-8*x;
3316         /* $2^{27}\ln((2^{31}-1)/2^{20})\approx 1023359037.125$ */
3317       } else {
3318        z=8*(174436200-x); /* |z| is always nonnegative */
3319       }
3320       y=el_gordo;
3321     };
3322     @<Multiply |y| by $\exp(-z/2^{27})$@>;
3323     if ( x<=127919879 ) 
3324        return ((y+8) / 16);
3325      else 
3326        return y;
3327   }
3328 }
3329
3330 @ The idea here is that subtracting |spec_log[k]| from |z| corresponds
3331 to multiplying |y| by $1-2^{-k}$.
3332
3333 A subtle point (which had to be checked) was that if $x=127919879$, the
3334 value of~|y| will decrease so that |y+8| doesn't overflow. In fact,
3335 $z$ will be 5 in this case, and |y| will decrease by~64 when |k=25|
3336 and by~16 when |k=27|.
3337
3338 @<Multiply |y| by...@>=
3339 k=1;
3340 while ( z>0 ) { 
3341   while ( z>=spec_log[k] ) { 
3342     z-=spec_log[k];
3343     y=y-1-((y-two_to_the(k-1)) / two_to_the(k));
3344   }
3345   incr(k);
3346 }
3347
3348 @ The trigonometric subroutines use an auxiliary table such that
3349 |spec_atan[k]| contains an approximation to the |angle| whose tangent
3350 is~$1/2^k$. $\arctan2^{-k}$ times $2^{20}\cdot180/\pi$ 
3351
3352 @<Constants ...@>=
3353 static const angle spec_atan[27] = { 0, 27855475, 14718068, 7471121, 3750058, 
3354 1876857, 938658, 469357, 234682, 117342, 58671, 29335, 14668, 7334, 3667, 
3355 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1 };
3356
3357 @ Given integers |x| and |y|, not both zero, the |n_arg| function
3358 returns the |angle| whose tangent points in the direction $(x,y)$.
3359 This subroutine first determines the correct octant, then solves the
3360 problem for |0<=y<=x|, then converts the result appropriately to
3361 return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|.
3362 (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of
3363 |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.)
3364
3365 The octants are represented in a ``Gray code,'' since that turns out
3366 to be computationally simplest.
3367
3368 @d negate_x 1
3369 @d negate_y 2
3370 @d switch_x_and_y 4
3371 @d first_octant 1
3372 @d second_octant (first_octant+switch_x_and_y)
3373 @d third_octant (first_octant+switch_x_and_y+negate_x)
3374 @d fourth_octant (first_octant+negate_x)
3375 @d fifth_octant (first_octant+negate_x+negate_y)
3376 @d sixth_octant (first_octant+switch_x_and_y+negate_x+negate_y)
3377 @d seventh_octant (first_octant+switch_x_and_y+negate_y)
3378 @d eighth_octant (first_octant+negate_y)
3379
3380 @c 
3381 angle mp_n_arg (MP mp,integer x, integer y) {
3382   angle z; /* auxiliary register */
3383   integer t; /* temporary storage */
3384   small_number k; /* loop counter */
3385   int octant; /* octant code */
3386   if ( x>=0 ) {
3387     octant=first_octant;
3388   } else { 
3389     negate(x); octant=first_octant+negate_x;
3390   }
3391   if ( y<0 ) { 
3392     negate(y); octant=octant+negate_y;
3393   }
3394   if ( x<y ) { 
3395     t=y; y=x; x=t; octant=octant+switch_x_and_y;
3396   }
3397   if ( x==0 ) { 
3398     @<Handle undefined arg@>; 
3399   } else { 
3400     @<Set variable |z| to the arg of $(x,y)$@>;
3401     @<Return an appropriate answer based on |z| and |octant|@>;
3402   }
3403 }
3404
3405 @ @<Handle undefined arg@>=
3406
3407   print_err("angle(0,0) is taken as zero");
3408 @.angle(0,0)...zero@>
3409   help2("The `angle' between two identical points is undefined.")
3410        ("I'm zeroing this one. Proceed, with fingers crossed.");
3411   mp_error(mp); 
3412   return 0;
3413 }
3414
3415 @ @<Return an appropriate answer...@>=
3416 switch (octant) {
3417 case first_octant: return z;
3418 case second_octant: return (ninety_deg-z);
3419 case third_octant: return (ninety_deg+z);
3420 case fourth_octant: return (one_eighty_deg-z);
3421 case fifth_octant: return (z-one_eighty_deg);
3422 case sixth_octant: return (-z-ninety_deg);
3423 case seventh_octant: return (z-ninety_deg);
3424 case eighth_octant: return (-z);
3425 }; /* there are no other cases */
3426 return 0
3427
3428 @ At this point we have |x>=y>=0|, and |x>0|. The numbers are scaled up
3429 or down until $2^{28}\L x<2^{29}$, so that accurate fixed-point calculations
3430 will be made.
3431
3432 @<Set variable |z| to the arg...@>=
3433 while ( x>=fraction_two ) { 
3434   x=halfp(x); y=halfp(y);
3435 }
3436 z=0;
3437 if ( y>0 ) { 
3438  while ( x<fraction_one ) { 
3439     x+=x; y+=y; 
3440  };
3441  @<Increase |z| to the arg of $(x,y)$@>;
3442 }
3443
3444 @ During the calculations of this section, variables |x| and~|y|
3445 represent actual coordinates $(x,2^{-k}y)$. We will maintain the
3446 condition |x>=y|, so that the tangent will be at most $2^{-k}$.
3447 If $x<2y$, the tangent is greater than $2^{-k-1}$. The transformation
3448 $(a,b)\mapsto(a+b\tan\phi,b-a\tan\phi)$ replaces $(a,b)$ by
3449 coordinates whose angle has decreased by~$\phi$; in the special case
3450 $a=x$, $b=2^{-k}y$, and $\tan\phi=2^{-k-1}$, this operation reduces
3451 to the particularly simple iteration shown here. [Cf.~John E. Meggitt,
3452 @^Meggitt, John E.@>
3453 {\sl IBM Journal of Research and Development\/ \bf6} (1962), 210--226.]
3454
3455 The initial value of |x| will be multiplied by at most
3456 $(1+{1\over2})(1+{1\over8})(1+{1\over32})\cdots\approx 1.7584$; hence
3457 there is no chance of integer overflow.
3458
3459 @<Increase |z|...@>=
3460 k=0;
3461 do {  
3462   y+=y; incr(k);
3463   if ( y>x ){ 
3464     z=z+spec_atan[k]; t=x; x=x+(y / two_to_the(k+k)); y=y-t;
3465   };
3466 } while (k!=15);
3467 do {  
3468   y+=y; incr(k);
3469   if ( y>x ) { z=z+spec_atan[k]; y=y-x; };
3470 } while (k!=26)
3471
3472 @ Conversely, the |n_sin_cos| routine takes an |angle| and produces the sine
3473 and cosine of that angle. The results of this routine are
3474 stored in global integer variables |n_sin| and |n_cos|.
3475
3476 @<Glob...@>=
3477 fraction n_sin;fraction n_cos; /* results computed by |n_sin_cos| */
3478
3479 @ Given an integer |z| that is $2^{20}$ times an angle $\theta$ in degrees,
3480 the purpose of |n_sin_cos(z)| is to set
3481 |x=@t$r\cos\theta$@>| and |y=@t$r\sin\theta$@>| (approximately),
3482 for some rather large number~|r|. The maximum of |x| and |y|
3483 will be between $2^{28}$ and $2^{30}$, so that there will be hardly
3484 any loss of accuracy. Then |x| and~|y| are divided by~|r|.
3485
3486 @c 
3487 void mp_n_sin_cos (MP mp,angle z) { /* computes a multiple of the sine
3488                                        and cosine */ 
3489   small_number k; /* loop control variable */
3490   int q; /* specifies the quadrant */
3491   fraction r; /* magnitude of |(x,y)| */
3492   integer x,y,t; /* temporary registers */
3493   while ( z<0 ) z=z+three_sixty_deg;
3494   z=z % three_sixty_deg; /* now |0<=z<three_sixty_deg| */
3495   q=z / forty_five_deg; z=z % forty_five_deg;
3496   x=fraction_one; y=x;
3497   if ( ! odd(q) ) z=forty_five_deg-z;
3498   @<Subtract angle |z| from |(x,y)|@>;
3499   @<Convert |(x,y)| to the octant determined by~|q|@>;
3500   r=mp_pyth_add(mp, x,y); 
3501   mp->n_cos=mp_make_fraction(mp, x,r); 
3502   mp->n_sin=mp_make_fraction(mp, y,r);
3503 }
3504
3505 @ In this case the octants are numbered sequentially.
3506
3507 @<Convert |(x,...@>=
3508 switch (q) {
3509 case 0: break;
3510 case 1: t=x; x=y; y=t; break;
3511 case 2: t=x; x=-y; y=t; break;
3512 case 3: negate(x); break;
3513 case 4: negate(x); negate(y); break;
3514 case 5: t=x; x=-y; y=-t; break;
3515 case 6: t=x; x=y; y=-t; break;
3516 case 7: negate(y); break;
3517 } /* there are no other cases */
3518
3519 @ The main iteration of |n_sin_cos| is similar to that of |n_arg| but
3520 applied in reverse. The values of |spec_atan[k]| decrease slowly enough
3521 that this loop is guaranteed to terminate before the (nonexistent) value
3522 |spec_atan[27]| would be required.
3523
3524 @<Subtract angle |z|...@>=
3525 k=1;
3526 while ( z>0 ){ 
3527   if ( z>=spec_atan[k] ) { 
3528     z=z-spec_atan[k]; t=x;
3529     x=t+y / two_to_the(k);
3530     y=y-t / two_to_the(k);
3531   }
3532   incr(k);
3533 }
3534 if ( y<0 ) y=0 /* this precaution may never be needed */
3535
3536 @ And now let's complete our collection of numeric utility routines
3537 by considering random number generation.
3538 \MP\ generates pseudo-random numbers with the additive scheme recommended
3539 in Section 3.6 of {\sl The Art of Computer Programming}; however, the
3540 results are random fractions between 0 and |fraction_one-1|, inclusive.
3541
3542 There's an auxiliary array |randoms| that contains 55 pseudo-random
3543 fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
3544 we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
3545 The global variable |j_random| tells which element has most recently
3546 been consumed.
3547 The global variable |sys_random_seed| was introduced in version 0.9,
3548 for the sole reason of stressing the fact that the initial value of the
3549 random seed is system-dependant. The pascal code below will initialize
3550 this variable to |(internal[time] div unity)+internal[day]|, but this is
3551 not good enough on modern fast machines that are capable of running
3552 multiple MetaPost processes within the same second.
3553 @^system dependencies@>
3554
3555 @<Glob...@>=
3556 fraction randoms[55]; /* the last 55 random values generated */
3557 int j_random; /* the number of unused |randoms| */
3558 scaled sys_random_seed; /* the default random seed */
3559
3560 @ @<Types...@>=
3561 typedef scaled (*get_random_seed_command)(MP mp);
3562
3563 @ @<Glob...@>=
3564 get_random_seed_command get_random_seed;
3565
3566 @ @<Option variables@>=
3567 get_random_seed_command get_random_seed;
3568
3569 @ @<Allocate or initialize ...@>=
3570 set_callback_option(get_random_seed);
3571
3572 @ @<Exported function headers@>=
3573 scaled mp_get_random_seed (MP mp);
3574
3575 @ @c 
3576 scaled mp_get_random_seed (MP mp) {
3577   return (mp->internal[mp_time] / unity)+mp->internal[day];
3578 }
3579
3580 @ To consume a random fraction, the program below will say `|next_random|'
3581 and then it will fetch |randoms[j_random]|.
3582
3583 @d next_random { if ( mp->j_random==0 ) mp_new_randoms(mp);
3584   else decr(mp->j_random); }
3585
3586 @c 
3587 void mp_new_randoms (MP mp) {
3588   int k; /* index into |randoms| */
3589   fraction x; /* accumulator */
3590   for (k=0;k<=23;k++) { 
3591    x=mp->randoms[k]-mp->randoms[k+31];
3592     if ( x<0 ) x=x+fraction_one;
3593     mp->randoms[k]=x;
3594   }
3595   for (k=24;k<= 54;k++){ 
3596     x=mp->randoms[k]-mp->randoms[k-24];
3597     if ( x<0 ) x=x+fraction_one;
3598     mp->randoms[k]=x;
3599   }
3600   mp->j_random=54;
3601 }
3602
3603 @ @<Declarations@>=
3604 void mp_init_randoms (MP mp,scaled seed);
3605
3606 @ To initialize the |randoms| table, we call the following routine.
3607
3608 @c 
3609 void mp_init_randoms (MP mp,scaled seed) {
3610   fraction j,jj,k; /* more or less random integers */
3611   int i; /* index into |randoms| */
3612   j=abs(seed);
3613   while ( j>=fraction_one ) j=halfp(j);
3614   k=1;
3615   for (i=0;i<=54;i++ ){ 
3616     jj=k; k=j-k; j=jj;
3617     if ( k<0 ) k=k+fraction_one;
3618     mp->randoms[(i*21)% 55]=j;
3619   }
3620   mp_new_randoms(mp); 
3621   mp_new_randoms(mp); 
3622   mp_new_randoms(mp); /* ``warm up'' the array */
3623 }
3624
3625 @ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
3626 or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
3627
3628 Note that the call of |take_fraction| will produce the values 0 and~|x|
3629 with about half the probability that it will produce any other particular
3630 values between 0 and~|x|, because it rounds its answers.
3631
3632 @c 
3633 scaled mp_unif_rand (MP mp,scaled x) {
3634   scaled y; /* trial value */
3635   next_random; y=mp_take_fraction(mp, abs(x),mp->randoms[mp->j_random]);
3636   if ( y==abs(x) ) return 0;
3637   else if ( x>0 ) return y;
3638   else return (-y);
3639 }
3640
3641 @ Finally, a normal deviate with mean zero and unit standard deviation
3642 can readily be obtained with the ratio method (Algorithm 3.4.1R in
3643 {\sl The Art of Computer Programming\/}).
3644
3645 @c 
3646 scaled mp_norm_rand (MP mp) {
3647   integer x,u,l; /* what the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$ */
3648   do { 
3649     do {  
3650       next_random;
3651       x=mp_take_fraction(mp, 112429,mp->randoms[mp->j_random]-fraction_half);
3652       /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */
3653       next_random; u=mp->randoms[mp->j_random];
3654     } while (abs(x)>=u);
3655     x=mp_make_fraction(mp, x,u);
3656     l=139548960-mp_m_log(mp, u); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */
3657   } while (mp_ab_vs_cd(mp, 1024,l,x,x)<0);
3658   return x;
3659 }
3660
3661 @* \[9] Packed data.
3662 In order to make efficient use of storage space, \MP\ bases its major data
3663 structures on a |memory_word|, which contains either a (signed) integer,
3664 possibly scaled, or a small number of fields that are one half or one
3665 quarter of the size used for storing integers.
3666
3667 If |x| is a variable of type |memory_word|, it contains up to four
3668 fields that can be referred to as follows:
3669 $$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
3670 |x|&.|int|&(an |integer|)\cr
3671 |x|&.|sc|\qquad&(a |scaled| integer)\cr
3672 |x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
3673 |x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
3674   field)\cr
3675 |x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
3676   &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
3677 This is somewhat cumbersome to write, and not very readable either, but
3678 macros will be used to make the notation shorter and more transparent.
3679 The code below gives a formal definition of |memory_word| and
3680 its subsidiary types, using packed variant records. \MP\ makes no
3681 assumptions about the relative positions of the fields within a word.
3682
3683 @d max_quarterword 0x3FFF /* largest allowable value in a |quarterword| */
3684 @d max_halfword 0xFFFFFFF /* largest allowable value in a |halfword| */
3685
3686 @ Here are the inequalities that the quarterword and halfword values
3687 must satisfy (or rather, the inequalities that they mustn't satisfy):
3688
3689 @<Check the ``constant''...@>=
3690 if (mp->ini_version) {
3691   if ( mp->mem_max!=mp->mem_top ) mp->bad=8;
3692 } else {
3693   if ( mp->mem_max<mp->mem_top ) mp->bad=8;
3694 }
3695 if ( max_quarterword<255 ) mp->bad=9;
3696 if ( max_halfword<65535 ) mp->bad=10;
3697 if ( max_quarterword>max_halfword ) mp->bad=11;
3698 if ( mp->mem_max>=max_halfword ) mp->bad=12;
3699 if ( mp->max_strings>max_halfword ) mp->bad=13;
3700
3701 @ The macros |qi| and |qo| are used for input to and output 
3702 from quarterwords. These are legacy macros.
3703 @^system dependencies@>
3704
3705 @d qo(A) (A) /* to read eight bits from a quarterword */
3706 @d qi(A) (A) /* to store eight bits in a quarterword */
3707
3708 @ The reader should study the following definitions closely:
3709 @^system dependencies@>
3710
3711 @d sc cint /* |scaled| data is equivalent to |integer| */
3712
3713 @<Types...@>=
3714 typedef short quarterword; /* 1/4 of a word */
3715 typedef int halfword; /* 1/2 of a word */
3716 typedef union {
3717   struct {
3718     halfword RH, LH;
3719   } v;
3720   struct { /* Make B0,B1 overlap the most significant bytes of LH.  */
3721     halfword junk;
3722     quarterword B0, B1;
3723   } u;
3724 } two_halves;
3725 typedef struct {
3726   struct {
3727     quarterword B2, B3, B0, B1;
3728   } u;
3729 } four_quarters;
3730 typedef union {
3731   two_halves hh;
3732   integer cint;
3733   four_quarters qqqq;
3734 } memory_word;
3735 #define b0 u.B0
3736 #define b1 u.B1
3737 #define b2 u.B2
3738 #define b3 u.B3
3739 #define rh v.RH
3740 #define lh v.LH
3741
3742 @ When debugging, we may want to print a |memory_word| without knowing
3743 what type it is; so we print it in all modes.
3744 @^dirty \PASCAL@>@^debugging@>
3745
3746 @c 
3747 void mp_print_word (MP mp,memory_word w) {
3748   /* prints |w| in all ways */
3749   mp_print_int(mp, w.cint); mp_print_char(mp, ' ');
3750   mp_print_scaled(mp, w.sc); mp_print_char(mp, ' '); 
3751   mp_print_scaled(mp, w.sc / 010000); mp_print_ln(mp);
3752   mp_print_int(mp, w.hh.lh); mp_print_char(mp, '='); 
3753   mp_print_int(mp, w.hh.b0); mp_print_char(mp, ':');
3754   mp_print_int(mp, w.hh.b1); mp_print_char(mp, ';'); 
3755   mp_print_int(mp, w.hh.rh); mp_print_char(mp, ' ');
3756   mp_print_int(mp, w.qqqq.b0); mp_print_char(mp, ':'); 
3757   mp_print_int(mp, w.qqqq.b1); mp_print_char(mp, ':');
3758   mp_print_int(mp, w.qqqq.b2); mp_print_char(mp, ':'); 
3759   mp_print_int(mp, w.qqqq.b3);
3760 }
3761
3762
3763 @* \[10] Dynamic memory allocation.
3764
3765 The \MP\ system does nearly all of its own memory allocation, so that it
3766 can readily be transported into environments that do not have automatic
3767 facilities for strings, garbage collection, etc., and so that it can be in
3768 control of what error messages the user receives. The dynamic storage
3769 requirements of \MP\ are handled by providing a large array |mem| in
3770 which consecutive blocks of words are used as nodes by the \MP\ routines.
3771
3772 Pointer variables are indices into this array, or into another array
3773 called |eqtb| that will be explained later. A pointer variable might
3774 also be a special flag that lies outside the bounds of |mem|, so we
3775 allow pointers to assume any |halfword| value. The minimum memory
3776 index represents a null pointer.
3777
3778 @d null 0 /* the null pointer */
3779
3780 @<Types...@>=
3781 typedef halfword pointer; /* a flag or a location in |mem| or |eqtb| */
3782
3783 @ The |mem| array is divided into two regions that are allocated separately,
3784 but the dividing line between these two regions is not fixed; they grow
3785 together until finding their ``natural'' size in a particular job.
3786 Locations less than or equal to |lo_mem_max| are used for storing
3787 variable-length records consisting of two or more words each. This region
3788 is maintained using an algorithm similar to the one described in exercise
3789 2.5--19 of {\sl The Art of Computer Programming}. However, no size field
3790 appears in the allocated nodes; the program is responsible for knowing the
3791 relevant size when a node is freed. Locations greater than or equal to
3792 |hi_mem_min| are used for storing one-word records; a conventional
3793 \.{AVAIL} stack is used for allocation in this region.
3794
3795 Locations of |mem| between |0| and |mem_top| may be dumped as part
3796 of preloaded format files, by the \.{INIMP} preprocessor.
3797 @.INIMP@>
3798 Production versions of \MP\ may extend the memory at the top end in order to
3799 provide more space; these locations, between |mem_top| and |mem_max|,
3800 are always used for single-word nodes.
3801
3802 The key pointers that govern |mem| allocation have a prescribed order:
3803 $$\hbox{|null=0<lo_mem_max<hi_mem_min<mem_top<=mem_end<=mem_max|.}$$
3804
3805 @<Glob...@>=
3806 memory_word *mem; /* the big dynamic storage area */
3807 pointer lo_mem_max; /* the largest location of variable-size memory in use */
3808 pointer hi_mem_min; /* the smallest location of one-word memory in use */
3809
3810
3811
3812 @d xfree(A) do { mp_xfree(A); A=NULL; } while (0)
3813 @d xrealloc mp_xrealloc
3814 @d xmalloc  mp_xmalloc
3815 @d xstrdup  mp_xstrdup
3816 @d XREALLOC(a,b,c) a = xrealloc(a,(b+1),sizeof(c));
3817
3818 @<Declare helpers@>=
3819 void mp_xfree (void *x);
3820 void *mp_xrealloc (void *p, size_t nmem, size_t size) ;
3821 void *mp_xmalloc (size_t nmem, size_t size) ;
3822 char *mp_xstrdup(const char *s);
3823
3824 @ The |max_size_test| guards against overflow, on the assumption that
3825 |size_t| is at least 31bits wide.
3826
3827 @d max_size_test 0x7FFFFFFF
3828
3829 @c
3830 void mp_xfree (void *x) {
3831   if (x!=NULL) free(x);
3832 }
3833 void  *mp_xrealloc (void *p, size_t nmem, size_t size) {
3834   void *w ; 
3835   if ((max_size_test/size)<nmem) {
3836     fprintf(stderr,"Memory size overflow!\n");
3837     exit(1);
3838   }
3839   w = realloc (p,(nmem*size));
3840   if (w==NULL) {
3841     fprintf(stderr,"Out of memory!\n");
3842     exit(1);
3843   }
3844   return w;
3845 }
3846 void  *mp_xmalloc (size_t nmem, size_t size) {
3847   void *w;
3848   if ((max_size_test/size)<nmem) {
3849     fprintf(stderr,"Memory size overflow!\n");
3850     exit(1);
3851   }
3852   w = malloc (nmem*size);
3853   if (w==NULL) {
3854     fprintf(stderr,"Out of memory!\n");
3855     exit(1);
3856   }
3857   return w;
3858 }
3859 char *mp_xstrdup(const char *s) {
3860   char *w; 
3861   if (s==NULL)
3862     return NULL;
3863   w = strdup(s);
3864   if (w==NULL) {
3865     fprintf(stderr,"Out of memory!\n");
3866     exit(1);
3867   }
3868   return w;
3869 }
3870
3871
3872
3873 @<Allocate or initialize ...@>=
3874 mp->mem = xmalloc ((mp->mem_max+1),sizeof (memory_word));
3875 memset(mp->mem,0,(mp->mem_max+1)*sizeof (memory_word));
3876
3877 @ @<Dealloc variables@>=
3878 xfree(mp->mem);
3879
3880 @ Users who wish to study the memory requirements of particular applications can
3881 can use optional special features that keep track of current and
3882 maximum memory usage. When code between the delimiters |stat| $\ldots$
3883 |tats| is not ``commented out,'' \MP\ will run a bit slower but it will
3884 report these statistics when |tracing_stats| is positive.
3885
3886 @<Glob...@>=
3887 integer var_used; integer dyn_used; /* how much memory is in use */
3888
3889 @ Let's consider the one-word memory region first, since it's the
3890 simplest. The pointer variable |mem_end| holds the highest-numbered location
3891 of |mem| that has ever been used. The free locations of |mem| that
3892 occur between |hi_mem_min| and |mem_end|, inclusive, are of type
3893 |two_halves|, and we write |info(p)| and |link(p)| for the |lh|
3894 and |rh| fields of |mem[p]| when it is of this type. The single-word
3895 free locations form a linked list
3896 $$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
3897 terminated by |null|.
3898
3899 @d link(A)   mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3900 @d info(A)   mp->mem[(A)].hh.lh /* the |info| field of a memory word */
3901
3902 @<Glob...@>=
3903 pointer avail; /* head of the list of available one-word nodes */
3904 pointer mem_end; /* the last one-word node used in |mem| */
3905
3906 @ If one-word memory is exhausted, it might mean that the user has forgotten
3907 a token like `\&{enddef}' or `\&{endfor}'. We will define some procedures
3908 later that try to help pinpoint the trouble.
3909
3910 @c 
3911 @<Declare the procedure called |show_token_list|@>;
3912 @<Declare the procedure called |runaway|@>
3913
3914 @ The function |get_avail| returns a pointer to a new one-word node whose
3915 |link| field is null. However, \MP\ will halt if there is no more room left.
3916 @^inner loop@>
3917
3918 @c 
3919 pointer mp_get_avail (MP mp) { /* single-word node allocation */
3920   pointer p; /* the new node being got */
3921   p=mp->avail; /* get top location in the |avail| stack */
3922   if ( p!=null ) {
3923     mp->avail=link(mp->avail); /* and pop it off */
3924   } else if ( mp->mem_end<mp->mem_max ) { /* or go into virgin territory */
3925     incr(mp->mem_end); p=mp->mem_end;
3926   } else { 
3927     decr(mp->hi_mem_min); p=mp->hi_mem_min;
3928     if ( mp->hi_mem_min<=mp->lo_mem_max ) { 
3929       mp_runaway(mp); /* if memory is exhausted, display possible runaway text */
3930       mp_overflow(mp, "main memory size",mp->mem_max);
3931       /* quit; all one-word nodes are busy */
3932 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
3933     }
3934   }
3935   link(p)=null; /* provide an oft-desired initialization of the new node */
3936   incr(mp->dyn_used);/* maintain statistics */
3937   return p;
3938 };
3939
3940 @ Conversely, a one-word node is recycled by calling |free_avail|.
3941
3942 @d free_avail(A)  /* single-word node liberation */
3943   { link((A))=mp->avail; mp->avail=(A); decr(mp->dyn_used);  }
3944
3945 @ There's also a |fast_get_avail| routine, which saves the procedure-call
3946 overhead at the expense of extra programming. This macro is used in
3947 the places that would otherwise account for the most calls of |get_avail|.
3948 @^inner loop@>
3949
3950 @d fast_get_avail(A) { 
3951   (A)=mp->avail; /* avoid |get_avail| if possible, to save time */
3952   if ( (A)==null ) { (A)=mp_get_avail(mp); } 
3953   else { mp->avail=link((A)); link((A))=null;  incr(mp->dyn_used); }
3954   }
3955
3956 @ The available-space list that keeps track of the variable-size portion
3957 of |mem| is a nonempty, doubly-linked circular list of empty nodes,
3958 pointed to by the roving pointer |rover|.
3959
3960 Each empty node has size 2 or more; the first word contains the special
3961 value |max_halfword| in its |link| field and the size in its |info| field;
3962 the second word contains the two pointers for double linking.
3963
3964 Each nonempty node also has size 2 or more. Its first word is of type
3965 |two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
3966 Otherwise there is complete flexibility with respect to the contents
3967 of its other fields and its other words.
3968
3969 (We require |mem_max<max_halfword| because terrible things can happen
3970 when |max_halfword| appears in the |link| field of a nonempty node.)
3971
3972 @d empty_flag   max_halfword /* the |link| of an empty variable-size node */
3973 @d is_empty(A)   (link((A))==empty_flag) /* tests for empty node */
3974 @d node_size   info /* the size field in empty variable-size nodes */
3975 @d llink(A)   info((A)+1) /* left link in doubly-linked list of empty nodes */
3976 @d rlink(A)   link((A)+1) /* right link in doubly-linked list of empty nodes */
3977
3978 @<Glob...@>=
3979 pointer rover; /* points to some node in the list of empties */
3980
3981 @ A call to |get_node| with argument |s| returns a pointer to a new node
3982 of size~|s|, which must be 2~or more. The |link| field of the first word
3983 of this new node is set to null. An overflow stop occurs if no suitable
3984 space exists.
3985
3986 If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
3987 areas and returns the value |max_halfword|.
3988
3989 @<Declarations@>=
3990 pointer mp_get_node (MP mp,integer s) ;
3991
3992 @ @c 
3993 pointer mp_get_node (MP mp,integer s) { /* variable-size node allocation */
3994   pointer p; /* the node currently under inspection */
3995   pointer q;  /* the node physically after node |p| */
3996   integer r; /* the newly allocated node, or a candidate for this honor */
3997   integer t,tt; /* temporary registers */
3998 @^inner loop@>
3999  RESTART: 
4000   p=mp->rover; /* start at some free node in the ring */
4001   do {  
4002     @<Try to allocate within node |p| and its physical successors,
4003      and |goto found| if allocation was possible@>;
4004     p=rlink(p); /* move to the next node in the ring */
4005   } while (p!=mp->rover); /* repeat until the whole list has been traversed */
4006   if ( s==010000000000 ) { 
4007     return max_halfword;
4008   };
4009   if ( mp->lo_mem_max+2<mp->hi_mem_min ) {
4010     if ( mp->lo_mem_max+2<=max_halfword ) {
4011       @<Grow more variable-size memory and |goto restart|@>;
4012     }
4013   }
4014   mp_overflow(mp, "main memory size",mp->mem_max);
4015   /* sorry, nothing satisfactory is left */
4016 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4017 FOUND: 
4018   link(r)=null; /* this node is now nonempty */
4019   mp->var_used=mp->var_used+s; /* maintain usage statistics */
4020   return r;
4021 }
4022
4023 @ The lower part of |mem| grows by 1000 words at a time, unless
4024 we are very close to going under. When it grows, we simply link
4025 a new node into the available-space list. This method of controlled
4026 growth helps to keep the |mem| usage consecutive when \MP\ is
4027 implemented on ``virtual memory'' systems.
4028 @^virtual memory@>
4029
4030 @<Grow more variable-size memory and |goto restart|@>=
4031
4032   if ( mp->hi_mem_min-mp->lo_mem_max>=1998 ) {
4033     t=mp->lo_mem_max+1000;
4034   } else {
4035     t=mp->lo_mem_max+1+(mp->hi_mem_min-mp->lo_mem_max) / 2; 
4036     /* |lo_mem_max+2<=t<hi_mem_min| */
4037   }
4038   if ( t>max_halfword ) t=max_halfword;
4039   p=llink(mp->rover); q=mp->lo_mem_max; rlink(p)=q; llink(mp->rover)=q;
4040   rlink(q)=mp->rover; llink(q)=p; link(q)=empty_flag; node_size(q)=t-mp->lo_mem_max;
4041   mp->lo_mem_max=t; link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4042   mp->rover=q; 
4043   goto RESTART;
4044 }
4045
4046 @ @<Try to allocate...@>=
4047 q=p+node_size(p); /* find the physical successor */
4048 while ( is_empty(q) ) { /* merge node |p| with node |q| */
4049   t=rlink(q); tt=llink(q);
4050 @^inner loop@>
4051   if ( q==mp->rover ) mp->rover=t;
4052   llink(t)=tt; rlink(tt)=t;
4053   q=q+node_size(q);
4054 }
4055 r=q-s;
4056 if ( r>p+1 ) {
4057   @<Allocate from the top of node |p| and |goto found|@>;
4058 }
4059 if ( r==p ) { 
4060   if ( rlink(p)!=p ) {
4061     @<Allocate entire node |p| and |goto found|@>;
4062   }
4063 }
4064 node_size(p)=q-p /* reset the size in case it grew */
4065
4066 @ @<Allocate from the top...@>=
4067
4068   node_size(p)=r-p; /* store the remaining size */
4069   mp->rover=p; /* start searching here next time */
4070   goto FOUND;
4071 }
4072
4073 @ Here we delete node |p| from the ring, and let |rover| rove around.
4074
4075 @<Allocate entire...@>=
4076
4077   mp->rover=rlink(p); t=llink(p);
4078   llink(mp->rover)=t; rlink(t)=mp->rover;
4079   goto FOUND;
4080 }
4081
4082 @ Conversely, when some variable-size node |p| of size |s| is no longer needed,
4083 the operation |free_node(p,s)| will make its words available, by inserting
4084 |p| as a new empty node just before where |rover| now points.
4085
4086 @<Declarations@>=
4087 void mp_free_node (MP mp, pointer p, halfword s) ;
4088
4089 @ @c 
4090 void mp_free_node (MP mp, pointer p, halfword s) { /* variable-size node
4091   liberation */
4092   pointer q; /* |llink(rover)| */
4093   node_size(p)=s; link(p)=empty_flag;
4094 @^inner loop@>
4095   q=llink(mp->rover); llink(p)=q; rlink(p)=mp->rover; /* set both links */
4096   llink(mp->rover)=p; rlink(q)=p; /* insert |p| into the ring */
4097   mp->var_used=mp->var_used-s; /* maintain statistics */
4098 }
4099
4100 @ Just before \.{INIMP} writes out the memory, it sorts the doubly linked
4101 available space list. The list is probably very short at such times, so a
4102 simple insertion sort is used. The smallest available location will be
4103 pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
4104
4105 @c 
4106 void mp_sort_avail (MP mp) { /* sorts the available variable-size nodes
4107   by location */
4108   pointer p,q,r; /* indices into |mem| */
4109   pointer old_rover; /* initial |rover| setting */
4110   p=mp_get_node(mp, 010000000000); /* merge adjacent free areas */
4111   p=rlink(mp->rover); rlink(mp->rover)=max_halfword; old_rover=mp->rover;
4112   while ( p!=old_rover ) {
4113     @<Sort |p| into the list starting at |rover|
4114      and advance |p| to |rlink(p)|@>;
4115   }
4116   p=mp->rover;
4117   while ( rlink(p)!=max_halfword ) { 
4118     llink(rlink(p))=p; p=rlink(p);
4119   };
4120   rlink(p)=mp->rover; llink(mp->rover)=p;
4121 }
4122
4123 @ The following |while| loop is guaranteed to
4124 terminate, since the list that starts at
4125 |rover| ends with |max_halfword| during the sorting procedure.
4126
4127 @<Sort |p|...@>=
4128 if ( p<mp->rover ) { 
4129   q=p; p=rlink(q); rlink(q)=mp->rover; mp->rover=q;
4130 } else  { 
4131   q=mp->rover;
4132   while ( rlink(q)<p ) q=rlink(q);
4133   r=rlink(p); rlink(p)=rlink(q); rlink(q)=p; p=r;
4134 }
4135
4136 @* \[11] Memory layout.
4137 Some areas of |mem| are dedicated to fixed usage, since static allocation is
4138 more efficient than dynamic allocation when we can get away with it. For
4139 example, locations |0| to |1| are always used to store a
4140 two-word dummy token whose second word is zero.
4141 The following macro definitions accomplish the static allocation by giving
4142 symbolic names to the fixed positions. Static variable-size nodes appear
4143 in locations |0| through |lo_mem_stat_max|, and static single-word nodes
4144 appear in locations |hi_mem_stat_min| through |mem_top|, inclusive.
4145
4146 @d null_dash (2) /* the first two words are reserved for a null value */
4147 @d dep_head (null_dash+3) /* we will define |dash_node_size=3| */
4148 @d zero_val (dep_head+2) /* two words for a permanently zero value */
4149 @d temp_val (zero_val+2) /* two words for a temporary value node */
4150 @d end_attr temp_val /* we use |end_attr+2| only */
4151 @d inf_val (end_attr+2) /* and |inf_val+1| only */
4152 @d test_pen (inf_val+2)
4153   /* nine words for a pen used when testing the turning number */
4154 @d bad_vardef (test_pen+9) /* two words for \&{vardef} error recovery */
4155 @d lo_mem_stat_max (bad_vardef+1)  /* largest statically
4156   allocated word in the variable-size |mem| */
4157 @#
4158 @d sentinel mp->mem_top /* end of sorted lists */
4159 @d temp_head (mp->mem_top-1) /* head of a temporary list of some kind */
4160 @d hold_head (mp->mem_top-2) /* head of a temporary list of another kind */
4161 @d spec_head (mp->mem_top-3) /* head of a list of unprocessed \&{special} items */
4162 @d hi_mem_stat_min (mp->mem_top-3) /* smallest statically allocated word in
4163   the one-word |mem| */
4164
4165 @ The following code gets the dynamic part of |mem| off to a good start,
4166 when \MP\ is initializing itself the slow way.
4167
4168 @<Initialize table entries (done by \.{INIMP} only)@>=
4169 @^data structure assumptions@>
4170 mp->rover=lo_mem_stat_max+1; /* initialize the dynamic memory */
4171 link(mp->rover)=empty_flag;
4172 node_size(mp->rover)=1000; /* which is a 1000-word available node */
4173 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
4174 mp->lo_mem_max=mp->rover+1000; link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4175 for (k=hi_mem_stat_min;k<=(int)mp->mem_top;k++) {
4176   mp->mem[k]=mp->mem[mp->lo_mem_max]; /* clear list heads */
4177 }
4178 mp->avail=null; mp->mem_end=mp->mem_top;
4179 mp->hi_mem_min=hi_mem_stat_min; /* initialize the one-word memory */
4180 mp->var_used=lo_mem_stat_max+1; 
4181 mp->dyn_used=mp->mem_top+1-(hi_mem_stat_min);  /* initialize statistics */
4182 @<Initialize a pen at |test_pen| so that it fits in nine words@>;
4183
4184 @ The procedure |flush_list(p)| frees an entire linked list of one-word
4185 nodes that starts at a given position, until coming to |sentinel| or a
4186 pointer that is not in the one-word region. Another procedure,
4187 |flush_node_list|, frees an entire linked list of one-word and two-word
4188 nodes, until coming to a |null| pointer.
4189 @^inner loop@>
4190
4191 @c 
4192 void mp_flush_list (MP mp,pointer p) { /* makes list of single-word nodes  available */
4193   pointer q,r; /* list traversers */
4194   if ( p>=mp->hi_mem_min ) if ( p!=sentinel ) { 
4195     r=p;
4196     do {  
4197       q=r; r=link(r); 
4198       decr(mp->dyn_used);
4199       if ( r<mp->hi_mem_min ) break;
4200     } while (r!=sentinel);
4201   /* now |q| is the last node on the list */
4202     link(q)=mp->avail; mp->avail=p;
4203   }
4204 }
4205 @#
4206 void mp_flush_node_list (MP mp,pointer p) {
4207   pointer q; /* the node being recycled */
4208   while ( p!=null ){ 
4209     q=p; p=link(p);
4210     if ( q<mp->hi_mem_min ) 
4211       mp_free_node(mp, q,2);
4212     else 
4213       free_avail(q);
4214   }
4215 }
4216
4217 @ If \MP\ is extended improperly, the |mem| array might get screwed up.
4218 For example, some pointers might be wrong, or some ``dead'' nodes might not
4219 have been freed when the last reference to them disappeared. Procedures
4220 |check_mem| and |search_mem| are available to help diagnose such
4221 problems. These procedures make use of two arrays called |free| and
4222 |was_free| that are present only if \MP's debugging routines have
4223 been included. (You may want to decrease the size of |mem| while you
4224 @^debugging@>
4225 are debugging.)
4226
4227 Because |boolean|s are typedef-d as ints, it is better to use
4228 unsigned chars here.
4229
4230 @<Glob...@>=
4231 unsigned char *free; /* free cells */
4232 unsigned char *was_free; /* previously free cells */
4233 pointer was_mem_end; pointer was_lo_max; pointer was_hi_min;
4234   /* previous |mem_end|, |lo_mem_max|,and |hi_mem_min| */
4235 boolean panicking; /* do we want to check memory constantly? */
4236
4237 @ @<Allocate or initialize ...@>=
4238 mp->free = xmalloc ((mp->mem_max+1),sizeof (unsigned char));
4239 mp->was_free = xmalloc ((mp->mem_max+1), sizeof (unsigned char));
4240
4241 @ @<Dealloc variables@>=
4242 xfree(mp->free);
4243 xfree(mp->was_free);
4244
4245 @ @<Allocate or ...@>=
4246 mp->was_mem_end=0; /* indicate that everything was previously free */
4247 mp->was_lo_max=0; mp->was_hi_min=mp->mem_max;
4248 mp->panicking=false;
4249
4250 @ @<Declare |mp_reallocate| functions@>=
4251 void mp_reallocate_memory(MP mp, int l) ;
4252
4253 @ @c
4254 void mp_reallocate_memory(MP mp, int l) {
4255    XREALLOC(mp->free,     l, unsigned char);
4256    XREALLOC(mp->was_free, l, unsigned char);
4257    if (mp->mem) {
4258          int newarea = l-mp->mem_max;
4259      XREALLOC(mp->mem,      l, memory_word);
4260      memset (mp->mem+(mp->mem_max+1),0,sizeof(memory_word)*(newarea));
4261    } else {
4262      XREALLOC(mp->mem,      l, memory_word);
4263      memset(mp->mem,0,sizeof(memory_word)*(l+1));
4264    }
4265    mp->mem_max = l;
4266    if (mp->ini_version) 
4267      mp->mem_top = l;
4268 }
4269
4270
4271
4272 @ Procedure |check_mem| makes sure that the available space lists of
4273 |mem| are well formed, and it optionally prints out all locations
4274 that are reserved now but were free the last time this procedure was called.
4275
4276 @c 
4277 void mp_check_mem (MP mp,boolean print_locs ) {
4278   pointer p,q,r; /* current locations of interest in |mem| */
4279   boolean clobbered; /* is something amiss? */
4280   for (p=0;p<=mp->lo_mem_max;p++) {
4281     mp->free[p]=false; /* you can probably do this faster */
4282   }
4283   for (p=mp->hi_mem_min;p<= mp->mem_end;p++) {
4284     mp->free[p]=false; /* ditto */
4285   }
4286   @<Check single-word |avail| list@>;
4287   @<Check variable-size |avail| list@>;
4288   @<Check flags of unavailable nodes@>;
4289   @<Check the list of linear dependencies@>;
4290   if ( print_locs ) {
4291     @<Print newly busy locations@>;
4292   }
4293   for (p=0;p<=mp->lo_mem_max;p++) {
4294     mp->was_free[p]=mp->free[p];
4295   }
4296   for (p=mp->hi_mem_min;p<=mp->mem_end;p++) {
4297     mp->was_free[p]=mp->free[p];
4298   }
4299   /* |was_free:=free| might be faster */
4300   mp->was_mem_end=mp->mem_end; 
4301   mp->was_lo_max=mp->lo_mem_max; 
4302   mp->was_hi_min=mp->hi_mem_min;
4303 }
4304
4305 @ @<Check single-word...@>=
4306 p=mp->avail; q=null; clobbered=false;
4307 while ( p!=null ) { 
4308   if ( (p>mp->mem_end)||(p<mp->hi_mem_min) ) clobbered=true;
4309   else if ( mp->free[p] ) clobbered=true;
4310   if ( clobbered ) { 
4311     mp_print_nl(mp, "AVAIL list clobbered at ");
4312 @.AVAIL list clobbered...@>
4313     mp_print_int(mp, q); break;
4314   }
4315   mp->free[p]=true; q=p; p=link(q);
4316 }
4317
4318 @ @<Check variable-size...@>=
4319 p=mp->rover; q=null; clobbered=false;
4320 do {  
4321   if ( (p>=mp->lo_mem_max)||(p<0) ) clobbered=true;
4322   else if ( (rlink(p)>=mp->lo_mem_max)||(rlink(p)<0) ) clobbered=true;
4323   else if (  !(is_empty(p))||(node_size(p)<2)||
4324    (p+node_size(p)>mp->lo_mem_max)|| (llink(rlink(p))!=p) ) clobbered=true;
4325   if ( clobbered ) { 
4326     mp_print_nl(mp, "Double-AVAIL list clobbered at ");
4327 @.Double-AVAIL list clobbered...@>
4328     mp_print_int(mp, q); break;
4329   }
4330   for (q=p;q<=p+node_size(p)-1;q++) { /* mark all locations free */
4331     if ( mp->free[q] ) { 
4332       mp_print_nl(mp, "Doubly free location at ");
4333 @.Doubly free location...@>
4334       mp_print_int(mp, q); break;
4335     }
4336     mp->free[q]=true;
4337   }
4338   q=p; p=rlink(p);
4339 } while (p!=mp->rover)
4340
4341
4342 @ @<Check flags...@>=
4343 p=0;
4344 while ( p<=mp->lo_mem_max ) { /* node |p| should not be empty */
4345   if ( is_empty(p) ) {
4346     mp_print_nl(mp, "Bad flag at "); mp_print_int(mp, p);
4347 @.Bad flag...@>
4348   }
4349   while ( (p<=mp->lo_mem_max) && ! mp->free[p] ) incr(p);
4350   while ( (p<=mp->lo_mem_max) && mp->free[p] ) incr(p);
4351 }
4352
4353 @ @<Print newly busy...@>=
4354
4355   @<Do intialization required before printing new busy locations@>;
4356   mp_print_nl(mp, "New busy locs:");
4357 @.New busy locs@>
4358   for (p=0;p<= mp->lo_mem_max;p++ ) {
4359     if ( ! mp->free[p] && ((p>mp->was_lo_max) || mp->was_free[p]) ) {
4360       @<Indicate that |p| is a new busy location@>;
4361     }
4362   }
4363   for (p=mp->hi_mem_min;p<=mp->mem_end;p++ ) {
4364     if ( ! mp->free[p] &&
4365         ((p<mp->was_hi_min) || (p>mp->was_mem_end) || mp->was_free[p]) ) {
4366       @<Indicate that |p| is a new busy location@>;
4367     }
4368   }
4369   @<Finish printing new busy locations@>;
4370 }
4371
4372 @ There might be many new busy locations so we are careful to print contiguous
4373 blocks compactly.  During this operation |q| is the last new busy location and
4374 |r| is the start of the block containing |q|.
4375
4376 @<Indicate that |p| is a new busy location@>=
4377
4378   if ( p>q+1 ) { 
4379     if ( q>r ) { 
4380       mp_print(mp, ".."); mp_print_int(mp, q);
4381     }
4382     mp_print_char(mp, ' '); mp_print_int(mp, p);
4383     r=p;
4384   }
4385   q=p;
4386 }
4387
4388 @ @<Do intialization required before printing new busy locations@>=
4389 q=mp->mem_max; r=mp->mem_max
4390
4391 @ @<Finish printing new busy locations@>=
4392 if ( q>r ) { 
4393   mp_print(mp, ".."); mp_print_int(mp, q);
4394 }
4395
4396 @ The |search_mem| procedure attempts to answer the question ``Who points
4397 to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
4398 that might not be of type |two_halves|. Strictly speaking, this is
4399 @^dirty \PASCAL@>
4400 undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
4401 point to |p| purely by coincidence). But for debugging purposes, we want
4402 to rule out the places that do {\sl not\/} point to |p|, so a few false
4403 drops are tolerable.
4404
4405 @c
4406 void mp_search_mem (MP mp, pointer p) { /* look for pointers to |p| */
4407   integer q; /* current position being searched */
4408   for (q=0;q<=mp->lo_mem_max;q++) { 
4409     if ( link(q)==p ){ 
4410       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4411     }
4412     if ( info(q)==p ) { 
4413       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4414     }
4415   }
4416   for (q=mp->hi_mem_min;q<=mp->mem_end;q++) {
4417     if ( link(q)==p ) {
4418       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4419     }
4420     if ( info(q)==p ) {
4421       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4422     }
4423   }
4424   @<Search |eqtb| for equivalents equal to |p|@>;
4425 }
4426
4427 @* \[12] The command codes.
4428 Before we can go much further, we need to define symbolic names for the internal
4429 code numbers that represent the various commands obeyed by \MP. These codes
4430 are somewhat arbitrary, but not completely so. For example,
4431 some codes have been made adjacent so that |case| statements in the
4432 program need not consider cases that are widely spaced, or so that |case|
4433 statements can be replaced by |if| statements. A command can begin an
4434 expression if and only if its code lies between |min_primary_command| and
4435 |max_primary_command|, inclusive. The first token of a statement that doesn't
4436 begin with an expression has a command code between |min_command| and
4437 |max_statement_command|, inclusive. Anything less than |min_command| is
4438 eliminated during macro expansions, and anything no more than |max_pre_command|
4439 is eliminated when expanding \TeX\ material.  Ranges such as
4440 |min_secondary_command..max_secondary_command| are used when parsing
4441 expressions, but the relative ordering within such a range is generally not
4442 critical.
4443
4444 The ordering of the highest-numbered commands
4445 (|comma<semicolon<end_group<stop|) is crucial for the parsing and
4446 error-recovery methods of this program as is the ordering |if_test<fi_or_else|
4447 for the smallest two commands.  The ordering is also important in the ranges
4448 |numeric_token..plus_or_minus| and |left_brace..ampersand|.
4449
4450 At any rate, here is the list, for future reference.
4451
4452 @d start_tex 1 /* begin \TeX\ material (\&{btex}, \&{verbatimtex}) */
4453 @d etex_marker 2 /* end \TeX\ material (\&{etex}) */
4454 @d mpx_break 3 /* stop reading an \.{MPX} file (\&{mpxbreak}) */
4455 @d max_pre_command mpx_break
4456 @d if_test 4 /* conditional text (\&{if}) */
4457 @d fi_or_else 5 /* delimiters for conditionals (\&{elseif}, \&{else}, \&{fi} */
4458 @d input 6 /* input a source file (\&{input}, \&{endinput}) */
4459 @d iteration 7 /* iterate (\&{for}, \&{forsuffixes}, \&{forever}, \&{endfor}) */
4460 @d repeat_loop 8 /* special command substituted for \&{endfor} */
4461 @d exit_test 9 /* premature exit from a loop (\&{exitif}) */
4462 @d relax 10 /* do nothing (\.{\char`\\}) */
4463 @d scan_tokens 11 /* put a string into the input buffer */
4464 @d expand_after 12 /* look ahead one token */
4465 @d defined_macro 13 /* a macro defined by the user */
4466 @d min_command (defined_macro+1)
4467 @d save_command 14 /* save a list of tokens (\&{save}) */
4468 @d interim_command 15 /* save an internal quantity (\&{interim}) */
4469 @d let_command 16 /* redefine a symbolic token (\&{let}) */
4470 @d new_internal 17 /* define a new internal quantity (\&{newinternal}) */
4471 @d macro_def 18 /* define a macro (\&{def}, \&{vardef}, etc.) */
4472 @d ship_out_command 19 /* output a character (\&{shipout}) */
4473 @d add_to_command 20 /* add to edges (\&{addto}) */
4474 @d bounds_command 21  /* add bounding path to edges (\&{setbounds}, \&{clip}) */
4475 @d tfm_command 22 /* command for font metric info (\&{ligtable}, etc.) */
4476 @d protection_command 23 /* set protection flag (\&{outer}, \&{inner}) */
4477 @d show_command 24 /* diagnostic output (\&{show}, \&{showvariable}, etc.) */
4478 @d mode_command 25 /* set interaction level (\&{batchmode}, etc.) */
4479 @d random_seed 26 /* initialize random number generator (\&{randomseed}) */
4480 @d message_command 27 /* communicate to user (\&{message}, \&{errmessage}) */
4481 @d every_job_command 28 /* designate a starting token (\&{everyjob}) */
4482 @d delimiters 29 /* define a pair of delimiters (\&{delimiters}) */
4483 @d special_command 30 /* output special info (\&{special})
4484                        or font map info (\&{fontmapfile}, \&{fontmapline}) */
4485 @d write_command 31 /* write text to a file (\&{write}) */
4486 @d type_name 32 /* declare a type (\&{numeric}, \&{pair}, etc. */
4487 @d max_statement_command type_name
4488 @d min_primary_command type_name
4489 @d left_delimiter 33 /* the left delimiter of a matching pair */
4490 @d begin_group 34 /* beginning of a group (\&{begingroup}) */
4491 @d nullary 35 /* an operator without arguments (e.g., \&{normaldeviate}) */
4492 @d unary 36 /* an operator with one argument (e.g., \&{sqrt}) */
4493 @d str_op 37 /* convert a suffix to a string (\&{str}) */
4494 @d cycle 38 /* close a cyclic path (\&{cycle}) */
4495 @d primary_binary 39 /* binary operation taking `\&{of}' (e.g., \&{point}) */
4496 @d capsule_token 40 /* a value that has been put into a token list */
4497 @d string_token 41 /* a string constant (e.g., |"hello"|) */
4498 @d internal_quantity 42 /* internal numeric parameter (e.g., \&{pausing}) */
4499 @d min_suffix_token internal_quantity
4500 @d tag_token 43 /* a symbolic token without a primitive meaning */
4501 @d numeric_token 44 /* a numeric constant (e.g., \.{3.14159}) */
4502 @d max_suffix_token numeric_token
4503 @d plus_or_minus 45 /* either `\.+' or `\.-' */
4504 @d max_primary_command plus_or_minus /* should also be |numeric_token+1| */
4505 @d min_tertiary_command plus_or_minus
4506 @d tertiary_secondary_macro 46 /* a macro defined by \&{secondarydef} */
4507 @d tertiary_binary 47 /* an operator at the tertiary level (e.g., `\.{++}') */
4508 @d max_tertiary_command tertiary_binary
4509 @d left_brace 48 /* the operator `\.{\char`\{}' */
4510 @d min_expression_command left_brace
4511 @d path_join 49 /* the operator `\.{..}' */
4512 @d ampersand 50 /* the operator `\.\&' */
4513 @d expression_tertiary_macro 51 /* a macro defined by \&{tertiarydef} */
4514 @d expression_binary 52 /* an operator at the expression level (e.g., `\.<') */
4515 @d equals 53 /* the operator `\.=' */
4516 @d max_expression_command equals
4517 @d and_command 54 /* the operator `\&{and}' */
4518 @d min_secondary_command and_command
4519 @d secondary_primary_macro 55 /* a macro defined by \&{primarydef} */
4520 @d slash 56 /* the operator `\./' */
4521 @d secondary_binary 57 /* an operator at the binary level (e.g., \&{shifted}) */
4522 @d max_secondary_command secondary_binary
4523 @d param_type 58 /* type of parameter (\&{primary}, \&{expr}, \&{suffix}, etc.) */
4524 @d controls 59 /* specify control points explicitly (\&{controls}) */
4525 @d tension 60 /* specify tension between knots (\&{tension}) */
4526 @d at_least 61 /* bounded tension value (\&{atleast}) */
4527 @d curl_command 62 /* specify curl at an end knot (\&{curl}) */
4528 @d macro_special 63 /* special macro operators (\&{quote}, \.{\#\AT!}, etc.) */
4529 @d right_delimiter 64 /* the right delimiter of a matching pair */
4530 @d left_bracket 65 /* the operator `\.[' */
4531 @d right_bracket 66 /* the operator `\.]' */
4532 @d right_brace 67 /* the operator `\.{\char`\}}' */
4533 @d with_option 68 /* option for filling (\&{withpen}, \&{withweight}, etc.) */
4534 @d thing_to_add 69
4535   /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */
4536 @d of_token 70 /* the operator `\&{of}' */
4537 @d to_token 71 /* the operator `\&{to}' */
4538 @d step_token 72 /* the operator `\&{step}' */
4539 @d until_token 73 /* the operator `\&{until}' */
4540 @d within_token 74 /* the operator `\&{within}' */
4541 @d lig_kern_token 75
4542   /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}, etc. */
4543 @d assignment 76 /* the operator `\.{:=}' */
4544 @d skip_to 77 /* the operation `\&{skipto}' */
4545 @d bchar_label 78 /* the operator `\.{\char'174\char'174:}' */
4546 @d double_colon 79 /* the operator `\.{::}' */
4547 @d colon 80 /* the operator `\.:' */
4548 @#
4549 @d comma 81 /* the operator `\.,', must be |colon+1| */
4550 @d end_of_statement (mp->cur_cmd>comma)
4551 @d semicolon 82 /* the operator `\.;', must be |comma+1| */
4552 @d end_group 83 /* end a group (\&{endgroup}), must be |semicolon+1| */
4553 @d stop 84 /* end a job (\&{end}, \&{dump}), must be |end_group+1| */
4554 @d max_command_code stop
4555 @d outer_tag (max_command_code+1) /* protection code added to command code */
4556
4557 @<Types...@>=
4558 typedef int command_code;
4559
4560 @ Variables and capsules in \MP\ have a variety of ``types,''
4561 distinguished by the code numbers defined here. These numbers are also
4562 not completely arbitrary.  Things that get expanded must have types
4563 |>mp_independent|; a type remaining after expansion is numeric if and only if
4564 its code number is at least |numeric_type|; objects containing numeric
4565 parts must have types between |transform_type| and |pair_type|;
4566 all other types must be smaller than |transform_type|; and among the types
4567 that are not unknown or vacuous, the smallest two must be |boolean_type|
4568 and |string_type| in that order.
4569  
4570 @d undefined 0 /* no type has been declared */
4571 @d unknown_tag 1 /* this constant is added to certain type codes below */
4572 @d unknown_types mp_unknown_boolean: case mp_unknown_string:
4573   case mp_unknown_pen: case mp_unknown_picture: case mp_unknown_path
4574
4575 @<Types...@>=
4576 enum {
4577 mp_vacuous=1, /* no expression was present */
4578 mp_boolean_type, /* \&{boolean} with a known value */
4579 mp_unknown_boolean,
4580 mp_string_type, /* \&{string} with a known value */
4581 mp_unknown_string,
4582 mp_pen_type, /* \&{pen} with a known value */
4583 mp_unknown_pen,
4584 mp_path_type, /* \&{path} with a known value */
4585 mp_unknown_path,
4586 mp_picture_type, /* \&{picture} with a known value */
4587 mp_unknown_picture,
4588 mp_transform_type, /* \&{transform} variable or capsule */
4589 mp_color_type, /* \&{color} variable or capsule */
4590 mp_cmykcolor_type, /* \&{cmykcolor} variable or capsule */
4591 mp_pair_type, /* \&{pair} variable or capsule */
4592 mp_numeric_type, /* variable that has been declared \&{numeric} but not used */
4593 mp_known, /* \&{numeric} with a known value */
4594 mp_dependent, /* a linear combination with |fraction| coefficients */
4595 mp_proto_dependent, /* a linear combination with |scaled| coefficients */
4596 mp_independent, /* \&{numeric} with unknown value */
4597 mp_token_list, /* variable name or suffix argument or text argument */
4598 mp_structured, /* variable with subscripts and attributes */
4599 mp_unsuffixed_macro, /* variable defined with \&{vardef} but no \.{\AT!\#} */
4600 mp_suffixed_macro /* variable defined with \&{vardef} and \.{\AT!\#} */
4601 };
4602
4603 @ @<Declarations@>=
4604 void mp_print_type (MP mp,small_number t) ;
4605
4606 @ @<Basic printing procedures@>=
4607 void mp_print_type (MP mp,small_number t) { 
4608   switch (t) {
4609   case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
4610   case mp_boolean_type:mp_print(mp, "boolean"); break;
4611   case mp_unknown_boolean:mp_print(mp, "unknown boolean"); break;
4612   case mp_string_type:mp_print(mp, "string"); break;
4613   case mp_unknown_string:mp_print(mp, "unknown string"); break;
4614   case mp_pen_type:mp_print(mp, "pen"); break;
4615   case mp_unknown_pen:mp_print(mp, "unknown pen"); break;
4616   case mp_path_type:mp_print(mp, "path"); break;
4617   case mp_unknown_path:mp_print(mp, "unknown path"); break;
4618   case mp_picture_type:mp_print(mp, "picture"); break;
4619   case mp_unknown_picture:mp_print(mp, "unknown picture"); break;
4620   case mp_transform_type:mp_print(mp, "transform"); break;
4621   case mp_color_type:mp_print(mp, "color"); break;
4622   case mp_cmykcolor_type:mp_print(mp, "cmykcolor"); break;
4623   case mp_pair_type:mp_print(mp, "pair"); break;
4624   case mp_known:mp_print(mp, "known numeric"); break;
4625   case mp_dependent:mp_print(mp, "dependent"); break;
4626   case mp_proto_dependent:mp_print(mp, "proto-dependent"); break;
4627   case mp_numeric_type:mp_print(mp, "numeric"); break;
4628   case mp_independent:mp_print(mp, "independent"); break;
4629   case mp_token_list:mp_print(mp, "token list"); break;
4630   case mp_structured:mp_print(mp, "mp_structured"); break;
4631   case mp_unsuffixed_macro:mp_print(mp, "unsuffixed macro"); break;
4632   case mp_suffixed_macro:mp_print(mp, "suffixed macro"); break;
4633   default: mp_print(mp, "undefined"); break;
4634   }
4635 }
4636
4637 @ Values inside \MP\ are stored in two-word nodes that have a |name_type|
4638 as well as a |type|. The possibilities for |name_type| are defined
4639 here; they will be explained in more detail later.
4640
4641 @<Types...@>=
4642 enum {
4643  mp_root=0, /* |name_type| at the top level of a variable */
4644  mp_saved_root, /* same, when the variable has been saved */
4645  mp_structured_root, /* |name_type| where a |mp_structured| branch occurs */
4646  mp_subscr, /* |name_type| in a subscript node */
4647  mp_attr, /* |name_type| in an attribute node */
4648  mp_x_part_sector, /* |name_type| in the \&{xpart} of a node */
4649  mp_y_part_sector, /* |name_type| in the \&{ypart} of a node */
4650  mp_xx_part_sector, /* |name_type| in the \&{xxpart} of a node */
4651  mp_xy_part_sector, /* |name_type| in the \&{xypart} of a node */
4652  mp_yx_part_sector, /* |name_type| in the \&{yxpart} of a node */
4653  mp_yy_part_sector, /* |name_type| in the \&{yypart} of a node */
4654  mp_red_part_sector, /* |name_type| in the \&{redpart} of a node */
4655  mp_green_part_sector, /* |name_type| in the \&{greenpart} of a node */
4656  mp_blue_part_sector, /* |name_type| in the \&{bluepart} of a node */
4657  mp_cyan_part_sector, /* |name_type| in the \&{redpart} of a node */
4658  mp_magenta_part_sector, /* |name_type| in the \&{greenpart} of a node */
4659  mp_yellow_part_sector, /* |name_type| in the \&{bluepart} of a node */
4660  mp_black_part_sector, /* |name_type| in the \&{greenpart} of a node */
4661  mp_grey_part_sector, /* |name_type| in the \&{bluepart} of a node */
4662  mp_capsule, /* |name_type| in stashed-away subexpressions */
4663  mp_token  /* |name_type| in a numeric token or string token */
4664 };
4665
4666 @ Primitive operations that produce values have a secondary identification
4667 code in addition to their command code; it's something like genera and species.
4668 For example, `\.*' has the command code |primary_binary|, and its
4669 secondary identification is |times|. The secondary codes start at 30 so that
4670 they don't overlap with the type codes; some type codes (e.g., |mp_string_type|)
4671 are used as operators as well as type identifications.  The relative values
4672 are not critical, except for |true_code..false_code|, |or_op..and_op|,
4673 and |filled_op..bounded_op|.  The restrictions are that
4674 |and_op-false_code=or_op-true_code|, that the ordering of
4675 |x_part...blue_part| must match that of |x_part_sector..mp_blue_part_sector|,
4676 and the ordering of |filled_op..bounded_op| must match that of the code
4677 values they test for.
4678
4679 @d true_code 30 /* operation code for \.{true} */
4680 @d false_code 31 /* operation code for \.{false} */
4681 @d null_picture_code 32 /* operation code for \.{nullpicture} */
4682 @d null_pen_code 33 /* operation code for \.{nullpen} */
4683 @d job_name_op 34 /* operation code for \.{jobname} */
4684 @d read_string_op 35 /* operation code for \.{readstring} */
4685 @d pen_circle 36 /* operation code for \.{pencircle} */
4686 @d normal_deviate 37 /* operation code for \.{normaldeviate} */
4687 @d read_from_op 38 /* operation code for \.{readfrom} */
4688 @d close_from_op 39 /* operation code for \.{closefrom} */
4689 @d odd_op 40 /* operation code for \.{odd} */
4690 @d known_op 41 /* operation code for \.{known} */
4691 @d unknown_op 42 /* operation code for \.{unknown} */
4692 @d not_op 43 /* operation code for \.{not} */
4693 @d decimal 44 /* operation code for \.{decimal} */
4694 @d reverse 45 /* operation code for \.{reverse} */
4695 @d make_path_op 46 /* operation code for \.{makepath} */
4696 @d make_pen_op 47 /* operation code for \.{makepen} */
4697 @d oct_op 48 /* operation code for \.{oct} */
4698 @d hex_op 49 /* operation code for \.{hex} */
4699 @d ASCII_op 50 /* operation code for \.{ASCII} */
4700 @d char_op 51 /* operation code for \.{char} */
4701 @d length_op 52 /* operation code for \.{length} */
4702 @d turning_op 53 /* operation code for \.{turningnumber} */
4703 @d color_model_part 54 /* operation code for \.{colormodel} */
4704 @d x_part 55 /* operation code for \.{xpart} */
4705 @d y_part 56 /* operation code for \.{ypart} */
4706 @d xx_part 57 /* operation code for \.{xxpart} */
4707 @d xy_part 58 /* operation code for \.{xypart} */
4708 @d yx_part 59 /* operation code for \.{yxpart} */
4709 @d yy_part 60 /* operation code for \.{yypart} */
4710 @d red_part 61 /* operation code for \.{redpart} */
4711 @d green_part 62 /* operation code for \.{greenpart} */
4712 @d blue_part 63 /* operation code for \.{bluepart} */
4713 @d cyan_part 64 /* operation code for \.{cyanpart} */
4714 @d magenta_part 65 /* operation code for \.{magentapart} */
4715 @d yellow_part 66 /* operation code for \.{yellowpart} */
4716 @d black_part 67 /* operation code for \.{blackpart} */
4717 @d grey_part 68 /* operation code for \.{greypart} */
4718 @d font_part 69 /* operation code for \.{fontpart} */
4719 @d text_part 70 /* operation code for \.{textpart} */
4720 @d path_part 71 /* operation code for \.{pathpart} */
4721 @d pen_part 72 /* operation code for \.{penpart} */
4722 @d dash_part 73 /* operation code for \.{dashpart} */
4723 @d sqrt_op 74 /* operation code for \.{sqrt} */
4724 @d m_exp_op 75 /* operation code for \.{mexp} */
4725 @d m_log_op 76 /* operation code for \.{mlog} */
4726 @d sin_d_op 77 /* operation code for \.{sind} */
4727 @d cos_d_op 78 /* operation code for \.{cosd} */
4728 @d floor_op 79 /* operation code for \.{floor} */
4729 @d uniform_deviate 80 /* operation code for \.{uniformdeviate} */
4730 @d char_exists_op 81 /* operation code for \.{charexists} */
4731 @d font_size 82 /* operation code for \.{fontsize} */
4732 @d ll_corner_op 83 /* operation code for \.{llcorner} */
4733 @d lr_corner_op 84 /* operation code for \.{lrcorner} */
4734 @d ul_corner_op 85 /* operation code for \.{ulcorner} */
4735 @d ur_corner_op 86 /* operation code for \.{urcorner} */
4736 @d arc_length 87 /* operation code for \.{arclength} */
4737 @d angle_op 88 /* operation code for \.{angle} */
4738 @d cycle_op 89 /* operation code for \.{cycle} */
4739 @d filled_op 90 /* operation code for \.{filled} */
4740 @d stroked_op 91 /* operation code for \.{stroked} */
4741 @d textual_op 92 /* operation code for \.{textual} */
4742 @d clipped_op 93 /* operation code for \.{clipped} */
4743 @d bounded_op 94 /* operation code for \.{bounded} */
4744 @d plus 95 /* operation code for \.+ */
4745 @d minus 96 /* operation code for \.- */
4746 @d times 97 /* operation code for \.* */
4747 @d over 98 /* operation code for \./ */
4748 @d pythag_add 99 /* operation code for \.{++} */
4749 @d pythag_sub 100 /* operation code for \.{+-+} */
4750 @d or_op 101 /* operation code for \.{or} */
4751 @d and_op 102 /* operation code for \.{and} */
4752 @d less_than 103 /* operation code for \.< */
4753 @d less_or_equal 104 /* operation code for \.{<=} */
4754 @d greater_than 105 /* operation code for \.> */
4755 @d greater_or_equal 106 /* operation code for \.{>=} */
4756 @d equal_to 107 /* operation code for \.= */
4757 @d unequal_to 108 /* operation code for \.{<>} */
4758 @d concatenate 109 /* operation code for \.\& */
4759 @d rotated_by 110 /* operation code for \.{rotated} */
4760 @d slanted_by 111 /* operation code for \.{slanted} */
4761 @d scaled_by 112 /* operation code for \.{scaled} */
4762 @d shifted_by 113 /* operation code for \.{shifted} */
4763 @d transformed_by 114 /* operation code for \.{transformed} */
4764 @d x_scaled 115 /* operation code for \.{xscaled} */
4765 @d y_scaled 116 /* operation code for \.{yscaled} */
4766 @d z_scaled 117 /* operation code for \.{zscaled} */
4767 @d in_font 118 /* operation code for \.{infont} */
4768 @d intersect 119 /* operation code for \.{intersectiontimes} */
4769 @d double_dot 120 /* operation code for improper \.{..} */
4770 @d substring_of 121 /* operation code for \.{substring} */
4771 @d min_of substring_of
4772 @d subpath_of 122 /* operation code for \.{subpath} */
4773 @d direction_time_of 123 /* operation code for \.{directiontime} */
4774 @d point_of 124 /* operation code for \.{point} */
4775 @d precontrol_of 125 /* operation code for \.{precontrol} */
4776 @d postcontrol_of 126 /* operation code for \.{postcontrol} */
4777 @d pen_offset_of 127 /* operation code for \.{penoffset} */
4778 @d arc_time_of 128 /* operation code for \.{arctime} */
4779 @d mp_version 129 /* operation code for \.{mpversion} */
4780
4781 @c void mp_print_op (MP mp,quarterword c) { 
4782   if (c<=mp_numeric_type ) {
4783     mp_print_type(mp, c);
4784   } else {
4785     switch (c) {
4786     case true_code:mp_print(mp, "true"); break;
4787     case false_code:mp_print(mp, "false"); break;
4788     case null_picture_code:mp_print(mp, "nullpicture"); break;
4789     case null_pen_code:mp_print(mp, "nullpen"); break;
4790     case job_name_op:mp_print(mp, "jobname"); break;
4791     case read_string_op:mp_print(mp, "readstring"); break;
4792     case pen_circle:mp_print(mp, "pencircle"); break;
4793     case normal_deviate:mp_print(mp, "normaldeviate"); break;
4794     case read_from_op:mp_print(mp, "readfrom"); break;
4795     case close_from_op:mp_print(mp, "closefrom"); break;
4796     case odd_op:mp_print(mp, "odd"); break;
4797     case known_op:mp_print(mp, "known"); break;
4798     case unknown_op:mp_print(mp, "unknown"); break;
4799     case not_op:mp_print(mp, "not"); break;
4800     case decimal:mp_print(mp, "decimal"); break;
4801     case reverse:mp_print(mp, "reverse"); break;
4802     case make_path_op:mp_print(mp, "makepath"); break;
4803     case make_pen_op:mp_print(mp, "makepen"); break;
4804     case oct_op:mp_print(mp, "oct"); break;
4805     case hex_op:mp_print(mp, "hex"); break;
4806     case ASCII_op:mp_print(mp, "ASCII"); break;
4807     case char_op:mp_print(mp, "char"); break;
4808     case length_op:mp_print(mp, "length"); break;
4809     case turning_op:mp_print(mp, "turningnumber"); break;
4810     case x_part:mp_print(mp, "xpart"); break;
4811     case y_part:mp_print(mp, "ypart"); break;
4812     case xx_part:mp_print(mp, "xxpart"); break;
4813     case xy_part:mp_print(mp, "xypart"); break;
4814     case yx_part:mp_print(mp, "yxpart"); break;
4815     case yy_part:mp_print(mp, "yypart"); break;
4816     case red_part:mp_print(mp, "redpart"); break;
4817     case green_part:mp_print(mp, "greenpart"); break;
4818     case blue_part:mp_print(mp, "bluepart"); break;
4819     case cyan_part:mp_print(mp, "cyanpart"); break;
4820     case magenta_part:mp_print(mp, "magentapart"); break;
4821     case yellow_part:mp_print(mp, "yellowpart"); break;
4822     case black_part:mp_print(mp, "blackpart"); break;
4823     case grey_part:mp_print(mp, "greypart"); break;
4824     case color_model_part:mp_print(mp, "colormodel"); break;
4825     case font_part:mp_print(mp, "fontpart"); break;
4826     case text_part:mp_print(mp, "textpart"); break;
4827     case path_part:mp_print(mp, "pathpart"); break;
4828     case pen_part:mp_print(mp, "penpart"); break;
4829     case dash_part:mp_print(mp, "dashpart"); break;
4830     case sqrt_op:mp_print(mp, "sqrt"); break;
4831     case m_exp_op:mp_print(mp, "mexp"); break;
4832     case m_log_op:mp_print(mp, "mlog"); break;
4833     case sin_d_op:mp_print(mp, "sind"); break;
4834     case cos_d_op:mp_print(mp, "cosd"); break;
4835     case floor_op:mp_print(mp, "floor"); break;
4836     case uniform_deviate:mp_print(mp, "uniformdeviate"); break;
4837     case char_exists_op:mp_print(mp, "charexists"); break;
4838     case font_size:mp_print(mp, "fontsize"); break;
4839     case ll_corner_op:mp_print(mp, "llcorner"); break;
4840     case lr_corner_op:mp_print(mp, "lrcorner"); break;
4841     case ul_corner_op:mp_print(mp, "ulcorner"); break;
4842     case ur_corner_op:mp_print(mp, "urcorner"); break;
4843     case arc_length:mp_print(mp, "arclength"); break;
4844     case angle_op:mp_print(mp, "angle"); break;
4845     case cycle_op:mp_print(mp, "cycle"); break;
4846     case filled_op:mp_print(mp, "filled"); break;
4847     case stroked_op:mp_print(mp, "stroked"); break;
4848     case textual_op:mp_print(mp, "textual"); break;
4849     case clipped_op:mp_print(mp, "clipped"); break;
4850     case bounded_op:mp_print(mp, "bounded"); break;
4851     case plus:mp_print_char(mp, '+'); break;
4852     case minus:mp_print_char(mp, '-'); break;
4853     case times:mp_print_char(mp, '*'); break;
4854     case over:mp_print_char(mp, '/'); break;
4855     case pythag_add:mp_print(mp, "++"); break;
4856     case pythag_sub:mp_print(mp, "+-+"); break;
4857     case or_op:mp_print(mp, "or"); break;
4858     case and_op:mp_print(mp, "and"); break;
4859     case less_than:mp_print_char(mp, '<'); break;
4860     case less_or_equal:mp_print(mp, "<="); break;
4861     case greater_than:mp_print_char(mp, '>'); break;
4862     case greater_or_equal:mp_print(mp, ">="); break;
4863     case equal_to:mp_print_char(mp, '='); break;
4864     case unequal_to:mp_print(mp, "<>"); break;
4865     case concatenate:mp_print(mp, "&"); break;
4866     case rotated_by:mp_print(mp, "rotated"); break;
4867     case slanted_by:mp_print(mp, "slanted"); break;
4868     case scaled_by:mp_print(mp, "scaled"); break;
4869     case shifted_by:mp_print(mp, "shifted"); break;
4870     case transformed_by:mp_print(mp, "transformed"); break;
4871     case x_scaled:mp_print(mp, "xscaled"); break;
4872     case y_scaled:mp_print(mp, "yscaled"); break;
4873     case z_scaled:mp_print(mp, "zscaled"); break;
4874     case in_font:mp_print(mp, "infont"); break;
4875     case intersect:mp_print(mp, "intersectiontimes"); break;
4876     case substring_of:mp_print(mp, "substring"); break;
4877     case subpath_of:mp_print(mp, "subpath"); break;
4878     case direction_time_of:mp_print(mp, "directiontime"); break;
4879     case point_of:mp_print(mp, "point"); break;
4880     case precontrol_of:mp_print(mp, "precontrol"); break;
4881     case postcontrol_of:mp_print(mp, "postcontrol"); break;
4882     case pen_offset_of:mp_print(mp, "penoffset"); break;
4883     case arc_time_of:mp_print(mp, "arctime"); break;
4884     case mp_version:mp_print(mp, "mpversion"); break;
4885     default: mp_print(mp, ".."); break;
4886     }
4887   }
4888 }
4889
4890 @ \MP\ also has a bunch of internal parameters that a user might want to
4891 fuss with. Every such parameter has an identifying code number, defined here.
4892
4893 @d tracing_titles 1 /* show titles online when they appear */
4894 @d tracing_equations 2 /* show each variable when it becomes known */
4895 @d tracing_capsules 3 /* show capsules too */
4896 @d tracing_choices 4 /* show the control points chosen for paths */
4897 @d tracing_specs 5 /* show path subdivision prior to filling with polygonal a pen */
4898 @d tracing_commands 6 /* show commands and operations before they are performed */
4899 @d tracing_restores 7 /* show when a variable or internal is restored */
4900 @d tracing_macros 8 /* show macros before they are expanded */
4901 @d tracing_output 9 /* show digitized edges as they are output */
4902 @d tracing_stats 10 /* show memory usage at end of job */
4903 @d tracing_lost_chars 11 /* show characters that aren't \&{infont} */
4904 @d tracing_online 12 /* show long diagnostics on terminal and in the log file */
4905 @d year 13 /* the current year (e.g., 1984) */
4906 @d month 14 /* the current month (e.g, 3 $\equiv$ March) */
4907 @d day 15 /* the current day of the month */
4908 @d mp_time 16 /* the number of minutes past midnight when this job started */
4909 @d char_code 17 /* the number of the next character to be output */
4910 @d char_ext 18 /* the extension code of the next character to be output */
4911 @d char_wd 19 /* the width of the next character to be output */
4912 @d char_ht 20 /* the height of the next character to be output */
4913 @d char_dp 21 /* the depth of the next character to be output */
4914 @d char_ic 22 /* the italic correction of the next character to be output */
4915 @d design_size 23 /* the unit of measure used for |char_wd..char_ic|, in points */
4916 @d pausing 24 /* positive to display lines on the terminal before they are read */
4917 @d showstopping 25 /* positive to stop after each \&{show} command */
4918 @d fontmaking 26 /* positive if font metric output is to be produced */
4919 @d linejoin 27 /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */
4920 @d linecap 28 /* as in \ps: 0 for butt, 1 for round, 2 for square */
4921 @d miterlimit 29 /* controls miter length as in \ps */
4922 @d warning_check 30 /* controls error message when variable value is large */
4923 @d boundary_char 31 /* the right boundary character for ligatures */
4924 @d prologues 32 /* positive to output conforming PostScript using built-in fonts */
4925 @d true_corners 33 /* positive to make \&{llcorner} etc. ignore \&{setbounds} */
4926 @d default_color_model 34 /* the default color model for unspecified items */
4927 @d restore_clip_color 35
4928 @d mpprocset 36 /* wether or not create PostScript command shortcuts */
4929 @d gtroffmode 37 /* whether the user specified |-troff| on the command line */
4930 @d max_given_internal 37
4931
4932 @<Glob...@>=
4933 scaled *internal;  /* the values of internal quantities */
4934 char **int_name;  /* their names */
4935 int int_ptr;  /* the maximum internal quantity defined so far */
4936 int max_internal; /* current maximum number of internal quantities */
4937 boolean troff_mode; 
4938
4939 @ @<Option variables@>=
4940 boolean troff_mode; 
4941
4942 @ @<Allocate or initialize ...@>=
4943 mp->max_internal=2*max_given_internal;
4944 mp->internal = xmalloc ((mp->max_internal+1), sizeof(scaled));
4945 mp->int_name = xmalloc ((mp->max_internal+1), sizeof(char *));
4946 mp->troff_mode=(opt->troff_mode>0 ? true : false);
4947
4948 @ @<Exported ...@>=
4949 int mp_troff_mode(MP mp);
4950
4951 @ @c
4952 int mp_troff_mode(MP mp) { return mp->troff_mode; }
4953
4954 @ @<Set initial ...@>=
4955 for (k=0;k<= mp->max_internal; k++ ) { 
4956    mp->internal[k]=0; 
4957    mp->int_name[k]=NULL; 
4958 }
4959 mp->int_ptr=max_given_internal;
4960
4961 @ The symbolic names for internal quantities are put into \MP's hash table
4962 by using a routine called |primitive|, which will be defined later. Let us
4963 enter them now, so that we don't have to list all those names again
4964 anywhere else.
4965
4966 @<Put each of \MP's primitives into the hash table@>=
4967 mp_primitive(mp, "tracingtitles",internal_quantity,tracing_titles);
4968 @:tracingtitles_}{\&{tracingtitles} primitive@>
4969 mp_primitive(mp, "tracingequations",internal_quantity,tracing_equations);
4970 @:tracing_equations_}{\&{tracingequations} primitive@>
4971 mp_primitive(mp, "tracingcapsules",internal_quantity,tracing_capsules);
4972 @:tracing_capsules_}{\&{tracingcapsules} primitive@>
4973 mp_primitive(mp, "tracingchoices",internal_quantity,tracing_choices);
4974 @:tracing_choices_}{\&{tracingchoices} primitive@>
4975 mp_primitive(mp, "tracingspecs",internal_quantity,tracing_specs);
4976 @:tracing_specs_}{\&{tracingspecs} primitive@>
4977 mp_primitive(mp, "tracingcommands",internal_quantity,tracing_commands);
4978 @:tracing_commands_}{\&{tracingcommands} primitive@>
4979 mp_primitive(mp, "tracingrestores",internal_quantity,tracing_restores);
4980 @:tracing_restores_}{\&{tracingrestores} primitive@>
4981 mp_primitive(mp, "tracingmacros",internal_quantity,tracing_macros);
4982 @:tracing_macros_}{\&{tracingmacros} primitive@>
4983 mp_primitive(mp, "tracingoutput",internal_quantity,tracing_output);
4984 @:tracing_output_}{\&{tracingoutput} primitive@>
4985 mp_primitive(mp, "tracingstats",internal_quantity,tracing_stats);
4986 @:tracing_stats_}{\&{tracingstats} primitive@>
4987 mp_primitive(mp, "tracinglostchars",internal_quantity,tracing_lost_chars);
4988 @:tracing_lost_chars_}{\&{tracinglostchars} primitive@>
4989 mp_primitive(mp, "tracingonline",internal_quantity,tracing_online);
4990 @:tracing_online_}{\&{tracingonline} primitive@>
4991 mp_primitive(mp, "year",internal_quantity,year);
4992 @:year_}{\&{year} primitive@>
4993 mp_primitive(mp, "month",internal_quantity,month);
4994 @:month_}{\&{month} primitive@>
4995 mp_primitive(mp, "day",internal_quantity,day);
4996 @:day_}{\&{day} primitive@>
4997 mp_primitive(mp, "time",internal_quantity,mp_time);
4998 @:time_}{\&{time} primitive@>
4999 mp_primitive(mp, "charcode",internal_quantity,char_code);
5000 @:char_code_}{\&{charcode} primitive@>
5001 mp_primitive(mp, "charext",internal_quantity,char_ext);
5002 @:char_ext_}{\&{charext} primitive@>
5003 mp_primitive(mp, "charwd",internal_quantity,char_wd);
5004 @:char_wd_}{\&{charwd} primitive@>
5005 mp_primitive(mp, "charht",internal_quantity,char_ht);
5006 @:char_ht_}{\&{charht} primitive@>
5007 mp_primitive(mp, "chardp",internal_quantity,char_dp);
5008 @:char_dp_}{\&{chardp} primitive@>
5009 mp_primitive(mp, "charic",internal_quantity,char_ic);
5010 @:char_ic_}{\&{charic} primitive@>
5011 mp_primitive(mp, "designsize",internal_quantity,design_size);
5012 @:design_size_}{\&{designsize} primitive@>
5013 mp_primitive(mp, "pausing",internal_quantity,pausing);
5014 @:pausing_}{\&{pausing} primitive@>
5015 mp_primitive(mp, "showstopping",internal_quantity,showstopping);
5016 @:showstopping_}{\&{showstopping} primitive@>
5017 mp_primitive(mp, "fontmaking",internal_quantity,fontmaking);
5018 @:fontmaking_}{\&{fontmaking} primitive@>
5019 mp_primitive(mp, "linejoin",internal_quantity,linejoin);
5020 @:linejoin_}{\&{linejoin} primitive@>
5021 mp_primitive(mp, "linecap",internal_quantity,linecap);
5022 @:linecap_}{\&{linecap} primitive@>
5023 mp_primitive(mp, "miterlimit",internal_quantity,miterlimit);
5024 @:miterlimit_}{\&{miterlimit} primitive@>
5025 mp_primitive(mp, "warningcheck",internal_quantity,warning_check);
5026 @:warning_check_}{\&{warningcheck} primitive@>
5027 mp_primitive(mp, "boundarychar",internal_quantity,boundary_char);
5028 @:boundary_char_}{\&{boundarychar} primitive@>
5029 mp_primitive(mp, "prologues",internal_quantity,prologues);
5030 @:prologues_}{\&{prologues} primitive@>
5031 mp_primitive(mp, "truecorners",internal_quantity,true_corners);
5032 @:true_corners_}{\&{truecorners} primitive@>
5033 mp_primitive(mp, "mpprocset",internal_quantity,mpprocset);
5034 @:mpprocset_}{\&{mpprocset} primitive@>
5035 mp_primitive(mp, "troffmode",internal_quantity,gtroffmode);
5036 @:troffmode_}{\&{troffmode} primitive@>
5037 mp_primitive(mp, "defaultcolormodel",internal_quantity,default_color_model);
5038 @:default_color_model_}{\&{defaultcolormodel} primitive@>
5039 mp_primitive(mp, "restoreclipcolor",internal_quantity,restore_clip_color);
5040 @:restore_clip_color_}{\&{restoreclipcolor} primitive@>
5041
5042 @ Colors can be specified in four color models. In the special
5043 case of |no_model|, MetaPost does not output any color operator to
5044 the postscript output.
5045
5046 Note: these values are passed directly on to |with_option|. This only
5047 works because the other possible values passed to |with_option| are
5048 8 and 10 respectively (from |with_pen| and |with_picture|).
5049
5050 There is a first state, that is only used for |gs_colormodel|. It flags
5051 the fact that there has not been any kind of color specification by
5052 the user so far in the game.
5053
5054 @d no_model 1
5055 @d grey_model 3
5056 @d rgb_model 5
5057 @d cmyk_model 7
5058 @d uninitialized_model 9
5059
5060 @<Initialize table entries (done by \.{INIMP} only)@>=
5061 mp->internal[default_color_model]=(rgb_model*unity);
5062 mp->internal[restore_clip_color]=unity;
5063
5064 @ Well, we do have to list the names one more time, for use in symbolic
5065 printouts.
5066
5067 @<Initialize table...@>=
5068 mp->int_name[tracing_titles]=xstrdup("tracingtitles");
5069 mp->int_name[tracing_equations]=xstrdup("tracingequations");
5070 mp->int_name[tracing_capsules]=xstrdup("tracingcapsules");
5071 mp->int_name[tracing_choices]=xstrdup("tracingchoices");
5072 mp->int_name[tracing_specs]=xstrdup("tracingspecs");
5073 mp->int_name[tracing_commands]=xstrdup("tracingcommands");
5074 mp->int_name[tracing_restores]=xstrdup("tracingrestores");
5075 mp->int_name[tracing_macros]=xstrdup("tracingmacros");
5076 mp->int_name[tracing_output]=xstrdup("tracingoutput");
5077 mp->int_name[tracing_stats]=xstrdup("tracingstats");
5078 mp->int_name[tracing_lost_chars]=xstrdup("tracinglostchars");
5079 mp->int_name[tracing_online]=xstrdup("tracingonline");
5080 mp->int_name[year]=xstrdup("year");
5081 mp->int_name[month]=xstrdup("month");
5082 mp->int_name[day]=xstrdup("day");
5083 mp->int_name[mp_time]=xstrdup("time");
5084 mp->int_name[char_code]=xstrdup("charcode");
5085 mp->int_name[char_ext]=xstrdup("charext");
5086 mp->int_name[char_wd]=xstrdup("charwd");
5087 mp->int_name[char_ht]=xstrdup("charht");
5088 mp->int_name[char_dp]=xstrdup("chardp");
5089 mp->int_name[char_ic]=xstrdup("charic");
5090 mp->int_name[design_size]=xstrdup("designsize");
5091 mp->int_name[pausing]=xstrdup("pausing");
5092 mp->int_name[showstopping]=xstrdup("showstopping");
5093 mp->int_name[fontmaking]=xstrdup("fontmaking");
5094 mp->int_name[linejoin]=xstrdup("linejoin");
5095 mp->int_name[linecap]=xstrdup("linecap");
5096 mp->int_name[miterlimit]=xstrdup("miterlimit");
5097 mp->int_name[warning_check]=xstrdup("warningcheck");
5098 mp->int_name[boundary_char]=xstrdup("boundarychar");
5099 mp->int_name[prologues]=xstrdup("prologues");
5100 mp->int_name[true_corners]=xstrdup("truecorners");
5101 mp->int_name[default_color_model]=xstrdup("defaultcolormodel");
5102 mp->int_name[mpprocset]=xstrdup("mpprocset");
5103 mp->int_name[gtroffmode]=xstrdup("troffmode");
5104 mp->int_name[restore_clip_color]=xstrdup("restoreclipcolor");
5105
5106 @ The following procedure, which is called just before \MP\ initializes its
5107 input and output, establishes the initial values of the date and time.
5108 @^system dependencies@>
5109
5110 Note that the values are |scaled| integers. Hence \MP\ can no longer
5111 be used after the year 32767.
5112
5113 @c 
5114 void mp_fix_date_and_time (MP mp) { 
5115   time_t clock = time ((time_t *) 0);
5116   struct tm *tmptr = localtime (&clock);
5117   mp->internal[mp_time]=
5118       (tmptr->tm_hour*60+tmptr->tm_min)*unity; /* minutes since midnight */
5119   mp->internal[day]=(tmptr->tm_mday)*unity; /* fourth day of the month */
5120   mp->internal[month]=(tmptr->tm_mon+1)*unity; /* seventh month of the year */
5121   mp->internal[year]=(tmptr->tm_year+1900)*unity; /* Anno Domini */
5122 }
5123
5124 @ @<Declarations@>=
5125 void mp_fix_date_and_time (MP mp) ;
5126
5127 @ \MP\ is occasionally supposed to print diagnostic information that
5128 goes only into the transcript file, unless |tracing_online| is positive.
5129 Now that we have defined |tracing_online| we can define
5130 two routines that adjust the destination of print commands:
5131
5132 @<Declarations@>=
5133 void mp_begin_diagnostic (MP mp) ;
5134 void mp_end_diagnostic (MP mp,boolean blank_line);
5135 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) ;
5136
5137 @ @<Basic printing...@>=
5138 @<Declare a function called |true_line|@>;
5139 void mp_begin_diagnostic (MP mp) { /* prepare to do some tracing */
5140   mp->old_setting=mp->selector;
5141   if ( mp->selector==ps_file_only ) mp->selector=mp->non_ps_setting;
5142   if ((mp->internal[tracing_online]<=0)&&(mp->selector==term_and_log)){ 
5143     decr(mp->selector);
5144     if ( mp->history==spotless ) mp->history=warning_issued;
5145   }
5146 }
5147 @#
5148 void mp_end_diagnostic (MP mp,boolean blank_line) {
5149   /* restore proper conditions after tracing */
5150   mp_print_nl(mp, "");
5151   if ( blank_line ) mp_print_ln(mp);
5152   mp->selector=mp->old_setting;
5153 }
5154
5155 @ The global variable |non_ps_setting| is initialized when it is time to print
5156 on |ps_file|.
5157
5158 @<Glob...@>=
5159 unsigned int old_setting;
5160 unsigned int non_ps_setting;
5161
5162 @ We will occasionally use |begin_diagnostic| in connection with line-number
5163 printing, as follows. (The parameter |s| is typically |"Path"| or
5164 |"Cycle spec"|, etc.)
5165
5166 @<Basic printing...@>=
5167 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) { 
5168   mp_begin_diagnostic(mp);
5169   if ( nuline ) mp_print_nl(mp, s); else mp_print(mp, s);
5170   mp_print(mp, " at line "); 
5171   mp_print_int(mp, mp_true_line(mp));
5172   mp_print(mp, t); mp_print_char(mp, ':');
5173 }
5174
5175 @ The 256 |ASCII_code| characters are grouped into classes by means of
5176 the |char_class| table. Individual class numbers have no semantic
5177 or syntactic significance, except in a few instances defined here.
5178 There's also |max_class|, which can be used as a basis for additional
5179 class numbers in nonstandard extensions of \MP.
5180
5181 @d digit_class 0 /* the class number of \.{0123456789} */
5182 @d period_class 1 /* the class number of `\..' */
5183 @d space_class 2 /* the class number of spaces and nonstandard characters */
5184 @d percent_class 3 /* the class number of `\.\%' */
5185 @d string_class 4 /* the class number of `\."' */
5186 @d right_paren_class 8 /* the class number of `\.)' */
5187 @d isolated_classes 5: case 6: case 7: case 8 /* characters that make length-one tokens only */
5188 @d letter_class 9 /* letters and the underline character */
5189 @d left_bracket_class 17 /* `\.[' */
5190 @d right_bracket_class 18 /* `\.]' */
5191 @d invalid_class 20 /* bad character in the input */
5192 @d max_class 20 /* the largest class number */
5193
5194 @<Glob...@>=
5195 int char_class[256]; /* the class numbers */
5196
5197 @ If changes are made to accommodate non-ASCII character sets, they should
5198 follow the guidelines in Appendix~C of {\sl The {\logos METAFONT\/}book}.
5199 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
5200 @^system dependencies@>
5201
5202 @<Set initial ...@>=
5203 for (k='0';k<='9';k++) 
5204   mp->char_class[k]=digit_class;
5205 mp->char_class['.']=period_class;
5206 mp->char_class[' ']=space_class;
5207 mp->char_class['%']=percent_class;
5208 mp->char_class['"']=string_class;
5209 mp->char_class[',']=5;
5210 mp->char_class[';']=6;
5211 mp->char_class['(']=7;
5212 mp->char_class[')']=right_paren_class;
5213 for (k='A';k<= 'Z';k++ )
5214   mp->char_class[k]=letter_class;
5215 for (k='a';k<='z';k++) 
5216   mp->char_class[k]=letter_class;
5217 mp->char_class['_']=letter_class;
5218 mp->char_class['<']=10;
5219 mp->char_class['=']=10;
5220 mp->char_class['>']=10;
5221 mp->char_class[':']=10;
5222 mp->char_class['|']=10;
5223 mp->char_class['`']=11;
5224 mp->char_class['\'']=11;
5225 mp->char_class['+']=12;
5226 mp->char_class['-']=12;
5227 mp->char_class['/']=13;
5228 mp->char_class['*']=13;
5229 mp->char_class['\\']=13;
5230 mp->char_class['!']=14;
5231 mp->char_class['?']=14;
5232 mp->char_class['#']=15;
5233 mp->char_class['&']=15;
5234 mp->char_class['@@']=15;
5235 mp->char_class['$']=15;
5236 mp->char_class['^']=16;
5237 mp->char_class['~']=16;
5238 mp->char_class['[']=left_bracket_class;
5239 mp->char_class[']']=right_bracket_class;
5240 mp->char_class['{']=19;
5241 mp->char_class['}']=19;
5242 for (k=0;k<' ';k++)
5243   mp->char_class[k]=invalid_class;
5244 mp->char_class['\t']=space_class;
5245 mp->char_class['\f']=space_class;
5246 for (k=127;k<=255;k++)
5247   mp->char_class[k]=invalid_class;
5248
5249 @* \[13] The hash table.
5250 Symbolic tokens are stored and retrieved by means of a fairly standard hash
5251 table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
5252 in {\sl The Art of Computer Programming\/}). Once a symbolic token enters the
5253 table, it is never removed.
5254
5255 The actual sequence of characters forming a symbolic token is
5256 stored in the |str_pool| array together with all the other strings. An
5257 auxiliary array |hash| consists of items with two halfword fields per
5258 word. The first of these, called |next(p)|, points to the next identifier
5259 belonging to the same coalesced list as the identifier corresponding to~|p|;
5260 and the other, called |text(p)|, points to the |str_start| entry for
5261 |p|'s identifier. If position~|p| of the hash table is empty, we have
5262 |text(p)=0|; if position |p| is either empty or the end of a coalesced
5263 hash list, we have |next(p)=0|.
5264
5265 An auxiliary pointer variable called |hash_used| is maintained in such a
5266 way that all locations |p>=hash_used| are nonempty. The global variable
5267 |st_count| tells how many symbolic tokens have been defined, if statistics
5268 are being kept.
5269
5270 The first 256 locations of |hash| are reserved for symbols of length one.
5271
5272 There's a parallel array called |eqtb| that contains the current equivalent
5273 values of each symbolic token. The entries of this array consist of
5274 two halfwords called |eq_type| (a command code) and |equiv| (a secondary
5275 piece of information that qualifies the |eq_type|).
5276
5277 @d next(A)   mp->hash[(A)].lh /* link for coalesced lists */
5278 @d text(A)   mp->hash[(A)].rh /* string number for symbolic token name */
5279 @d eq_type(A)   mp->eqtb[(A)].lh /* the current ``meaning'' of a symbolic token */
5280 @d equiv(A)   mp->eqtb[(A)].rh /* parametric part of a token's meaning */
5281 @d hash_base 257 /* hashing actually starts here */
5282 @d hash_is_full   (mp->hash_used==hash_base) /* are all positions occupied? */
5283
5284 @<Glob...@>=
5285 pointer hash_used; /* allocation pointer for |hash| */
5286 integer st_count; /* total number of known identifiers */
5287
5288 @ Certain entries in the hash table are ``frozen'' and not redefinable,
5289 since they are used in error recovery.
5290
5291 @d hash_top (hash_base+mp->hash_size) /* the first location of the frozen area */
5292 @d frozen_inaccessible hash_top /* |hash| location to protect the frozen area */
5293 @d frozen_repeat_loop (hash_top+1) /* |hash| location of a loop-repeat token */
5294 @d frozen_right_delimiter (hash_top+2) /* |hash| location of a permanent `\.)' */
5295 @d frozen_left_bracket (hash_top+3) /* |hash| location of a permanent `\.[' */
5296 @d frozen_slash (hash_top+4) /* |hash| location of a permanent `\./' */
5297 @d frozen_colon (hash_top+5) /* |hash| location of a permanent `\.:' */
5298 @d frozen_semicolon (hash_top+6) /* |hash| location of a permanent `\.;' */
5299 @d frozen_end_for (hash_top+7) /* |hash| location of a permanent \&{endfor} */
5300 @d frozen_end_def (hash_top+8) /* |hash| location of a permanent \&{enddef} */
5301 @d frozen_fi (hash_top+9) /* |hash| location of a permanent \&{fi} */
5302 @d frozen_end_group (hash_top+10) /* |hash| location of a permanent `\.{endgroup}' */
5303 @d frozen_etex (hash_top+11) /* |hash| location of a permanent \&{etex} */
5304 @d frozen_mpx_break (hash_top+12) /* |hash| location of a permanent \&{mpxbreak} */
5305 @d frozen_bad_vardef (hash_top+13) /* |hash| location of `\.{a bad variable}' */
5306 @d frozen_undefined (hash_top+14) /* |hash| location that never gets defined */
5307 @d hash_end (hash_top+14) /* the actual size of the |hash| and |eqtb| arrays */
5308
5309 @<Glob...@>=
5310 two_halves *hash; /* the hash table */
5311 two_halves *eqtb; /* the equivalents */
5312
5313 @ @<Allocate or initialize ...@>=
5314 mp->hash = xmalloc((hash_end+1),sizeof(two_halves));
5315 mp->eqtb = xmalloc((hash_end+1),sizeof(two_halves));
5316
5317 @ @<Dealloc variables@>=
5318 xfree(mp->hash);
5319 xfree(mp->eqtb);
5320
5321 @ @<Set init...@>=
5322 next(1)=0; text(1)=0; eq_type(1)=tag_token; equiv(1)=null;
5323 for (k=2;k<=hash_end;k++)  { 
5324   mp->hash[k]=mp->hash[1]; mp->eqtb[k]=mp->eqtb[1];
5325 }
5326
5327 @ @<Initialize table entries...@>=
5328 mp->hash_used=frozen_inaccessible; /* nothing is used */
5329 mp->st_count=0;
5330 text(frozen_bad_vardef)=intern("a bad variable");
5331 text(frozen_etex)=intern("etex");
5332 text(frozen_mpx_break)=intern("mpxbreak");
5333 text(frozen_fi)=intern("fi");
5334 text(frozen_end_group)=intern("endgroup");
5335 text(frozen_end_def)=intern("enddef");
5336 text(frozen_end_for)=intern("endfor");
5337 text(frozen_semicolon)=intern(";");
5338 text(frozen_colon)=intern(":");
5339 text(frozen_slash)=intern("/");
5340 text(frozen_left_bracket)=intern("[");
5341 text(frozen_right_delimiter)=intern(")");
5342 text(frozen_inaccessible)=intern(" INACCESSIBLE");
5343 eq_type(frozen_right_delimiter)=right_delimiter;
5344
5345 @ @<Check the ``constant'' values...@>=
5346 if ( hash_end+mp->max_internal>max_halfword ) mp->bad=17;
5347
5348 @ Here is the subroutine that searches the hash table for an identifier
5349 that matches a given string of length~|l| appearing in |buffer[j..
5350 (j+l-1)]|. If the identifier is not found, it is inserted; hence it
5351 will always be found, and the corresponding hash table address
5352 will be returned.
5353
5354 @c 
5355 pointer mp_id_lookup (MP mp,integer j, integer l) { /* search the hash table */
5356   integer h; /* hash code */
5357   pointer p; /* index in |hash| array */
5358   pointer k; /* index in |buffer| array */
5359   if (l==1) {
5360     @<Treat special case of length 1 and |break|@>;
5361   }
5362   @<Compute the hash code |h|@>;
5363   p=h+hash_base; /* we start searching here; note that |0<=h<hash_prime| */
5364   while (true)  { 
5365         if (text(p)>0 && length(text(p))==l && mp_str_eq_buf(mp, text(p),j)) 
5366       break;
5367     if ( next(p)==0 ) {
5368       @<Insert a new symbolic token after |p|, then
5369         make |p| point to it and |break|@>;
5370     }
5371     p=next(p);
5372   }
5373   return p;
5374 };
5375
5376 @ @<Treat special case of length 1...@>=
5377  p=mp->buffer[j]+1; text(p)=p-1; return p;
5378
5379
5380 @ @<Insert a new symbolic...@>=
5381 {
5382 if ( text(p)>0 ) { 
5383   do {  
5384     if ( hash_is_full )
5385       mp_overflow(mp, "hash size",mp->hash_size);
5386 @:MetaPost capacity exceeded hash size}{\quad hash size@>
5387     decr(mp->hash_used);
5388   } while (text(mp->hash_used)!=0); /* search for an empty location in |hash| */
5389   next(p)=mp->hash_used; 
5390   p=mp->hash_used;
5391 }
5392 str_room(l);
5393 for (k=j;k<=j+l-1;k++) {
5394   append_char(mp->buffer[k]);
5395 }
5396 text(p)=mp_make_string(mp); 
5397 mp->str_ref[text(p)]=max_str_ref;
5398 incr(mp->st_count);
5399 break;
5400 }
5401
5402
5403 @ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
5404 should be a prime number.  The theory of hashing tells us to expect fewer
5405 than two table probes, on the average, when the search is successful.
5406 [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
5407 @^Vitter, Jeffrey Scott@>
5408
5409 @<Compute the hash code |h|@>=
5410 h=mp->buffer[j];
5411 for (k=j+1;k<=j+l-1;k++){ 
5412   h=h+h+mp->buffer[k];
5413   while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
5414 }
5415
5416 @ @<Search |eqtb| for equivalents equal to |p|@>=
5417 for (q=1;q<=hash_end;q++) { 
5418   if ( equiv(q)==p ) { 
5419     mp_print_nl(mp, "EQUIV("); 
5420     mp_print_int(mp, q); 
5421     mp_print_char(mp, ')');
5422   }
5423 }
5424
5425 @ We need to put \MP's ``primitive'' symbolic tokens into the hash
5426 table, together with their command code (which will be the |eq_type|)
5427 and an operand (which will be the |equiv|). The |primitive| procedure
5428 does this, in a way that no \MP\ user can. The global value |cur_sym|
5429 contains the new |eqtb| pointer after |primitive| has acted.
5430
5431 @c 
5432 void mp_primitive (MP mp, char *ss, halfword c, halfword o) {
5433   pool_pointer k; /* index into |str_pool| */
5434   small_number j; /* index into |buffer| */
5435   small_number l; /* length of the string */
5436   str_number s;
5437   s = intern(ss);
5438   k=mp->str_start[s]; l=str_stop(s)-k;
5439   /* we will move |s| into the (empty) |buffer| */
5440   for (j=0;j<=l-1;j++) {
5441     mp->buffer[j]=mp->str_pool[k+j];
5442   }
5443   mp->cur_sym=mp_id_lookup(mp, 0,l);
5444   if ( s>=256 ) { /* we don't want to have the string twice */
5445     mp_flush_string(mp, text(mp->cur_sym)); text(mp->cur_sym)=s;
5446   };
5447   eq_type(mp->cur_sym)=c; 
5448   equiv(mp->cur_sym)=o;
5449 }
5450
5451
5452 @ Many of \MP's primitives need no |equiv|, since they are identifiable
5453 by their |eq_type| alone. These primitives are loaded into the hash table
5454 as follows:
5455
5456 @<Put each of \MP's primitives into the hash table@>=
5457 mp_primitive(mp, "..",path_join,0);
5458 @:.._}{\.{..} primitive@>
5459 mp_primitive(mp, "[",left_bracket,0); mp->eqtb[frozen_left_bracket]=mp->eqtb[mp->cur_sym];
5460 @:[ }{\.{[} primitive@>
5461 mp_primitive(mp, "]",right_bracket,0);
5462 @:] }{\.{]} primitive@>
5463 mp_primitive(mp, "}",right_brace,0);
5464 @:]]}{\.{\char`\}} primitive@>
5465 mp_primitive(mp, "{",left_brace,0);
5466 @:][}{\.{\char`\{} primitive@>
5467 mp_primitive(mp, ":",colon,0); mp->eqtb[frozen_colon]=mp->eqtb[mp->cur_sym];
5468 @:: }{\.{:} primitive@>
5469 mp_primitive(mp, "::",double_colon,0);
5470 @::: }{\.{::} primitive@>
5471 mp_primitive(mp, "||:",bchar_label,0);
5472 @:::: }{\.{\char'174\char'174:} primitive@>
5473 mp_primitive(mp, ":=",assignment,0);
5474 @::=_}{\.{:=} primitive@>
5475 mp_primitive(mp, ",",comma,0);
5476 @:, }{\., primitive@>
5477 mp_primitive(mp, ";",semicolon,0); mp->eqtb[frozen_semicolon]=mp->eqtb[mp->cur_sym];
5478 @:; }{\.; primitive@>
5479 mp_primitive(mp, "\\",relax,0);
5480 @:]]\\}{\.{\char`\\} primitive@>
5481 @#
5482 mp_primitive(mp, "addto",add_to_command,0);
5483 @:add_to_}{\&{addto} primitive@>
5484 mp_primitive(mp, "atleast",at_least,0);
5485 @:at_least_}{\&{atleast} primitive@>
5486 mp_primitive(mp, "begingroup",begin_group,0); mp->bg_loc=mp->cur_sym;
5487 @:begin_group_}{\&{begingroup} primitive@>
5488 mp_primitive(mp, "controls",controls,0);
5489 @:controls_}{\&{controls} primitive@>
5490 mp_primitive(mp, "curl",curl_command,0);
5491 @:curl_}{\&{curl} primitive@>
5492 mp_primitive(mp, "delimiters",delimiters,0);
5493 @:delimiters_}{\&{delimiters} primitive@>
5494 mp_primitive(mp, "endgroup",end_group,0);
5495  mp->eqtb[frozen_end_group]=mp->eqtb[mp->cur_sym]; mp->eg_loc=mp->cur_sym;
5496 @:endgroup_}{\&{endgroup} primitive@>
5497 mp_primitive(mp, "everyjob",every_job_command,0);
5498 @:every_job_}{\&{everyjob} primitive@>
5499 mp_primitive(mp, "exitif",exit_test,0);
5500 @:exit_if_}{\&{exitif} primitive@>
5501 mp_primitive(mp, "expandafter",expand_after,0);
5502 @:expand_after_}{\&{expandafter} primitive@>
5503 mp_primitive(mp, "interim",interim_command,0);
5504 @:interim_}{\&{interim} primitive@>
5505 mp_primitive(mp, "let",let_command,0);
5506 @:let_}{\&{let} primitive@>
5507 mp_primitive(mp, "newinternal",new_internal,0);
5508 @:new_internal_}{\&{newinternal} primitive@>
5509 mp_primitive(mp, "of",of_token,0);
5510 @:of_}{\&{of} primitive@>
5511 mp_primitive(mp, "randomseed",random_seed,0);
5512 @:random_seed_}{\&{randomseed} primitive@>
5513 mp_primitive(mp, "save",save_command,0);
5514 @:save_}{\&{save} primitive@>
5515 mp_primitive(mp, "scantokens",scan_tokens,0);
5516 @:scan_tokens_}{\&{scantokens} primitive@>
5517 mp_primitive(mp, "shipout",ship_out_command,0);
5518 @:ship_out_}{\&{shipout} primitive@>
5519 mp_primitive(mp, "skipto",skip_to,0);
5520 @:skip_to_}{\&{skipto} primitive@>
5521 mp_primitive(mp, "special",special_command,0);
5522 @:special}{\&{special} primitive@>
5523 mp_primitive(mp, "fontmapfile",special_command,1);
5524 @:fontmapfile}{\&{fontmapfile} primitive@>
5525 mp_primitive(mp, "fontmapline",special_command,2);
5526 @:fontmapline}{\&{fontmapline} primitive@>
5527 mp_primitive(mp, "step",step_token,0);
5528 @:step_}{\&{step} primitive@>
5529 mp_primitive(mp, "str",str_op,0);
5530 @:str_}{\&{str} primitive@>
5531 mp_primitive(mp, "tension",tension,0);
5532 @:tension_}{\&{tension} primitive@>
5533 mp_primitive(mp, "to",to_token,0);
5534 @:to_}{\&{to} primitive@>
5535 mp_primitive(mp, "until",until_token,0);
5536 @:until_}{\&{until} primitive@>
5537 mp_primitive(mp, "within",within_token,0);
5538 @:within_}{\&{within} primitive@>
5539 mp_primitive(mp, "write",write_command,0);
5540 @:write_}{\&{write} primitive@>
5541
5542 @ Each primitive has a corresponding inverse, so that it is possible to
5543 display the cryptic numeric contents of |eqtb| in symbolic form.
5544 Every call of |primitive| in this program is therefore accompanied by some
5545 straightforward code that forms part of the |print_cmd_mod| routine
5546 explained below.
5547
5548 @<Cases of |print_cmd_mod| for symbolic printing of primitives@>=
5549 case add_to_command:mp_print(mp, "addto"); break;
5550 case assignment:mp_print(mp, ":="); break;
5551 case at_least:mp_print(mp, "atleast"); break;
5552 case bchar_label:mp_print(mp, "||:"); break;
5553 case begin_group:mp_print(mp, "begingroup"); break;
5554 case colon:mp_print(mp, ":"); break;
5555 case comma:mp_print(mp, ","); break;
5556 case controls:mp_print(mp, "controls"); break;
5557 case curl_command:mp_print(mp, "curl"); break;
5558 case delimiters:mp_print(mp, "delimiters"); break;
5559 case double_colon:mp_print(mp, "::"); break;
5560 case end_group:mp_print(mp, "endgroup"); break;
5561 case every_job_command:mp_print(mp, "everyjob"); break;
5562 case exit_test:mp_print(mp, "exitif"); break;
5563 case expand_after:mp_print(mp, "expandafter"); break;
5564 case interim_command:mp_print(mp, "interim"); break;
5565 case left_brace:mp_print(mp, "{"); break;
5566 case left_bracket:mp_print(mp, "["); break;
5567 case let_command:mp_print(mp, "let"); break;
5568 case new_internal:mp_print(mp, "newinternal"); break;
5569 case of_token:mp_print(mp, "of"); break;
5570 case path_join:mp_print(mp, ".."); break;
5571 case random_seed:mp_print(mp, "randomseed"); break;
5572 case relax:mp_print_char(mp, '\\'); break;
5573 case right_brace:mp_print(mp, "}"); break;
5574 case right_bracket:mp_print(mp, "]"); break;
5575 case save_command:mp_print(mp, "save"); break;
5576 case scan_tokens:mp_print(mp, "scantokens"); break;
5577 case semicolon:mp_print(mp, ";"); break;
5578 case ship_out_command:mp_print(mp, "shipout"); break;
5579 case skip_to:mp_print(mp, "skipto"); break;
5580 case special_command: if ( m==2 ) mp_print(mp, "fontmapline"); else
5581                  if ( m==1 ) mp_print(mp, "fontmapfile"); else
5582                  mp_print(mp, "special"); break;
5583 case step_token:mp_print(mp, "step"); break;
5584 case str_op:mp_print(mp, "str"); break;
5585 case tension:mp_print(mp, "tension"); break;
5586 case to_token:mp_print(mp, "to"); break;
5587 case until_token:mp_print(mp, "until"); break;
5588 case within_token:mp_print(mp, "within"); break;
5589 case write_command:mp_print(mp, "write"); break;
5590
5591 @ We will deal with the other primitives later, at some point in the program
5592 where their |eq_type| and |equiv| values are more meaningful.  For example,
5593 the primitives for macro definitions will be loaded when we consider the
5594 routines that define macros.
5595 It is easy to find where each particular
5596 primitive was treated by looking in the index at the end; for example, the
5597 section where |"def"| entered |eqtb| is listed under `\&{def} primitive'.
5598
5599 @* \[14] Token lists.
5600 A \MP\ token is either symbolic or numeric or a string, or it denotes
5601 a macro parameter or capsule; so there are five corresponding ways to encode it
5602 @^token@>
5603 internally: (1)~A symbolic token whose hash code is~|p|
5604 is represented by the number |p|, in the |info| field of a single-word
5605 node in~|mem|. (2)~A numeric token whose |scaled| value is~|v| is
5606 represented in a two-word node of~|mem|; the |type| field is |known|,
5607 the |name_type| field is |token|, and the |value| field holds~|v|.
5608 The fact that this token appears in a two-word node rather than a
5609 one-word node is, of course, clear from the node address.
5610 (3)~A string token is also represented in a two-word node; the |type|
5611 field is |mp_string_type|, the |name_type| field is |token|, and the
5612 |value| field holds the corresponding |str_number|.  (4)~Capsules have
5613 |name_type=capsule|, and their |type| and |value| fields represent
5614 arbitrary values (in ways to be explained later).  (5)~Macro parameters
5615 are like symbolic tokens in that they appear in |info| fields of
5616 one-word nodes. The $k$th parameter is represented by |expr_base+k| if it
5617 is of type \&{expr}, or by |suffix_base+k| if it is of type \&{suffix}, or
5618 by |text_base+k| if it is of type \&{text}.  (Here |0<=k<param_size|.)
5619 Actual values of these parameters are kept in a separate stack, as we will
5620 see later.  The constants |expr_base|, |suffix_base|, and |text_base| are,
5621 of course, chosen so that there will be no confusion between symbolic
5622 tokens and parameters of various types.
5623
5624 Note that
5625 the `\\{type}' field of a node has nothing to do with ``type'' in a
5626 printer's sense. It's curious that the same word is used in such different ways.
5627
5628 @d type(A)   mp->mem[(A)].hh.b0 /* identifies what kind of value this is */
5629 @d name_type(A)   mp->mem[(A)].hh.b1 /* a clue to the name of this value */
5630 @d token_node_size 2 /* the number of words in a large token node */
5631 @d value_loc(A) ((A)+1) /* the word that contains the |value| field */
5632 @d value(A) mp->mem[value_loc((A))].cint /* the value stored in a large token node */
5633 @d expr_base (hash_end+1) /* code for the zeroth \&{expr} parameter */
5634 @d suffix_base (expr_base+mp->param_size) /* code for the zeroth \&{suffix} parameter */
5635 @d text_base (suffix_base+mp->param_size) /* code for the zeroth \&{text} parameter */
5636
5637 @<Check the ``constant''...@>=
5638 if ( text_base+mp->param_size>max_halfword ) mp->bad=18;
5639
5640 @ We have set aside a two word node beginning at |null| so that we can have
5641 |value(null)=0|.  We will make use of this coincidence later.
5642
5643 @<Initialize table entries...@>=
5644 link(null)=null; value(null)=0;
5645
5646 @ A numeric token is created by the following trivial routine.
5647
5648 @c 
5649 pointer mp_new_num_tok (MP mp,scaled v) {
5650   pointer p; /* the new node */
5651   p=mp_get_node(mp, token_node_size); value(p)=v;
5652   type(p)=mp_known; name_type(p)=mp_token; 
5653   return p;
5654 }
5655
5656 @ A token list is a singly linked list of nodes in |mem|, where
5657 each node contains a token and a link.  Here's a subroutine that gets rid
5658 of a token list when it is no longer needed.
5659
5660 @<Declarations@>=
5661 void mp_token_recycle (MP mp);
5662
5663
5664 @c void mp_flush_token_list (MP mp,pointer p) {
5665   pointer q; /* the node being recycled */
5666   while ( p!=null ) { 
5667     q=p; p=link(p);
5668     if ( q>=mp->hi_mem_min ) {
5669      free_avail(q);
5670     } else { 
5671       switch (type(q)) {
5672       case mp_vacuous: case mp_boolean_type: case mp_known:
5673         break;
5674       case mp_string_type:
5675         delete_str_ref(value(q));
5676         break;
5677       case unknown_types: case mp_pen_type: case mp_path_type: 
5678       case mp_picture_type: case mp_pair_type: case mp_color_type:
5679       case mp_cmykcolor_type: case mp_transform_type: case mp_dependent:
5680       case mp_proto_dependent: case mp_independent:
5681         mp->g_pointer=q; mp_token_recycle(mp);
5682         break;
5683       default: mp_confusion(mp, "token");
5684 @:this can't happen token}{\quad token@>
5685       }
5686       mp_free_node(mp, q,token_node_size);
5687     }
5688   }
5689 }
5690
5691 @ The procedure |show_token_list|, which prints a symbolic form of
5692 the token list that starts at a given node |p|, illustrates these
5693 conventions. The token list being displayed should not begin with a reference
5694 count. However, the procedure is intended to be fairly robust, so that if the
5695 memory links are awry or if |p| is not really a pointer to a token list,
5696 almost nothing catastrophic can happen.
5697
5698 An additional parameter |q| is also given; this parameter is either null
5699 or it points to a node in the token list where a certain magic computation
5700 takes place that will be explained later. (Basically, |q| is non-null when
5701 we are printing the two-line context information at the time of an error
5702 message; |q| marks the place corresponding to where the second line
5703 should begin.)
5704
5705 The generation will stop, and `\.{\char`\ ETC.}' will be printed, if the length
5706 of printing exceeds a given limit~|l|; the length of printing upon entry is
5707 assumed to be a given amount called |null_tally|. (Note that
5708 |show_token_list| sometimes uses itself recursively to print
5709 variable names within a capsule.)
5710 @^recursion@>
5711
5712 Unusual entries are printed in the form of all-caps tokens
5713 preceded by a space, e.g., `\.{\char`\ BAD}'.
5714
5715 @<Declarations@>=
5716 void mp_print_capsule (MP mp);
5717
5718 @ @<Declare the procedure called |show_token_list|@>=
5719 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5720                          integer null_tally) ;
5721
5722 @ @c
5723 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5724                          integer null_tally) {
5725   small_number class,c; /* the |char_class| of previous and new tokens */
5726   integer r,v; /* temporary registers */
5727   class=percent_class;
5728   mp->tally=null_tally;
5729   while ( (p!=null) && (mp->tally<l) ) { 
5730     if ( p==q ) 
5731       @<Do magic computation@>;
5732     @<Display token |p| and set |c| to its class;
5733       but |return| if there are problems@>;
5734     class=c; p=link(p);
5735   }
5736   if ( p!=null ) 
5737      mp_print(mp, " ETC.");
5738 @.ETC@>
5739   return;
5740 };
5741
5742 @ @<Display token |p| and set |c| to its class...@>=
5743 c=letter_class; /* the default */
5744 if ( (p<0)||(p>mp->mem_end) ) { 
5745   mp_print(mp, " CLOBBERED"); return;
5746 @.CLOBBERED@>
5747 }
5748 if ( p<mp->hi_mem_min ) { 
5749   @<Display two-word token@>;
5750 } else { 
5751   r=info(p);
5752   if ( r>=expr_base ) {
5753      @<Display a parameter token@>;
5754   } else {
5755     if ( r<1 ) {
5756       if ( r==0 ) { 
5757         @<Display a collective subscript@>
5758       } else {
5759         mp_print(mp, " IMPOSSIBLE");
5760 @.IMPOSSIBLE@>
5761       }
5762     } else { 
5763       r=text(r);
5764       if ( (r<0)||(r>mp->max_str_ptr) ) {
5765         mp_print(mp, " NONEXISTENT");
5766 @.NONEXISTENT@>
5767       } else {
5768        @<Print string |r| as a symbolic token
5769         and set |c| to its class@>;
5770       }
5771     }
5772   }
5773 }
5774
5775 @ @<Display two-word token@>=
5776 if ( name_type(p)==mp_token ) {
5777   if ( type(p)==mp_known ) {
5778     @<Display a numeric token@>;
5779   } else if ( type(p)!=mp_string_type ) {
5780     mp_print(mp, " BAD");
5781 @.BAD@>
5782   } else { 
5783     mp_print_char(mp, '"'); mp_print_str(mp, value(p)); mp_print_char(mp, '"');
5784     c=string_class;
5785   }
5786 } else if ((name_type(p)!=mp_capsule)||(type(p)<mp_vacuous)||(type(p)>mp_independent) ) {
5787   mp_print(mp, " BAD");
5788 } else { 
5789   mp->g_pointer=p; mp_print_capsule(mp); c=right_paren_class;
5790 }
5791
5792 @ @<Display a numeric token@>=
5793 if ( class==digit_class ) 
5794   mp_print_char(mp, ' ');
5795 v=value(p);
5796 if ( v<0 ){ 
5797   if ( class==left_bracket_class ) 
5798     mp_print_char(mp, ' ');
5799   mp_print_char(mp, '['); mp_print_scaled(mp, v); mp_print_char(mp, ']');
5800   c=right_bracket_class;
5801 } else { 
5802   mp_print_scaled(mp, v); c=digit_class;
5803 }
5804
5805
5806 @ Strictly speaking, a genuine token will never have |info(p)=0|.
5807 But we will see later (in the |print_variable_name| routine) that
5808 it is convenient to let |info(p)=0| stand for `\.{[]}'.
5809
5810 @<Display a collective subscript@>=
5811 {
5812 if ( class==left_bracket_class ) 
5813   mp_print_char(mp, ' ');
5814 mp_print(mp, "[]"); c=right_bracket_class;
5815 }
5816
5817 @ @<Display a parameter token@>=
5818 {
5819 if ( r<suffix_base ) { 
5820   mp_print(mp, "(EXPR"); r=r-(expr_base);
5821 @.EXPR@>
5822 } else if ( r<text_base ) { 
5823   mp_print(mp, "(SUFFIX"); r=r-(suffix_base);
5824 @.SUFFIX@>
5825 } else { 
5826   mp_print(mp, "(TEXT"); r=r-(text_base);
5827 @.TEXT@>
5828 }
5829 mp_print_int(mp, r); mp_print_char(mp, ')'); c=right_paren_class;
5830 }
5831
5832
5833 @ @<Print string |r| as a symbolic token...@>=
5834
5835 c=mp->char_class[mp->str_pool[mp->str_start[r]]];
5836 if ( c==class ) {
5837   switch (c) {
5838   case letter_class:mp_print_char(mp, '.'); break;
5839   case isolated_classes: break;
5840   default: mp_print_char(mp, ' '); break;
5841   }
5842 }
5843 mp_print_str(mp, r);
5844 }
5845
5846 @ The following procedures have been declared |forward| with no parameters,
5847 because the author dislikes \PASCAL's convention about |forward| procedures
5848 with parameters. It was necessary to do something, because |show_token_list|
5849 is recursive (although the recursion is limited to one level), and because
5850 |flush_token_list| is syntactically (but not semantically) recursive.
5851 @^recursion@>
5852
5853 @<Declare miscellaneous procedures that were declared |forward|@>=
5854 void mp_print_capsule (MP mp) { 
5855   mp_print_char(mp, '('); mp_print_exp(mp, mp->g_pointer,0); mp_print_char(mp, ')');
5856 };
5857 @#
5858 void mp_token_recycle (MP mp) { 
5859   mp_recycle_value(mp, mp->g_pointer);
5860 };
5861
5862 @ @<Glob...@>=
5863 pointer g_pointer; /* (global) parameter to the |forward| procedures */
5864
5865 @ Macro definitions are kept in \MP's memory in the form of token lists
5866 that have a few extra one-word nodes at the beginning.
5867
5868 The first node contains a reference count that is used to tell when the
5869 list is no longer needed. To emphasize the fact that a reference count is
5870 present, we shall refer to the |info| field of this special node as the
5871 |ref_count| field.
5872 @^reference counts@>
5873
5874 The next node or nodes after the reference count serve to describe the
5875 formal parameters. They either contain a code word that specifies all
5876 of the parameters, or they contain zero or more parameter tokens followed
5877 by the code `|general_macro|'.
5878
5879 @d ref_count info
5880   /* reference count preceding a macro definition or picture header */
5881 @d add_mac_ref(A) incr(ref_count((A))) /* make a new reference to a macro list */
5882 @d general_macro 0 /* preface to a macro defined with a parameter list */
5883 @d primary_macro 1 /* preface to a macro with a \&{primary} parameter */
5884 @d secondary_macro 2 /* preface to a macro with a \&{secondary} parameter */
5885 @d tertiary_macro 3 /* preface to a macro with a \&{tertiary} parameter */
5886 @d expr_macro 4 /* preface to a macro with an undelimited \&{expr} parameter */
5887 @d of_macro 5 /* preface to a macro with
5888   undelimited `\&{expr} |x| \&{of}~|y|' parameters */
5889 @d suffix_macro 6 /* preface to a macro with an undelimited \&{suffix} parameter */
5890 @d text_macro 7 /* preface to a macro with an undelimited \&{text} parameter */
5891
5892 @c 
5893 void mp_delete_mac_ref (MP mp,pointer p) {
5894   /* |p| points to the reference count of a macro list that is
5895     losing one reference */
5896   if ( ref_count(p)==null ) mp_flush_token_list(mp, p);
5897   else decr(ref_count(p));
5898 }
5899
5900 @ The following subroutine displays a macro, given a pointer to its
5901 reference count.
5902
5903 @c 
5904 @<Declare the procedure called |print_cmd_mod|@>;
5905 void mp_show_macro (MP mp, pointer p, integer q, integer l) {
5906   pointer r; /* temporary storage */
5907   p=link(p); /* bypass the reference count */
5908   while ( info(p)>text_macro ){ 
5909     r=link(p); link(p)=null;
5910     mp_show_token_list(mp, p,null,l,0); link(p)=r; p=r;
5911     if ( l>0 ) l=l-mp->tally; else return;
5912   } /* control printing of `\.{ETC.}' */
5913 @.ETC@>
5914   mp->tally=0;
5915   switch(info(p)) {
5916   case general_macro:mp_print(mp, "->"); break;
5917 @.->@>
5918   case primary_macro: case secondary_macro: case tertiary_macro:
5919     mp_print_char(mp, '<');
5920     mp_print_cmd_mod(mp, param_type,info(p)); 
5921     mp_print(mp, ">->");
5922     break;
5923   case expr_macro:mp_print(mp, "<expr>->"); break;
5924   case of_macro:mp_print(mp, "<expr>of<primary>->"); break;
5925   case suffix_macro:mp_print(mp, "<suffix>->"); break;
5926   case text_macro:mp_print(mp, "<text>->"); break;
5927   } /* there are no other cases */
5928   mp_show_token_list(mp, link(p),q,l-mp->tally,0);
5929 }
5930
5931 @* \[15] Data structures for variables.
5932 The variables of \MP\ programs can be simple, like `\.x', or they can
5933 combine the structural properties of arrays and records, like `\.{x20a.b}'.
5934 A \MP\ user assigns a type to a variable like \.{x20a.b} by saying, for
5935 example, `\.{boolean} \.{x20a.b}'. It's time for us to study how such
5936 things are represented inside of the computer.
5937
5938 Each variable value occupies two consecutive words, either in a two-word
5939 node called a value node, or as a two-word subfield of a larger node.  One
5940 of those two words is called the |value| field; it is an integer,
5941 containing either a |scaled| numeric value or the representation of some
5942 other type of quantity. (It might also be subdivided into halfwords, in
5943 which case it is referred to by other names instead of |value|.) The other
5944 word is broken into subfields called |type|, |name_type|, and |link|.  The
5945 |type| field is a quarterword that specifies the variable's type, and
5946 |name_type| is a quarterword from which \MP\ can reconstruct the
5947 variable's name (sometimes by using the |link| field as well).  Thus, only
5948 1.25 words are actually devoted to the value itself; the other
5949 three-quarters of a word are overhead, but they aren't wasted because they
5950 allow \MP\ to deal with sparse arrays and to provide meaningful diagnostics.
5951
5952 In this section we shall be concerned only with the structural aspects of
5953 variables, not their values. Later parts of the program will change the
5954 |type| and |value| fields, but we shall treat those fields as black boxes
5955 whose contents should not be touched.
5956
5957 However, if the |type| field is |mp_structured|, there is no |value| field,
5958 and the second word is broken into two pointer fields called |attr_head|
5959 and |subscr_head|. Those fields point to additional nodes that
5960 contain structural information, as we shall see.
5961
5962 @d subscr_head_loc(A)   (A)+1 /* where |value|, |subscr_head| and |attr_head| are */
5963 @d attr_head(A)   info(subscr_head_loc((A))) /* pointer to attribute info */
5964 @d subscr_head(A)   link(subscr_head_loc((A))) /* pointer to subscript info */
5965 @d value_node_size 2 /* the number of words in a value node */
5966
5967 @ An attribute node is three words long. Two of these words contain |type|
5968 and |value| fields as described above, and the third word contains
5969 additional information:  There is an |attr_loc| field, which contains the
5970 hash address of the token that names this attribute; and there's also a
5971 |parent| field, which points to the value node of |mp_structured| type at the
5972 next higher level (i.e., at the level to which this attribute is
5973 subsidiary).  The |name_type| in an attribute node is `|attr|'.  The
5974 |link| field points to the next attribute with the same parent; these are
5975 arranged in increasing order, so that |attr_loc(link(p))>attr_loc(p)|. The
5976 final attribute node links to the constant |end_attr|, whose |attr_loc|
5977 field is greater than any legal hash address. The |attr_head| in the
5978 parent points to a node whose |name_type| is |mp_structured_root|; this
5979 node represents the null attribute, i.e., the variable that is relevant
5980 when no attributes are attached to the parent. The |attr_head| node is either
5981 a value node, a subscript node, or an attribute node, depending on what
5982 the parent would be if it were not structured; but the subscript and
5983 attribute fields are ignored, so it effectively contains only the data of
5984 a value node. The |link| field in this special node points to an attribute
5985 node whose |attr_loc| field is zero; the latter node represents a collective
5986 subscript `\.{[]}' attached to the parent, and its |link| field points to
5987 the first non-special attribute node (or to |end_attr| if there are none).
5988
5989 A subscript node likewise occupies three words, with |type| and |value| fields
5990 plus extra information; its |name_type| is |subscr|. In this case the
5991 third word is called the |subscript| field, which is a |scaled| integer.
5992 The |link| field points to the subscript node with the next larger
5993 subscript, if any; otherwise the |link| points to the attribute node
5994 for collective subscripts at this level. We have seen that the latter node
5995 contains an upward pointer, so that the parent can be deduced.
5996
5997 The |name_type| in a parent-less value node is |root|, and the |link|
5998 is the hash address of the token that names this value.
5999
6000 In other words, variables have a hierarchical structure that includes
6001 enough threads running around so that the program is able to move easily
6002 between siblings, parents, and children. An example should be helpful:
6003 (The reader is advised to draw a picture while reading the following
6004 description, since that will help to firm up the ideas.)
6005 Suppose that `\.x' and `\.{x.a}' and `\.{x[]b}' and `\.{x5}'
6006 and `\.{x20b}' have been mentioned in a user's program, where
6007 \.{x[]b} has been declared to be of \&{boolean} type. Let |h(x)|, |h(a)|,
6008 and |h(b)| be the hash addresses of \.x, \.a, and~\.b. Then
6009 |eq_type(h(x))=name| and |equiv(h(x))=p|, where |p|~is a two-word value
6010 node with |name_type(p)=root| and |link(p)=h(x)|. We have |type(p)=mp_structured|,
6011 |attr_head(p)=q|, and |subscr_head(p)=r|, where |q| points to a value
6012 node and |r| to a subscript node. (Are you still following this? Use
6013 a pencil to draw a diagram.) The lone variable `\.x' is represented by
6014 |type(q)| and |value(q)|; furthermore
6015 |name_type(q)=mp_structured_root| and |link(q)=q1|, where |q1| points
6016 to an attribute node representing `\.{x[]}'. Thus |name_type(q1)=attr|,
6017 |attr_loc(q1)=collective_subscript=0|, |parent(q1)=p|,
6018 |type(q1)=mp_structured|, |attr_head(q1)=qq|, and |subscr_head(q1)=qq1|;
6019 |qq| is a value node with |type(qq)=mp_numeric_type| (assuming that \.{x5} is
6020 numeric, because |qq| represents `\.{x[]}' with no further attributes),
6021 |name_type(qq)=mp_structured_root|, and
6022 |link(qq)=qq1|. (Now pay attention to the next part.) Node |qq1| is
6023 an attribute node representing `\.{x[][]}', which has never yet
6024 occurred; its |type| field is |undefined|, and its |value| field is
6025 undefined. We have |name_type(qq1)=attr|, |attr_loc(qq1)=collective_subscript|,
6026 |parent(qq1)=q1|, and |link(qq1)=qq2|. Since |qq2| represents
6027 `\.{x[]b}', |type(qq2)=mp_unknown_boolean|; also |attr_loc(qq2)=h(b)|,
6028 |parent(qq2)=q1|, |name_type(qq2)=attr|, |link(qq2)=end_attr|.
6029 (Maybe colored lines will help untangle your picture.)
6030  Node |r| is a subscript node with |type| and |value|
6031 representing `\.{x5}'; |name_type(r)=subscr|, |subscript(r)=5.0|,
6032 and |link(r)=r1| is another subscript node. To complete the picture,
6033 see if you can guess what |link(r1)| is; give up? It's~|q1|.
6034 Furthermore |subscript(r1)=20.0|, |name_type(r1)=subscr|,
6035 |type(r1)=mp_structured|, |attr_head(r1)=qqq|, |subscr_head(r1)=qqq1|,
6036 and we finish things off with three more nodes
6037 |qqq|, |qqq1|, and |qqq2| hung onto~|r1|. (Perhaps you should start again
6038 with a larger sheet of paper.) The value of variable \.{x20b}
6039 appears in node~|qqq2|, as you can well imagine.
6040
6041 If the example in the previous paragraph doesn't make things crystal
6042 clear, a glance at some of the simpler subroutines below will reveal how
6043 things work out in practice.
6044
6045 The only really unusual thing about these conventions is the use of
6046 collective subscript attributes. The idea is to avoid repeating a lot of
6047 type information when many elements of an array are identical macros
6048 (for which distinct values need not be stored) or when they don't have
6049 all of the possible attributes. Branches of the structure below collective
6050 subscript attributes do not carry actual values except for macro identifiers;
6051 branches of the structure below subscript nodes do not carry significant
6052 information in their collective subscript attributes.
6053
6054 @d attr_loc_loc(A) ((A)+2) /* where the |attr_loc| and |parent| fields are */
6055 @d attr_loc(A) info(attr_loc_loc((A))) /* hash address of this attribute */
6056 @d parent(A) link(attr_loc_loc((A))) /* pointer to |mp_structured| variable */
6057 @d subscript_loc(A) ((A)+2) /* where the |subscript| field lives */
6058 @d subscript(A) mp->mem[subscript_loc((A))].sc /* subscript of this variable */
6059 @d attr_node_size 3 /* the number of words in an attribute node */
6060 @d subscr_node_size 3 /* the number of words in a subscript node */
6061 @d collective_subscript 0 /* code for the attribute `\.{[]}' */
6062
6063 @<Initialize table...@>=
6064 attr_loc(end_attr)=hash_end+1; parent(end_attr)=null;
6065
6066 @ Variables of type \&{pair} will have values that point to four-word
6067 nodes containing two numeric values. The first of these values has
6068 |name_type=mp_x_part_sector| and the second has |name_type=mp_y_part_sector|;
6069 the |link| in the first points back to the node whose |value| points
6070 to this four-word node.
6071
6072 Variables of type \&{transform} are similar, but in this case their
6073 |value| points to a 12-word node containing six values, identified by
6074 |x_part_sector|, |y_part_sector|, |mp_xx_part_sector|, |mp_xy_part_sector|,
6075 |mp_yx_part_sector|, and |mp_yy_part_sector|.
6076 Finally, variables of type \&{color} have three values in six words
6077 identified by |mp_red_part_sector|, |mp_green_part_sector|, and |mp_blue_part_sector|.
6078
6079 When an entire structured variable is saved, the |root| indication
6080 is temporarily replaced by |saved_root|.
6081
6082 Some variables have no name; they just are used for temporary storage
6083 while expressions are being evaluated. We call them {\sl capsules}.
6084
6085 @d x_part_loc(A) (A) /* where the \&{xpart} is found in a pair or transform node */
6086 @d y_part_loc(A) ((A)+2) /* where the \&{ypart} is found in a pair or transform node */
6087 @d xx_part_loc(A) ((A)+4) /* where the \&{xxpart} is found in a transform node */
6088 @d xy_part_loc(A) ((A)+6) /* where the \&{xypart} is found in a transform node */
6089 @d yx_part_loc(A) ((A)+8) /* where the \&{yxpart} is found in a transform node */
6090 @d yy_part_loc(A) ((A)+10) /* where the \&{yypart} is found in a transform node */
6091 @d red_part_loc(A) (A) /* where the \&{redpart} is found in a color node */
6092 @d green_part_loc(A) ((A)+2) /* where the \&{greenpart} is found in a color node */
6093 @d blue_part_loc(A) ((A)+4) /* where the \&{bluepart} is found in a color node */
6094 @d cyan_part_loc(A) (A) /* where the \&{cyanpart} is found in a color node */
6095 @d magenta_part_loc(A) ((A)+2) /* where the \&{magentapart} is found in a color node */
6096 @d yellow_part_loc(A) ((A)+4) /* where the \&{yellowpart} is found in a color node */
6097 @d black_part_loc(A) ((A)+6) /* where the \&{blackpart} is found in a color node */
6098 @d grey_part_loc(A) (A) /* where the \&{greypart} is found in a color node */
6099 @#
6100 @d pair_node_size 4 /* the number of words in a pair node */
6101 @d transform_node_size 12 /* the number of words in a transform node */
6102 @d color_node_size 6 /* the number of words in a color node */
6103 @d cmykcolor_node_size 8 /* the number of words in a color node */
6104
6105 @<Glob...@>=
6106 small_number big_node_size[mp_pair_type+1];
6107 small_number sector0[mp_pair_type+1];
6108 small_number sector_offset[mp_black_part_sector+1];
6109
6110 @ The |sector0| array gives for each big node type, |name_type| values
6111 for its first subfield; the |sector_offset| array gives for each
6112 |name_type| value, the offset from the first subfield in words;
6113 and the |big_node_size| array gives the size in words for each type of
6114 big node.
6115
6116 @<Set init...@>=
6117 mp->big_node_size[mp_transform_type]=transform_node_size;
6118 mp->big_node_size[mp_pair_type]=pair_node_size;
6119 mp->big_node_size[mp_color_type]=color_node_size;
6120 mp->big_node_size[mp_cmykcolor_type]=cmykcolor_node_size;
6121 mp->sector0[mp_transform_type]=mp_x_part_sector;
6122 mp->sector0[mp_pair_type]=mp_x_part_sector;
6123 mp->sector0[mp_color_type]=mp_red_part_sector;
6124 mp->sector0[mp_cmykcolor_type]=mp_cyan_part_sector;
6125 for (k=mp_x_part_sector;k<= mp_yy_part_sector;k++ ) {
6126   mp->sector_offset[k]=2*(k-mp_x_part_sector);
6127 }
6128 for (k=mp_red_part_sector;k<= mp_blue_part_sector ; k++) {
6129   mp->sector_offset[k]=2*(k-mp_red_part_sector);
6130 }
6131 for (k=mp_cyan_part_sector;k<= mp_black_part_sector;k++ ) {
6132   mp->sector_offset[k]=2*(k-mp_cyan_part_sector);
6133 }
6134
6135 @ If |type(p)=mp_pair_type| or |mp_transform_type| and if |value(p)=null|, the
6136 procedure call |init_big_node(p)| will allocate a pair or transform node
6137 for~|p|.  The individual parts of such nodes are initially of type
6138 |mp_independent|.
6139
6140 @c 
6141 void mp_init_big_node (MP mp,pointer p) {
6142   pointer q; /* the new node */
6143   small_number s; /* its size */
6144   s=mp->big_node_size[type(p)]; q=mp_get_node(mp, s);
6145   do {  
6146     s=s-2; 
6147     @<Make variable |q+s| newly independent@>;
6148     name_type(q+s)=halfp(s)+mp->sector0[type(p)]; 
6149     link(q+s)=null;
6150   } while (s!=0);
6151   link(q)=p; value(p)=q;
6152 }
6153
6154 @ The |id_transform| function creates a capsule for the
6155 identity transformation.
6156
6157 @c 
6158 pointer mp_id_transform (MP mp) {
6159   pointer p,q,r; /* list manipulation registers */
6160   p=mp_get_node(mp, value_node_size); type(p)=mp_transform_type;
6161   name_type(p)=mp_capsule; value(p)=null; mp_init_big_node(mp, p); q=value(p);
6162   r=q+transform_node_size;
6163   do {  
6164     r=r-2;
6165     type(r)=mp_known; value(r)=0;
6166   } while (r!=q);
6167   value(xx_part_loc(q))=unity; 
6168   value(yy_part_loc(q))=unity;
6169   return p;
6170 }
6171
6172 @ Tokens are of type |tag_token| when they first appear, but they point
6173 to |null| until they are first used as the root of a variable.
6174 The following subroutine establishes the root node on such grand occasions.
6175
6176 @c 
6177 void mp_new_root (MP mp,pointer x) {
6178   pointer p; /* the new node */
6179   p=mp_get_node(mp, value_node_size); type(p)=undefined; name_type(p)=mp_root;
6180   link(p)=x; equiv(x)=p;
6181 }
6182
6183 @ These conventions for variable representation are illustrated by the
6184 |print_variable_name| routine, which displays the full name of a
6185 variable given only a pointer to its two-word value packet.
6186
6187 @<Declarations@>=
6188 void mp_print_variable_name (MP mp, pointer p);
6189
6190 @ @c 
6191 void mp_print_variable_name (MP mp, pointer p) {
6192   pointer q; /* a token list that will name the variable's suffix */
6193   pointer r; /* temporary for token list creation */
6194   while ( name_type(p)>=mp_x_part_sector ) {
6195     @<Preface the output with a part specifier; |return| in the
6196       case of a capsule@>;
6197   }
6198   q=null;
6199   while ( name_type(p)>mp_saved_root ) {
6200     @<Ascend one level, pushing a token onto list |q|
6201      and replacing |p| by its parent@>;
6202   }
6203   r=mp_get_avail(mp); info(r)=link(p); link(r)=q;
6204   if ( name_type(p)==mp_saved_root ) mp_print(mp, "(SAVED)");
6205 @.SAVED@>
6206   mp_show_token_list(mp, r,null,el_gordo,mp->tally); 
6207   mp_flush_token_list(mp, r);
6208 }
6209
6210 @ @<Ascend one level, pushing a token onto list |q|...@>=
6211
6212   if ( name_type(p)==mp_subscr ) { 
6213     r=mp_new_num_tok(mp, subscript(p));
6214     do {  
6215       p=link(p);
6216     } while (name_type(p)!=mp_attr);
6217   } else if ( name_type(p)==mp_structured_root ) {
6218     p=link(p); goto FOUND;
6219   } else { 
6220     if ( name_type(p)!=mp_attr ) mp_confusion(mp, "var");
6221 @:this can't happen var}{\quad var@>
6222     r=mp_get_avail(mp); info(r)=attr_loc(p);
6223   }
6224   link(r)=q; q=r;
6225 FOUND:  
6226   p=parent(p);
6227 }
6228
6229 @ @<Preface the output with a part specifier...@>=
6230 { switch (name_type(p)) {
6231   case mp_x_part_sector: mp_print_char(mp, 'x'); break;
6232   case mp_y_part_sector: mp_print_char(mp, 'y'); break;
6233   case mp_xx_part_sector: mp_print(mp, "xx"); break;
6234   case mp_xy_part_sector: mp_print(mp, "xy"); break;
6235   case mp_yx_part_sector: mp_print(mp, "yx"); break;
6236   case mp_yy_part_sector: mp_print(mp, "yy"); break;
6237   case mp_red_part_sector: mp_print(mp, "red"); break;
6238   case mp_green_part_sector: mp_print(mp, "green"); break;
6239   case mp_blue_part_sector: mp_print(mp, "blue"); break;
6240   case mp_cyan_part_sector: mp_print(mp, "cyan"); break;
6241   case mp_magenta_part_sector: mp_print(mp, "magenta"); break;
6242   case mp_yellow_part_sector: mp_print(mp, "yellow"); break;
6243   case mp_black_part_sector: mp_print(mp, "black"); break;
6244   case mp_grey_part_sector: mp_print(mp, "grey"); break;
6245   case mp_capsule: 
6246     mp_print(mp, "%CAPSULE"); mp_print_int(mp, p-null); return;
6247     break;
6248 @.CAPSULE@>
6249   } /* there are no other cases */
6250   mp_print(mp, "part "); 
6251   p=link(p-mp->sector_offset[name_type(p)]);
6252 }
6253
6254 @ The |interesting| function returns |true| if a given variable is not
6255 in a capsule, or if the user wants to trace capsules.
6256
6257 @c 
6258 boolean mp_interesting (MP mp,pointer p) {
6259   small_number t; /* a |name_type| */
6260   if ( mp->internal[tracing_capsules]>0 ) {
6261     return true;
6262   } else { 
6263     t=name_type(p);
6264     if ( t>=mp_x_part_sector ) if ( t!=mp_capsule )
6265       t=name_type(link(p-mp->sector_offset[t]));
6266     return (t!=mp_capsule);
6267   }
6268 }
6269
6270 @ Now here is a subroutine that converts an unstructured type into an
6271 equivalent structured type, by inserting a |mp_structured| node that is
6272 capable of growing. This operation is done only when |name_type(p)=root|,
6273 |subscr|, or |attr|.
6274
6275 The procedure returns a pointer to the new node that has taken node~|p|'s
6276 place in the structure. Node~|p| itself does not move, nor are its
6277 |value| or |type| fields changed in any way.
6278
6279 @c 
6280 pointer mp_new_structure (MP mp,pointer p) {
6281   pointer q,r=0; /* list manipulation registers */
6282   switch (name_type(p)) {
6283   case mp_root: 
6284     q=link(p); r=mp_get_node(mp, value_node_size); equiv(q)=r;
6285     break;
6286   case mp_subscr: 
6287     @<Link a new subscript node |r| in place of node |p|@>;
6288     break;
6289   case mp_attr: 
6290     @<Link a new attribute node |r| in place of node |p|@>;
6291     break;
6292   default: 
6293     mp_confusion(mp, "struct");
6294 @:this can't happen struct}{\quad struct@>
6295     break;
6296   }
6297   link(r)=link(p); type(r)=mp_structured; name_type(r)=name_type(p);
6298   attr_head(r)=p; name_type(p)=mp_structured_root;
6299   q=mp_get_node(mp, attr_node_size); link(p)=q; subscr_head(r)=q;
6300   parent(q)=r; type(q)=undefined; name_type(q)=mp_attr; link(q)=end_attr;
6301   attr_loc(q)=collective_subscript; 
6302   return r;
6303 };
6304
6305 @ @<Link a new subscript node |r| in place of node |p|@>=
6306
6307   q=p;
6308   do {  
6309     q=link(q);
6310   } while (name_type(q)!=mp_attr);
6311   q=parent(q); r=subscr_head_loc(q); /* |link(r)=subscr_head(q)| */
6312   do {  
6313     q=r; r=link(r);
6314   } while (r!=p);
6315   r=mp_get_node(mp, subscr_node_size);
6316   link(q)=r; subscript(r)=subscript(p);
6317 }
6318
6319 @ If the attribute is |collective_subscript|, there are two pointers to
6320 node~|p|, so we must change both of them.
6321
6322 @<Link a new attribute node |r| in place of node |p|@>=
6323
6324   q=parent(p); r=attr_head(q);
6325   do {  
6326     q=r; r=link(r);
6327   } while (r!=p);
6328   r=mp_get_node(mp, attr_node_size); link(q)=r;
6329   mp->mem[attr_loc_loc(r)]=mp->mem[attr_loc_loc(p)]; /* copy |attr_loc| and |parent| */
6330   if ( attr_loc(p)==collective_subscript ) { 
6331     q=subscr_head_loc(parent(p));
6332     while ( link(q)!=p ) q=link(q);
6333     link(q)=r;
6334   }
6335 }
6336
6337 @ The |find_variable| routine is given a pointer~|t| to a nonempty token
6338 list of suffixes; it returns a pointer to the corresponding two-word
6339 value. For example, if |t| points to token \.x followed by a numeric
6340 token containing the value~7, |find_variable| finds where the value of
6341 \.{x7} is stored in memory. This may seem a simple task, and it
6342 usually is, except when \.{x7} has never been referenced before.
6343 Indeed, \.x may never have even been subscripted before; complexities
6344 arise with respect to updating the collective subscript information.
6345
6346 If a macro type is detected anywhere along path~|t|, or if the first
6347 item on |t| isn't a |tag_token|, the value |null| is returned.
6348 Otherwise |p| will be a non-null pointer to a node such that
6349 |undefined<type(p)<mp_structured|.
6350
6351 @d abort_find { return null; }
6352
6353 @c 
6354 pointer mp_find_variable (MP mp,pointer t) {
6355   pointer p,q,r,s; /* nodes in the ``value'' line */
6356   pointer pp,qq,rr,ss; /* nodes in the ``collective'' line */
6357   integer n; /* subscript or attribute */
6358   memory_word save_word; /* temporary storage for a word of |mem| */
6359 @^inner loop@>
6360   p=info(t); t=link(t);
6361   if ( (eq_type(p) % outer_tag) != tag_token ) abort_find;
6362   if ( equiv(p)==null ) mp_new_root(mp, p);
6363   p=equiv(p); pp=p;
6364   while ( t!=null ) { 
6365     @<Make sure that both nodes |p| and |pp| are of |mp_structured| type@>;
6366     if ( t<mp->hi_mem_min ) {
6367       @<Descend one level for the subscript |value(t)|@>
6368     } else {
6369       @<Descend one level for the attribute |info(t)|@>;
6370     }
6371     t=link(t);
6372   }
6373   if ( type(pp)>=mp_structured ) {
6374     if ( type(pp)==mp_structured ) pp=attr_head(pp); else abort_find;
6375   }
6376   if ( type(p)==mp_structured ) p=attr_head(p);
6377   if ( type(p)==undefined ) { 
6378     if ( type(pp)==undefined ) { type(pp)=mp_numeric_type; value(pp)=null; };
6379     type(p)=type(pp); value(p)=null;
6380   };
6381   return p;
6382 }
6383
6384 @ Although |pp| and |p| begin together, they diverge when a subscript occurs;
6385 |pp|~stays in the collective line while |p|~goes through actual subscript
6386 values.
6387
6388 @<Make sure that both nodes |p| and |pp|...@>=
6389 if ( type(pp)!=mp_structured ) { 
6390   if ( type(pp)>mp_structured ) abort_find;
6391   ss=mp_new_structure(mp, pp);
6392   if ( p==pp ) p=ss;
6393   pp=ss;
6394 }; /* now |type(pp)=mp_structured| */
6395 if ( type(p)!=mp_structured ) /* it cannot be |>mp_structured| */
6396   p=mp_new_structure(mp, p) /* now |type(p)=mp_structured| */
6397
6398 @ We want this part of the program to be reasonably fast, in case there are
6399 @^inner loop@>
6400 lots of subscripts at the same level of the data structure. Therefore
6401 we store an ``infinite'' value in the word that appears at the end of the
6402 subscript list, even though that word isn't part of a subscript node.
6403
6404 @<Descend one level for the subscript |value(t)|@>=
6405
6406   n=value(t);
6407   pp=link(attr_head(pp)); /* now |attr_loc(pp)=collective_subscript| */
6408   q=link(attr_head(p)); save_word=mp->mem[subscript_loc(q)];
6409   subscript(q)=el_gordo; s=subscr_head_loc(p); /* |link(s)=subscr_head(p)| */
6410   do {  
6411     r=s; s=link(s);
6412   } while (n>subscript(s));
6413   if ( n==subscript(s) ) {
6414     p=s;
6415   } else { 
6416     p=mp_get_node(mp, subscr_node_size); link(r)=p; link(p)=s;
6417     subscript(p)=n; name_type(p)=mp_subscr; type(p)=undefined;
6418   }
6419   mp->mem[subscript_loc(q)]=save_word;
6420 }
6421
6422 @ @<Descend one level for the attribute |info(t)|@>=
6423
6424   n=info(t);
6425   ss=attr_head(pp);
6426   do {  
6427     rr=ss; ss=link(ss);
6428   } while (n>attr_loc(ss));
6429   if ( n<attr_loc(ss) ) { 
6430     qq=mp_get_node(mp, attr_node_size); link(rr)=qq; link(qq)=ss;
6431     attr_loc(qq)=n; name_type(qq)=mp_attr; type(qq)=undefined;
6432     parent(qq)=pp; ss=qq;
6433   }
6434   if ( p==pp ) { 
6435     p=ss; pp=ss;
6436   } else { 
6437     pp=ss; s=attr_head(p);
6438     do {  
6439       r=s; s=link(s);
6440     } while (n>attr_loc(s));
6441     if ( n==attr_loc(s) ) {
6442       p=s;
6443     } else { 
6444       q=mp_get_node(mp, attr_node_size); link(r)=q; link(q)=s;
6445       attr_loc(q)=n; name_type(q)=mp_attr; type(q)=undefined;
6446       parent(q)=p; p=q;
6447     }
6448   }
6449 }
6450
6451 @ Variables lose their former values when they appear in a type declaration,
6452 or when they are defined to be macros or \&{let} equal to something else.
6453 A subroutine will be defined later that recycles the storage associated
6454 with any particular |type| or |value|; our goal now is to study a higher
6455 level process called |flush_variable|, which selectively frees parts of a
6456 variable structure.
6457
6458 This routine has some complexity because of examples such as
6459 `\hbox{\tt numeric x[]a[]b}'
6460 which recycles all variables of the form \.{x[i]a[j]b} (and no others), while
6461 `\hbox{\tt vardef x[]a[]=...}'
6462 discards all variables of the form \.{x[i]a[j]} followed by an arbitrary
6463 suffix, except for the collective node \.{x[]a[]} itself. The obvious way
6464 to handle such examples is to use recursion; so that's what we~do.
6465 @^recursion@>
6466
6467 Parameter |p| points to the root information of the variable;
6468 parameter |t| points to a list of one-word nodes that represent
6469 suffixes, with |info=collective_subscript| for subscripts.
6470
6471 @<Declarations@>=
6472 @<Declare subroutines for printing expressions@>
6473 @<Declare basic dependency-list subroutines@>
6474 @<Declare the recycling subroutines@>
6475 void mp_flush_cur_exp (MP mp,scaled v) ;
6476 @<Declare the procedure called |flush_below_variable|@>
6477
6478 @ @c 
6479 void mp_flush_variable (MP mp,pointer p, pointer t, boolean discard_suffixes) {
6480   pointer q,r; /* list manipulation */
6481   halfword n; /* attribute to match */
6482   while ( t!=null ) { 
6483     if ( type(p)!=mp_structured ) return;
6484     n=info(t); t=link(t);
6485     if ( n==collective_subscript ) { 
6486       r=subscr_head_loc(p); q=link(r); /* |q=subscr_head(p)| */
6487       while ( name_type(q)==mp_subscr ){ 
6488         mp_flush_variable(mp, q,t,discard_suffixes);
6489         if ( t==null ) {
6490           if ( type(q)==mp_structured ) r=q;
6491           else  { link(r)=link(q); mp_free_node(mp, q,subscr_node_size);   }
6492         } else {
6493           r=q;
6494         }
6495         q=link(r);
6496       }
6497     }
6498     p=attr_head(p);
6499     do {  
6500       r=p; p=link(p);
6501     } while (attr_loc(p)<n);
6502     if ( attr_loc(p)!=n ) return;
6503   }
6504   if ( discard_suffixes ) {
6505     mp_flush_below_variable(mp, p);
6506   } else { 
6507     if ( type(p)==mp_structured ) p=attr_head(p);
6508     mp_recycle_value(mp, p);
6509   }
6510 }
6511
6512 @ The next procedure is simpler; it wipes out everything but |p| itself,
6513 which becomes undefined.
6514
6515 @<Declare the procedure called |flush_below_variable|@>=
6516 void mp_flush_below_variable (MP mp, pointer p);
6517
6518 @ @c
6519 void mp_flush_below_variable (MP mp,pointer p) {
6520    pointer q,r; /* list manipulation registers */
6521   if ( type(p)!=mp_structured ) {
6522     mp_recycle_value(mp, p); /* this sets |type(p)=undefined| */
6523   } else { 
6524     q=subscr_head(p);
6525     while ( name_type(q)==mp_subscr ) { 
6526       mp_flush_below_variable(mp, q); r=q; q=link(q);
6527       mp_free_node(mp, r,subscr_node_size);
6528     }
6529     r=attr_head(p); q=link(r); mp_recycle_value(mp, r);
6530     if ( name_type(p)<=mp_saved_root ) mp_free_node(mp, r,value_node_size);
6531     else mp_free_node(mp, r,subscr_node_size);
6532     /* we assume that |subscr_node_size=attr_node_size| */
6533     do {  
6534       mp_flush_below_variable(mp, q); r=q; q=link(q); mp_free_node(mp, r,attr_node_size);
6535     } while (q!=end_attr);
6536     type(p)=undefined;
6537   }
6538 }
6539
6540 @ Just before assigning a new value to a variable, we will recycle the
6541 old value and make the old value undefined. The |und_type| routine
6542 determines what type of undefined value should be given, based on
6543 the current type before recycling.
6544
6545 @c 
6546 small_number mp_und_type (MP mp,pointer p) { 
6547   switch (type(p)) {
6548   case undefined: case mp_vacuous:
6549     return undefined;
6550   case mp_boolean_type: case mp_unknown_boolean:
6551     return mp_unknown_boolean;
6552   case mp_string_type: case mp_unknown_string:
6553     return mp_unknown_string;
6554   case mp_pen_type: case mp_unknown_pen:
6555     return mp_unknown_pen;
6556   case mp_path_type: case mp_unknown_path:
6557     return mp_unknown_path;
6558   case mp_picture_type: case mp_unknown_picture:
6559     return mp_unknown_picture;
6560   case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
6561   case mp_pair_type: case mp_numeric_type: 
6562     return type(p);
6563   case mp_known: case mp_dependent: case mp_proto_dependent: case mp_independent:
6564     return mp_numeric_type;
6565   } /* there are no other cases */
6566   return 0;
6567 }
6568
6569 @ The |clear_symbol| routine is used when we want to redefine the equivalent
6570 of a symbolic token. It must remove any variable structure or macro
6571 definition that is currently attached to that symbol. If the |saving|
6572 parameter is true, a subsidiary structure is saved instead of destroyed.
6573
6574 @c 
6575 void mp_clear_symbol (MP mp,pointer p, boolean saving) {
6576   pointer q; /* |equiv(p)| */
6577   q=equiv(p);
6578   switch (eq_type(p) % outer_tag)  {
6579   case defined_macro:
6580   case secondary_primary_macro:
6581   case tertiary_secondary_macro:
6582   case expression_tertiary_macro: 
6583     if ( ! saving ) mp_delete_mac_ref(mp, q);
6584     break;
6585   case tag_token:
6586     if ( q!=null ) {
6587       if ( saving ) {
6588         name_type(q)=mp_saved_root;
6589       } else { 
6590         mp_flush_below_variable(mp, q); mp_free_node(mp,q,value_node_size); 
6591       }
6592     }
6593     break;
6594   default:
6595     break;
6596   }
6597   mp->eqtb[p]=mp->eqtb[frozen_undefined];
6598 };
6599
6600 @* \[16] Saving and restoring equivalents.
6601 The nested structure given by \&{begingroup} and \&{endgroup}
6602 allows |eqtb| entries to be saved and restored, so that temporary changes
6603 can be made without difficulty.  When the user requests a current value to
6604 be saved, \MP\ puts that value into its ``save stack.'' An appearance of
6605 \&{endgroup} ultimately causes the old values to be removed from the save
6606 stack and put back in their former places.
6607
6608 The save stack is a linked list containing three kinds of entries,
6609 distinguished by their |info| fields. If |p| points to a saved item,
6610 then
6611
6612 \smallskip\hang
6613 |info(p)=0| stands for a group boundary; each \&{begingroup} contributes
6614 such an item to the save stack and each \&{endgroup} cuts back the stack
6615 until the most recent such entry has been removed.
6616
6617 \smallskip\hang
6618 |info(p)=q|, where |1<=q<=hash_end|, means that |mem[p+1]| holds the former
6619 contents of |eqtb[q]|. Such save stack entries are generated by \&{save}
6620 commands or suitable \&{interim} commands.
6621
6622 \smallskip\hang
6623 |info(p)=hash_end+q|, where |q>0|, means that |value(p)| is a |scaled|
6624 integer to be restored to internal parameter number~|q|. Such entries
6625 are generated by \&{interim} commands.
6626
6627 \smallskip\noindent
6628 The global variable |save_ptr| points to the top item on the save stack.
6629
6630 @d save_node_size 2 /* number of words per non-boundary save-stack node */
6631 @d saved_equiv(A) mp->mem[(A)+1].hh /* where an |eqtb| entry gets saved */
6632 @d save_boundary_item(A) { (A)=mp_get_avail(mp); info((A))=0;
6633   link((A))=mp->save_ptr; mp->save_ptr=(A);
6634   }
6635
6636 @<Glob...@>=
6637 pointer save_ptr; /* the most recently saved item */
6638
6639 @ @<Set init...@>=mp->save_ptr=null;
6640
6641 @ The |save_variable| routine is given a hash address |q|; it salts this
6642 address in the save stack, together with its current equivalent,
6643 then makes token~|q| behave as though it were brand new.
6644
6645 Nothing is stacked when |save_ptr=null|, however; there's no way to remove
6646 things from the stack when the program is not inside a group, so there's
6647 no point in wasting the space.
6648
6649 @c void mp_save_variable (MP mp,pointer q) {
6650   pointer p; /* temporary register */
6651   if ( mp->save_ptr!=null ){ 
6652     p=mp_get_node(mp, save_node_size); info(p)=q; link(p)=mp->save_ptr;
6653     saved_equiv(p)=mp->eqtb[q]; mp->save_ptr=p;
6654   }
6655   mp_clear_symbol(mp, q,(mp->save_ptr!=null));
6656 }
6657
6658 @ Similarly, |save_internal| is given the location |q| of an internal
6659 quantity like |tracing_pens|. It creates a save stack entry of the
6660 third kind.
6661
6662 @c void mp_save_internal (MP mp,halfword q) {
6663   pointer p; /* new item for the save stack */
6664   if ( mp->save_ptr!=null ){ 
6665      p=mp_get_node(mp, save_node_size); info(p)=hash_end+q;
6666     link(p)=mp->save_ptr; value(p)=mp->internal[q]; mp->save_ptr=p;
6667   }
6668 }
6669
6670 @ At the end of a group, the |unsave| routine restores all of the saved
6671 equivalents in reverse order. This routine will be called only when there
6672 is at least one boundary item on the save stack.
6673
6674 @c 
6675 void mp_unsave (MP mp) {
6676   pointer q; /* index to saved item */
6677   pointer p; /* temporary register */
6678   while ( info(mp->save_ptr)!=0 ) {
6679     q=info(mp->save_ptr);
6680     if ( q>hash_end ) {
6681       if ( mp->internal[tracing_restores]>0 ) {
6682         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6683         mp_print(mp, mp->int_name[q-(hash_end)]); mp_print_char(mp, '=');
6684         mp_print_scaled(mp, value(mp->save_ptr)); mp_print_char(mp, '}');
6685         mp_end_diagnostic(mp, false);
6686       }
6687       mp->internal[q-(hash_end)]=value(mp->save_ptr);
6688     } else { 
6689       if ( mp->internal[tracing_restores]>0 ) {
6690         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6691         mp_print_text(q); mp_print_char(mp, '}');
6692         mp_end_diagnostic(mp, false);
6693       }
6694       mp_clear_symbol(mp, q,false);
6695       mp->eqtb[q]=saved_equiv(mp->save_ptr);
6696       if ( eq_type(q) % outer_tag==tag_token ) {
6697         p=equiv(q);
6698         if ( p!=null ) name_type(p)=mp_root;
6699       }
6700     }
6701     p=link(mp->save_ptr); 
6702     mp_free_node(mp, mp->save_ptr,save_node_size); mp->save_ptr=p;
6703   }
6704   p=link(mp->save_ptr); free_avail(mp->save_ptr); mp->save_ptr=p;
6705 }
6706
6707 @* \[17] Data structures for paths.
6708 When a \MP\ user specifies a path, \MP\ will create a list of knots
6709 and control points for the associated cubic spline curves. If the
6710 knots are $z_0$, $z_1$, \dots, $z_n$, there are control points
6711 $z_k^+$ and $z_{k+1}^-$ such that the cubic splines between knots
6712 $z_k$ and $z_{k+1}$ are defined by B\'ezier's formula
6713 @:Bezier}{B\'ezier, Pierre Etienne@>
6714 $$\eqalign{z(t)&=B(z_k,z_k^+,z_{k+1}^-,z_{k+1};t)\cr
6715 &=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_{k+1}^-+t^3z_{k+1}\cr}$$
6716 for |0<=t<=1|.
6717
6718 There is a 8-word node for each knot $z_k$, containing one word of
6719 control information and six words for the |x| and |y| coordinates of
6720 $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears in the
6721 |left_type| and |right_type| fields, which each occupy a quarter of
6722 the first word in the node; they specify properties of the curve as it
6723 enters and leaves the knot. There's also a halfword |link| field,
6724 which points to the following knot, and a final supplementary word (of
6725 which only a quarter is used).
6726
6727 If the path is a closed contour, knots 0 and |n| are identical;
6728 i.e., the |link| in knot |n-1| points to knot~0. But if the path
6729 is not closed, the |left_type| of knot~0 and the |right_type| of knot~|n|
6730 are equal to |endpoint|. In the latter case the |link| in knot~|n| points
6731 to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used.
6732
6733 @d left_type(A)   mp->mem[(A)].hh.b0 /* characterizes the path entering this knot */
6734 @d right_type(A)   mp->mem[(A)].hh.b1 /* characterizes the path leaving this knot */
6735 @d endpoint 0 /* |left_type| at path beginning and |right_type| at path end */
6736 @d x_coord(A)   mp->mem[(A)+1].sc /* the |x| coordinate of this knot */
6737 @d y_coord(A)   mp->mem[(A)+2].sc /* the |y| coordinate of this knot */
6738 @d left_x(A)   mp->mem[(A)+3].sc /* the |x| coordinate of previous control point */
6739 @d left_y(A)   mp->mem[(A)+4].sc /* the |y| coordinate of previous control point */
6740 @d right_x(A)   mp->mem[(A)+5].sc /* the |x| coordinate of next control point */
6741 @d right_y(A)   mp->mem[(A)+6].sc /* the |y| coordinate of next control point */
6742 @d x_loc(A)   ((A)+1) /* where the |x| coordinate is stored in a knot */
6743 @d y_loc(A)   ((A)+2) /* where the |y| coordinate is stored in a knot */
6744 @d knot_coord(A)   mp->mem[(A)].sc /* |x| or |y| coordinate given |x_loc| or |y_loc| */
6745 @d left_coord(A)   mp->mem[(A)+2].sc
6746   /* coordinate of previous control point given |x_loc| or |y_loc| */
6747 @d right_coord(A)   mp->mem[(A)+4].sc
6748   /* coordinate of next control point given |x_loc| or |y_loc| */
6749 @d knot_node_size 8 /* number of words in a knot node */
6750
6751 @ Before the B\'ezier control points have been calculated, the memory
6752 space they will ultimately occupy is taken up by information that can be
6753 used to compute them. There are four cases:
6754
6755 \yskip
6756 \textindent{$\bullet$} If |right_type=open|, the curve should leave
6757 the knot in the same direction it entered; \MP\ will figure out a
6758 suitable direction.
6759
6760 \yskip
6761 \textindent{$\bullet$} If |right_type=curl|, the curve should leave the
6762 knot in a direction depending on the angle at which it enters the next
6763 knot and on the curl parameter stored in |right_curl|.
6764
6765 \yskip
6766 \textindent{$\bullet$} If |right_type=given|, the curve should leave the
6767 knot in a nonzero direction stored as an |angle| in |right_given|.
6768
6769 \yskip
6770 \textindent{$\bullet$} If |right_type=explicit|, the B\'ezier control
6771 point for leaving this knot has already been computed; it is in the
6772 |right_x| and |right_y| fields.
6773
6774 \yskip\noindent
6775 The rules for |left_type| are similar, but they refer to the curve entering
6776 the knot, and to \\{left} fields instead of \\{right} fields.
6777
6778 Non-|explicit| control points will be chosen based on ``tension'' parameters
6779 in the |left_tension| and |right_tension| fields. The
6780 `\&{atleast}' option is represented by negative tension values.
6781 @:at_least_}{\&{atleast} primitive@>
6782
6783 For example, the \MP\ path specification
6784 $$\.{z0..z1..tension atleast 1..\{curl 2\}z2..z3\{-1,-2\}..tension
6785   3 and 4..p},$$
6786 where \.p is the path `\.{z4..controls z45 and z54..z5}', will be represented
6787 by the six knots
6788 \def\lodash{\hbox to 1.1em{\thinspace\hrulefill\thinspace}}
6789 $$\vbox{\halign{#\hfil&&\qquad#\hfil\cr
6790 |left_type|&\\{left} info&|x_coord,y_coord|&|right_type|&\\{right} info\cr
6791 \noalign{\yskip}
6792 |endpoint|&\lodash$,\,$\lodash&$x_0,y_0$&|curl|&$1.0,1.0$\cr
6793 |open|&\lodash$,1.0$&$x_1,y_1$&|open|&\lodash$,-1.0$\cr
6794 |curl|&$2.0,-1.0$&$x_2,y_2$&|curl|&$2.0,1.0$\cr
6795 |given|&$d,1.0$&$x_3,y_3$&|given|&$d,3.0$\cr
6796 |open|&\lodash$,4.0$&$x_4,y_4$&|explicit|&$x_{45},y_{45}$\cr
6797 |explicit|&$x_{54},y_{54}$&$x_5,y_5$&|endpoint|&\lodash$,\,$\lodash\cr}}$$
6798 Here |d| is the |angle| obtained by calling |n_arg(-unity,-two)|.
6799 Of course, this example is more complicated than anything a normal user
6800 would ever write.
6801
6802 These types must satisfy certain restrictions because of the form of \MP's
6803 path syntax:
6804 (i)~|open| type never appears in the same node together with |endpoint|,
6805 |given|, or |curl|.
6806 (ii)~The |right_type| of a node is |explicit| if and only if the
6807 |left_type| of the following node is |explicit|.
6808 (iii)~|endpoint| types occur only at the ends, as mentioned above.
6809
6810 @d left_curl left_x /* curl information when entering this knot */
6811 @d left_given left_x /* given direction when entering this knot */
6812 @d left_tension left_y /* tension information when entering this knot */
6813 @d right_curl right_x /* curl information when leaving this knot */
6814 @d right_given right_x /* given direction when leaving this knot */
6815 @d right_tension right_y /* tension information when leaving this knot */
6816 @d explicit 1 /* |left_type| or |right_type| when control points are known */
6817 @d given 2 /* |left_type| or |right_type| when a direction is given */
6818 @d curl 3 /* |left_type| or |right_type| when a curl is desired */
6819 @d open 4 /* |left_type| or |right_type| when \MP\ should choose the direction */
6820
6821 @ Knots can be user-supplied, or they can be created by program code,
6822 like the |split_cubic| function, or |copy_path|. The distinction is
6823 needed for the cleanup routine that runs after |split_cubic|, because
6824 it should only delete knots it has previously inserted, and never
6825 anything that was user-supplied. In order to be able to differentiate
6826 one knot from another, we will set |originator(p):=metapost_user| when
6827 it appeared in the actual metapost program, and
6828 |originator(p):=program_code| in all other cases.
6829
6830 @d originator(A)   mp->mem[(A)+7].hh.b0 /* the creator of this knot */
6831 @d program_code 0 /* not created by a user */
6832 @d metapost_user 1 /* created by a user */
6833
6834 @ Here is a routine that prints a given knot list
6835 in symbolic form. It illustrates the conventions discussed above,
6836 and checks for anomalies that might arise while \MP\ is being debugged.
6837
6838 @<Declare subroutines for printing expressions@>=
6839 void mp_pr_path (MP mp,pointer h);
6840
6841 @ @c
6842 void mp_pr_path (MP mp,pointer h) {
6843   pointer p,q; /* for list traversal */
6844   p=h;
6845   do {  
6846     q=link(p);
6847     if ( (p==null)||(q==null) ) { 
6848       mp_print_nl(mp, "???"); return; /* this won't happen */
6849 @.???@>
6850     }
6851     @<Print information for adjacent knots |p| and |q|@>;
6852   DONE1:
6853     p=q;
6854     if ( (p!=h)||(left_type(h)!=endpoint) ) {
6855       @<Print two dots, followed by |given| or |curl| if present@>;
6856     }
6857   } while (p!=h);
6858   if ( left_type(h)!=endpoint ) 
6859     mp_print(mp, "cycle");
6860 }
6861
6862 @ @<Print information for adjacent knots...@>=
6863 mp_print_two(mp, x_coord(p),y_coord(p));
6864 switch (right_type(p)) {
6865 case endpoint: 
6866   if ( left_type(p)==open ) mp_print(mp, "{open?}"); /* can't happen */
6867 @.open?@>
6868   if ( (left_type(q)!=endpoint)||(q!=h) ) q=null; /* force an error */
6869   goto DONE1;
6870   break;
6871 case explicit: 
6872   @<Print control points between |p| and |q|, then |goto done1|@>;
6873   break;
6874 case open: 
6875   @<Print information for a curve that begins |open|@>;
6876   break;
6877 case curl:
6878 case given: 
6879   @<Print information for a curve that begins |curl| or |given|@>;
6880   break;
6881 default:
6882   mp_print(mp, "???"); /* can't happen */
6883 @.???@>
6884   break;
6885 }
6886 if ( left_type(q)<=explicit ) {
6887   mp_print(mp, "..control?"); /* can't happen */
6888 @.control?@>
6889 } else if ( (right_tension(p)!=unity)||(left_tension(q)!=unity) ) {
6890   @<Print tension between |p| and |q|@>;
6891 }
6892
6893 @ Since |n_sin_cos| produces |fraction| results, which we will print as if they
6894 were |scaled|, the magnitude of a |given| direction vector will be~4096.
6895
6896 @<Print two dots...@>=
6897
6898   mp_print_nl(mp, " ..");
6899   if ( left_type(p)==given ) { 
6900     mp_n_sin_cos(mp, left_given(p)); mp_print_char(mp, '{');
6901     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ',');
6902     mp_print_scaled(mp, mp->n_sin); mp_print_char(mp, '}');
6903   } else if ( left_type(p)==curl ){ 
6904     mp_print(mp, "{curl "); 
6905     mp_print_scaled(mp, left_curl(p)); mp_print_char(mp, '}');
6906   }
6907 }
6908
6909 @ @<Print tension between |p| and |q|@>=
6910
6911   mp_print(mp, "..tension ");
6912   if ( right_tension(p)<0 ) mp_print(mp, "atleast");
6913   mp_print_scaled(mp, abs(right_tension(p)));
6914   if ( right_tension(p)!=left_tension(q) ){ 
6915     mp_print(mp, " and ");
6916     if ( left_tension(q)<0 ) mp_print(mp, "atleast");
6917     mp_print_scaled(mp, abs(left_tension(q)));
6918   }
6919 }
6920
6921 @ @<Print control points between |p| and |q|, then |goto done1|@>=
6922
6923   mp_print(mp, "..controls "); 
6924   mp_print_two(mp, right_x(p),right_y(p)); 
6925   mp_print(mp, " and ");
6926   if ( left_type(q)!=explicit ) { 
6927     mp_print(mp, "??"); /* can't happen */
6928 @.??@>
6929   } else {
6930     mp_print_two(mp, left_x(q),left_y(q));
6931   }
6932   goto DONE1;
6933 }
6934
6935 @ @<Print information for a curve that begins |open|@>=
6936 if ( (left_type(p)!=explicit)&&(left_type(p)!=open) ) {
6937   mp_print(mp, "{open?}"); /* can't happen */
6938 @.open?@>
6939 }
6940
6941 @ A curl of 1 is shown explicitly, so that the user sees clearly that
6942 \MP's default curl is present.
6943
6944 The code here uses the fact that |left_curl==left_given| and
6945 |right_curl==right_given|.
6946
6947 @<Print information for a curve that begins |curl|...@>=
6948
6949   if ( left_type(p)==open )  
6950     mp_print(mp, "??"); /* can't happen */
6951 @.??@>
6952   if ( right_type(p)==curl ) { 
6953     mp_print(mp, "{curl "); mp_print_scaled(mp, right_curl(p));
6954   } else { 
6955     mp_n_sin_cos(mp, right_given(p)); mp_print_char(mp, '{');
6956     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ','); 
6957     mp_print_scaled(mp, mp->n_sin);
6958   }
6959   mp_print_char(mp, '}');
6960 }
6961
6962 @ It is convenient to have another version of |pr_path| that prints the path
6963 as a diagnostic message.
6964
6965 @<Declare subroutines for printing expressions@>=
6966 void mp_print_path (MP mp,pointer h, char *s, boolean nuline) { 
6967   mp_print_diagnostic(mp, "Path", s, nuline); mp_print_ln(mp);
6968 @.Path at line...@>
6969   mp_pr_path(mp, h);
6970   mp_end_diagnostic(mp, true);
6971 }
6972
6973 @ If we want to duplicate a knot node, we can say |copy_knot|:
6974
6975 @c 
6976 pointer mp_copy_knot (MP mp,pointer p) {
6977   pointer q; /* the copy */
6978   int k; /* runs through the words of a knot node */
6979   q=mp_get_node(mp, knot_node_size);
6980   for (k=0;k<=knot_node_size-1;k++) {
6981     mp->mem[q+k]=mp->mem[p+k];
6982   }
6983   originator(q)=originator(p);
6984   return q;
6985 }
6986
6987 @ The |copy_path| routine makes a clone of a given path.
6988
6989 @c 
6990 pointer mp_copy_path (MP mp, pointer p) {
6991   pointer q,pp,qq; /* for list manipulation */
6992   q=mp_copy_knot(mp, p);
6993   qq=q; pp=link(p);
6994   while ( pp!=p ) { 
6995     link(qq)=mp_copy_knot(mp, pp);
6996     qq=link(qq);
6997     pp=link(pp);
6998   }
6999   link(qq)=q;
7000   return q;
7001 }
7002
7003 @ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure
7004 returns a pointer to the first node of the copy, if the path is a cycle,
7005 but to the final node of a non-cyclic copy. The global
7006 variable |path_tail| will point to the final node of the original path;
7007 this trick makes it easier to implement `\&{doublepath}'.
7008
7009 All node types are assumed to be |endpoint| or |explicit| only.
7010
7011 @c 
7012 pointer mp_htap_ypoc (MP mp,pointer p) {
7013   pointer q,pp,qq,rr; /* for list manipulation */
7014   q=mp_get_node(mp, knot_node_size); /* this will correspond to |p| */
7015   qq=q; pp=p;
7016   while (1) { 
7017     right_type(qq)=left_type(pp); left_type(qq)=right_type(pp);
7018     x_coord(qq)=x_coord(pp); y_coord(qq)=y_coord(pp);
7019     right_x(qq)=left_x(pp); right_y(qq)=left_y(pp);
7020     left_x(qq)=right_x(pp); left_y(qq)=right_y(pp);
7021     originator(qq)=originator(pp);
7022     if ( link(pp)==p ) { 
7023       link(q)=qq; mp->path_tail=pp; return q;
7024     }
7025     rr=mp_get_node(mp, knot_node_size); link(rr)=qq; qq=rr; pp=link(pp);
7026   }
7027 }
7028
7029 @ @<Glob...@>=
7030 pointer path_tail; /* the node that links to the beginning of a path */
7031
7032 @ When a cyclic list of knot nodes is no longer needed, it can be recycled by
7033 calling the following subroutine.
7034
7035 @<Declare the recycling subroutines@>=
7036 void mp_toss_knot_list (MP mp,pointer p) ;
7037
7038 @ @c
7039 void mp_toss_knot_list (MP mp,pointer p) {
7040   pointer q; /* the node being freed */
7041   pointer r; /* the next node */
7042   q=p;
7043   do {  
7044     r=link(q); 
7045     mp_free_node(mp, q,knot_node_size); q=r;
7046   } while (q!=p);
7047 }
7048
7049 @* \[18] Choosing control points.
7050 Now we must actually delve into one of \MP's more difficult routines,
7051 the |make_choices| procedure that chooses angles and control points for
7052 the splines of a curve when the user has not specified them explicitly.
7053 The parameter to |make_choices| points to a list of knots and
7054 path information, as described above.
7055
7056 A path decomposes into independent segments at ``breakpoint'' knots,
7057 which are knots whose left and right angles are both prespecified in
7058 some way (i.e., their |left_type| and |right_type| aren't both open).
7059
7060 @c 
7061 @<Declare the procedure called |solve_choices|@>;
7062 void mp_make_choices (MP mp,pointer knots) {
7063   pointer h; /* the first breakpoint */
7064   pointer p,q; /* consecutive breakpoints being processed */
7065   @<Other local variables for |make_choices|@>;
7066   check_arith; /* make sure that |arith_error=false| */
7067   if ( mp->internal[tracing_choices]>0 )
7068     mp_print_path(mp, knots,", before choices",true);
7069   @<If consecutive knots are equal, join them explicitly@>;
7070   @<Find the first breakpoint, |h|, on the path;
7071     insert an artificial breakpoint if the path is an unbroken cycle@>;
7072   p=h;
7073   do {  
7074     @<Fill in the control points between |p| and the next breakpoint,
7075       then advance |p| to that breakpoint@>;
7076   } while (p!=h);
7077   if ( mp->internal[tracing_choices]>0 )
7078     mp_print_path(mp, knots,", after choices",true);
7079   if ( mp->arith_error ) {
7080     @<Report an unexpected problem during the choice-making@>;
7081   }
7082 }
7083
7084 @ @<Report an unexpected problem during the choice...@>=
7085
7086   print_err("Some number got too big");
7087 @.Some number got too big@>
7088   help2("The path that I just computed is out of range.")
7089        ("So it will probably look funny. Proceed, for a laugh.");
7090   mp_put_get_error(mp); mp->arith_error=false;
7091 }
7092
7093 @ Two knots in a row with the same coordinates will always be joined
7094 by an explicit ``curve'' whose control points are identical with the
7095 knots.
7096
7097 @<If consecutive knots are equal, join them explicitly@>=
7098 p=knots;
7099 do {  
7100   q=link(p);
7101   if ( x_coord(p)==x_coord(q) && y_coord(p)==y_coord(q) && right_type(p)>explicit ) { 
7102     right_type(p)=explicit;
7103     if ( left_type(p)==open ) { 
7104       left_type(p)=curl; left_curl(p)=unity;
7105     }
7106     left_type(q)=explicit;
7107     if ( right_type(q)==open ) { 
7108       right_type(q)=curl; right_curl(q)=unity;
7109     }
7110     right_x(p)=x_coord(p); left_x(q)=x_coord(p);
7111     right_y(p)=y_coord(p); left_y(q)=y_coord(p);
7112   }
7113   p=q;
7114 } while (p!=knots)
7115
7116 @ If there are no breakpoints, it is necessary to compute the direction
7117 angles around an entire cycle. In this case the |left_type| of the first
7118 node is temporarily changed to |end_cycle|.
7119
7120 @d end_cycle (open+1)
7121
7122 @<Find the first breakpoint, |h|, on the path...@>=
7123 h=knots;
7124 while (1) { 
7125   if ( left_type(h)!=open ) break;
7126   if ( right_type(h)!=open ) break;
7127   h=link(h);
7128   if ( h==knots ) { 
7129     left_type(h)=end_cycle; break;
7130   }
7131 }
7132
7133 @ If |right_type(p)<given| and |q=link(p)|, we must have
7134 |right_type(p)=left_type(q)=explicit| or |endpoint|.
7135
7136 @<Fill in the control points between |p| and the next breakpoint...@>=
7137 q=link(p);
7138 if ( right_type(p)>=given ) { 
7139   while ( (left_type(q)==open)&&(right_type(q)==open) ) q=link(q);
7140   @<Fill in the control information between
7141     consecutive breakpoints |p| and |q|@>;
7142 } else if ( right_type(p)==endpoint ) {
7143   @<Give reasonable values for the unused control points between |p| and~|q|@>;
7144 }
7145 p=q
7146
7147 @ This step makes it possible to transform an explicitly computed path without
7148 checking the |left_type| and |right_type| fields.
7149
7150 @<Give reasonable values for the unused control points between |p| and~|q|@>=
7151
7152   right_x(p)=x_coord(p); right_y(p)=y_coord(p);
7153   left_x(q)=x_coord(q); left_y(q)=y_coord(q);
7154 }
7155
7156 @ Before we can go further into the way choices are made, we need to
7157 consider the underlying theory. The basic ideas implemented in |make_choices|
7158 are due to John Hobby, who introduced the notion of ``mock curvature''
7159 @^Hobby, John Douglas@>
7160 at a knot. Angles are chosen so that they preserve mock curvature when
7161 a knot is passed, and this has been found to produce excellent results.
7162
7163 It is convenient to introduce some notations that simplify the necessary
7164 formulas. Let $d_{k,k+1}=\vert z\k-z_k\vert$ be the (nonzero) distance
7165 between knots |k| and |k+1|; and let
7166 $${z\k-z_k\over z_k-z_{k-1}}={d_{k,k+1}\over d_{k-1,k}}e^{i\psi_k}$$
7167 so that a polygonal line from $z_{k-1}$ to $z_k$ to $z\k$ turns left
7168 through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$.
7169 The control points for the spline from $z_k$ to $z\k$ will be denoted by
7170 $$\eqalign{z_k^+&=z_k+
7171   \textstyle{1\over3}\rho_k e^{i\theta_k}(z\k-z_k),\cr
7172  z\k^-&=z\k-
7173   \textstyle{1\over3}\sigma\k e^{-i\phi\k}(z\k-z_k),\cr}$$
7174 where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the
7175 beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the
7176 corresponding ``offset angles.'' These angles satisfy the condition
7177 $$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$
7178 whenever the curve leaves an intermediate knot~|k| in the direction that
7179 it enters.
7180
7181 @ Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of
7182 the curve at its beginning and ending points. This means that
7183 $\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$,
7184 where $f(\theta,\phi)$ is \MP's standard velocity function defined in
7185 the |velocity| subroutine. The cubic spline $B(z_k^{\phantom+},z_k^+,
7186 z\k^-,z\k^{\phantom+};t)$
7187 has curvature
7188 @^curvature@>
7189 $${2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_{k,k+1}}
7190 \qquad{\rm and}\qquad
7191 {2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_{k,k+1}}$$
7192 at |t=0| and |t=1|, respectively. The mock curvature is the linear
7193 @^mock curvature@>
7194 approximation to this true curvature that arises in the limit for
7195 small $\theta_k$ and~$\phi\k$, if second-order terms are discarded.
7196 The standard velocity function satisfies
7197 $$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$
7198 hence the mock curvatures are respectively
7199 $${2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_{k,k+1}}
7200 \qquad{\rm and}\qquad
7201 {2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_{k,k+1}}.\eqno(**)$$
7202
7203 @ The turning angles $\psi_k$ are given, and equation $(*)$ above
7204 determines $\phi_k$ when $\theta_k$ is known, so the task of
7205 angle selection is essentially to choose appropriate values for each
7206 $\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables
7207 from $(**)$, we obtain a system of linear equations of the form
7208 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7209 where
7210 $$A_k={\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7211 \qquad B_k={3-\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7212 \qquad C_k={3-\beta\k\over\alpha_k^2d_{k,k+1}},
7213 \qquad D_k={\beta\k\over\alpha_k^2d_{k,k+1}}.$$
7214 The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$
7215 will be at most $4\over3$. It follows that $B_k\G{5\over4}A_k$ and
7216 $C_k\G{5\over4}D_k$; hence the equations are diagonally dominant;
7217 hence they have a unique solution. Moreover, in most cases the tensions
7218 are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the
7219 solution numerically stable, and there is an exponential damping
7220 effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by
7221 a factor of~$O(2^{-j})$.
7222
7223 @ However, we still must consider the angles at the starting and ending
7224 knots of a non-cyclic path. These angles might be given explicitly, or
7225 they might be specified implicitly in terms of an amount of ``curl.''
7226
7227 Let's assume that angles need to be determined for a non-cyclic path
7228 starting at $z_0$ and ending at~$z_n$. Then equations of the form
7229 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta_{k+1}=R_k$$
7230 have been given for $0<k<n$, and it will be convenient to introduce
7231 equations of the same form for $k=0$ and $k=n$, where
7232 $$A_0=B_0=C_n=D_n=0.$$
7233 If $\theta_0$ is supposed to have a given value $E_0$, we simply
7234 define $C_0=0$, $D_0=0$, and $R_0=E_0$. Otherwise a curl
7235 parameter, $\gamma_0$, has been specified at~$z_0$; this means
7236 that the mock curvature at $z_0$ should be $\gamma_0$ times the
7237 mock curvature at $z_1$; i.e.,
7238 $${2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_{01}}
7239 =\gamma_0{2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_{01}}.$$
7240 This equation simplifies to
7241 $$(\alpha_0\chi_0+3-\beta_1)\theta_0+
7242  \bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1=
7243  -\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$
7244 where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0=
7245 \chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$.
7246 It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$,
7247 hence the linear equations remain nonsingular.
7248
7249 Similar considerations apply at the right end, when the final angle $\phi_n$
7250 may or may not need to be determined. It is convenient to let $\psi_n=0$,
7251 hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$,
7252 or we have
7253 $$\bigl((3-\beta_n)\chi_n+\alpha_{n-1}\bigr)\theta_{n-1}+
7254 (\beta_n\chi_n+3-\alpha_{n-1})\theta_n=0,\qquad
7255   \chi_n={\beta_n^2\gamma_n\over\alpha_{n-1}^2}.$$
7256
7257 When |make_choices| chooses angles, it must compute the coefficients of
7258 these linear equations, then solve the equations. To compute the coefficients,
7259 it is necessary to compute arctangents of the given turning angles~$\psi_k$.
7260 When the equations are solved, the chosen directions $\theta_k$ are put
7261 back into the form of control points by essentially computing sines and
7262 cosines.
7263
7264 @ OK, we are ready to make the hard choices of |make_choices|.
7265 Most of the work is relegated to an auxiliary procedure
7266 called |solve_choices|, which has been introduced to keep
7267 |make_choices| from being extremely long.
7268
7269 @<Fill in the control information between...@>=
7270 @<Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$;
7271   set $n$ to the length of the path@>;
7272 @<Remove |open| types at the breakpoints@>;
7273 mp_solve_choices(mp, p,q,n)
7274
7275 @ It's convenient to precompute quantities that will be needed several
7276 times later. The values of |delta_x[k]| and |delta_y[k]| will be the
7277 coordinates of $z\k-z_k$, and the magnitude of this vector will be
7278 |delta[k]=@t$d_{k,k+1}$@>|. The path angle $\psi_k$ between $z_k-z_{k-1}$
7279 and $z\k-z_k$ will be stored in |psi[k]|.
7280
7281 @<Glob...@>=
7282 int path_size; /* maximum number of knots between breakpoints of a path */
7283 scaled *delta_x;
7284 scaled *delta_y;
7285 scaled *delta; /* knot differences */
7286 angle  *psi; /* turning angles */
7287
7288 @ @<Allocate or initialize ...@>=
7289 mp->delta_x = NULL;
7290 mp->delta_y = NULL;
7291 mp->delta = NULL;
7292 mp->psi = NULL;
7293
7294 @ @<Dealloc variables@>=
7295 xfree(mp->delta_x);
7296 xfree(mp->delta_y);
7297 xfree(mp->delta);
7298 xfree(mp->psi);
7299
7300 @ @<Other local variables for |make_choices|@>=
7301   int k,n; /* current and final knot numbers */
7302   pointer s,t; /* registers for list traversal */
7303   scaled delx,dely; /* directions where |open| meets |explicit| */
7304   fraction sine,cosine; /* trig functions of various angles */
7305
7306 @ @<Calculate the turning angles...@>=
7307 {
7308 RESTART:
7309   k=0; s=p; n=mp->path_size;
7310   do {  
7311     t=link(s);
7312     mp->delta_x[k]=x_coord(t)-x_coord(s);
7313     mp->delta_y[k]=y_coord(t)-y_coord(s);
7314     mp->delta[k]=mp_pyth_add(mp, mp->delta_x[k],mp->delta_y[k]);
7315     if ( k>0 ) { 
7316       sine=mp_make_fraction(mp, mp->delta_y[k-1],mp->delta[k-1]);
7317       cosine=mp_make_fraction(mp, mp->delta_x[k-1],mp->delta[k-1]);
7318       mp->psi[k]=mp_n_arg(mp, mp_take_fraction(mp, mp->delta_x[k],cosine)+
7319         mp_take_fraction(mp, mp->delta_y[k],sine),
7320         mp_take_fraction(mp, mp->delta_y[k],cosine)-
7321           mp_take_fraction(mp, mp->delta_x[k],sine));
7322     }
7323     incr(k); s=t;
7324     if ( k==mp->path_size ) {
7325       mp_reallocate_paths(mp, mp->path_size+(mp->path_size>>2));
7326       goto RESTART; /* retry, loop size has changed */
7327     }
7328     if ( s==q ) n=k;
7329   } while (! (k>=n)&&(left_type(s)!=end_cycle));
7330   if ( k==n ) mp->psi[n]=0; else mp->psi[k]=mp->psi[1];
7331 }
7332
7333 @ When we get to this point of the code, |right_type(p)| is either
7334 |given| or |curl| or |open|. If it is |open|, we must have
7335 |left_type(p)=end_cycle| or |left_type(p)=explicit|. In the latter
7336 case, the |open| type is converted to |given|; however, if the
7337 velocity coming into this knot is zero, the |open| type is
7338 converted to a |curl|, since we don't know the incoming direction.
7339
7340 Similarly, |left_type(q)| is either |given| or |curl| or |open| or
7341 |end_cycle|. The |open| possibility is reduced either to |given| or to |curl|.
7342
7343 @<Remove |open| types at the breakpoints@>=
7344 if ( left_type(q)==open ) { 
7345   delx=right_x(q)-x_coord(q); dely=right_y(q)-y_coord(q);
7346   if ( (delx==0)&&(dely==0) ) { 
7347     left_type(q)=curl; left_curl(q)=unity;
7348   } else { 
7349     left_type(q)=given; left_given(q)=mp_n_arg(mp, delx,dely);
7350   }
7351 }
7352 if ( (right_type(p)==open)&&(left_type(p)==explicit) ) { 
7353   delx=x_coord(p)-left_x(p); dely=y_coord(p)-left_y(p);
7354   if ( (delx==0)&&(dely==0) ) { 
7355     right_type(p)=curl; right_curl(p)=unity;
7356   } else { 
7357     right_type(p)=given; right_given(p)=mp_n_arg(mp, delx,dely);
7358   }
7359 }
7360
7361 @ Linear equations need to be solved whenever |n>1|; and also when |n=1|
7362 and exactly one of the breakpoints involves a curl. The simplest case occurs
7363 when |n=1| and there is a curl at both breakpoints; then we simply draw
7364 a straight line.
7365
7366 But before coding up the simple cases, we might as well face the general case,
7367 since we must deal with it sooner or later, and since the general case
7368 is likely to give some insight into the way simple cases can be handled best.
7369
7370 When there is no cycle, the linear equations to be solved form a tridiagonal
7371 system, and we can apply the standard technique of Gaussian elimination
7372 to convert that system to a sequence of equations of the form
7373 $$\theta_0+u_0\theta_1=v_0,\quad
7374 \theta_1+u_1\theta_2=v_1,\quad\ldots,\quad
7375 \theta_{n-1}+u_{n-1}\theta_n=v_{n-1},\quad
7376 \theta_n=v_n.$$
7377 It is possible to do this diagonalization while generating the equations.
7378 Once $\theta_n$ is known, it is easy to determine $\theta_{n-1}$, \dots,
7379 $\theta_1$, $\theta_0$; thus, the equations will be solved.
7380
7381 The procedure is slightly more complex when there is a cycle, but the
7382 basic idea will be nearly the same. In the cyclic case the right-hand
7383 sides will be $v_k+w_k\theta_0$ instead of simply $v_k$, and we will start
7384 the process off with $u_0=v_0=0$, $w_0=1$. The final equation will be not
7385 $\theta_n=v_n$ but $\theta_n+u_n\theta_1=v_n+w_n\theta_0$; an appropriate
7386 ending routine will take account of the fact that $\theta_n=\theta_0$ and
7387 eliminate the $w$'s from the system, after which the solution can be
7388 obtained as before.
7389
7390 When $u_k$, $v_k$, and $w_k$ are being computed, the three pointer
7391 variables |r|, |s|,~|t| will point respectively to knots |k-1|, |k|,
7392 and~|k+1|. The $u$'s and $w$'s are scaled by $2^{28}$, i.e., they are
7393 of type |fraction|; the $\theta$'s and $v$'s are of type |angle|.
7394
7395 @<Glob...@>=
7396 angle *theta; /* values of $\theta_k$ */
7397 fraction *uu; /* values of $u_k$ */
7398 angle *vv; /* values of $v_k$ */
7399 fraction *ww; /* values of $w_k$ */
7400
7401 @ @<Allocate or initialize ...@>=
7402 mp->theta = NULL;
7403 mp->uu = NULL;
7404 mp->vv = NULL;
7405 mp->ww = NULL;
7406
7407 @ @<Dealloc variables@>=
7408 xfree(mp->theta);
7409 xfree(mp->uu);
7410 xfree(mp->vv);
7411 xfree(mp->ww);
7412
7413 @ @<Declare |mp_reallocate| functions@>=
7414 void mp_reallocate_paths (MP mp, int l);
7415
7416 @ @c
7417 void mp_reallocate_paths (MP mp, int l) {
7418   XREALLOC (mp->delta_x, l, scaled);
7419   XREALLOC (mp->delta_y, l, scaled);
7420   XREALLOC (mp->delta,   l, scaled);
7421   XREALLOC (mp->psi,     l, angle);
7422   XREALLOC (mp->theta,   l, angle);
7423   XREALLOC (mp->uu,      l, fraction);
7424   XREALLOC (mp->vv,      l, angle);
7425   XREALLOC (mp->ww,      l, fraction);
7426   mp->path_size = l;
7427 }
7428
7429 @ Our immediate problem is to get the ball rolling by setting up the
7430 first equation or by realizing that no equations are needed, and to fit
7431 this initialization into a framework suitable for the overall computation.
7432
7433 @<Declare the procedure called |solve_choices|@>=
7434 @<Declare subroutines needed by |solve_choices|@>;
7435 void mp_solve_choices (MP mp,pointer p, pointer q, halfword n) {
7436   int k; /* current knot number */
7437   pointer r,s,t; /* registers for list traversal */
7438   @<Other local variables for |solve_choices|@>;
7439   k=0; s=p; r=0;
7440   while (1) { 
7441     t=link(s);
7442     if ( k==0 ) {
7443       @<Get the linear equations started; or |return|
7444         with the control points in place, if linear equations
7445         needn't be solved@>
7446     } else  { 
7447       switch (left_type(s)) {
7448       case end_cycle: case open:
7449         @<Set up equation to match mock curvatures
7450           at $z_k$; then |goto found| with $\theta_n$
7451           adjusted to equal $\theta_0$, if a cycle has ended@>;
7452         break;
7453       case curl:
7454         @<Set up equation for a curl at $\theta_n$
7455           and |goto found|@>;
7456         break;
7457       case given:
7458         @<Calculate the given value of $\theta_n$
7459           and |goto found|@>;
7460         break;
7461       } /* there are no other cases */
7462     }
7463     r=s; s=t; incr(k);
7464   }
7465 FOUND:
7466   @<Finish choosing angles and assigning control points@>;
7467 }
7468
7469 @ On the first time through the loop, we have |k=0| and |r| is not yet
7470 defined. The first linear equation, if any, will have $A_0=B_0=0$.
7471
7472 @<Get the linear equations started...@>=
7473 switch (right_type(s)) {
7474 case given: 
7475   if ( left_type(t)==given ) {
7476     @<Reduce to simple case of two givens  and |return|@>
7477   } else {
7478     @<Set up the equation for a given value of $\theta_0$@>;
7479   }
7480   break;
7481 case curl: 
7482   if ( left_type(t)==curl ) {
7483     @<Reduce to simple case of straight line and |return|@>
7484   } else {
7485     @<Set up the equation for a curl at $\theta_0$@>;
7486   }
7487   break;
7488 case open: 
7489   mp->uu[0]=0; mp->vv[0]=0; mp->ww[0]=fraction_one;
7490   /* this begins a cycle */
7491   break;
7492 } /* there are no other cases */
7493
7494 @ The general equation that specifies equality of mock curvature at $z_k$ is
7495 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7496 as derived above. We want to combine this with the already-derived equation
7497 $\theta_{k-1}+u_{k-1}\theta_k=v_{k-1}+w_{k-1}\theta_0$ in order to obtain
7498 a new equation
7499 $\theta_k+u_k\theta\k=v_k+w_k\theta_0$. This can be done by dividing the
7500 equation
7501 $$(B_k-u_{k-1}A_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k-A_kv_{k-1}
7502     -A_kw_{k-1}\theta_0$$
7503 by $B_k-u_{k-1}A_k+C_k$. The trick is to do this carefully with
7504 fixed-point arithmetic, avoiding the chance of overflow while retaining
7505 suitable precision.
7506
7507 The calculations will be performed in several registers that
7508 provide temporary storage for intermediate quantities.
7509
7510 @<Other local variables for |solve_choices|@>=
7511 fraction aa,bb,cc,ff,acc; /* temporary registers */
7512 scaled dd,ee; /* likewise, but |scaled| */
7513 scaled lt,rt; /* tension values */
7514
7515 @ @<Set up equation to match mock curvatures...@>=
7516 { @<Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$,
7517     $\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$,
7518     and $\\{cc}=(B_k-u_{k-1}A_k)/B_k$@>;
7519   @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>;
7520   mp->uu[k]=mp_take_fraction(mp, ff,bb);
7521   @<Calculate the values of $v_k$ and $w_k$@>;
7522   if ( left_type(s)==end_cycle ) {
7523     @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>;
7524   }
7525 }
7526
7527 @ Since tension values are never less than 3/4, the values |aa| and
7528 |bb| computed here are never more than 4/5.
7529
7530 @<Calculate the values $\\{aa}=...@>=
7531 if ( abs(right_tension(r))==unity) { 
7532   aa=fraction_half; dd=2*mp->delta[k];
7533 } else { 
7534   aa=mp_make_fraction(mp, unity,3*abs(right_tension(r))-unity);
7535   dd=mp_take_fraction(mp, mp->delta[k],
7536     fraction_three-mp_make_fraction(mp, unity,abs(right_tension(r))));
7537 }
7538 if ( abs(left_tension(t))==unity ){ 
7539   bb=fraction_half; ee=2*mp->delta[k-1];
7540 } else { 
7541   bb=mp_make_fraction(mp, unity,3*abs(left_tension(t))-unity);
7542   ee=mp_take_fraction(mp, mp->delta[k-1],
7543     fraction_three-mp_make_fraction(mp, unity,abs(left_tension(t))));
7544 }
7545 cc=fraction_one-mp_take_fraction(mp, mp->uu[k-1],aa)
7546
7547 @ The ratio to be calculated in this step can be written in the form
7548 $$\beta_k^2\cdot\\{ee}\over\beta_k^2\cdot\\{ee}+\alpha_k^2\cdot
7549   \\{cc}\cdot\\{dd},$$
7550 because of the quantities just calculated. The values of |dd| and |ee|
7551 will not be needed after this step has been performed.
7552
7553 @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>=
7554 dd=mp_take_fraction(mp, dd,cc); lt=abs(left_tension(s)); rt=abs(right_tension(s));
7555 if ( lt!=rt ) { /* $\beta_k^{-1}\ne\alpha_k^{-1}$ */
7556   if ( lt<rt ) { 
7557     ff=mp_make_fraction(mp, lt,rt);
7558     ff=mp_take_fraction(mp, ff,ff); /* $\alpha_k^2/\beta_k^2$ */
7559     dd=mp_take_fraction(mp, dd,ff);
7560   } else { 
7561     ff=mp_make_fraction(mp, rt,lt);
7562     ff=mp_take_fraction(mp, ff,ff); /* $\beta_k^2/\alpha_k^2$ */
7563     ee=mp_take_fraction(mp, ee,ff);
7564   }
7565 }
7566 ff=mp_make_fraction(mp, ee,ee+dd)
7567
7568 @ The value of $u_{k-1}$ will be |<=1| except when $k=1$ and the previous
7569 equation was specified by a curl. In that case we must use a special
7570 method of computation to prevent overflow.
7571
7572 Fortunately, the calculations turn out to be even simpler in this ``hard''
7573 case. The curl equation makes $w_0=0$ and $v_0=-u_0\psi_1$, hence
7574 $-B_1\psi_1-A_1v_0=-(B_1-u_0A_1)\psi_1=-\\{cc}\cdot B_1\psi_1$.
7575
7576 @<Calculate the values of $v_k$ and $w_k$@>=
7577 acc=-mp_take_fraction(mp, mp->psi[k+1],mp->uu[k]);
7578 if ( right_type(r)==curl ) { 
7579   mp->ww[k]=0;
7580   mp->vv[k]=acc-mp_take_fraction(mp, mp->psi[1],fraction_one-ff);
7581 } else { 
7582   ff=mp_make_fraction(mp, fraction_one-ff,cc); /* this is
7583     $B_k/(C_k+B_k-u_{k-1}A_k)<5$ */
7584   acc=acc-mp_take_fraction(mp, mp->psi[k],ff);
7585   ff=mp_take_fraction(mp, ff,aa); /* this is $A_k/(C_k+B_k-u_{k-1}A_k)$ */
7586   mp->vv[k]=acc-mp_take_fraction(mp, mp->vv[k-1],ff);
7587   if ( mp->ww[k-1]==0 ) mp->ww[k]=0;
7588   else mp->ww[k]=-mp_take_fraction(mp, mp->ww[k-1],ff);
7589 }
7590
7591 @ When a complete cycle has been traversed, we have $\theta_k+u_k\theta\k=
7592 v_k+w_k\theta_0$, for |1<=k<=n|. We would like to determine the value of
7593 $\theta_n$ and reduce the system to the form $\theta_k+u_k\theta\k=v_k$
7594 for |0<=k<n|, so that the cyclic case can be finished up just as if there
7595 were no cycle.
7596
7597 The idea in the following code is to observe that
7598 $$\eqalign{\theta_n&=v_n+w_n\theta_0-u_n\theta_1=\cdots\cr
7599 &=v_n+w_n\theta_0-u_n\bigl(v_1+w_1\theta_0-u_1(v_2+\cdots
7600   -u_{n-2}(v_{n-1}+w_{n-1}\theta_0-u_{n-1}\theta_0))\bigr),\cr}$$
7601 so we can solve for $\theta_n=\theta_0$.
7602
7603 @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>=
7604
7605 aa=0; bb=fraction_one; /* we have |k=n| */
7606 do {  decr(k);
7607 if ( k==0 ) k=n;
7608   aa=mp->vv[k]-mp_take_fraction(mp, aa,mp->uu[k]);
7609   bb=mp->ww[k]-mp_take_fraction(mp, bb,mp->uu[k]);
7610 } while (k!=n); /* now $\theta_n=\\{aa}+\\{bb}\cdot\theta_n$ */
7611 aa=mp_make_fraction(mp, aa,fraction_one-bb);
7612 mp->theta[n]=aa; mp->vv[0]=aa;
7613 for (k=1;k<=n-1;k++) {
7614   mp->vv[k]=mp->vv[k]+mp_take_fraction(mp, aa,mp->ww[k]);
7615 }
7616 goto FOUND;
7617 }
7618
7619 @ @d reduce_angle(A) if ( abs((A))>one_eighty_deg ) {
7620   if ( (A)>0 ) (A)=(A)-three_sixty_deg; else (A)=(A)+three_sixty_deg; }
7621
7622 @<Calculate the given value of $\theta_n$...@>=
7623
7624   mp->theta[n]=left_given(s)-mp_n_arg(mp, mp->delta_x[n-1],mp->delta_y[n-1]);
7625   reduce_angle(mp->theta[n]);
7626   goto FOUND;
7627 }
7628
7629 @ @<Set up the equation for a given value of $\theta_0$@>=
7630
7631   mp->vv[0]=right_given(s)-mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7632   reduce_angle(mp->vv[0]);
7633   mp->uu[0]=0; mp->ww[0]=0;
7634 }
7635
7636 @ @<Set up the equation for a curl at $\theta_0$@>=
7637 { cc=right_curl(s); lt=abs(left_tension(t)); rt=abs(right_tension(s));
7638   if ( (rt==unity)&&(lt==unity) )
7639     mp->uu[0]=mp_make_fraction(mp, cc+cc+unity,cc+two);
7640   else 
7641     mp->uu[0]=mp_curl_ratio(mp, cc,rt,lt);
7642   mp->vv[0]=-mp_take_fraction(mp, mp->psi[1],mp->uu[0]); mp->ww[0]=0;
7643 }
7644
7645 @ @<Set up equation for a curl at $\theta_n$...@>=
7646 { cc=left_curl(s); lt=abs(left_tension(s)); rt=abs(right_tension(r));
7647   if ( (rt==unity)&&(lt==unity) )
7648     ff=mp_make_fraction(mp, cc+cc+unity,cc+two);
7649   else 
7650     ff=mp_curl_ratio(mp, cc,lt,rt);
7651   mp->theta[n]=-mp_make_fraction(mp, mp_take_fraction(mp, mp->vv[n-1],ff),
7652     fraction_one-mp_take_fraction(mp, ff,mp->uu[n-1]));
7653   goto FOUND;
7654 }
7655
7656 @ The |curl_ratio| subroutine has three arguments, which our previous notation
7657 encourages us to call $\gamma$, $\alpha^{-1}$, and $\beta^{-1}$. It is
7658 a somewhat tedious program to calculate
7659 $${(3-\alpha)\alpha^2\gamma+\beta^3\over
7660   \alpha^3\gamma+(3-\beta)\beta^2},$$
7661 with the result reduced to 4 if it exceeds 4. (This reduction of curl
7662 is necessary only if the curl and tension are both large.)
7663 The values of $\alpha$ and $\beta$ will be at most~4/3.
7664
7665 @<Declare subroutines needed by |solve_choices|@>=
7666 fraction mp_curl_ratio (MP mp,scaled gamma, scaled a_tension, 
7667                         scaled b_tension) {
7668   fraction alpha,beta,num,denom,ff; /* registers */
7669   alpha=mp_make_fraction(mp, unity,a_tension);
7670   beta=mp_make_fraction(mp, unity,b_tension);
7671   if ( alpha<=beta ) {
7672     ff=mp_make_fraction(mp, alpha,beta); ff=mp_take_fraction(mp, ff,ff);
7673     gamma=mp_take_fraction(mp, gamma,ff);
7674     beta=beta / 010000; /* convert |fraction| to |scaled| */
7675     denom=mp_take_fraction(mp, gamma,alpha)+three-beta;
7676     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7677   } else { 
7678     ff=mp_make_fraction(mp, beta,alpha); ff=mp_take_fraction(mp, ff,ff);
7679     beta=mp_take_fraction(mp, beta,ff) / 010000; /* convert |fraction| to |scaled| */
7680     denom=mp_take_fraction(mp, gamma,alpha)+(ff / 1365)-beta;
7681       /* $1365\approx 2^{12}/3$ */
7682     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7683   }
7684   if ( num>=denom+denom+denom+denom ) return fraction_four;
7685   else return mp_make_fraction(mp, num,denom);
7686 }
7687
7688 @ We're in the home stretch now.
7689
7690 @<Finish choosing angles and assigning control points@>=
7691 for (k=n-1;k>=0;k--) {
7692   mp->theta[k]=mp->vv[k]-mp_take_fraction(mp,mp->theta[k+1],mp->uu[k]);
7693 }
7694 s=p; k=0;
7695 do {  
7696   t=link(s);
7697   mp_n_sin_cos(mp, mp->theta[k]); mp->st=mp->n_sin; mp->ct=mp->n_cos;
7698   mp_n_sin_cos(mp, -mp->psi[k+1]-mp->theta[k+1]); mp->sf=mp->n_sin; mp->cf=mp->n_cos;
7699   mp_set_controls(mp, s,t,k);
7700   incr(k); s=t;
7701 } while (k!=n)
7702
7703 @ The |set_controls| routine actually puts the control points into
7704 a pair of consecutive nodes |p| and~|q|. Global variables are used to
7705 record the values of $\sin\theta$, $\cos\theta$, $\sin\phi$, and
7706 $\cos\phi$ needed in this calculation.
7707
7708 @<Glob...@>=
7709 fraction st;
7710 fraction ct;
7711 fraction sf;
7712 fraction cf; /* sines and cosines */
7713
7714 @ @<Declare subroutines needed by |solve_choices|@>=
7715 void mp_set_controls (MP mp,pointer p, pointer q, integer k) {
7716   fraction rr,ss; /* velocities, divided by thrice the tension */
7717   scaled lt,rt; /* tensions */
7718   fraction sine; /* $\sin(\theta+\phi)$ */
7719   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7720   rr=mp_velocity(mp, mp->st,mp->ct,mp->sf,mp->cf,rt);
7721   ss=mp_velocity(mp, mp->sf,mp->cf,mp->st,mp->ct,lt);
7722   if ( (right_tension(p)<0)||(left_tension(q)<0) ) {
7723     @<Decrease the velocities,
7724       if necessary, to stay inside the bounding triangle@>;
7725   }
7726   right_x(p)=x_coord(p)+mp_take_fraction(mp, 
7727                           mp_take_fraction(mp, mp->delta_x[k],mp->ct)-
7728                           mp_take_fraction(mp, mp->delta_y[k],mp->st),rr);
7729   right_y(p)=y_coord(p)+mp_take_fraction(mp, 
7730                           mp_take_fraction(mp, mp->delta_y[k],mp->ct)+
7731                           mp_take_fraction(mp, mp->delta_x[k],mp->st),rr);
7732   left_x(q)=x_coord(q)-mp_take_fraction(mp, 
7733                          mp_take_fraction(mp, mp->delta_x[k],mp->cf)+
7734                          mp_take_fraction(mp, mp->delta_y[k],mp->sf),ss);
7735   left_y(q)=y_coord(q)-mp_take_fraction(mp, 
7736                          mp_take_fraction(mp, mp->delta_y[k],mp->cf)-
7737                          mp_take_fraction(mp, mp->delta_x[k],mp->sf),ss);
7738   right_type(p)=explicit; left_type(q)=explicit;
7739 }
7740
7741 @ The boundedness conditions $\\{rr}\L\sin\phi\,/\sin(\theta+\phi)$ and
7742 $\\{ss}\L\sin\theta\,/\sin(\theta+\phi)$ are to be enforced if $\sin\theta$,
7743 $\sin\phi$, and $\sin(\theta+\phi)$ all have the same sign. Otherwise
7744 there is no ``bounding triangle.''
7745 @:at_least_}{\&{atleast} primitive@>
7746
7747 @<Decrease the velocities, if necessary...@>=
7748 if (((mp->st>=0)&&(mp->sf>=0))||((mp->st<=0)&&(mp->sf<=0)) ) {
7749   sine=mp_take_fraction(mp, abs(mp->st),mp->cf)+
7750                             mp_take_fraction(mp, abs(mp->sf),mp->ct);
7751   if ( sine>0 ) {
7752     sine=mp_take_fraction(mp, sine,fraction_one+unity); /* safety factor */
7753     if ( right_tension(p)<0 )
7754      if ( mp_ab_vs_cd(mp, abs(mp->sf),fraction_one,rr,sine)<0 )
7755       rr=mp_make_fraction(mp, abs(mp->sf),sine);
7756     if ( left_tension(q)<0 )
7757      if ( mp_ab_vs_cd(mp, abs(mp->st),fraction_one,ss,sine)<0 )
7758       ss=mp_make_fraction(mp, abs(mp->st),sine);
7759   }
7760 }
7761
7762 @ Only the simple cases remain to be handled.
7763
7764 @<Reduce to simple case of two givens and |return|@>=
7765
7766   aa=mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7767   mp_n_sin_cos(mp, right_given(p)-aa); mp->ct=mp->n_cos; mp->st=mp->n_sin;
7768   mp_n_sin_cos(mp, left_given(q)-aa); mp->cf=mp->n_cos; mp->sf=-mp->n_sin;
7769   mp_set_controls(mp, p,q,0); return;
7770 }
7771
7772 @ @<Reduce to simple case of straight line and |return|@>=
7773
7774   right_type(p)=explicit; left_type(q)=explicit;
7775   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7776   if ( rt==unity ) {
7777     if ( mp->delta_x[0]>=0 ) right_x(p)=x_coord(p)+((mp->delta_x[0]+1) / 3);
7778     else right_x(p)=x_coord(p)+((mp->delta_x[0]-1) / 3);
7779     if ( mp->delta_y[0]>=0 ) right_y(p)=y_coord(p)+((mp->delta_y[0]+1) / 3);
7780     else right_y(p)=y_coord(p)+((mp->delta_y[0]-1) / 3);
7781   } else { 
7782     ff=mp_make_fraction(mp, unity,3*rt); /* $\alpha/3$ */
7783     right_x(p)=x_coord(p)+mp_take_fraction(mp, mp->delta_x[0],ff);
7784     right_y(p)=y_coord(p)+mp_take_fraction(mp, mp->delta_y[0],ff);
7785   }
7786   if ( lt==unity ) {
7787     if ( mp->delta_x[0]>=0 ) left_x(q)=x_coord(q)-((mp->delta_x[0]+1) / 3);
7788     else left_x(q)=x_coord(q)-((mp->delta_x[0]-1) / 3);
7789     if ( mp->delta_y[0]>=0 ) left_y(q)=y_coord(q)-((mp->delta_y[0]+1) / 3);
7790     else left_y(q)=y_coord(q)-((mp->delta_y[0]-1) / 3);
7791   } else  { 
7792     ff=mp_make_fraction(mp, unity,3*lt); /* $\beta/3$ */
7793     left_x(q)=x_coord(q)-mp_take_fraction(mp, mp->delta_x[0],ff);
7794     left_y(q)=y_coord(q)-mp_take_fraction(mp, mp->delta_y[0],ff);
7795   }
7796   return;
7797 }
7798
7799 @* \[19] Measuring paths.
7800 \MP's \&{llcorner}, \&{lrcorner}, \&{ulcorner}, and \&{urcorner} operators
7801 allow the user to measure the bounding box of anything that can go into a
7802 picture.  It's easy to get rough bounds on the $x$ and $y$ extent of a path
7803 by just finding the bounding box of the knots and the control points. We
7804 need a more accurate version of the bounding box, but we can still use the
7805 easy estimate to save time by focusing on the interesting parts of the path.
7806
7807 @ Computing an accurate bounding box involves a theme that will come up again
7808 and again. Given a Bernshte{\u\i}n polynomial
7809 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
7810 $$B(z_0,z_1,\ldots,z_n;t)=\sum_k{n\choose k}t^k(1-t)^{n-k}z_k,$$
7811 we can conveniently bisect its range as follows:
7812
7813 \smallskip
7814 \textindent{1)} Let $z_k^{(0)}=z_k$, for |0<=k<=n|.
7815
7816 \smallskip
7817 \textindent{2)} Let $z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$, for
7818 |0<=k<n-j|, for |0<=j<n|.
7819
7820 \smallskip\noindent
7821 Then
7822 $$B(z_0,z_1,\ldots,z_n;t)=B(z_0^{(0)},z_0^{(1)},\ldots,z_0^{(n)};2t)
7823  =B(z_0^{(n)},z_1^{(n-1)},\ldots,z_n^{(0)};2t-1).$$
7824 This formula gives us the coefficients of polynomials to use over the ranges
7825 $0\L t\L{1\over2}$ and ${1\over2}\L t\L1$.
7826
7827 @ Now here's a subroutine that's handy for all sorts of path computations:
7828 Given a quadratic polynomial $B(a,b,c;t)$, the |crossing_point| function
7829 returns the unique |fraction| value |t| between 0 and~1 at which
7830 $B(a,b,c;t)$ changes from positive to negative, or returns
7831 |t=fraction_one+1| if no such value exists. If |a<0| (so that $B(a,b,c;t)$
7832 is already negative at |t=0|), |crossing_point| returns the value zero.
7833
7834 @d no_crossing {  return (fraction_one+1); }
7835 @d one_crossing { return fraction_one; }
7836 @d zero_crossing { return 0; }
7837 @d mp_crossing_point(M,A,B,C) mp_do_crossing_point(A,B,C)
7838
7839 @c fraction mp_do_crossing_point (integer a, integer b, integer c) {
7840   integer d; /* recursive counter */
7841   integer x,xx,x0,x1,x2; /* temporary registers for bisection */
7842   if ( a<0 ) zero_crossing;
7843   if ( c>=0 ) { 
7844     if ( b>=0 ) {
7845       if ( c>0 ) { no_crossing; }
7846       else if ( (a==0)&&(b==0) ) { no_crossing;} 
7847       else { one_crossing; } 
7848     }
7849     if ( a==0 ) zero_crossing;
7850   } else if ( a==0 ) {
7851     if ( b<=0 ) zero_crossing;
7852   }
7853   @<Use bisection to find the crossing point, if one exists@>;
7854 }
7855
7856 @ The general bisection method is quite simple when $n=2$, hence
7857 |crossing_point| does not take much time. At each stage in the
7858 recursion we have a subinterval defined by |l| and~|j| such that
7859 $B(a,b,c;2^{-l}(j+t))=B(x_0,x_1,x_2;t)$, and we want to ``zero in'' on
7860 the subinterval where $x_0\G0$ and $\min(x_1,x_2)<0$.
7861
7862 It is convenient for purposes of calculation to combine the values
7863 of |l| and~|j| in a single variable $d=2^l+j$, because the operation
7864 of bisection then corresponds simply to doubling $d$ and possibly
7865 adding~1. Furthermore it proves to be convenient to modify
7866 our previous conventions for bisection slightly, maintaining the
7867 variables $X_0=2^lx_0$, $X_1=2^l(x_0-x_1)$, and $X_2=2^l(x_1-x_2)$.
7868 With these variables the conditions $x_0\ge0$ and $\min(x_1,x_2)<0$ are
7869 equivalent to $\max(X_1,X_1+X_2)>X_0\ge0$.
7870
7871 The following code maintains the invariant relations
7872 $0\L|x0|<\max(|x1|,|x1|+|x2|)$,
7873 $\vert|x1|\vert<2^{30}$, $\vert|x2|\vert<2^{30}$;
7874 it has been constructed in such a way that no arithmetic overflow
7875 will occur if the inputs satisfy
7876 $a<2^{30}$, $\vert a-b\vert<2^{30}$, and $\vert b-c\vert<2^{30}$.
7877
7878 @<Use bisection to find the crossing point...@>=
7879 d=1; x0=a; x1=a-b; x2=b-c;
7880 do {  
7881   x=half(x1+x2);
7882   if ( x1-x0>x0 ) { 
7883     x2=x; x0+=x0; d+=d;  
7884   } else { 
7885     xx=x1+x-x0;
7886     if ( xx>x0 ) { 
7887       x2=x; x0+=x0; d+=d;
7888     }  else { 
7889       x0=x0-xx;
7890       if ( x<=x0 ) { if ( x+x2<=x0 ) no_crossing; }
7891       x1=x; d=d+d+1;
7892     }
7893   }
7894 } while (d<fraction_one);
7895 return (d-fraction_one)
7896
7897 @ Here is a routine that computes the $x$ or $y$ coordinate of the point on
7898 a cubic corresponding to the |fraction| value~|t|.
7899
7900 It is convenient to define a \.{WEB} macro |t_of_the_way| such that
7901 |t_of_the_way(a,b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|.
7902
7903 @d t_of_the_way(A,B) ((A)-mp_take_fraction(mp,(A)-(B),t))
7904
7905 @c scaled mp_eval_cubic (MP mp,pointer p, pointer q, fraction t) {
7906   scaled x1,x2,x3; /* intermediate values */
7907   x1=t_of_the_way(knot_coord(p),right_coord(p));
7908   x2=t_of_the_way(right_coord(p),left_coord(q));
7909   x3=t_of_the_way(left_coord(q),knot_coord(q));
7910   x1=t_of_the_way(x1,x2);
7911   x2=t_of_the_way(x2,x3);
7912   return t_of_the_way(x1,x2);
7913 }
7914
7915 @ The actual bounding box information is stored in global variables.
7916 Since it is convenient to address the $x$ and $y$ information
7917 separately, we define arrays indexed by |x_code..y_code| and use
7918 macros to give them more convenient names.
7919
7920 @<Types...@>=
7921 enum {
7922   mp_x_code=0, /* index for |minx| and |maxx| */
7923   mp_y_code /* index for |miny| and |maxy| */
7924 };
7925
7926
7927 @d minx mp->bbmin[mp_x_code]
7928 @d maxx mp->bbmax[mp_x_code]
7929 @d miny mp->bbmin[mp_y_code]
7930 @d maxy mp->bbmax[mp_y_code]
7931
7932 @<Glob...@>=
7933 scaled bbmin[mp_y_code+1];
7934 scaled bbmax[mp_y_code+1]; 
7935 /* the result of procedures that compute bounding box information */
7936
7937 @ Now we're ready for the key part of the bounding box computation.
7938 The |bound_cubic| procedure updates |bbmin[c]| and |bbmax[c]| based on
7939 $$B(\hbox{|knot_coord(p)|}, \hbox{|right_coord(p)|},
7940     \hbox{|left_coord(q)|}, \hbox{|knot_coord(q)|};t)
7941 $$
7942 for $0<t\le1$.  In other words, the procedure adjusts the bounds to
7943 accommodate |knot_coord(q)| and any extremes over the range $0<t<1$.
7944 The |c| parameter is |x_code| or |y_code|.
7945
7946 @c void mp_bound_cubic (MP mp,pointer p, pointer q, small_number c) {
7947   boolean wavy; /* whether we need to look for extremes */
7948   scaled del1,del2,del3,del,dmax; /* proportional to the control
7949      points of a quadratic derived from a cubic */
7950   fraction t,tt; /* where a quadratic crosses zero */
7951   scaled x; /* a value that |bbmin[c]| and |bbmax[c]| must accommodate */
7952   x=knot_coord(q);
7953   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
7954   @<Check the control points against the bounding box and set |wavy:=true|
7955     if any of them lie outside@>;
7956   if ( wavy ) {
7957     del1=right_coord(p)-knot_coord(p);
7958     del2=left_coord(q)-right_coord(p);
7959     del3=knot_coord(q)-left_coord(q);
7960     @<Scale up |del1|, |del2|, and |del3| for greater accuracy;
7961       also set |del| to the first nonzero element of |(del1,del2,del3)|@>;
7962     if ( del<0 ) {
7963       negate(del1); negate(del2); negate(del3);
7964     };
7965     t=mp_crossing_point(mp, del1,del2,del3);
7966     if ( t<fraction_one ) {
7967       @<Test the extremes of the cubic against the bounding box@>;
7968     }
7969   }
7970 }
7971
7972 @ @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>=
7973 if ( x<mp->bbmin[c] ) mp->bbmin[c]=x;
7974 if ( x>mp->bbmax[c] ) mp->bbmax[c]=x
7975
7976 @ @<Check the control points against the bounding box and set...@>=
7977 wavy=true;
7978 if ( mp->bbmin[c]<=right_coord(p) )
7979   if ( right_coord(p)<=mp->bbmax[c] )
7980     if ( mp->bbmin[c]<=left_coord(q) )
7981       if ( left_coord(q)<=mp->bbmax[c] )
7982         wavy=false
7983
7984 @ If |del1=del2=del3=0|, it's impossible to obey the title of this
7985 section. We just set |del=0| in that case.
7986
7987 @<Scale up |del1|, |del2|, and |del3| for greater accuracy...@>=
7988 if ( del1!=0 ) del=del1;
7989 else if ( del2!=0 ) del=del2;
7990 else del=del3;
7991 if ( del!=0 ) {
7992   dmax=abs(del1);
7993   if ( abs(del2)>dmax ) dmax=abs(del2);
7994   if ( abs(del3)>dmax ) dmax=abs(del3);
7995   while ( dmax<fraction_half ) {
7996     dmax+=dmax; del1+=del1; del2+=del2; del3+=del3;
7997   }
7998 }
7999
8000 @ Since |crossing_point| has tried to choose |t| so that
8001 $B(|del1|,|del2|,|del3|;\tau)$ crosses zero at $\tau=|t|$ with negative
8002 slope, the value of |del2| computed below should not be positive.
8003 But rounding error could make it slightly positive in which case we
8004 must cut it to zero to avoid confusion.
8005
8006 @<Test the extremes of the cubic against the bounding box@>=
8007
8008   x=mp_eval_cubic(mp, p,q,t);
8009   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8010   del2=t_of_the_way(del2,del3);
8011     /* now |0,del2,del3| represent the derivative on the remaining interval */
8012   if ( del2>0 ) del2=0;
8013   tt=mp_crossing_point(mp, 0,-del2,-del3);
8014   if ( tt<fraction_one ) {
8015     @<Test the second extreme against the bounding box@>;
8016   }
8017 }
8018
8019 @ @<Test the second extreme against the bounding box@>=
8020 {
8021    x=mp_eval_cubic(mp, p,q,t_of_the_way(tt,fraction_one));
8022   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8023 }
8024
8025 @ Finding the bounding box of a path is basically a matter of applying
8026 |bound_cubic| twice for each pair of adjacent knots.
8027
8028 @c void mp_path_bbox (MP mp,pointer h) {
8029   pointer p,q; /* a pair of adjacent knots */
8030    minx=x_coord(h); miny=y_coord(h);
8031   maxx=minx; maxy=miny;
8032   p=h;
8033   do {  
8034     if ( right_type(p)==endpoint ) return;
8035     q=link(p);
8036     mp_bound_cubic(mp, x_loc(p),x_loc(q),mp_x_code);
8037     mp_bound_cubic(mp, y_loc(p),y_loc(q),mp_y_code);
8038     p=q;
8039   } while (p!=h);
8040 }
8041
8042 @ Another important way to measure a path is to find its arc length.  This
8043 is best done by using the general bisection algorithm to subdivide the path
8044 until obtaining ``well behaved'' subpaths whose arc lengths can be approximated
8045 by simple means.
8046
8047 Since the arc length is the integral with respect to time of the magnitude of
8048 the velocity, it is natural to use Simpson's rule for the approximation.
8049 @^Simpson's rule@>
8050 If $\dot B(t)$ is the spline velocity, Simpson's rule gives
8051 $$ \vb\dot B(0)\vb + 4\vb\dot B({1\over2})\vb + \vb\dot B(1)\vb \over 6 $$
8052 for the arc length of a path of length~1.  For a cubic spline
8053 $B(z_0,z_1,z_2,z_3;t)$, the time derivative $\dot B(t)$ is
8054 $3B(dz_0,dz_1,dz_2;t)$, where $dz_i=z_{i+1}-z_i$.  Hence the arc length
8055 approximation is
8056 $$ {\vb dz_0\vb \over 2} + 2\vb dz_{02}\vb + {\vb dz_2\vb \over 2}, $$
8057 where
8058 $$ dz_{02}={1\over2}\left({dz_0+dz_1\over 2}+{dz_1+dz_2\over 2}\right)$$
8059 is the result of the bisection algorithm.
8060
8061 @ The remaining problem is how to decide when a subpath is ``well behaved.''
8062 This could be done via the theoretical error bound for Simpson's rule,
8063 @^Simpson's rule@>
8064 but this is impractical because it requires an estimate of the fourth
8065 derivative of the quantity being integrated.  It is much easier to just perform
8066 a bisection step and see how much the arc length estimate changes.  Since the
8067 error for Simpson's rule is proportional to the fourth power of the sample
8068 spacing, the remaining error is typically about $1\over16$ of the amount of
8069 the change.  We say ``typically'' because the error has a pseudo-random behavior
8070 that could cause the two estimates to agree when each contain large errors.
8071
8072 To protect against disasters such as undetected cusps, the bisection process
8073 should always continue until all the $dz_i$ vectors belong to a single
8074 $90^\circ$ sector.  This ensures that no point on the spline can have velocity
8075 less than 70\% of the minimum of $\vb dz_0\vb$, $\vb dz_1\vb$ and $\vb dz_2\vb$.
8076 If such a spline happens to produce an erroneous arc length estimate that
8077 is little changed by bisection, the amount of the error is likely to be fairly
8078 small.  We will try to arrange things so that freak accidents of this type do
8079 not destroy the inverse relationship between the \&{arclength} and
8080 \&{arctime} operations.
8081 @:arclength_}{\&{arclength} primitive@>
8082 @:arctime_}{\&{arctime} primitive@>
8083
8084 @ The \&{arclength} and \&{arctime} operations are both based on a recursive
8085 @^recursion@>
8086 function that finds the arc length of a cubic spline given $dz_0$, $dz_1$,
8087 $dz_2$. This |arc_test| routine also takes an arc length goal |a_goal| and
8088 returns the time when the arc length reaches |a_goal| if there is such a time.
8089 Thus the return value is either an arc length less than |a_goal| or, if the
8090 arc length would be at least |a_goal|, it returns a time value decreased by
8091 |two|.  This allows the caller to use the sign of the result to distinguish
8092 between arc lengths and time values.  On certain types of overflow, it is
8093 possible for |a_goal| and the result of |arc_test| both to be |el_gordo|.
8094 Otherwise, the result is always less than |a_goal|.
8095
8096 Rather than halving the control point coordinates on each recursive call to
8097 |arc_test|, it is better to keep them proportional to velocity on the original
8098 curve and halve the results instead.  This means that recursive calls can
8099 potentially use larger error tolerances in their arc length estimates.  How
8100 much larger depends on to what extent the errors behave as though they are
8101 independent of each other.  To save computing time, we use optimistic assumptions
8102 and increase the tolerance by a factor of about $\sqrt2$ for each recursive
8103 call.
8104
8105 In addition to the tolerance parameter, |arc_test| should also have parameters
8106 for ${1\over3}\vb\dot B(0)\vb$, ${2\over3}\vb\dot B({1\over2})\vb$, and
8107 ${1\over3}\vb\dot B(1)\vb$.  These quantities are relatively expensive to compute
8108 and they are needed in different instances of |arc_test|.
8109
8110 @c @t\4@>@<Declare subroutines needed by |arc_test|@>;
8111 scaled mp_arc_test (MP mp, scaled dx0, scaled dy0, scaled dx1, scaled dy1, 
8112                     scaled dx2, scaled dy2, scaled  v0, scaled v02, 
8113                     scaled v2, scaled a_goal, scaled tol) {
8114   boolean simple; /* are the control points confined to a $90^\circ$ sector? */
8115   scaled dx01, dy01, dx12, dy12, dx02, dy02;  /* bisection results */
8116   scaled v002, v022;
8117     /* twice the velocity magnitudes at $t={1\over4}$ and $t={3\over4}$ */
8118   scaled arc; /* best arc length estimate before recursion */
8119   @<Other local variables in |arc_test|@>;
8120   @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,
8121     |dx2|, |dy2|@>;
8122   @<Initialize |v002|, |v022|, and the arc length estimate |arc|; if it overflows
8123     set |arc_test| and |return|@>;
8124   @<Test if the control points are confined to one quadrant or rotating them
8125     $45^\circ$ would put them in one quadrant.  Then set |simple| appropriately@>;
8126   if ( simple && (abs(arc-v02-halfp(v0+v2)) <= tol) ) {
8127     if ( arc < a_goal ) {
8128       return arc;
8129     } else {
8130        @<Estimate when the arc length reaches |a_goal| and set |arc_test| to
8131          that time minus |two|@>;
8132     }
8133   } else {
8134     @<Use one or two recursive calls to compute the |arc_test| function@>;
8135   }
8136 }
8137
8138 @ The |tol| value should by multiplied by $\sqrt 2$ before making recursive
8139 calls, but $1.5$ is an adequate approximation.  It is best to avoid using
8140 |make_fraction| in this inner loop.
8141 @^inner loop@>
8142
8143 @<Use one or two recursive calls to compute the |arc_test| function@>=
8144
8145   @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is as
8146     large as possible@>;
8147   tol = tol + halfp(tol);
8148   a = mp_arc_test(mp, dx0,dy0, dx01,dy01, dx02,dy02, v0, v002, 
8149                   halfp(v02), a_new, tol);
8150   if ( a<0 )  {
8151      return (-halfp(two-a));
8152   } else { 
8153     @<Update |a_new| to reduce |a_new+a_aux| by |a|@>;
8154     b = mp_arc_test(mp, dx02,dy02, dx12,dy12, dx2,dy2,
8155                     halfp(v02), v022, v2, a_new, tol);
8156     if ( b<0 )  
8157       return (-halfp(-b) - half_unit);
8158     else  
8159       return (a + half(b-a));
8160   }
8161 }
8162
8163 @ @<Other local variables in |arc_test|@>=
8164 scaled a,b; /* results of recursive calls */
8165 scaled a_new,a_aux; /* the sum of these gives the |a_goal| */
8166
8167 @ @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is...@>=
8168 a_aux = el_gordo - a_goal;
8169 if ( a_goal > a_aux ) {
8170   a_aux = a_goal - a_aux;
8171   a_new = el_gordo;
8172 } else { 
8173   a_new = a_goal + a_goal;
8174   a_aux = 0;
8175 }
8176
8177 @ There is no need to maintain |a_aux| at this point so we use it as a temporary
8178 to force the additions and subtractions to be done in an order that avoids
8179 overflow.
8180
8181 @<Update |a_new| to reduce |a_new+a_aux| by |a|@>=
8182 if ( a > a_aux ) {
8183   a_aux = a_aux - a;
8184   a_new = a_new + a_aux;
8185 }
8186
8187 @ This code assumes all {\it dx} and {\it dy} variables have magnitude less than
8188 |fraction_four|.  To simplify the rest of the |arc_test| routine, we strengthen
8189 this assumption by requiring the norm of each $({\it dx},{\it dy})$ pair to obey
8190 this bound.  Note that recursive calls will maintain this invariant.
8191
8192 @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,...@>=
8193 dx01 = half(dx0 + dx1);
8194 dx12 = half(dx1 + dx2);
8195 dx02 = half(dx01 + dx12);
8196 dy01 = half(dy0 + dy1);
8197 dy12 = half(dy1 + dy2);
8198 dy02 = half(dy01 + dy12)
8199
8200 @ We should be careful to keep |arc<el_gordo| so that calling |arc_test| with
8201 |a_goal=el_gordo| is guaranteed to yield the arc length.
8202
8203 @<Initialize |v002|, |v022|, and the arc length estimate |arc|;...@>=
8204 v002 = mp_pyth_add(mp, dx01+half(dx0+dx02), dy01+half(dy0+dy02));
8205 v022 = mp_pyth_add(mp, dx12+half(dx02+dx2), dy12+half(dy02+dy2));
8206 tmp = halfp(v02+2);
8207 arc1 = v002 + half(halfp(v0+tmp) - v002);
8208 arc = v022 + half(halfp(v2+tmp) - v022);
8209 if ( (arc < el_gordo-arc1) )  {
8210   arc = arc+arc1;
8211 } else { 
8212   mp->arith_error = true;
8213   if ( a_goal==el_gordo )  return (el_gordo);
8214   else return (-two);
8215 }
8216
8217 @ @<Other local variables in |arc_test|@>=
8218 scaled tmp, tmp2; /* all purpose temporary registers */
8219 scaled arc1; /* arc length estimate for the first half */
8220
8221 @ @<Test if the control points are confined to one quadrant or rotating...@>=
8222 simple = ((dx0>=0) && (dx1>=0) && (dx2>=0)) ||
8223          ((dx0<=0) && (dx1<=0) && (dx2<=0));
8224 if ( simple )
8225   simple = ((dy0>=0) && (dy1>=0) && (dy2>=0)) ||
8226            ((dy0<=0) && (dy1<=0) && (dy2<=0));
8227 if ( ! simple ) {
8228   simple = ((dx0>=dy0) && (dx1>=dy1) && (dx2>=dy2)) ||
8229            ((dx0<=dy0) && (dx1<=dy1) && (dx2<=dy2));
8230   if ( simple ) 
8231     simple = ((-dx0>=dy0) && (-dx1>=dy1) && (-dx2>=dy2)) ||
8232              ((-dx0<=dy0) && (-dx1<=dy1) && (-dx2<=dy2));
8233 }
8234
8235 @ Since Simpson's rule is based on approximating the integrand by a parabola,
8236 @^Simpson's rule@>
8237 it is appropriate to use the same approximation to decide when the integral
8238 reaches the intermediate value |a_goal|.  At this point
8239 $$\eqalign{
8240     {\vb\dot B(0)\vb\over 3} &= \hbox{|v0|}, \qquad
8241     {\vb\dot B({1\over4})\vb\over 3} = {\hbox{|v002|}\over 2}, \qquad
8242     {\vb\dot B({1\over2})\vb\over 3} = {\hbox{|v02|}\over 2}, \cr
8243     {\vb\dot B({3\over4})\vb\over 3} &= {\hbox{|v022|}\over 2}, \qquad
8244     {\vb\dot B(1)\vb\over 3} = \hbox{|v2|} \cr
8245 }
8246 $$
8247 and
8248 $$ {\vb\dot B(t)\vb\over 3} \approx
8249   \cases{B\left(\hbox{|v0|},
8250       \hbox{|v002|}-{1\over 2}\hbox{|v0|}-{1\over 4}\hbox{|v02|},
8251       {1\over 2}\hbox{|v02|}; 2t \right)&
8252     if $t\le{1\over 2}$\cr
8253   B\left({1\over 2}\hbox{|v02|},
8254       \hbox{|v022|}-{1\over 4}\hbox{|v02|}-{1\over 2}\hbox{|v2|},
8255       \hbox{|v2|}; 2t-1 \right)&
8256     if $t\ge{1\over 2}$.\cr}
8257  \eqno (*)
8258 $$
8259 We can integrate $\vb\dot B(t)\vb$ by using
8260 $$\int 3B(a,b,c;\tau)\,dt =
8261   {B(0,a,a+b,a+b+c;\tau) + {\rm constant} \over {d\tau\over dt}}.
8262 $$
8263
8264 This construction allows us to find the time when the arc length reaches
8265 |a_goal| by solving a cubic equation of the form
8266 $$ B(0,a,a+b,a+b+c;\tau) = x, $$
8267 where $\tau$ is $2t$ or $2t+1$, $x$ is |a_goal| or |a_goal-arc1|, and $a$, $b$,
8268 and $c$ are the Bernshte{\u\i}n coefficients from $(*)$ divided by
8269 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
8270 $d\tau\over dt$.  We shall define a function |solve_rising_cubic| that finds
8271 $\tau$ given $a$, $b$, $c$, and $x$.
8272
8273 @<Estimate when the arc length reaches |a_goal| and set |arc_test| to...@>=
8274
8275   tmp = (v02 + 2) / 4;
8276   if ( a_goal<=arc1 ) {
8277     tmp2 = halfp(v0);
8278     return 
8279       (halfp(mp_solve_rising_cubic(mp, tmp2, arc1-tmp2-tmp, tmp, a_goal))- two);
8280   } else { 
8281     tmp2 = halfp(v2);
8282     return ((half_unit - two) +
8283       halfp(mp_solve_rising_cubic(mp, tmp, arc-arc1-tmp-tmp2, tmp2, a_goal-arc1)));
8284   }
8285 }
8286
8287 @ Here is the |solve_rising_cubic| routine that finds the time~$t$ when
8288 $$ B(0, a, a+b, a+b+c; t) = x. $$
8289 This routine is based on |crossing_point| but is simplified by the
8290 assumptions that $B(a,b,c;t)\ge0$ for $0\le t\le1$ and that |0<=x<=a+b+c|.
8291 If rounding error causes this condition to be violated slightly, we just ignore
8292 it and proceed with binary search.  This finds a time when the function value
8293 reaches |x| and the slope is positive.
8294
8295 @<Declare subroutines needed by |arc_test|@>=
8296 scaled mp_solve_rising_cubic (MP mp,scaled a, scaled b,  scaled c, scaled x) {
8297   scaled ab, bc, ac; /* bisection results */
8298   integer t; /* $2^k+q$ where unscaled answer is in $[q2^{-k},(q+1)2^{-k})$ */
8299   integer xx; /* temporary for updating |x| */
8300   if ( (a<0) || (c<0) ) mp_confusion(mp, "rising?");
8301 @:this can't happen rising?}{\quad rising?@>
8302   if ( x<=0 ) {
8303         return 0;
8304   } else if ( x >= a+b+c ) {
8305     return unity;
8306   } else { 
8307     t = 1;
8308     @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than
8309       |el_gordo div 3|@>;
8310     do {  
8311       t+=t;
8312       @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>;
8313       xx = x - a - ab - ac;
8314       if ( xx < -x ) { x+=x; b=ab; c=ac;  }
8315       else { x = x + xx;  a=ac; b=mp->bc; t = t+1; };
8316     } while (t < unity);
8317     return (t - unity);
8318   }
8319 }
8320
8321 @ @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>=
8322 ab = half(a+b);
8323 bc = half(b+c);
8324 ac = half(ab+bc)
8325
8326 @ @d one_third_el_gordo 05252525252 /* upper bound on |a|, |b|, and |c| */
8327
8328 @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than...@>=
8329 while ((a>one_third_el_gordo)||(b>one_third_el_gordo)||(c>one_third_el_gordo)) { 
8330   a = halfp(a);
8331   b = half(b);
8332   c = halfp(c);
8333   x = halfp(x);
8334 }
8335
8336 @ It is convenient to have a simpler interface to |arc_test| that requires no
8337 unnecessary arguments and ensures that each $({\it dx},{\it dy})$ pair has
8338 length less than |fraction_four|.
8339
8340 @d arc_tol   16  /* quit when change in arc length estimate reaches this */
8341
8342 @c scaled mp_do_arc_test (MP mp,scaled dx0, scaled dy0, scaled dx1, 
8343                           scaled dy1, scaled dx2, scaled dy2, scaled a_goal) {
8344   scaled v0,v1,v2; /* length of each $({\it dx},{\it dy})$ pair */
8345   scaled v02; /* twice the norm of the quadratic at $t={1\over2}$ */
8346   v0 = mp_pyth_add(mp, dx0,dy0);
8347   v1 = mp_pyth_add(mp, dx1,dy1);
8348   v2 = mp_pyth_add(mp, dx2,dy2);
8349   if ( (v0>=fraction_four) || (v1>=fraction_four) || (v2>=fraction_four) ) { 
8350     mp->arith_error = true;
8351     if ( a_goal==el_gordo )  return el_gordo;
8352     else return (-two);
8353   } else { 
8354     v02 = mp_pyth_add(mp, dx1+half(dx0+dx2), dy1+half(dy0+dy2));
8355     return (mp_arc_test(mp, dx0,dy0, dx1,dy1, dx2,dy2,
8356                                  v0, v02, v2, a_goal, arc_tol));
8357   }
8358 }
8359
8360 @ Now it is easy to find the arc length of an entire path.
8361
8362 @c scaled mp_get_arc_length (MP mp,pointer h) {
8363   pointer p,q; /* for traversing the path */
8364   scaled a,a_tot; /* current and total arc lengths */
8365   a_tot = 0;
8366   p = h;
8367   while ( right_type(p)!=endpoint ){ 
8368     q = link(p);
8369     a = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8370       left_x(q)-right_x(p), left_y(q)-right_y(p),
8371       x_coord(q)-left_x(q), y_coord(q)-left_y(q), el_gordo);
8372     a_tot = mp_slow_add(mp, a, a_tot);
8373     if ( q==h ) break;  else p=q;
8374   }
8375   check_arith;
8376   return a_tot;
8377 }
8378
8379 @ The inverse operation of finding the time on a path~|h| when the arc length
8380 reaches some value |arc0| can also be accomplished via |do_arc_test|.  Some care
8381 is required to handle very large times or negative times on cyclic paths.  For
8382 non-cyclic paths, |arc0| values that are negative or too large cause
8383 |get_arc_time| to return 0 or the length of path~|h|.
8384
8385 If |arc0| is greater than the arc length of a cyclic path~|h|, the result is a
8386 time value greater than the length of the path.  Since it could be much greater,
8387 we must be prepared to compute the arc length of path~|h| and divide this into
8388 |arc0| to find how many multiples of the length of path~|h| to add.
8389
8390 @c scaled mp_get_arc_time (MP mp,pointer h, scaled  arc0) {
8391   pointer p,q; /* for traversing the path */
8392   scaled t_tot; /* accumulator for the result */
8393   scaled t; /* the result of |do_arc_test| */
8394   scaled arc; /* portion of |arc0| not used up so far */
8395   integer n; /* number of extra times to go around the cycle */
8396   if ( arc0<0 ) {
8397     @<Deal with a negative |arc0| value and |return|@>;
8398   }
8399   if ( arc0==el_gordo ) decr(arc0);
8400   t_tot = 0;
8401   arc = arc0;
8402   p = h;
8403   while ( (right_type(p)!=endpoint) && (arc>0) ) {
8404     q = link(p);
8405     t = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8406       left_x(q)-right_x(p), left_y(q)-right_y(p),
8407       x_coord(q)-left_x(q), y_coord(q)-left_y(q), arc);
8408     @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>;
8409     if ( q==h ) {
8410       @<Update |t_tot| and |arc| to avoid going around the cyclic
8411         path too many times but set |arith_error:=true| and |goto done| on
8412         overflow@>;
8413     }
8414     p = q;
8415   }
8416   check_arith;
8417   return t_tot;
8418 }
8419
8420 @ @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>=
8421 if ( t<0 ) { t_tot = t_tot + t + two;  arc = 0;  }
8422 else { t_tot = t_tot + unity;  arc = arc - t;  }
8423
8424 @ @<Deal with a negative |arc0| value and |return|@>=
8425
8426   if ( left_type(h)==endpoint ) {
8427     t_tot=0;
8428   } else { 
8429     p = mp_htap_ypoc(mp, h);
8430     t_tot = -mp_get_arc_time(mp, p, -arc0);
8431     mp_toss_knot_list(mp, p);
8432   }
8433   check_arith;
8434   return t_tot;
8435 }
8436
8437 @ @<Update |t_tot| and |arc| to avoid going around the cyclic...@>=
8438 if ( arc>0 ) { 
8439   n = arc / (arc0 - arc);
8440   arc = arc - n*(arc0 - arc);
8441   if ( t_tot > el_gordo / (n+1) ) { 
8442     mp->arith_error = true;
8443     t_tot = el_gordo;
8444     break;
8445   }
8446   t_tot = (n + 1)*t_tot;
8447 }
8448
8449 @* \[20] Data structures for pens.
8450 A Pen in \MP\ can be either elliptical or polygonal.  Elliptical pens result
8451 in \ps\ \&{stroke} commands, while anything drawn with a polygonal pen is
8452 @:stroke}{\&{stroke} command@>
8453 converted into an area fill as described in the next part of this program.
8454 The mathematics behind this process is based on simple aspects of the theory
8455 of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge Stolfi
8456 [``A kinematic framework for computational geometry,'' Proc.\ IEEE Symp.\
8457 Foundations of Computer Science {\bf 24} (1983), 100--111].
8458
8459 Polygonal pens are created from paths via \MP's \&{makepen} primitive.
8460 @:makepen_}{\&{makepen} primitive@>
8461 This path representation is almost sufficient for our purposes except that
8462 a pen path should always be a convex polygon with the vertices in
8463 counter-clockwise order.
8464 Since we will need to scan pen polygons both forward and backward, a pen
8465 should be represented as a doubly linked ring of knot nodes.  There is
8466 room for the extra back pointer because we do not need the
8467 |left_type| or |right_type| fields.  In fact, we don't need the |left_x|,
8468 |left_y|, |right_x|, or |right_y| fields either but we leave these alone
8469 so that certain procedures can operate on both pens and paths.  In particular,
8470 pens can be copied using |copy_path| and recycled using |toss_knot_list|.
8471
8472 @d knil info
8473   /* this replaces the |left_type| and |right_type| fields in a pen knot */
8474
8475 @ The |make_pen| procedure turns a path into a pen by initializing
8476 the |knil| pointers and making sure the knots form a convex polygon.
8477 Thus each cubic in the given path becomes a straight line and the control
8478 points are ignored.  If the path is not cyclic, the ends are connected by a
8479 straight line.
8480
8481 @d copy_pen(A) mp_make_pen(mp, mp_copy_path(mp, (A)),false)
8482
8483 @c @<Declare a function called |convex_hull|@>;
8484 pointer mp_make_pen (MP mp,pointer h, boolean need_hull) {
8485   pointer p,q; /* two consecutive knots */
8486   q=h;
8487   do {  
8488     p=q; q=link(q);
8489     knil(q)=p;
8490   } while (q!=h);
8491   if ( need_hull ){ 
8492     h=mp_convex_hull(mp, h);
8493     @<Make sure |h| isn't confused with an elliptical pen@>;
8494   }
8495   return h;
8496 }
8497
8498 @ The only information required about an elliptical pen is the overall
8499 transformation that has been applied to the original \&{pencircle}.
8500 @:pencircle_}{\&{pencircle} primitive@>
8501 Since it suffices to keep track of how the three points $(0,0)$, $(1,0)$,
8502 and $(0,1)$ are transformed, an elliptical pen can be stored in a single
8503 knot node and transformed as if it were a path.
8504
8505 @d pen_is_elliptical(A) ((A)==link((A)))
8506
8507 @c pointer mp_get_pen_circle (MP mp,scaled diam) {
8508   pointer h; /* the knot node to return */
8509   h=mp_get_node(mp, knot_node_size);
8510   link(h)=h; knil(h)=h;
8511   originator(h)=program_code;
8512   x_coord(h)=0; y_coord(h)=0;
8513   left_x(h)=diam; left_y(h)=0;
8514   right_x(h)=0; right_y(h)=diam;
8515   return h;
8516 }
8517
8518 @ If the polygon being returned by |make_pen| has only one vertex, it will
8519 be interpreted as an elliptical pen.  This is no problem since a degenerate
8520 polygon can equally well be thought of as a degenerate ellipse.  We need only
8521 initialize the |left_x|, |left_y|, |right_x|, and |right_y| fields.
8522
8523 @<Make sure |h| isn't confused with an elliptical pen@>=
8524 if ( pen_is_elliptical( h) ){ 
8525   left_x(h)=x_coord(h); left_y(h)=y_coord(h);
8526   right_x(h)=x_coord(h); right_y(h)=y_coord(h);
8527 }
8528
8529 @ We have to cheat a little here but most operations on pens only use
8530 the first three words in each knot node.
8531 @^data structure assumptions@>
8532
8533 @<Initialize a pen at |test_pen| so that it fits in nine words@>=
8534 x_coord(test_pen)=-half_unit;
8535 y_coord(test_pen)=0;
8536 x_coord(test_pen+3)=half_unit;
8537 y_coord(test_pen+3)=0;
8538 x_coord(test_pen+6)=0;
8539 y_coord(test_pen+6)=unity;
8540 link(test_pen)=test_pen+3;
8541 link(test_pen+3)=test_pen+6;
8542 link(test_pen+6)=test_pen;
8543 knil(test_pen)=test_pen+6;
8544 knil(test_pen+3)=test_pen;
8545 knil(test_pen+6)=test_pen+3
8546
8547 @ Printing a polygonal pen is very much like printing a path
8548
8549 @<Declare subroutines for printing expressions@>=
8550 void mp_pr_pen (MP mp,pointer h) {
8551   pointer p,q; /* for list traversal */
8552   if ( pen_is_elliptical(h) ) {
8553     @<Print the elliptical pen |h|@>;
8554   } else { 
8555     p=h;
8556     do {  
8557       mp_print_two(mp, x_coord(p),y_coord(p));
8558       mp_print_nl(mp, " .. ");
8559       @<Advance |p| making sure the links are OK and |return| if there is
8560         a problem@>;
8561      } while (p!=h);
8562      mp_print(mp, "cycle");
8563   }
8564 }
8565
8566 @ @<Advance |p| making sure the links are OK and |return| if there is...@>=
8567 q=link(p);
8568 if ( (q==null) || (knil(q)!=p) ) { 
8569   mp_print_nl(mp, "???"); return; /* this won't happen */
8570 @.???@>
8571 }
8572 p=q
8573
8574 @ @<Print the elliptical pen |h|@>=
8575
8576 mp_print(mp, "pencircle transformed (");
8577 mp_print_scaled(mp, x_coord(h));
8578 mp_print_char(mp, ',');
8579 mp_print_scaled(mp, y_coord(h));
8580 mp_print_char(mp, ',');
8581 mp_print_scaled(mp, left_x(h)-x_coord(h));
8582 mp_print_char(mp, ',');
8583 mp_print_scaled(mp, right_x(h)-x_coord(h));
8584 mp_print_char(mp, ',');
8585 mp_print_scaled(mp, left_y(h)-y_coord(h));
8586 mp_print_char(mp, ',');
8587 mp_print_scaled(mp, right_y(h)-y_coord(h));
8588 mp_print_char(mp, ')');
8589 }
8590
8591 @ Here us another version of |pr_pen| that prints the pen as a diagnostic
8592 message.
8593
8594 @<Declare subroutines for printing expressions@>=
8595 void mp_print_pen (MP mp,pointer h, char *s, boolean nuline) { 
8596   mp_print_diagnostic(mp, "Pen",s,nuline); mp_print_ln(mp);
8597 @.Pen at line...@>
8598   mp_pr_pen(mp, h);
8599   mp_end_diagnostic(mp, true);
8600 }
8601
8602 @ Making a polygonal pen into a path involves restoring the |left_type| and
8603 |right_type| fields and setting the control points so as to make a polygonal
8604 path.
8605
8606 @c 
8607 void mp_make_path (MP mp,pointer h) {
8608   pointer p; /* for traversing the knot list */
8609   small_number k; /* a loop counter */
8610   @<Other local variables in |make_path|@>;
8611   if ( pen_is_elliptical(h) ) {
8612     @<Make the elliptical pen |h| into a path@>;
8613   } else { 
8614     p=h;
8615     do {  
8616       left_type(p)=explicit;
8617       right_type(p)=explicit;
8618       @<copy the coordinates of knot |p| into its control points@>;
8619        p=link(p);
8620     } while (p!=h);
8621   }
8622 }
8623
8624 @ @<copy the coordinates of knot |p| into its control points@>=
8625 left_x(p)=x_coord(p);
8626 left_y(p)=y_coord(p);
8627 right_x(p)=x_coord(p);
8628 right_y(p)=y_coord(p)
8629
8630 @ We need an eight knot path to get a good approximation to an ellipse.
8631
8632 @<Make the elliptical pen |h| into a path@>=
8633
8634   @<Extract the transformation parameters from the elliptical pen~|h|@>;
8635   p=h;
8636   for (k=0;k<=7;k++ ) { 
8637     @<Initialize |p| as the |k|th knot of a circle of unit diameter,
8638       transforming it appropriately@>;
8639     if ( k==7 ) link(p)=h;  else link(p)=mp_get_node(mp, knot_node_size);
8640     p=link(p);
8641   }
8642 }
8643
8644 @ @<Extract the transformation parameters from the elliptical pen~|h|@>=
8645 center_x=x_coord(h);
8646 center_y=y_coord(h);
8647 width_x=left_x(h)-center_x;
8648 width_y=left_y(h)-center_y;
8649 height_x=right_x(h)-center_x;
8650 height_y=right_y(h)-center_y
8651
8652 @ @<Other local variables in |make_path|@>=
8653 scaled center_x,center_y; /* translation parameters for an elliptical pen */
8654 scaled width_x,width_y; /* the effect of a unit change in $x$ */
8655 scaled height_x,height_y; /* the effect of a unit change in $y$ */
8656 scaled dx,dy; /* the vector from knot |p| to its right control point */
8657 integer kk;
8658   /* |k| advanced $270^\circ$ around the ring (cf. $\sin\theta=\cos(\theta+270)$) */
8659
8660 @ The only tricky thing here are the tables |half_cos| and |d_cos| used to
8661 find the point $k/8$ of the way around the circle and the direction vector
8662 to use there.
8663
8664 @<Initialize |p| as the |k|th knot of a circle of unit diameter,...@>=
8665 kk=(k+6)% 8;
8666 x_coord(p)=center_x+mp_take_fraction(mp, mp->half_cos[k],width_x)
8667            +mp_take_fraction(mp, mp->half_cos[kk],height_x);
8668 y_coord(p)=center_y+mp_take_fraction(mp, mp->half_cos[k],width_y)
8669            +mp_take_fraction(mp, mp->half_cos[kk],height_y);
8670 dx=-mp_take_fraction(mp, mp->d_cos[kk],width_x)
8671    +mp_take_fraction(mp, mp->d_cos[k],height_x);
8672 dy=-mp_take_fraction(mp, mp->d_cos[kk],width_y)
8673    +mp_take_fraction(mp, mp->d_cos[k],height_y);
8674 right_x(p)=x_coord(p)+dx;
8675 right_y(p)=y_coord(p)+dy;
8676 left_x(p)=x_coord(p)-dx;
8677 left_y(p)=y_coord(p)-dy;
8678 left_type(p)=explicit;
8679 right_type(p)=explicit;
8680 originator(p)=program_code
8681
8682 @ @<Glob...@>=
8683 fraction half_cos[8]; /* ${1\over2}\cos(45k)$ */
8684 fraction d_cos[8]; /* a magic constant times $\cos(45k)$ */
8685
8686 @ The magic constant for |d_cos| is the distance between $({1\over2},0)$ and
8687 $({1\over4}\sqrt2,{1\over4}\sqrt2)$ times the result of the |velocity|
8688 function for $\theta=\phi=22.5^\circ$.  This comes out to be
8689 $$ d = {\sqrt{2-\sqrt2}\over 3+3\cos22.5^\circ}
8690   \approx 0.132608244919772.
8691 $$
8692
8693 @<Set init...@>=
8694 mp->half_cos[0]=fraction_half;
8695 mp->half_cos[1]=94906266; /* $2^{26}\sqrt2\approx94906265.62$ */
8696 mp->half_cos[2]=0;
8697 mp->d_cos[0]=35596755; /* $2^{28}d\approx35596754.69$ */
8698 mp->d_cos[1]=25170707; /* $2^{27}\sqrt2\,d\approx25170706.63$ */
8699 mp->d_cos[2]=0;
8700 for (k=3;k<= 4;k++ ) { 
8701   mp->half_cos[k]=-mp->half_cos[4-k];
8702   mp->d_cos[k]=-mp->d_cos[4-k];
8703 }
8704 for (k=5;k<= 7;k++ ) { 
8705   mp->half_cos[k]=mp->half_cos[8-k];
8706   mp->d_cos[k]=mp->d_cos[8-k];
8707 }
8708
8709 @ The |convex_hull| function forces a pen polygon to be convex when it is
8710 returned by |make_pen| and after any subsequent transformation where rounding
8711 error might allow the convexity to be lost.
8712 The convex hull algorithm used here is described by F.~P. Preparata and
8713 M.~I. Shamos [{\sl Computational Geometry}, Springer-Verlag, 1985].
8714
8715 @<Declare a function called |convex_hull|@>=
8716 @<Declare a procedure called |move_knot|@>;
8717 pointer mp_convex_hull (MP mp,pointer h) { /* Make a polygonal pen convex */
8718   pointer l,r; /* the leftmost and rightmost knots */
8719   pointer p,q; /* knots being scanned */
8720   pointer s; /* the starting point for an upcoming scan */
8721   scaled dx,dy; /* a temporary pointer */
8722   if ( pen_is_elliptical(h) ) {
8723      return h;
8724   } else { 
8725     @<Set |l| to the leftmost knot in polygon~|h|@>;
8726     @<Set |r| to the rightmost knot in polygon~|h|@>;
8727     if ( l!=r ) { 
8728       s=link(r);
8729       @<Find any knots on the path from |l| to |r| above the |l|-|r| line and
8730         move them past~|r|@>;
8731       @<Find any knots on the path from |s| to |l| below the |l|-|r| line and
8732         move them past~|l|@>;
8733       @<Sort the path from |l| to |r| by increasing $x$@>;
8734       @<Sort the path from |r| to |l| by decreasing $x$@>;
8735     }
8736     if ( l!=link(l) ) {
8737       @<Do a Gramm scan and remove vertices where there is no left turn@>;
8738     }
8739     return l;
8740   }
8741 }
8742
8743 @ All comparisons are done primarily on $x$ and secondarily on $y$.
8744
8745 @<Set |l| to the leftmost knot in polygon~|h|@>=
8746 l=h;
8747 p=link(h);
8748 while ( p!=h ) { 
8749   if ( x_coord(p)<=x_coord(l) )
8750     if ( (x_coord(p)<x_coord(l)) || (y_coord(p)<y_coord(l)) )
8751       l=p;
8752   p=link(p);
8753 }
8754
8755 @ @<Set |r| to the rightmost knot in polygon~|h|@>=
8756 r=h;
8757 p=link(h);
8758 while ( p!=h ) { 
8759   if ( x_coord(p)>=x_coord(r) )
8760     if ( (x_coord(p)>x_coord(r)) || (y_coord(p)>y_coord(r)) )
8761       r=p;
8762   p=link(p);
8763 }
8764
8765 @ @<Find any knots on the path from |l| to |r| above the |l|-|r| line...@>=
8766 dx=x_coord(r)-x_coord(l);
8767 dy=y_coord(r)-y_coord(l);
8768 p=link(l);
8769 while ( p!=r ) { 
8770   q=link(p);
8771   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))>0 )
8772     mp_move_knot(mp, p, r);
8773   p=q;
8774 }
8775
8776 @ The |move_knot| procedure removes |p| from a doubly linked list and inserts
8777 it after |q|.
8778
8779 @ @<Declare a procedure called |move_knot|@>=
8780 void mp_move_knot (MP mp,pointer p, pointer q) { 
8781   link(knil(p))=link(p);
8782   knil(link(p))=knil(p);
8783   knil(p)=q;
8784   link(p)=link(q);
8785   link(q)=p;
8786   knil(link(p))=p;
8787 }
8788
8789 @ @<Find any knots on the path from |s| to |l| below the |l|-|r| line...@>=
8790 p=s;
8791 while ( p!=l ) { 
8792   q=link(p);
8793   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))<0 )
8794     mp_move_knot(mp, p,l);
8795   p=q;
8796 }
8797
8798 @ The list is likely to be in order already so we just do linear insertions.
8799 Secondary comparisons on $y$ ensure that the sort is consistent with the
8800 choice of |l| and |r|.
8801
8802 @<Sort the path from |l| to |r| by increasing $x$@>=
8803 p=link(l);
8804 while ( p!=r ) { 
8805   q=knil(p);
8806   while ( x_coord(q)>x_coord(p) ) q=knil(q);
8807   while ( x_coord(q)==x_coord(p) ) {
8808     if ( y_coord(q)>y_coord(p) ) q=knil(q); else break;
8809   }
8810   if ( q==knil(p) ) p=link(p);
8811   else { p=link(p); mp_move_knot(mp, knil(p),q); };
8812 }
8813
8814 @ @<Sort the path from |r| to |l| by decreasing $x$@>=
8815 p=link(r);
8816 while ( p!=l ){ 
8817   q=knil(p);
8818   while ( x_coord(q)<x_coord(p) ) q=knil(q);
8819   while ( x_coord(q)==x_coord(p) ) {
8820     if ( y_coord(q)<y_coord(p) ) q=knil(q); else break;
8821   }
8822   if ( q==knil(p) ) p=link(p);
8823   else { p=link(p); mp_move_knot(mp, knil(p),q); };
8824 }
8825
8826 @ The condition involving |ab_vs_cd| tests if there is not a left turn
8827 at knot |q|.  There usually will be a left turn so we streamline the case
8828 where the |then| clause is not executed.
8829
8830 @<Do a Gramm scan and remove vertices where there...@>=
8831
8832 p=l; q=link(l);
8833 while (1) { 
8834   dx=x_coord(q)-x_coord(p);
8835   dy=y_coord(q)-y_coord(p);
8836   p=q; q=link(q);
8837   if ( p==l ) break;
8838   if ( p!=r )
8839     if ( mp_ab_vs_cd(mp, dx,y_coord(q)-y_coord(p),dy,x_coord(q)-x_coord(p))<=0 ) {
8840       @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>;
8841     }
8842   }
8843 }
8844
8845 @ @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>=
8846
8847 s=knil(p);
8848 mp_free_node(mp, p,knot_node_size);
8849 link(s)=q; knil(q)=s;
8850 if ( s==l ) p=s;
8851 else { p=knil(s); q=s; };
8852 }
8853
8854 @ The |find_offset| procedure sets global variables |(cur_x,cur_y)| to the
8855 offset associated with the given direction |(x,y)|.  If two different offsets
8856 apply, it chooses one of them.
8857
8858 @c 
8859 void mp_find_offset (MP mp,scaled x, scaled y, pointer h) {
8860   pointer p,q; /* consecutive knots */
8861   scaled wx,wy,hx,hy;
8862   /* the transformation matrix for an elliptical pen */
8863   fraction xx,yy; /* untransformed offset for an elliptical pen */
8864   fraction d; /* a temporary register */
8865   if ( pen_is_elliptical(h) ) {
8866     @<Find the offset for |(x,y)| on the elliptical pen~|h|@>
8867   } else { 
8868     q=h;
8869     do {  
8870       p=q; q=link(q);
8871     } while (! mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)>=0);
8872     do {  
8873       p=q; q=link(q);
8874     } while (! mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)<=0);
8875     mp->cur_x=x_coord(p);
8876     mp->cur_y=y_coord(p);
8877   }
8878 }
8879
8880 @ @<Glob...@>=
8881 scaled cur_x;
8882 scaled cur_y; /* all-purpose return value registers */
8883
8884 @ @<Find the offset for |(x,y)| on the elliptical pen~|h|@>=
8885 if ( (x==0) && (y==0) ) {
8886   mp->cur_x=x_coord(h); mp->cur_y=y_coord(h);  
8887 } else { 
8888   @<Find the non-constant part of the transformation for |h|@>;
8889   while ( (abs(x)<fraction_half) && (abs(y)<fraction_half) ){ 
8890     x+=x; y+=y;  
8891   };
8892   @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the
8893     untransformed version of |(x,y)|@>;
8894   mp->cur_x=x_coord(h)+mp_take_fraction(mp, xx,wx)+mp_take_fraction(mp, yy,hx);
8895   mp->cur_y=y_coord(h)+mp_take_fraction(mp, xx,wy)+mp_take_fraction(mp, yy,hy);
8896 }
8897
8898 @ @<Find the non-constant part of the transformation for |h|@>=
8899 wx=left_x(h)-x_coord(h);
8900 wy=left_y(h)-y_coord(h);
8901 hx=right_x(h)-x_coord(h);
8902 hy=right_y(h)-y_coord(h)
8903
8904 @ @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the...@>=
8905 yy=-(mp_take_fraction(mp, x,hy)+mp_take_fraction(mp, y,-hx));
8906 xx=mp_take_fraction(mp, x,-wy)+mp_take_fraction(mp, y,wx);
8907 d=mp_pyth_add(mp, xx,yy);
8908 if ( d>0 ) { 
8909   xx=half(mp_make_fraction(mp, xx,d));
8910   yy=half(mp_make_fraction(mp, yy,d));
8911 }
8912
8913 @ Finding the bounding box of a pen is easy except if the pen is elliptical.
8914 But we can handle that case by just calling |find_offset| twice.  The answer
8915 is stored in the global variables |minx|, |maxx|, |miny|, and |maxy|.
8916
8917 @c 
8918 void mp_pen_bbox (MP mp,pointer h) {
8919   pointer p; /* for scanning the knot list */
8920   if ( pen_is_elliptical(h) ) {
8921     @<Find the bounding box of an elliptical pen@>;
8922   } else { 
8923     minx=x_coord(h); maxx=minx;
8924     miny=y_coord(h); maxy=miny;
8925     p=link(h);
8926     while ( p!=h ) {
8927       if ( x_coord(p)<minx ) minx=x_coord(p);
8928       if ( y_coord(p)<miny ) miny=y_coord(p);
8929       if ( x_coord(p)>maxx ) maxx=x_coord(p);
8930       if ( y_coord(p)>maxy ) maxy=y_coord(p);
8931       p=link(p);
8932     }
8933   }
8934 }
8935
8936 @ @<Find the bounding box of an elliptical pen@>=
8937
8938 mp_find_offset(mp, 0,fraction_one,h);
8939 maxx=mp->cur_x;
8940 minx=2*x_coord(h)-mp->cur_x;
8941 mp_find_offset(mp, -fraction_one,0,h);
8942 maxy=mp->cur_y;
8943 miny=2*y_coord(h)-mp->cur_y;
8944 }
8945
8946 @* \[21] Edge structures.
8947 Now we come to \MP's internal scheme for representing pictures.
8948 The representation is very different from \MF's edge structures
8949 because \MP\ pictures contain \ps\ graphics objects instead of pixel
8950 images.  However, the basic idea is somewhat similar in that shapes
8951 are represented via their boundaries.
8952
8953 The main purpose of edge structures is to keep track of graphical objects
8954 until it is time to translate them into \ps.  Since \MP\ does not need to
8955 know anything about an edge structure other than how to translate it into
8956 \ps\ and how to find its bounding box, edge structures can be just linked
8957 lists of graphical objects.  \MP\ has no easy way to determine whether
8958 two such objects overlap, but it suffices to draw the first one first and
8959 let the second one overwrite it if necessary.
8960
8961 @ Let's consider the types of graphical objects one at a time.
8962 First of all, a filled contour is represented by a eight-word node.  The first
8963 word contains |type| and |link| fields, and the next six words contain a
8964 pointer to a cyclic path and the value to use for \ps' \&{currentrgbcolor}
8965 parameter.  If a pen is used for filling |pen_p|, |ljoin_val| and |miterlim_val|
8966 give the relevant information.
8967
8968 @d path_p(A) link((A)+1)
8969   /* a pointer to the path that needs filling */
8970 @d pen_p(A) info((A)+1)
8971   /* a pointer to the pen to fill or stroke with */
8972 @d color_model(A) type((A)+2) /*  the color model  */
8973 @d obj_red_loc(A) ((A)+3)  /* the first of three locations for the color */
8974 @d obj_cyan_loc obj_red_loc  /* the first of four locations for the color */
8975 @d obj_grey_loc obj_red_loc  /* the location for the color */
8976 @d red_val(A) mp->mem[(A)+3].sc
8977   /* the red component of the color in the range $0\ldots1$ */
8978 @d cyan_val red_val
8979 @d grey_val red_val
8980 @d green_val(A) mp->mem[(A)+4].sc
8981   /* the green component of the color in the range $0\ldots1$ */
8982 @d magenta_val green_val
8983 @d blue_val(A) mp->mem[(A)+5].sc
8984   /* the blue component of the color in the range $0\ldots1$ */
8985 @d yellow_val blue_val
8986 @d black_val(A) mp->mem[(A)+6].sc
8987   /* the blue component of the color in the range $0\ldots1$ */
8988 @d ljoin_val(A) name_type((A))  /* the value of \&{linejoin} */
8989 @:linejoin_}{\&{linejoin} primitive@>
8990 @d miterlim_val(A) mp->mem[(A)+7].sc  /* the value of \&{miterlimit} */
8991 @:miterlimit_}{\&{miterlimit} primitive@>
8992 @d obj_color_part(A) mp->mem[(A)+3-red_part].sc
8993   /* interpret an object pointer that has been offset by |red_part..blue_part| */
8994 @d pre_script(A) mp->mem[(A)+8].hh.lh
8995 @d post_script(A) mp->mem[(A)+8].hh.rh
8996 @d fill_node_size 9
8997 @d fill_code 1
8998
8999 @c 
9000 pointer mp_new_fill_node (MP mp,pointer p) {
9001   /* make a fill node for cyclic path |p| and color black */
9002   pointer t; /* the new node */
9003   t=mp_get_node(mp, fill_node_size);
9004   type(t)=fill_code;
9005   path_p(t)=p;
9006   pen_p(t)=null; /* |null| means don't use a pen */
9007   red_val(t)=0;
9008   green_val(t)=0;
9009   blue_val(t)=0;
9010   black_val(t)=0;
9011   color_model(t)=uninitialized_model;
9012   pre_script(t)=null;
9013   post_script(t)=null;
9014   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9015   return t;
9016 }
9017
9018 @ @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>=
9019 if ( mp->internal[linejoin]>unity ) ljoin_val(t)=2;
9020 else if ( mp->internal[linejoin]>0 ) ljoin_val(t)=1;
9021 else ljoin_val(t)=0;
9022 if ( mp->internal[miterlimit]<unity )
9023   miterlim_val(t)=unity;
9024 else
9025   miterlim_val(t)=mp->internal[miterlimit]
9026
9027 @ A stroked path is represented by an eight-word node that is like a filled
9028 contour node except that it contains the current \&{linecap} value, a scale
9029 factor for the dash pattern, and a pointer that is non-null if the stroke
9030 is to be dashed.  The purpose of the scale factor is to allow a picture to
9031 be transformed without touching the picture that |dash_p| points to.
9032
9033 @d dash_p(A) link((A)+9)
9034   /* a pointer to the edge structure that gives the dash pattern */
9035 @d lcap_val(A) type((A)+9)
9036   /* the value of \&{linecap} */
9037 @:linecap_}{\&{linecap} primitive@>
9038 @d dash_scale(A) mp->mem[(A)+10].sc /* dash lengths are scaled by this factor */
9039 @d stroked_node_size 11
9040 @d stroked_code 2
9041
9042 @c 
9043 pointer mp_new_stroked_node (MP mp,pointer p) {
9044   /* make a stroked node for path |p| with |pen_p(p)| temporarily |null| */
9045   pointer t; /* the new node */
9046   t=mp_get_node(mp, stroked_node_size);
9047   type(t)=stroked_code;
9048   path_p(t)=p; pen_p(t)=null;
9049   dash_p(t)=null;
9050   dash_scale(t)=unity;
9051   red_val(t)=0;
9052   green_val(t)=0;
9053   blue_val(t)=0;
9054   black_val(t)=0;
9055   color_model(t)=uninitialized_model;
9056   pre_script(t)=null;
9057   post_script(t)=null;
9058   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9059   if ( mp->internal[linecap]>unity ) lcap_val(t)=2;
9060   else if ( mp->internal[linecap]>0 ) lcap_val(t)=1;
9061   else lcap_val(t)=0;
9062   return t;
9063 }
9064
9065 @ When a dashed line is computed in a transformed coordinate system, the dash
9066 lengths get scaled like the pen shape and we need to compensate for this.  Since
9067 there is no unique scale factor for an arbitrary transformation, we use the
9068 the square root of the determinant.  The properties of the determinant make it
9069 easier to maintain the |dash_scale|.  The computation is fairly straight-forward
9070 except for the initialization of the scale factor |s|.  The factor of 64 is
9071 needed because |square_rt| scales its result by $2^8$ while we need $2^{14}$
9072 to counteract the effect of |take_fraction|.
9073
9074 @<Declare subroutines needed by |print_edges|@>=
9075 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) {
9076   scaled maxabs; /* $max(|a|,|b|,|c|,|d|)$ */
9077   integer s; /* amount by which the result of |square_rt| needs to be scaled */
9078   @<Initialize |maxabs|@>;
9079   s=64;
9080   while ( (maxabs<fraction_one) && (s>1) ){ 
9081     a+=a; b+=b; c+=c; d+=d;
9082     maxabs+=maxabs; s=halfp(s);
9083   }
9084   return s*mp_square_rt(mp, abs(mp_take_fraction(mp, a,d)-mp_take_fraction(mp, b,c)));
9085 }
9086 @#
9087 scaled mp_get_pen_scale (MP mp,pointer p) { 
9088   return mp_sqrt_det(mp, 
9089     left_x(p)-x_coord(p), right_x(p)-x_coord(p),
9090     left_y(p)-y_coord(p), right_y(p)-y_coord(p));
9091 }
9092
9093 @ @<Initialize |maxabs|@>=
9094 maxabs=abs(a);
9095 if ( abs(b)>maxabs ) maxabs=abs(b);
9096 if ( abs(c)>maxabs ) maxabs=abs(c);
9097 if ( abs(d)>maxabs ) maxabs=abs(d)
9098
9099 @ When a picture contains text, this is represented by a fourteen-word node
9100 where the color information and |type| and |link| fields are augmented by
9101 additional fields that describe the text and  how it is transformed.
9102 The |path_p| and |pen_p| pointers are replaced by a number that identifies
9103 the font and a string number that gives the text to be displayed.
9104 The |width|, |height|, and |depth| fields
9105 give the dimensions of the text at its design size, and the remaining six
9106 words give a transformation to be applied to the text.  The |new_text_node|
9107 function initializes everything to default values so that the text comes out
9108 black with its reference point at the origin.
9109
9110 @d text_p(A) link((A)+1)  /* a string pointer for the text to display */
9111 @d font_n(A) info((A)+1)  /* the font number */
9112 @d width_val(A) mp->mem[(A)+7].sc  /* unscaled width of the text */
9113 @d height_val(A) mp->mem[(A)+9].sc  /* unscaled height of the text */
9114 @d depth_val(A) mp->mem[(A)+10].sc  /* unscaled depth of the text */
9115 @d text_tx_loc(A) ((A)+11)
9116   /* the first of six locations for transformation parameters */
9117 @d tx_val(A) mp->mem[(A)+11].sc  /* $x$ shift amount */
9118 @d ty_val(A) mp->mem[(A)+12].sc  /* $y$ shift amount */
9119 @d txx_val(A) mp->mem[(A)+13].sc  /* |txx| transformation parameter */
9120 @d txy_val(A) mp->mem[(A)+14].sc  /* |txy| transformation parameter */
9121 @d tyx_val(A) mp->mem[(A)+15].sc  /* |tyx| transformation parameter */
9122 @d tyy_val(A) mp->mem[(A)+16].sc  /* |tyy| transformation parameter */
9123 @d text_trans_part(A) mp->mem[(A)+11-x_part].sc
9124     /* interpret a text node ponter that has been offset by |x_part..yy_part| */
9125 @d text_node_size 17
9126 @d text_code 3
9127
9128 @c @<Declare text measuring subroutines@>;
9129 pointer mp_new_text_node (MP mp,char *f,str_number s) {
9130   /* make a text node for font |f| and text string |s| */
9131   pointer t; /* the new node */
9132   t=mp_get_node(mp, text_node_size);
9133   type(t)=text_code;
9134   text_p(t)=s;
9135   font_n(t)=mp_find_font(mp, f); /* this identifies the font */
9136   red_val(t)=0;
9137   green_val(t)=0;
9138   blue_val(t)=0;
9139   black_val(t)=0;
9140   color_model(t)=uninitialized_model;
9141   pre_script(t)=null;
9142   post_script(t)=null;
9143   tx_val(t)=0; ty_val(t)=0;
9144   txx_val(t)=unity; txy_val(t)=0;
9145   tyx_val(t)=0; tyy_val(t)=unity;
9146   mp_set_text_box(mp, t); /* this finds the bounding box */
9147   return t;
9148 }
9149
9150 @ The last two types of graphical objects that can occur in an edge structure
9151 are clipping paths and \&{setbounds} paths.  These are slightly more difficult
9152 @:set_bounds_}{\&{setbounds} primitive@>
9153 to implement because we must keep track of exactly what is being clipped or
9154 bounded when pictures get merged together.  For this reason, each clipping or
9155 \&{setbounds} operation is represented by a pair of nodes:  first comes a
9156 two-word node whose |path_p| gives the relevant path, then there is the list
9157 of objects to clip or bound followed by a two-word node whose second word is
9158 unused.
9159
9160 Using at least two words for each graphical object node allows them all to be
9161 allocated and deallocated similarly with a global array |gr_object_size| to
9162 give the size in words for each object type.
9163
9164 @d start_clip_size 2
9165 @d start_bounds_size 2
9166 @d stop_clip_size 2 /* the second word is not used here */
9167 @d stop_bounds_size 2 /* the second word is not used here */
9168 @#
9169 @d stop_type(A) ((A)+2)
9170   /* matching |type| for |start_clip_code| or |start_bounds_code| */
9171 @d has_color(A) (type((A))<mp_start_clip_code)
9172   /* does a graphical object have color fields? */
9173 @d has_pen(A) (type((A))<text_code)
9174   /* does a graphical object have a |pen_p| field? */
9175 @d is_start_or_stop(A) (type((A))>=mp_start_clip_code)
9176 @d is_stop(A) (type((A))>=mp_stop_clip_code)
9177
9178 @<Types...@>=
9179 enum {
9180  mp_start_clip_code=4, /* |type| of a node that starts clipping */
9181  mp_start_bounds_code, /* |type| of a node that gives a \&{setbounds} path */
9182  mp_stop_clip_code, /* |type| of a node that stops clipping */
9183  mp_stop_bounds_code /* |type| of a node that stops \&{setbounds} */
9184 };
9185
9186 @ @c 
9187 pointer mp_new_bounds_node (MP mp,pointer p, small_number  c) {
9188   /* make a node of type |c| where |p| is the clipping or \&{setbounds} path */
9189   pointer t; /* the new node */
9190   t=mp_get_node(mp, mp->gr_object_size[c]);
9191   type(t)=c;
9192   path_p(t)=p;
9193   return t;
9194 };
9195
9196 @ We need an array to keep track of the sizes of graphical objects.
9197
9198 @<Glob...@>=
9199 small_number gr_object_size[mp_stop_bounds_code+1];
9200
9201 @ @<Set init...@>=
9202 mp->gr_object_size[fill_code]=fill_node_size;
9203 mp->gr_object_size[stroked_code]=stroked_node_size;
9204 mp->gr_object_size[text_code]=text_node_size;
9205 mp->gr_object_size[mp_start_clip_code]=start_clip_size;
9206 mp->gr_object_size[mp_stop_clip_code]=stop_clip_size;
9207 mp->gr_object_size[mp_start_bounds_code]=start_bounds_size;
9208 mp->gr_object_size[mp_stop_bounds_code]=stop_bounds_size;
9209
9210 @ All the essential information in an edge structure is encoded as a linked list
9211 of graphical objects as we have just seen, but it is helpful to add some
9212 redundant information.  A single edge structure might be used as a dash pattern
9213 many times, and it would be nice to avoid scanning the same structure
9214 repeatedly.  Thus, an edge structure known to be a suitable dash pattern
9215 has a header that gives a list of dashes in a sorted order designed for rapid
9216 translation into \ps.
9217
9218 Each dash is represented by a three-word node containing the initial and final
9219 $x$~coordinates as well as the usual |link| field.  The |link| fields points to
9220 the dash node with the next higher $x$-coordinates and the final link points
9221 to a special location called |null_dash|.  (There should be no overlap between
9222 dashes).  Since the $y$~coordinate of the dash pattern is needed to determine
9223 the period of repetition, this needs to be stored in the edge header along
9224 with a pointer to the list of dash nodes.
9225
9226 @d start_x(A) mp->mem[(A)+1].sc  /* the starting $x$~coordinate in a dash node */
9227 @d stop_x(A) mp->mem[(A)+2].sc  /* the ending $x$~coordinate in a dash node */
9228 @d dash_node_size 3
9229 @d dash_list link
9230   /* in an edge header this points to the first dash node */
9231 @d dash_y(A) mp->mem[(A)+1].sc  /* $y$ value for the dash list in an edge header */
9232
9233 @ It is also convenient for an edge header to contain the bounding
9234 box information needed by the \&{llcorner} and \&{urcorner} operators
9235 so that this does not have to be recomputed unnecessarily.  This is done by
9236 adding fields for the $x$~and $y$ extremes as well as a pointer that indicates
9237 how far the bounding box computation has gotten.  Thus if the user asks for
9238 the bounding box and then adds some more text to the picture before asking
9239 for more bounding box information, the second computation need only look at
9240 the additional text.
9241
9242 When the bounding box has not been computed, the |bblast| pointer points
9243 to a dummy link at the head of the graphical object list while the |minx_val|
9244 and |miny_val| fields contain |el_gordo| and the |maxx_val| and |maxy_val|
9245 fields contain |-el_gordo|.
9246
9247 Since the bounding box of pictures containing objects of type
9248 |mp_start_bounds_code| depends on the value of \&{truecorners}, the bounding box
9249 @:true_corners_}{\&{truecorners} primitive@>
9250 data might not be valid for all values of this parameter.  Hence, the |bbtype|
9251 field is needed to keep track of this.
9252
9253 @d minx_val(A) mp->mem[(A)+2].sc
9254 @d miny_val(A) mp->mem[(A)+3].sc
9255 @d maxx_val(A) mp->mem[(A)+4].sc
9256 @d maxy_val(A) mp->mem[(A)+5].sc
9257 @d bblast(A) link((A)+6)  /* last item considered in bounding box computation */
9258 @d bbtype(A) info((A)+6)  /* tells how bounding box data depends on \&{truecorners} */
9259 @d dummy_loc(A) ((A)+7)  /* where the object list begins in an edge header */
9260 @d no_bounds 0
9261   /* |bbtype| value when bounding box data is valid for all \&{truecorners} values */
9262 @d bounds_set 1
9263   /* |bbtype| value when bounding box data is for \&{truecorners}${}\le 0$ */
9264 @d bounds_unset 2
9265   /* |bbtype| value when bounding box data is for \&{truecorners}${}>0$ */
9266
9267 @c 
9268 void mp_init_bbox (MP mp,pointer h) {
9269   /* Initialize the bounding box information in edge structure |h| */
9270   bblast(h)=dummy_loc(h);
9271   bbtype(h)=no_bounds;
9272   minx_val(h)=el_gordo;
9273   miny_val(h)=el_gordo;
9274   maxx_val(h)=-el_gordo;
9275   maxy_val(h)=-el_gordo;
9276 }
9277
9278 @ The only other entries in an edge header are a reference count in the first
9279 word and a pointer to the tail of the object list in the last word.
9280
9281 @d obj_tail(A) info((A)+7)  /* points to the last entry in the object list */
9282 @d edge_header_size 8
9283
9284 @c 
9285 void mp_init_edges (MP mp,pointer h) {
9286   /* initialize an edge header to null values */
9287   dash_list(h)=null_dash;
9288   obj_tail(h)=dummy_loc(h);
9289   link(dummy_loc(h))=null;
9290   ref_count(h)=null;
9291   mp_init_bbox(mp, h);
9292 }
9293
9294 @ Here is how edge structures are deleted.  The process can be recursive because
9295 of the need to dereference edge structures that are used as dash patterns.
9296 @^recursion@>
9297
9298 @d add_edge_ref(A) incr(ref_count((A)))
9299 @d delete_edge_ref(A) { if ( ref_count((A))==null ) mp_toss_edges(mp, (A));
9300   else decr(ref_count((A))); }
9301
9302 @<Declare the recycling subroutines@>=
9303 void mp_flush_dash_list (MP mp,pointer h);
9304 pointer mp_toss_gr_object (MP mp,pointer p) ;
9305 void mp_toss_edges (MP mp,pointer h) ;
9306
9307 @ @c void mp_toss_edges (MP mp,pointer h) {
9308   pointer p,q;  /* pointers that scan the list being recycled */
9309   pointer r; /* an edge structure that object |p| refers to */
9310   mp_flush_dash_list(mp, h);
9311   q=link(dummy_loc(h));
9312   while ( (q!=null) ) { 
9313     p=q; q=link(q);
9314     r=mp_toss_gr_object(mp, p);
9315     if ( r!=null ) delete_edge_ref(r);
9316   }
9317   mp_free_node(mp, h,edge_header_size);
9318 }
9319 void mp_flush_dash_list (MP mp,pointer h) {
9320   pointer p,q;  /* pointers that scan the list being recycled */
9321   q=dash_list(h);
9322   while ( q!=null_dash ) { 
9323     p=q; q=link(q);
9324     mp_free_node(mp, p,dash_node_size);
9325   }
9326   dash_list(h)=null_dash;
9327 }
9328 pointer mp_toss_gr_object (MP mp,pointer p) {
9329   /* returns an edge structure that needs to be dereferenced */
9330   pointer e; /* the edge structure to return */
9331   e=null;
9332   @<Prepare to recycle graphical object |p|@>;
9333   mp_free_node(mp, p,mp->gr_object_size[type(p)]);
9334   return e;
9335 }
9336
9337 @ @<Prepare to recycle graphical object |p|@>=
9338 switch (type(p)) {
9339 case fill_code: 
9340   mp_toss_knot_list(mp, path_p(p));
9341   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9342   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9343   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9344   break;
9345 case stroked_code: 
9346   mp_toss_knot_list(mp, path_p(p));
9347   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9348   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9349   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9350   e=dash_p(p);
9351   break;
9352 case text_code: 
9353   delete_str_ref(text_p(p));
9354   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9355   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9356   break;
9357 case mp_start_clip_code:
9358 case mp_start_bounds_code: 
9359   mp_toss_knot_list(mp, path_p(p));
9360   break;
9361 case mp_stop_clip_code:
9362 case mp_stop_bounds_code: 
9363   break;
9364 } /* there are no other cases */
9365
9366 @ If we use |add_edge_ref| to ``copy'' edge structures, the real copying needs
9367 to be done before making a significant change to an edge structure.  Much of
9368 the work is done in a separate routine |copy_objects| that copies a list of
9369 graphical objects into a new edge header.
9370
9371 @c @<Declare a function called |copy_objects|@>;
9372 pointer mp_private_edges (MP mp,pointer h) {
9373   /* make a private copy of the edge structure headed by |h| */
9374   pointer hh;  /* the edge header for the new copy */
9375   pointer p,pp;  /* pointers for copying the dash list */
9376   if ( ref_count(h)==null ) {
9377     return h;
9378   } else { 
9379     decr(ref_count(h));
9380     hh=mp_copy_objects(mp, link(dummy_loc(h)),null);
9381     @<Copy the dash list from |h| to |hh|@>;
9382     @<Copy the bounding box information from |h| to |hh| and make |bblast(hh)|
9383       point into the new object list@>;
9384     return hh;
9385   }
9386 }
9387
9388 @ Here we use the fact that |dash_list(hh)=link(hh)|.
9389 @^data structure assumptions@>
9390
9391 @<Copy the dash list from |h| to |hh|@>=
9392 pp=hh; p=dash_list(h);
9393 while ( (p!=null_dash) ) { 
9394   link(pp)=mp_get_node(mp, dash_node_size);
9395   pp=link(pp);
9396   start_x(pp)=start_x(p);
9397   stop_x(pp)=stop_x(p);
9398   p=link(p);
9399 }
9400 link(pp)=null_dash;
9401 dash_y(hh)=dash_y(h)
9402
9403 @ @<Copy the bounding box information from |h| to |hh|...@>=
9404 minx_val(hh)=minx_val(h);
9405 miny_val(hh)=miny_val(h);
9406 maxx_val(hh)=maxx_val(h);
9407 maxy_val(hh)=maxy_val(h);
9408 bbtype(hh)=bbtype(h);
9409 p=dummy_loc(h); pp=dummy_loc(hh);
9410 while ((p!=bblast(h)) ) { 
9411   if ( p==null ) mp_confusion(mp, "bblast");
9412 @:this can't happen bblast}{\quad bblast@>
9413   p=link(p); pp=link(pp);
9414 }
9415 bblast(hh)=pp
9416
9417 @ Here is the promised routine for copying graphical objects into a new edge
9418 structure.  It starts copying at object~|p| and stops just before object~|q|.
9419 If |q| is null, it copies the entire sublist headed at |p|.  The resulting edge
9420 structure requires further initialization by |init_bbox|.
9421
9422 @<Declare a function called |copy_objects|@>=
9423 pointer mp_copy_objects (MP mp, pointer p, pointer q) {
9424   pointer hh;  /* the new edge header */
9425   pointer pp;  /* the last newly copied object */
9426   small_number k;  /* temporary register */
9427   hh=mp_get_node(mp, edge_header_size);
9428   dash_list(hh)=null_dash;
9429   ref_count(hh)=null;
9430   pp=dummy_loc(hh);
9431   while ( (p!=q) ) {
9432     @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>;
9433   }
9434   obj_tail(hh)=pp;
9435   link(pp)=null;
9436   return hh;
9437 }
9438
9439 @ @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>=
9440 { k=mp->gr_object_size[type(p)];
9441   link(pp)=mp_get_node(mp, k);
9442   pp=link(pp);
9443   while ( (k>0) ) { decr(k); mp->mem[pp+k]=mp->mem[p+k];  };
9444   @<Fix anything in graphical object |pp| that should differ from the
9445     corresponding field in |p|@>;
9446   p=link(p);
9447 }
9448
9449 @ @<Fix anything in graphical object |pp| that should differ from the...@>=
9450 switch (type(p)) {
9451 case mp_start_clip_code:
9452 case mp_start_bounds_code: 
9453   path_p(pp)=mp_copy_path(mp, path_p(p));
9454   break;
9455 case fill_code: 
9456   path_p(pp)=mp_copy_path(mp, path_p(p));
9457   if ( pen_p(p)!=null ) pen_p(pp)=copy_pen(pen_p(p));
9458   break;
9459 case stroked_code: 
9460   path_p(pp)=mp_copy_path(mp, path_p(p));
9461   pen_p(pp)=copy_pen(pen_p(p));
9462   if ( dash_p(p)!=null ) add_edge_ref(dash_p(pp));
9463   break;
9464 case text_code: 
9465   add_str_ref(text_p(pp));
9466   break;
9467 case mp_stop_clip_code:
9468 case mp_stop_bounds_code: 
9469   break;
9470 }  /* there are no other cases */
9471
9472 @ Here is one way to find an acceptable value for the second argument to
9473 |copy_objects|.  Given a non-null graphical object list, |skip_1component|
9474 skips past one picture component, where a ``picture component'' is a single
9475 graphical object, or a start bounds or start clip object and everything up
9476 through the matching stop bounds or stop clip object.  The macro version avoids
9477 procedure call overhead and error handling: |skip_component(p)(e)| advances |p|
9478 unless |p| points to a stop bounds or stop clip node, in which case it executes
9479 |e| instead.
9480
9481 @d skip_component(A)
9482     if ( ! is_start_or_stop((A)) ) (A)=link((A));
9483     else if ( ! is_stop((A)) ) (A)=mp_skip_1component(mp, (A));
9484     else 
9485
9486 @c 
9487 pointer mp_skip_1component (MP mp,pointer p) {
9488   integer lev; /* current nesting level */
9489   lev=0;
9490   do {  
9491    if ( is_start_or_stop(p) ) {
9492      if ( is_stop(p) ) decr(lev);  else incr(lev);
9493    }
9494    p=link(p);
9495   } while (lev!=0);
9496   return p;
9497 }
9498
9499 @ Here is a diagnostic routine for printing an edge structure in symbolic form.
9500
9501 @<Declare subroutines for printing expressions@>=
9502 @<Declare subroutines needed by |print_edges|@>;
9503 void mp_print_edges (MP mp,pointer h, char *s, boolean nuline) {
9504   pointer p;  /* a graphical object to be printed */
9505   pointer hh,pp;  /* temporary pointers */
9506   scaled scf;  /* a scale factor for the dash pattern */
9507   boolean ok_to_dash;  /* |false| for polygonal pen strokes */
9508   mp_print_diagnostic(mp, "Edge structure",s,nuline);
9509   p=dummy_loc(h);
9510   while ( link(p)!=null ) { 
9511     p=link(p);
9512     mp_print_ln(mp);
9513     switch (type(p)) {
9514       @<Cases for printing graphical object node |p|@>;
9515     default: 
9516           mp_print(mp, "[unknown object type!]");
9517           break;
9518     }
9519   }
9520   mp_print_nl(mp, "End edges");
9521   if ( p!=obj_tail(h) ) mp_print(mp, "?");
9522 @.End edges?@>
9523   mp_end_diagnostic(mp, true);
9524 }
9525
9526 @ @<Cases for printing graphical object node |p|@>=
9527 case fill_code: 
9528   mp_print(mp, "Filled contour ");
9529   mp_print_obj_color(mp, p);
9530   mp_print_char(mp, ':'); mp_print_ln(mp);
9531   mp_pr_path(mp, path_p(p)); mp_print_ln(mp);
9532   if ( (pen_p(p)!=null) ) {
9533     @<Print join type for graphical object |p|@>;
9534     mp_print(mp, " with pen"); mp_print_ln(mp);
9535     mp_pr_pen(mp, pen_p(p));
9536   }
9537   break;
9538
9539 @ @<Print join type for graphical object |p|@>=
9540 switch (ljoin_val(p)) {
9541 case 0:
9542   mp_print(mp, "mitered joins limited ");
9543   mp_print_scaled(mp, miterlim_val(p));
9544   break;
9545 case 1:
9546   mp_print(mp, "round joins");
9547   break;
9548 case 2:
9549   mp_print(mp, "beveled joins");
9550   break;
9551 default: 
9552   mp_print(mp, "?? joins");
9553 @.??@>
9554   break;
9555 }
9556
9557 @ For stroked nodes, we need to print |lcap_val(p)| as well.
9558
9559 @<Print join and cap types for stroked node |p|@>=
9560 switch (lcap_val(p)) {
9561 case 0:mp_print(mp, "butt"); break;
9562 case 1:mp_print(mp, "round"); break;
9563 case 2:mp_print(mp, "square"); break;
9564 default: mp_print(mp, "??"); break;
9565 @.??@>
9566 }
9567 mp_print(mp, " ends, ");
9568 @<Print join type for graphical object |p|@>
9569
9570 @ Here is a routine that prints the color of a graphical object if it isn't
9571 black (the default color).
9572
9573 @<Declare subroutines needed by |print_edges|@>=
9574 @<Declare a procedure called |print_compact_node|@>;
9575 void mp_print_obj_color (MP mp,pointer p) { 
9576   if ( color_model(p)==grey_model ) {
9577     if ( grey_val(p)>0 ) { 
9578       mp_print(mp, "greyed ");
9579       mp_print_compact_node(mp, obj_grey_loc(p),1);
9580     };
9581   } else if ( color_model(p)==cmyk_model ) {
9582     if ( (cyan_val(p)>0) || (magenta_val(p)>0) || 
9583          (yellow_val(p)>0) || (black_val(p)>0) ) { 
9584       mp_print(mp, "processcolored ");
9585       mp_print_compact_node(mp, obj_cyan_loc(p),4);
9586     };
9587   } else if ( color_model(p)==rgb_model ) {
9588     if ( (red_val(p)>0) || (green_val(p)>0) || (blue_val(p)>0) ) { 
9589       mp_print(mp, "colored "); 
9590       mp_print_compact_node(mp, obj_red_loc(p),3);
9591     };
9592   }
9593 }
9594
9595 @ We also need a procedure for printing consecutive scaled values as if they
9596 were a known big node.
9597
9598 @<Declare a procedure called |print_compact_node|@>=
9599 void mp_print_compact_node (MP mp,pointer p, small_number k) {
9600   pointer q;  /* last location to print */
9601   q=p+k-1;
9602   mp_print_char(mp, '(');
9603   while ( p<=q ){ 
9604     mp_print_scaled(mp, mp->mem[p].sc);
9605     if ( p<q ) mp_print_char(mp, ',');
9606     incr(p);
9607   }
9608   mp_print_char(mp, ')');
9609 }
9610
9611 @ @<Cases for printing graphical object node |p|@>=
9612 case stroked_code: 
9613   mp_print(mp, "Filled pen stroke ");
9614   mp_print_obj_color(mp, p);
9615   mp_print_char(mp, ':'); mp_print_ln(mp);
9616   mp_pr_path(mp, path_p(p));
9617   if ( dash_p(p)!=null ) { 
9618     mp_print_nl(mp, "dashed (");
9619     @<Finish printing the dash pattern that |p| refers to@>;
9620   }
9621   mp_print_ln(mp);
9622   @<Print join and cap types for stroked node |p|@>;
9623   mp_print(mp, " with pen"); mp_print_ln(mp);
9624   if ( pen_p(p)==null ) mp_print(mp, "???"); /* shouldn't happen */
9625 @.???@>
9626   else mp_pr_pen(mp, pen_p(p));
9627   break;
9628
9629 @ Normally, the  |dash_list| field in an edge header is set to |null_dash|
9630 when it is not known to define a suitable dash pattern.  This is disallowed
9631 here because the |dash_p| field should never point to such an edge header.
9632 Note that memory is allocated for |start_x(null_dash)| and we are free to
9633 give it any convenient value.
9634
9635 @<Finish printing the dash pattern that |p| refers to@>=
9636 ok_to_dash=pen_is_elliptical(pen_p(p));
9637 if ( ! ok_to_dash ) scf=unity; else scf=dash_scale(p);
9638 hh=dash_p(p);
9639 pp=dash_list(hh);
9640 if ( (pp==null_dash) || (dash_y(hh)<0) ) {
9641   mp_print(mp, " ??");
9642 } else { start_x(null_dash)=start_x(pp)+dash_y(hh);
9643   while ( pp!=null_dash ) { 
9644     mp_print(mp, "on ");
9645     mp_print_scaled(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf));
9646     mp_print(mp, " off ");
9647     mp_print_scaled(mp, mp_take_scaled(mp, start_x(link(pp))-stop_x(pp),scf));
9648     pp = link(pp);
9649     if ( pp!=null_dash ) mp_print_char(mp, ' ');
9650   }
9651   mp_print(mp, ") shifted ");
9652   mp_print_scaled(mp, -mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
9653   if ( ! ok_to_dash || (dash_y(hh)==0) ) mp_print(mp, " (this will be ignored)");
9654 }
9655
9656 @ @<Declare subroutines needed by |print_edges|@>=
9657 scaled mp_dash_offset (MP mp,pointer h) {
9658   scaled x;  /* the answer */
9659   if ( (dash_list(h)==null_dash) || (dash_y(h)<0) ) mp_confusion(mp, "dash0");
9660 @:this can't happen dash0}{\quad dash0@>
9661   if ( dash_y(h)==0 ) {
9662     x=0; 
9663   } else { 
9664     x=-(start_x(dash_list(h)) % dash_y(h));
9665     if ( x<0 ) x=x+dash_y(h);
9666   }
9667   return x;
9668 }
9669
9670 @ @<Cases for printing graphical object node |p|@>=
9671 case text_code: 
9672   mp_print_char(mp, '"'); mp_print_str(mp,text_p(p));
9673   mp_print(mp, "\" infont \""); mp_print(mp, mp->font_name[font_n(p)]);
9674   mp_print_char(mp, '"'); mp_print_ln(mp);
9675   mp_print_obj_color(mp, p);
9676   mp_print(mp, "transformed ");
9677   mp_print_compact_node(mp, text_tx_loc(p),6);
9678   break;
9679
9680 @ @<Cases for printing graphical object node |p|@>=
9681 case mp_start_clip_code: 
9682   mp_print(mp, "clipping path:");
9683   mp_print_ln(mp);
9684   mp_pr_path(mp, path_p(p));
9685   break;
9686 case mp_stop_clip_code: 
9687   mp_print(mp, "stop clipping");
9688   break;
9689
9690 @ @<Cases for printing graphical object node |p|@>=
9691 case mp_start_bounds_code: 
9692   mp_print(mp, "setbounds path:");
9693   mp_print_ln(mp);
9694   mp_pr_path(mp, path_p(p));
9695   break;
9696 case mp_stop_bounds_code: 
9697   mp_print(mp, "end of setbounds");
9698   break;
9699
9700 @ To initialize the |dash_list| field in an edge header~|h|, we need a
9701 subroutine that scans an edge structure and tries to interpret it as a dash
9702 pattern.  This can only be done when there are no filled regions or clipping
9703 paths and all the pen strokes have the same color.  The first step is to let
9704 $y_0$ be the initial $y$~coordinate of the first pen stroke.  Then we implicitly
9705 project all the pen stroke paths onto the line $y=y_0$ and require that there
9706 be no retracing.  If the resulting paths cover a range of $x$~coordinates of
9707 length $\Delta x$, we set |dash_y(h)| to the length of the dash pattern by
9708 finding the maximum of $\Delta x$ and the absolute value of~$y_0$.
9709
9710 @c @<Declare a procedure called |x_retrace_error|@>;
9711 pointer mp_make_dashes (MP mp,pointer h) { /* returns |h| or |null| */
9712   pointer p;  /* this scans the stroked nodes in the object list */
9713   pointer p0;  /* if not |null| this points to the first stroked node */
9714   pointer pp,qq,rr;  /* pointers into |path_p(p)| */
9715   pointer d,dd;  /* pointers used to create the dash list */
9716   @<Other local variables in |make_dashes|@>;
9717   scaled y0=0;  /* the initial $y$ coordinate */
9718   if ( dash_list(h)!=null_dash ) 
9719         return h;
9720   p0=null;
9721   p=link(dummy_loc(h));
9722   while ( p!=null ) { 
9723     if ( type(p)!=stroked_code ) {
9724       @<Compain that the edge structure contains a node of the wrong type
9725         and |goto not_found|@>;
9726     }
9727     pp=path_p(p);
9728     if ( p0==null ){ p0=p; y0=y_coord(pp);  };
9729     @<Make |d| point to a new dash node created from stroke |p| and path |pp|
9730       or |goto not_found| if there is an error@>;
9731     @<Insert |d| into the dash list and |goto not_found| if there is an error@>;
9732     p=link(p);
9733   }
9734   if ( dash_list(h)==null_dash ) 
9735     goto NOT_FOUND; /* No error message */
9736   @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>;
9737   @<Set |dash_y(h)| and merge the first and last dashes if necessary@>;
9738   return h;
9739 NOT_FOUND: 
9740   @<Flush the dash list, recycle |h| and return |null|@>;
9741 };
9742
9743 @ @<Compain that the edge structure contains a node of the wrong type...@>=
9744
9745 print_err("Picture is too complicated to use as a dash pattern");
9746 help3("When you say `dashed p', picture p should not contain any")
9747   ("text, filled regions, or clipping paths.  This time it did")
9748   ("so I'll just make it a solid line instead.");
9749 mp_put_get_error(mp);
9750 goto NOT_FOUND;
9751 }
9752
9753 @ A similar error occurs when monotonicity fails.
9754
9755 @<Declare a procedure called |x_retrace_error|@>=
9756 void mp_x_retrace_error (MP mp) { 
9757 print_err("Picture is too complicated to use as a dash pattern");
9758 help3("When you say `dashed p', every path in p should be monotone")
9759   ("in x and there must be no overlapping.  This failed")
9760   ("so I'll just make it a solid line instead.");
9761 mp_put_get_error(mp);
9762 }
9763
9764 @ We stash |p| in |info(d)| if |dash_p(p)<>0| so that subsequent processing can
9765 handle the case where the pen stroke |p| is itself dashed.
9766
9767 @<Make |d| point to a new dash node created from stroke |p| and path...@>=
9768 @<Make sure |p| and |p0| are the same color and |goto not_found| if there is
9769   an error@>;
9770 rr=pp;
9771 if ( link(pp)!=pp ) {
9772   do {  
9773     qq=rr; rr=link(rr);
9774     @<Check for retracing between knots |qq| and |rr| and |goto not_found|
9775       if there is a problem@>;
9776   } while (right_type(rr)!=endpoint);
9777 }
9778 d=mp_get_node(mp, dash_node_size);
9779 if ( dash_p(p)==0 ) info(d)=0;  else info(d)=p;
9780 if ( x_coord(pp)<x_coord(rr) ) { 
9781   start_x(d)=x_coord(pp);
9782   stop_x(d)=x_coord(rr);
9783 } else { 
9784   start_x(d)=x_coord(rr);
9785   stop_x(d)=x_coord(pp);
9786 }
9787
9788 @ We also need to check for the case where the segment from |qq| to |rr| is
9789 monotone in $x$ but is reversed relative to the path from |pp| to |qq|.
9790
9791 @<Check for retracing between knots |qq| and |rr| and |goto not_found|...@>=
9792 x0=x_coord(qq);
9793 x1=right_x(qq);
9794 x2=left_x(rr);
9795 x3=x_coord(rr);
9796 if ( (x0>x1) || (x1>x2) || (x2>x3) ) {
9797   if ( (x0<x1) || (x1<x2) || (x2<x3) ) {
9798     if ( mp_ab_vs_cd(mp, x2-x1,x2-x1,x1-x0,x3-x2)>0 ) {
9799       mp_x_retrace_error(mp); goto NOT_FOUND;
9800     }
9801   }
9802 }
9803 if ( (x_coord(pp)>x0) || (x0>x3) ) {
9804   if ( (x_coord(pp)<x0) || (x0<x3) ) {
9805     mp_x_retrace_error(mp); goto NOT_FOUND;
9806   }
9807 }
9808
9809 @ @<Other local variables in |make_dashes|@>=
9810   scaled x0,x1,x2,x3;  /* $x$ coordinates of the segment from |qq| to |rr| */
9811
9812 @ @<Make sure |p| and |p0| are the same color and |goto not_found|...@>=
9813 if ( (red_val(p)!=red_val(p0)) || (black_val(p)!=black_val(p0)) ||
9814   (green_val(p)!=green_val(p0)) || (blue_val(p)!=blue_val(p0)) ) {
9815   print_err("Picture is too complicated to use as a dash pattern");
9816   help3("When you say `dashed p', everything in picture p should")
9817     ("be the same color.  I can\'t handle your color changes")
9818     ("so I'll just make it a solid line instead.");
9819   mp_put_get_error(mp);
9820   goto NOT_FOUND;
9821 }
9822
9823 @ @<Insert |d| into the dash list and |goto not_found| if there is an error@>=
9824 start_x(null_dash)=stop_x(d);
9825 dd=h; /* this makes |link(dd)=dash_list(h)| */
9826 while ( start_x(link(dd))<stop_x(d) )
9827   dd=link(dd);
9828 if ( dd!=h ) {
9829   if ( (stop_x(dd)>start_x(d)) )
9830     { mp_x_retrace_error(mp); goto NOT_FOUND;  };
9831 }
9832 link(d)=link(dd);
9833 link(dd)=d
9834
9835 @ @<Set |dash_y(h)| and merge the first and last dashes if necessary@>=
9836 d=dash_list(h);
9837 while ( (link(d)!=null_dash) )
9838   d=link(d);
9839 dd=dash_list(h);
9840 dash_y(h)=stop_x(d)-start_x(dd);
9841 if ( abs(y0)>dash_y(h) ) {
9842   dash_y(h)=abs(y0);
9843 } else if ( d!=dd ) { 
9844   dash_list(h)=link(dd);
9845   stop_x(d)=stop_x(dd)+dash_y(h);
9846   mp_free_node(mp, dd,dash_node_size);
9847 }
9848
9849 @ We get here when the argument is a null picture or when there is an error.
9850 Recovering from an error involves making |dash_list(h)| empty to indicate
9851 that |h| is not known to be a valid dash pattern.  We also dereference |h|
9852 since it is not being used for the return value.
9853
9854 @<Flush the dash list, recycle |h| and return |null|@>=
9855 mp_flush_dash_list(mp, h);
9856 delete_edge_ref(h);
9857 return null
9858
9859 @ Having carefully saved the dashed stroked nodes in the
9860 corresponding dash nodes, we must be prepared to break up these dashes into
9861 smaller dashes.
9862
9863 @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>=
9864 d=h;  /* now |link(d)=dash_list(h)| */
9865 while ( link(d)!=null_dash ) {
9866   ds=info(link(d));
9867   if ( ds==null ) { 
9868     d=link(d);
9869   } else {
9870     hh=dash_p(ds);
9871     hsf=dash_scale(ds);
9872     if ( (hh==null) ) mp_confusion(mp, "dash1");
9873 @:this can't happen dash0}{\quad dash1@>
9874     if ( dash_y(hh)==0 ) {
9875       d=link(d);
9876     } else { 
9877       if ( dash_list(hh)==null ) mp_confusion(mp, "dash1");
9878 @:this can't happen dash0}{\quad dash1@>
9879       @<Replace |link(d)| by a dashed version as determined by edge header
9880           |hh| and scale factor |ds|@>;
9881     }
9882   }
9883 }
9884
9885 @ @<Other local variables in |make_dashes|@>=
9886 pointer dln;  /* |link(d)| */
9887 pointer hh;  /* an edge header that tells how to break up |dln| */
9888 scaled hsf;  /* the dash pattern from |hh| gets scaled by this */
9889 pointer ds;  /* the stroked node from which |hh| and |hsf| are derived */
9890 scaled xoff;  /* added to $x$ values in |dash_list(hh)| to match |dln| */
9891
9892 @ @<Replace |link(d)| by a dashed version as determined by edge header...@>=
9893 dln=link(d);
9894 dd=dash_list(hh);
9895 xoff=start_x(dln)-mp_take_scaled(mp, hsf,start_x(dd))-
9896         mp_take_scaled(mp, hsf,mp_dash_offset(mp, hh));
9897 start_x(null_dash)=mp_take_scaled(mp, hsf,start_x(dd))
9898                    +mp_take_scaled(mp, hsf,dash_y(hh));
9899 stop_x(null_dash)=start_x(null_dash);
9900 @<Advance |dd| until finding the first dash that overlaps |dln| when
9901   offset by |xoff|@>;
9902 while ( start_x(dln)<=stop_x(dln) ) {
9903   @<If |dd| has `fallen off the end', back up to the beginning and fix |xoff|@>;
9904   @<Insert a dash between |d| and |dln| for the overlap with the offset version
9905     of |dd|@>;
9906   dd=link(dd);
9907   start_x(dln)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
9908 }
9909 link(d)=link(dln);
9910 mp_free_node(mp, dln,dash_node_size)
9911
9912 @ The name of this module is a bit of a lie because we actually just find the
9913 first |dd| where |take_scaled (hsf, stop_x(dd))| is large enough to make an
9914 overlap possible.  It could be that the unoffset version of dash |dln| falls
9915 in the gap between |dd| and its predecessor.
9916
9917 @<Advance |dd| until finding the first dash that overlaps |dln| when...@>=
9918 while ( xoff+mp_take_scaled(mp, hsf,stop_x(dd))<start_x(dln) ) {
9919   dd=link(dd);
9920 }
9921
9922 @ @<If |dd| has `fallen off the end', back up to the beginning and fix...@>=
9923 if ( dd==null_dash ) { 
9924   dd=dash_list(hh);
9925   xoff=xoff+mp_take_scaled(mp, hsf,dash_y(hh));
9926 }
9927
9928 @ At this point we already know that
9929 |start_x(dln)<=xoff+take_scaled(hsf,stop_x(dd))|.
9930
9931 @<Insert a dash between |d| and |dln| for the overlap with the offset...@>=
9932 if ( xoff+mp_take_scaled(mp, hsf,start_x(dd))<=stop_x(dln) ) {
9933   link(d)=mp_get_node(mp, dash_node_size);
9934   d=link(d);
9935   link(d)=dln;
9936   if ( start_x(dln)>xoff+mp_take_scaled(mp, hsf,start_x(dd)))
9937     start_x(d)=start_x(dln);
9938   else 
9939     start_x(d)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
9940   if ( stop_x(dln)<xoff+mp_take_scaled(mp, hsf,stop_x(dd)) ) 
9941     stop_x(d)=stop_x(dln);
9942   else 
9943     stop_x(d)=xoff+mp_take_scaled(mp, hsf,stop_x(dd));
9944 }
9945
9946 @ The next major task is to update the bounding box information in an edge
9947 header~|h|. This is done via a procedure |adjust_bbox| that enlarges an edge
9948 header's bounding box to accommodate the box computed by |path_bbox| or
9949 |pen_bbox|. (This is stored in global variables |minx|, |miny|, |maxx|, and
9950 |maxy|.)
9951
9952 @c void mp_adjust_bbox (MP mp,pointer h) { 
9953   if ( minx<minx_val(h) ) minx_val(h)=minx;
9954   if ( miny<miny_val(h) ) miny_val(h)=miny;
9955   if ( maxx>maxx_val(h) ) maxx_val(h)=maxx;
9956   if ( maxy>maxy_val(h) ) maxy_val(h)=maxy;
9957 }
9958
9959 @ Here is a special routine for updating the bounding box information in
9960 edge header~|h| to account for the squared-off ends of a non-cyclic path~|p|
9961 that is to be stroked with the pen~|pp|.
9962
9963 @c void mp_box_ends (MP mp, pointer p, pointer pp, pointer h) {
9964   pointer q;  /* a knot node adjacent to knot |p| */
9965   fraction dx,dy;  /* a unit vector in the direction out of the path at~|p| */
9966   scaled d;  /* a factor for adjusting the length of |(dx,dy)| */
9967   scaled z;  /* a coordinate being tested against the bounding box */
9968   scaled xx,yy;  /* the extreme pen vertex in the |(dx,dy)| direction */
9969   integer i; /* a loop counter */
9970   if ( right_type(p)!=endpoint ) { 
9971     q=link(p);
9972     while (1) { 
9973       @<Make |(dx,dy)| the final direction for the path segment from
9974         |q| to~|p|; set~|d|@>;
9975       d=mp_pyth_add(mp, dx,dy);
9976       if ( d>0 ) { 
9977          @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>;
9978          for (i=1;i<= 2;i++) { 
9979            @<Use |(dx,dy)| to generate a vertex of the square end cap and
9980              update the bounding box to accommodate it@>;
9981            dx=-dx; dy=-dy; 
9982         }
9983       }
9984       if ( right_type(p)==endpoint ) {
9985          return;
9986       } else {
9987         @<Advance |p| to the end of the path and make |q| the previous knot@>;
9988       } 
9989     }
9990   }
9991 }
9992
9993 @ @<Make |(dx,dy)| the final direction for the path segment from...@>=
9994 if ( q==link(p) ) { 
9995   dx=x_coord(p)-right_x(p);
9996   dy=y_coord(p)-right_y(p);
9997   if ( (dx==0)&&(dy==0) ) {
9998     dx=x_coord(p)-left_x(q);
9999     dy=y_coord(p)-left_y(q);
10000   }
10001 } else { 
10002   dx=x_coord(p)-left_x(p);
10003   dy=y_coord(p)-left_y(p);
10004   if ( (dx==0)&&(dy==0) ) {
10005     dx=x_coord(p)-right_x(q);
10006     dy=y_coord(p)-right_y(q);
10007   }
10008 }
10009 dx=x_coord(p)-x_coord(q);
10010 dy=y_coord(p)-y_coord(q)
10011
10012 @ @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>=
10013 dx=mp_make_fraction(mp, dx,d);
10014 dy=mp_make_fraction(mp, dy,d);
10015 mp_find_offset(mp, -dy,dx,pp);
10016 xx=mp->cur_x; yy=mp->cur_y
10017
10018 @ @<Use |(dx,dy)| to generate a vertex of the square end cap and...@>=
10019 mp_find_offset(mp, dx,dy,pp);
10020 d=mp_take_fraction(mp, xx-mp->cur_x,dx)+mp_take_fraction(mp, yy-mp->cur_y,dy);
10021 if ( ((d<0)&&(i==1)) || ((d>0)&&(i==2))) 
10022   mp_confusion(mp, "box_ends");
10023 @:this can't happen box ends}{\quad\\{box\_ends}@>
10024 z=x_coord(p)+mp->cur_x+mp_take_fraction(mp, d,dx);
10025 if ( z<minx_val(h) ) minx_val(h)=z;
10026 if ( z>maxx_val(h) ) maxx_val(h)=z;
10027 z=y_coord(p)+mp->cur_y+mp_take_fraction(mp, d,dy);
10028 if ( z<miny_val(h) ) miny_val(h)=z;
10029 if ( z>maxy_val(h) ) maxy_val(h)=z
10030
10031 @ @<Advance |p| to the end of the path and make |q| the previous knot@>=
10032 do {  
10033   q=p;
10034   p=link(p);
10035 } while (right_type(p)!=endpoint)
10036
10037 @ The major difficulty in finding the bounding box of an edge structure is the
10038 effect of clipping paths.  We treat them conservatively by only clipping to the
10039 clipping path's bounding box, but this still
10040 requires recursive calls to |set_bbox| in order to find the bounding box of
10041 @^recursion@>
10042 the objects to be clipped.  Such calls are distinguished by the fact that the
10043 boolean parameter |top_level| is false.
10044
10045 @c void mp_set_bbox (MP mp,pointer h, boolean top_level) {
10046   pointer p;  /* a graphical object being considered */
10047   scaled sminx,sminy,smaxx,smaxy;
10048   /* for saving the bounding box during recursive calls */
10049   scaled x0,x1,y0,y1;  /* temporary registers */
10050   integer lev;  /* nesting level for |mp_start_bounds_code| nodes */
10051   @<Wipe out any existing bounding box information if |bbtype(h)| is
10052   incompatible with |internal[true_corners]|@>;
10053   while ( link(bblast(h))!=null ) { 
10054     p=link(bblast(h));
10055     bblast(h)=p;
10056     switch (type(p)) {
10057     case mp_stop_clip_code: 
10058       if ( top_level ) mp_confusion(mp, "bbox");  else return;
10059 @:this can't happen bbox}{\quad bbox@>
10060       break;
10061     @<Other cases for updating the bounding box based on the type of object |p|@>;
10062     } /* all cases are enumerated above */
10063   }
10064   if ( ! top_level ) mp_confusion(mp, "bbox");
10065 }
10066
10067 @ @<Wipe out any existing bounding box information if |bbtype(h)| is...@>=
10068 switch (bbtype(h)) {
10069 case no_bounds: 
10070   break;
10071 case bounds_set: 
10072   if ( mp->internal[true_corners]>0 ) mp_init_bbox(mp, h);
10073   break;
10074 case bounds_unset: 
10075   if ( mp->internal[true_corners]<=0 ) mp_init_bbox(mp, h);
10076   break;
10077 } /* there are no other cases */
10078
10079 @ @<Other cases for updating the bounding box...@>=
10080 case fill_code: 
10081   mp_path_bbox(mp, path_p(p));
10082   if ( pen_p(p)!=null ) { 
10083     x0=minx; y0=miny;
10084     x1=maxx; y1=maxy;
10085     mp_pen_bbox(mp, pen_p(p));
10086     minx=minx+x0;
10087     miny=miny+y0;
10088     maxx=maxx+x1;
10089     maxy=maxy+y1;
10090   }
10091   mp_adjust_bbox(mp, h);
10092   break;
10093
10094 @ @<Other cases for updating the bounding box...@>=
10095 case mp_start_bounds_code: 
10096   if ( mp->internal[true_corners]>0 ) {
10097     bbtype(h)=bounds_unset;
10098   } else { 
10099     bbtype(h)=bounds_set;
10100     mp_path_bbox(mp, path_p(p));
10101     mp_adjust_bbox(mp, h);
10102     @<Scan to the matching |mp_stop_bounds_code| node and update |p| and
10103       |bblast(h)|@>;
10104   }
10105   break;
10106 case mp_stop_bounds_code: 
10107   if ( mp->internal[true_corners]<=0 ) mp_confusion(mp, "bbox2");
10108 @:this can't happen bbox2}{\quad bbox2@>
10109   break;
10110
10111 @ @<Scan to the matching |mp_stop_bounds_code| node and update |p| and...@>=
10112 lev=1;
10113 while ( lev!=0 ) { 
10114   if ( link(p)==null ) mp_confusion(mp, "bbox2");
10115 @:this can't happen bbox2}{\quad bbox2@>
10116   p=link(p);
10117   if ( type(p)==mp_start_bounds_code ) incr(lev);
10118   else if ( type(p)==mp_stop_bounds_code ) decr(lev);
10119 }
10120 bblast(h)=p
10121
10122 @ It saves a lot of grief here to be slightly conservative and not account for
10123 omitted parts of dashed lines.  We also don't worry about the material omitted
10124 when using butt end caps.  The basic computation is for round end caps and
10125 |box_ends| augments it for square end caps.
10126
10127 @<Other cases for updating the bounding box...@>=
10128 case stroked_code: 
10129   mp_path_bbox(mp, path_p(p));
10130   x0=minx; y0=miny;
10131   x1=maxx; y1=maxy;
10132   mp_pen_bbox(mp, pen_p(p));
10133   minx=minx+x0;
10134   miny=miny+y0;
10135   maxx=maxx+x1;
10136   maxy=maxy+y1;
10137   mp_adjust_bbox(mp, h);
10138   if ( (left_type(path_p(p))==endpoint)&&(lcap_val(p)==2) )
10139     mp_box_ends(mp, path_p(p), pen_p(p), h);
10140   break;
10141
10142 @ The height width and depth information stored in a text node determines a
10143 rectangle that needs to be transformed according to the transformation
10144 parameters stored in the text node.
10145
10146 @<Other cases for updating the bounding box...@>=
10147 case text_code: 
10148   x1=mp_take_scaled(mp, txx_val(p),width_val(p));
10149   y0=mp_take_scaled(mp, txy_val(p),-depth_val(p));
10150   y1=mp_take_scaled(mp, txy_val(p),height_val(p));
10151   minx=tx_val(p);
10152   maxx=minx;
10153   if ( y0<y1 ) { minx=minx+y0; maxx=maxx+y1;  }
10154   else         { minx=minx+y1; maxx=maxx+y0;  }
10155   if ( x1<0 ) minx=minx+x1;  else maxx=maxx+x1;
10156   x1=mp_take_scaled(mp, tyx_val(p),width_val(p));
10157   y0=mp_take_scaled(mp, tyy_val(p),-depth_val(p));
10158   y1=mp_take_scaled(mp, tyy_val(p),height_val(p));
10159   miny=ty_val(p);
10160   maxy=miny;
10161   if ( y0<y1 ) { miny=miny+y0; maxy=maxy+y1;  }
10162   else         { miny=miny+y1; maxy=maxy+y0;  }
10163   if ( x1<0 ) miny=miny+x1;  else maxy=maxy+x1;
10164   mp_adjust_bbox(mp, h);
10165   break;
10166
10167 @ This case involves a recursive call that advances |bblast(h)| to the node of
10168 type |mp_stop_clip_code| that matches |p|.
10169
10170 @<Other cases for updating the bounding box...@>=
10171 case mp_start_clip_code: 
10172   mp_path_bbox(mp, path_p(p));
10173   x0=minx; y0=miny;
10174   x1=maxx; y1=maxy;
10175   sminx=minx_val(h); sminy=miny_val(h);
10176   smaxx=maxx_val(h); smaxy=maxy_val(h);
10177   @<Reinitialize the bounding box in header |h| and call |set_bbox| recursively
10178     starting at |link(p)|@>;
10179   @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,
10180     |y0|, |y1|@>;
10181   minx=sminx; miny=sminy;
10182   maxx=smaxx; maxy=smaxy;
10183   mp_adjust_bbox(mp, h);
10184   break;
10185
10186 @ @<Reinitialize the bounding box in header |h| and call |set_bbox|...@>=
10187 minx_val(h)=el_gordo;
10188 miny_val(h)=el_gordo;
10189 maxx_val(h)=-el_gordo;
10190 maxy_val(h)=-el_gordo;
10191 mp_set_bbox(mp, h,false)
10192
10193 @ @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,...@>=
10194 if ( minx_val(h)<x0 ) minx_val(h)=x0;
10195 if ( miny_val(h)<y0 ) miny_val(h)=y0;
10196 if ( maxx_val(h)>x1 ) maxx_val(h)=x1;
10197 if ( maxy_val(h)>y1 ) maxy_val(h)=y1
10198
10199 @* \[22] Finding an envelope.
10200 When \MP\ has a path and a polygonal pen, it needs to express the desired
10201 shape in terms of things \ps\ can understand.  The present task is to compute
10202 a new path that describes the region to be filled.  It is convenient to
10203 define this as a two step process where the first step is determining what
10204 offset to use for each segment of the path.
10205
10206 @ Given a pointer |c| to a cyclic path,
10207 and a pointer~|h| to the first knot of a pen polygon,
10208 the |offset_prep| routine changes the path into cubics that are
10209 associated with particular pen offsets. Thus if the cubic between |p|
10210 and~|q| is associated with the |k|th offset and the cubic between |q| and~|r|
10211 has offset |l| then |info(q)=zero_off+l-k|. (The constant |zero_off| is added
10212 to because |l-k| could be negative.)
10213
10214 After overwriting the type information with offset differences, we no longer
10215 have a true path so we refer to the knot list returned by |offset_prep| as an
10216 ``envelope spec.''
10217 @^envelope spec@>
10218 Since an envelope spec only determines relative changes in pen offsets,
10219 |offset_prep| sets a global variable |spec_offset| to the relative change from
10220 |h| to the first offset.
10221
10222 @d zero_off 16384 /* added to offset changes to make them positive */
10223
10224 @<Glob...@>=
10225 integer spec_offset; /* number of pen edges between |h| and the initial offset */
10226
10227 @ @c @<Declare subroutines needed by |offset_prep|@>;
10228 pointer mp_offset_prep (MP mp,pointer c, pointer h) {
10229   halfword n; /* the number of vertices in the pen polygon */
10230   pointer p,q,r,w, ww; /* for list manipulation */
10231   integer k_needed; /* amount to be added to |info(p)| when it is computed */
10232   pointer w0; /* a pointer to pen offset to use just before |p| */
10233   scaled dxin,dyin; /* the direction into knot |p| */
10234   integer turn_amt; /* change in pen offsets for the current cubic */
10235   @<Other local variables for |offset_prep|@>;
10236   dx0=0; dy0=0;
10237   @<Initialize the pen size~|n|@>;
10238   @<Initialize the incoming direction and pen offset at |c|@>;
10239   p=c; k_needed=0;
10240   do {  
10241     q=link(p);
10242     @<Split the cubic between |p| and |q|, if necessary, into cubics
10243       associated with single offsets, after which |q| should
10244       point to the end of the final such cubic@>;
10245     @<Advance |p| to node |q|, removing any ``dead'' cubics that
10246       might have been introduced by the splitting process@>;
10247   } while (q!=c);
10248   @<Fix the offset change in |info(c)| and set the return value of
10249     |offset_prep|@>;
10250 }
10251
10252 @ We shall want to keep track of where certain knots on the cyclic path
10253 wind up in the envelope spec.  It doesn't suffice just to keep pointers to
10254 knot nodes because some nodes are deleted while removing dead cubics.  Thus
10255 |offset_prep| updates the following pointers
10256
10257 @<Glob...@>=
10258 pointer spec_p1;
10259 pointer spec_p2; /* pointers to distinguished knots */
10260
10261 @ @<Set init...@>=
10262 mp->spec_p1=null; mp->spec_p2=null;
10263
10264 @ @<Initialize the pen size~|n|@>=
10265 n=0; p=h;
10266 do {  
10267   incr(n);
10268   p=link(p);
10269 } while (p!=h)
10270
10271 @ Since the true incoming direction isn't known yet, we just pick a direction
10272 consistent with the pen offset~|h|.  If this is wrong, it can be corrected
10273 later.
10274
10275 @<Initialize the incoming direction and pen offset at |c|@>=
10276 dxin=x_coord(link(h))-x_coord(knil(h));
10277 dyin=y_coord(link(h))-y_coord(knil(h));
10278 if ( (dxin==0)&&(dyin==0) ) {
10279   dxin=y_coord(knil(h))-y_coord(h);
10280   dyin=x_coord(h)-x_coord(knil(h));
10281 }
10282 w0=h
10283
10284 @ We must be careful not to remove the only cubic in a cycle.
10285
10286 But we must also be careful for another reason. If the user-supplied
10287 path starts with a set of degenerate cubics, these should not be removed
10288 because at this point we cannot do so cleanly. The relevant bug is
10289 tracker id 267, bugs 52c, reported by Boguslav.
10290
10291 @<Advance |p| to node |q|, removing any ``dead'' cubics...@>=
10292 do {  r=link(p);
10293 if ( x_coord(p)==right_x(p) ) if ( y_coord(p)==right_y(p) )
10294  if ( x_coord(p)==left_x(r) ) if ( y_coord(p)==left_y(r) )
10295   if ( x_coord(p)==x_coord(r) ) if ( y_coord(p)==y_coord(r) )
10296     if ( r!=p ) if ( ((r!=q) || (originator(r)!=metapost_user)) ) {
10297       @<Remove the cubic following |p| and update the data structures
10298         to merge |r| into |p|@>;
10299 }
10300 p=r;
10301 } while (p!=q)
10302
10303 @ @<Remove the cubic following |p| and update the data structures...@>=
10304 { k_needed=info(p)-zero_off;
10305   if ( r==q ) { 
10306     q=p;
10307   } else { 
10308     info(p)=k_needed+info(r);
10309     k_needed=0;
10310   };
10311   if ( r==c ) { info(p)=info(c); c=p; };
10312   if ( r==mp->spec_p1 ) mp->spec_p1=p;
10313   if ( r==mp->spec_p2 ) mp->spec_p2=p;
10314   r=p; mp_remove_cubic(mp, p);
10315 }
10316
10317 @ Not setting the |info| field of the newly created knot allows the splitting
10318 routine to work for paths.
10319
10320 @<Declare subroutines needed by |offset_prep|@>=
10321 void mp_split_cubic (MP mp,pointer p, fraction t) { /* splits the cubic after |p| */
10322   scaled v; /* an intermediate value */
10323   pointer q,r; /* for list manipulation */
10324   q=link(p); r=mp_get_node(mp, knot_node_size); link(p)=r; link(r)=q;
10325   originator(r)=program_code;
10326   left_type(r)=explicit; right_type(r)=explicit;
10327   v=t_of_the_way(right_x(p),left_x(q));
10328   right_x(p)=t_of_the_way(x_coord(p),right_x(p));
10329   left_x(q)=t_of_the_way(left_x(q),x_coord(q));
10330   left_x(r)=t_of_the_way(right_x(p),v);
10331   right_x(r)=t_of_the_way(v,left_x(q));
10332   x_coord(r)=t_of_the_way(left_x(r),right_x(r));
10333   v=t_of_the_way(right_y(p),left_y(q));
10334   right_y(p)=t_of_the_way(y_coord(p),right_y(p));
10335   left_y(q)=t_of_the_way(left_y(q),y_coord(q));
10336   left_y(r)=t_of_the_way(right_y(p),v);
10337   right_y(r)=t_of_the_way(v,left_y(q));
10338   y_coord(r)=t_of_the_way(left_y(r),right_y(r));
10339 }
10340
10341 @ This does not set |info(p)| or |right_type(p)|.
10342
10343 @<Declare subroutines needed by |offset_prep|@>=
10344 void mp_remove_cubic (MP mp,pointer p) { /* removes the dead cubic following~|p| */
10345   pointer q; /* the node that disappears */
10346   q=link(p); link(p)=link(q);
10347   right_x(p)=right_x(q); right_y(p)=right_y(q);
10348   mp_free_node(mp, q,knot_node_size);
10349 }
10350
10351 @ Let $d\prec d'$ mean that the counter-clockwise angle from $d$ to~$d'$ is
10352 strictly between zero and $180^\circ$.  Then we can define $d\preceq d'$ to
10353 mean that the angle could be zero or $180^\circ$. If $w_k=(u_k,v_k)$ is the
10354 $k$th pen offset, the $k$th pen edge direction is defined by the formula
10355 $$d_k=(u\k-u_k,\,v\k-v_k).$$
10356 When listed by increasing $k$, these directions occur in counter-clockwise
10357 order so that $d_k\preceq d\k$ for all~$k$.
10358 The goal of |offset_prep| is to find an offset index~|k| to associate with
10359 each cubic, such that the direction $d(t)$ of the cubic satisfies
10360 $$d_{k-1}\preceq d(t)\preceq d_k\qquad\hbox{for $0\le t\le 1$.}\eqno(*)$$
10361 We may have to split a cubic into many pieces before each
10362 piece corresponds to a unique offset.
10363
10364 @<Split the cubic between |p| and |q|, if necessary, into cubics...@>=
10365 info(p)=zero_off+k_needed;
10366 k_needed=0;
10367 @<Prepare for derivative computations;
10368   |goto not_found| if the current cubic is dead@>;
10369 @<Find the initial direction |(dx,dy)|@>;
10370 @<Update |info(p)| and find the offset $w_k$ such that
10371   $d_{k-1}\preceq(\\{dx},\\{dy})\prec d_k$; also advance |w0| for
10372   the direction change at |p|@>;
10373 @<Find the final direction |(dxin,dyin)|@>;
10374 @<Decide on the net change in pen offsets and set |turn_amt|@>;
10375 @<Complete the offset splitting process@>;
10376 w0=mp_pen_walk(mp, w0,turn_amt);
10377 NOT_FOUND: do_nothing
10378
10379 @ @<Declare subroutines needed by |offset_prep|@>=
10380 pointer mp_pen_walk (MP mp,pointer w, integer k) {
10381   /* walk |k| steps around a pen from |w| */
10382   while ( k>0 ) { w=link(w); decr(k);  };
10383   while ( k<0 ) { w=knil(w); incr(k);  };
10384   return w;
10385 }
10386
10387 @ The direction of a cubic $B(z_0,z_1,z_2,z_3;t)=\bigl(x(t),y(t)\bigr)$ can be
10388 calculated from the quadratic polynomials
10389 ${1\over3}x'(t)=B(x_1-x_0,x_2-x_1,x_3-x_2;t)$ and
10390 ${1\over3}y'(t)=B(y_1-y_0,y_2-y_1,y_3-y_2;t)$.
10391 Since we may be calculating directions from several cubics
10392 split from the current one, it is desirable to do these calculations
10393 without losing too much precision. ``Scaled up'' values of the
10394 derivatives, which will be less tainted by accumulated errors than
10395 derivatives found from the cubics themselves, are maintained in
10396 local variables |x0|, |x1|, and |x2|, representing $X_0=2^l(x_1-x_0)$,
10397 $X_1=2^l(x_2-x_1)$, and $X_2=2^l(x_3-x_2)$; similarly |y0|, |y1|, and~|y2|
10398 represent $Y_0=2^l(y_1-y_0)$, $Y_1=2^l(y_2-y_1)$, and $Y_2=2^l(y_3-y_2)$.
10399
10400 @<Other local variables for |offset_prep|@>=
10401 integer x0,x1,x2,y0,y1,y2; /* representatives of derivatives */
10402 integer t0,t1,t2; /* coefficients of polynomial for slope testing */
10403 integer du,dv,dx,dy; /* for directions of the pen and the curve */
10404 integer dx0,dy0; /* initial direction for the first cubic in the curve */
10405 integer mp_max_coef; /* used while scaling */
10406 integer x0a,x1a,x2a,y0a,y1a,y2a; /* intermediate values */
10407 fraction t; /* where the derivative passes through zero */
10408 fraction s; /* a temporary value */
10409
10410 @ @<Prepare for derivative computations...@>=
10411 x0=right_x(p)-x_coord(p);
10412 x2=x_coord(q)-left_x(q);
10413 x1=left_x(q)-right_x(p);
10414 y0=right_y(p)-y_coord(p); y2=y_coord(q)-left_y(q);
10415 y1=left_y(q)-right_y(p);
10416 mp_max_coef=abs(x0);
10417 if ( abs(x1)>mp_max_coef ) mp_max_coef=abs(x1);
10418 if ( abs(x2)>mp_max_coef ) mp_max_coef=abs(x2);
10419 if ( abs(y0)>mp_max_coef ) mp_max_coef=abs(y0);
10420 if ( abs(y1)>mp_max_coef ) mp_max_coef=abs(y1);
10421 if ( abs(y2)>mp_max_coef ) mp_max_coef=abs(y2);
10422 if ( mp_max_coef==0 ) goto NOT_FOUND;
10423 while ( mp_max_coef<fraction_half ) {
10424   mp_max_coef+=mp_max_coef;
10425   x0+=x0; x1+=x1; x2+=x2;
10426   y0+=y0; y1+=y1; y2+=y2;
10427 }
10428
10429 @ Let us first solve a special case of the problem: Suppose we
10430 know an index~$k$ such that either (i)~$d(t)\succeq d_{k-1}$ for all~$t$
10431 and $d(0)\prec d_k$, or (ii)~$d(t)\preceq d_k$ for all~$t$ and
10432 $d(0)\succ d_{k-1}$.
10433 Then, in a sense, we're halfway done, since one of the two relations
10434 in $(*)$ is satisfied, and the other couldn't be satisfied for
10435 any other value of~|k|.
10436
10437 Actually, the conditions can be relaxed somewhat since a relation such as
10438 $d(t)\succeq d_{k-1}$ restricts $d(t)$ to a half plane when all that really
10439 matters is whether $d(t)$ crosses the ray in the $d_{k-1}$ direction from
10440 the origin.  The condition for case~(i) becomes $d_{k-1}\preceq d(0)\prec d_k$
10441 and $d(t)$ never crosses the $d_{k-1}$ ray in the clockwise direction.
10442 Case~(ii) is similar except $d(t)$ cannot cross the $d_k$ ray in the
10443 counterclockwise direction.
10444
10445 The |fin_offset_prep| subroutine solves the stated subproblem.
10446 It has a parameter called |rise| that is |1| in
10447 case~(i), |-1| in case~(ii). Parameters |x0| through |y2| represent
10448 the derivative of the cubic following |p|.
10449 The |w| parameter should point to offset~$w_k$ and |info(p)| should already
10450 be set properly.  The |turn_amt| parameter gives the absolute value of the
10451 overall net change in pen offsets.
10452
10453 @<Declare subroutines needed by |offset_prep|@>=
10454 void mp_fin_offset_prep (MP mp,pointer p, pointer w, integer 
10455   x0,integer x1, integer x2, integer y0, integer y1, integer y2, 
10456   integer rise, integer turn_amt)  {
10457   pointer ww; /* for list manipulation */
10458   scaled du,dv; /* for slope calculation */
10459   integer t0,t1,t2; /* test coefficients */
10460   fraction t; /* place where the derivative passes a critical slope */
10461   fraction s; /* slope or reciprocal slope */
10462   integer v; /* intermediate value for updating |x0..y2| */
10463   pointer q; /* original |link(p)| */
10464   q=link(p);
10465   while (1)  { 
10466     if ( rise>0 ) ww=link(w); /* a pointer to $w\k$ */
10467     else  ww=knil(w); /* a pointer to $w_{k-1}$ */
10468     @<Compute test coefficients |(t0,t1,t2)|
10469       for $d(t)$ versus $d_k$ or $d_{k-1}$@>;
10470     t=mp_crossing_point(mp, t0,t1,t2);
10471     if ( t>=fraction_one ) {
10472       if ( turn_amt>0 ) t=fraction_one;  else return;
10473     }
10474     @<Split the cubic at $t$,
10475       and split off another cubic if the derivative crosses back@>;
10476     w=ww;
10477   }
10478 }
10479
10480 @ We want $B(\\{t0},\\{t1},\\{t2};t)$ to be the dot product of $d(t)$ with a
10481 $-90^\circ$ rotation of the vector from |w| to |ww|.  This makes the resulting
10482 function cross from positive to negative when $d_{k-1}\preceq d(t)\preceq d_k$
10483 begins to fail.
10484
10485 @<Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...@>=
10486 du=x_coord(ww)-x_coord(w); dv=y_coord(ww)-y_coord(w);
10487 if ( abs(du)>=abs(dv) ) {
10488   s=mp_make_fraction(mp, dv,du);
10489   t0=mp_take_fraction(mp, x0,s)-y0;
10490   t1=mp_take_fraction(mp, x1,s)-y1;
10491   t2=mp_take_fraction(mp, x2,s)-y2;
10492   if ( du<0 ) { negate(t0); negate(t1); negate(t2);  }
10493 } else { 
10494   s=mp_make_fraction(mp, du,dv);
10495   t0=x0-mp_take_fraction(mp, y0,s);
10496   t1=x1-mp_take_fraction(mp, y1,s);
10497   t2=x2-mp_take_fraction(mp, y2,s);
10498   if ( dv<0 ) { negate(t0); negate(t1); negate(t2);  }
10499 }
10500 if ( t0<0 ) t0=0 /* should be positive without rounding error */
10501
10502 @ The curve has crossed $d_k$ or $d_{k-1}$; its initial segment satisfies
10503 $(*)$, and it might cross again, yielding another solution of $(*)$.
10504
10505 @<Split the cubic at $t$, and split off another...@>=
10506
10507 mp_split_cubic(mp, p,t); p=link(p); info(p)=zero_off+rise;
10508 decr(turn_amt);
10509 v=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10510 x0=t_of_the_way(v,x1);
10511 v=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10512 y0=t_of_the_way(v,y1);
10513 if ( turn_amt<0 ) {
10514   t1=t_of_the_way(t1,t2);
10515   if ( t1>0 ) t1=0; /* without rounding error, |t1| would be |<=0| */
10516   t=mp_crossing_point(mp, 0,-t1,-t2);
10517   if ( t>fraction_one ) t=fraction_one;
10518   incr(turn_amt);
10519   if ( (t==fraction_one)&&(link(p)!=q) ) {
10520     info(link(p))=info(link(p))-rise;
10521   } else { 
10522     mp_split_cubic(mp, p,t); info(link(p))=zero_off-rise;
10523     v=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10524     x2=t_of_the_way(x1,v);
10525     v=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10526     y2=t_of_the_way(y1,v);
10527   }
10528 }
10529 }
10530
10531 @ Now we must consider the general problem of |offset_prep|, when
10532 nothing is known about a given cubic. We start by finding its
10533 direction in the vicinity of |t=0|.
10534
10535 If $z'(t)=0$, the given cubic is numerically unstable but |offset_prep|
10536 has not yet introduced any more numerical errors.  Thus we can compute
10537 the true initial direction for the given cubic, even if it is almost
10538 degenerate.
10539
10540 @<Find the initial direction |(dx,dy)|@>=
10541 dx=x0; dy=y0;
10542 if ( dx==0 ) if ( dy==0 ) { 
10543   dx=x1; dy=y1;
10544   if ( dx==0 ) if ( dy==0 ) { 
10545     dx=x2; dy=y2;
10546   }
10547 }
10548 if ( p==c ) { dx0=dx; dy0=dy;  }
10549
10550 @ @<Find the final direction |(dxin,dyin)|@>=
10551 dxin=x2; dyin=y2;
10552 if ( dxin==0 ) if ( dyin==0 ) {
10553   dxin=x1; dyin=y1;
10554   if ( dxin==0 ) if ( dyin==0 ) {
10555     dxin=x0; dyin=y0;
10556   }
10557 }
10558
10559 @ The next step is to bracket the initial direction between consecutive
10560 edges of the pen polygon.  We must be careful to turn clockwise only if
10561 this makes the turn less than $180^\circ$. (A $180^\circ$ turn must be
10562 counter-clockwise in order to make \&{doublepath} envelopes come out
10563 @:double_path_}{\&{doublepath} primitive@>
10564 right.) This code depends on |w0| being the offset for |(dxin,dyin)|.
10565
10566 @<Update |info(p)| and find the offset $w_k$ such that...@>=
10567 turn_amt=mp_get_turn_amt(mp, w0, dx, dy, mp_ab_vs_cd(mp, dy,dxin,dx,dyin)>=0);
10568 w=mp_pen_walk(mp, w0, turn_amt);
10569 w0=w;
10570 info(p)=info(p)+turn_amt
10571
10572 @ Decide how many pen offsets to go away from |w| in order to find the offset
10573 for |(dx,dy)|, going counterclockwise if |ccw| is |true|.  This assumes that
10574 |w| is the offset for some direction $(x',y')$ from which the angle to |(dx,dy)|
10575 in the sense determined by |ccw| is less than or equal to $180^\circ$.
10576
10577 If the pen polygon has only two edges, they could both be parallel
10578 to |(dx,dy)|.  In this case, we must be careful to stop after crossing the first
10579 such edge in order to avoid an infinite loop.
10580
10581 @<Declare subroutines needed by |offset_prep|@>=
10582 integer mp_get_turn_amt (MP mp,pointer w, scaled  dx,
10583                          scaled dy, boolean  ccw) {
10584   pointer ww; /* a neighbor of knot~|w| */
10585   integer s; /* turn amount so far */
10586   integer t; /* |ab_vs_cd| result */
10587   s=0;
10588   if ( ccw ) { 
10589     ww=link(w);
10590     do {  
10591       t=mp_ab_vs_cd(mp, dy,x_coord(ww)-x_coord(w),
10592                         dx,y_coord(ww)-y_coord(w));
10593       if ( t<0 ) break;
10594       incr(s);
10595       w=ww; ww=link(ww);
10596     } while (t>0);
10597   } else { 
10598     ww=knil(w);
10599     while ( mp_ab_vs_cd(mp, dy,x_coord(w)-x_coord(ww),
10600                             dx,y_coord(w)-y_coord(ww))<0 ) { 
10601       decr(s);
10602       w=ww; ww=knil(ww);
10603     }
10604   }
10605   return s;
10606 }
10607
10608 @ When we're all done, the final offset is |w0| and the final curve direction
10609 is |(dxin,dyin)|.  With this knowledge of the incoming direction at |c|, we
10610 can correct |info(c)| which was erroneously based on an incoming offset
10611 of~|h|.
10612
10613 @d fix_by(A) info(c)=info(c)+(A)
10614
10615 @<Fix the offset change in |info(c)| and set the return value of...@>=
10616 mp->spec_offset=info(c)-zero_off;
10617 if ( link(c)==c ) {
10618   info(c)=zero_off+n;
10619 } else { 
10620   fix_by(k_needed);
10621   while ( w0!=h ) { fix_by(1); w0=link(w0);  };
10622   while ( info(c)<=zero_off-n ) fix_by(n);
10623   while ( info(c)>zero_off ) fix_by(-n);
10624   if ( (info(c)!=zero_off)&&(mp_ab_vs_cd(mp, dy0,dxin,dx0,dyin)>=0) ) fix_by(n);
10625 }
10626 return c
10627
10628 @ Finally we want to reduce the general problem to situations that
10629 |fin_offset_prep| can handle. We split the cubic into at most three parts
10630 with respect to $d_{k-1}$, and apply |fin_offset_prep| to each part.
10631
10632 @<Complete the offset splitting process@>=
10633 ww=knil(w);
10634 @<Compute test coeff...@>;
10635 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set
10636   |t:=fraction_one+1|@>;
10637 if ( t>fraction_one ) {
10638   mp_fin_offset_prep(mp, p,w,x0,x1,x2,y0,y1,y2,1,turn_amt);
10639 } else {
10640   mp_split_cubic(mp, p,t); r=link(p);
10641   x1a=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10642   x2a=t_of_the_way(x1a,x1);
10643   y1a=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10644   y2a=t_of_the_way(y1a,y1);
10645   mp_fin_offset_prep(mp, p,w,x0,x1a,x2a,y0,y1a,y2a,1,0); x0=x2a; y0=y2a;
10646   info(r)=zero_off-1;
10647   if ( turn_amt>=0 ) {
10648     t1=t_of_the_way(t1,t2);
10649     if ( t1>0 ) t1=0;
10650     t=mp_crossing_point(mp, 0,-t1,-t2);
10651     if ( t>fraction_one ) t=fraction_one;
10652     @<Split off another rising cubic for |fin_offset_prep|@>;
10653     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,0);
10654   } else {
10655     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,-1-turn_amt);
10656   }
10657 }
10658
10659 @ @<Split off another rising cubic for |fin_offset_prep|@>=
10660 mp_split_cubic(mp, r,t); info(link(r))=zero_off+1;
10661 x1a=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10662 x0a=t_of_the_way(x1,x1a);
10663 y1a=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10664 y0a=t_of_the_way(y1,y1a);
10665 mp_fin_offset_prep(mp, link(r),w,x0a,x1a,x2,y0a,y1a,y2,1,turn_amt);
10666 x2=x0a; y2=y0a
10667
10668 @ At this point, the direction of the incoming pen edge is |(-du,-dv)|.
10669 When the component of $d(t)$ perpendicular to |(-du,-dv)| crosses zero, we
10670 need to decide whether the directions are parallel or antiparallel.  We
10671 can test this by finding the dot product of $d(t)$ and |(-du,-dv)|, but this
10672 should be avoided when the value of |turn_amt| already determines the
10673 answer.  If |t2<0|, there is one crossing and it is antiparallel only if
10674 |turn_amt>=0|.  If |turn_amt<0|, there should always be at least one
10675 crossing and the first crossing cannot be antiparallel.
10676
10677 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set...@>=
10678 t=mp_crossing_point(mp, t0,t1,t2);
10679 if ( turn_amt>=0 ) {
10680   if ( t2<0 ) {
10681     t=fraction_one+1;
10682   } else { 
10683     u0=t_of_the_way(x0,x1);
10684     u1=t_of_the_way(x1,x2);
10685     ss=mp_take_fraction(mp, -du,t_of_the_way(u0,u1));
10686     v0=t_of_the_way(y0,y1);
10687     v1=t_of_the_way(y1,y2);
10688     ss=ss+mp_take_fraction(mp, -dv,t_of_the_way(v0,v1));
10689     if ( ss<0 ) t=fraction_one+1;
10690   }
10691 } else if ( t>fraction_one ) {
10692   t=fraction_one;
10693 }
10694
10695 @ @<Other local variables for |offset_prep|@>=
10696 integer u0,u1,v0,v1; /* intermediate values for $d(t)$ calculation */
10697 integer ss = 0; /* the part of the dot product computed so far */
10698 int d_sign; /* sign of overall change in direction for this cubic */
10699
10700 @ If the cubic almost has a cusp, it is a numerically ill-conditioned
10701 problem to decide which way it loops around but that's OK as long we're
10702 consistent.  To make \&{doublepath} envelopes work properly, reversing
10703 the path should always change the sign of |turn_amt|.
10704
10705 @<Decide on the net change in pen offsets and set |turn_amt|@>=
10706 d_sign=mp_ab_vs_cd(mp, dx,dyin, dxin,dy);
10707 if ( d_sign==0 ) {
10708   if ( dx==0 ) {
10709     if ( dy>0 ) d_sign=1;  else d_sign=-1;
10710   } else if ( dx>0 ) { 
10711     d_sign=1;  
10712   } else { 
10713     d_sign=-1; 
10714   }
10715 }
10716 @<Make |ss| negative if and only if the total change in direction is
10717   more than $180^\circ$@>;
10718 turn_amt=mp_get_turn_amt(mp, w, dxin, dyin, d_sign>0);
10719 if ( ss<0 ) turn_amt=turn_amt-d_sign*n
10720
10721 @ In order to be invariant under path reversal, the result of this computation
10722 should not change when |x0|, |y0|, $\ldots$ are all negated and |(x0,y0)| is
10723 then swapped with |(x2,y2)|.  We make use of the identities
10724 |take_fraction(-a,-b)=take_fraction(a,b)| and
10725 |t_of_the_way(-a,-b)=-(t_of_the_way(a,b))|.
10726
10727 @<Make |ss| negative if and only if the total change in direction is...@>=
10728 t0=half(mp_take_fraction(mp, x0,y2))-half(mp_take_fraction(mp, x2,y0));
10729 t1=half(mp_take_fraction(mp, x1,y0+y2))-half(mp_take_fraction(mp, y1,x0+x2));
10730 if ( t0==0 ) t0=d_sign; /* path reversal always negates |d_sign| */
10731 if ( t0>0 ) {
10732   t=mp_crossing_point(mp, t0,t1,-t0);
10733   u0=t_of_the_way(x0,x1);
10734   u1=t_of_the_way(x1,x2);
10735   v0=t_of_the_way(y0,y1);
10736   v1=t_of_the_way(y1,y2);
10737 } else { 
10738   t=mp_crossing_point(mp, -t0,t1,t0);
10739   u0=t_of_the_way(x2,x1);
10740   u1=t_of_the_way(x1,x0);
10741   v0=t_of_the_way(y2,y1);
10742   v1=t_of_the_way(y1,y0);
10743 }
10744 s=mp_take_fraction(mp, x0+x2,t_of_the_way(u0,u1))+
10745   mp_take_fraction(mp, y0+y2,t_of_the_way(v0,v1))
10746
10747 @ Here's a routine that prints an envelope spec in symbolic form.  It assumes
10748 that the |cur_pen| has not been walked around to the first offset.
10749
10750 @c 
10751 void mp_print_spec (MP mp,pointer cur_spec, pointer cur_pen, char *s) {
10752   pointer p,q; /* list traversal */
10753   pointer w; /* the current pen offset */
10754   mp_print_diagnostic(mp, "Envelope spec",s,true);
10755   p=cur_spec; w=mp_pen_walk(mp, cur_pen,mp->spec_offset);
10756   mp_print_ln(mp);
10757   mp_print_two(mp, x_coord(cur_spec),y_coord(cur_spec));
10758   mp_print(mp, " % beginning with offset ");
10759   mp_print_two(mp, x_coord(w),y_coord(w));
10760   do { 
10761     do {  
10762       q=link(p);
10763       @<Print the cubic between |p| and |q|@>;
10764       p=q;
10765     } while (! ((p==cur_spec) || (info(p)!=zero_off)));
10766     if ( info(p)!=zero_off ) {
10767       @<Update |w| as indicated by |info(p)| and print an explanation@>;
10768     }
10769   } while (p!=cur_spec);
10770   mp_print_nl(mp, " & cycle");
10771   mp_end_diagnostic(mp, true);
10772 }
10773
10774 @ @<Update |w| as indicated by |info(p)| and print an explanation@>=
10775
10776   w=mp_pen_walk(mp, w,info(p)-zero_off);
10777   mp_print(mp, " % ");
10778   if ( info(p)>zero_off ) mp_print(mp, "counter");
10779   mp_print(mp, "clockwise to offset ");
10780   mp_print_two(mp, x_coord(w),y_coord(w));
10781 }
10782
10783 @ @<Print the cubic between |p| and |q|@>=
10784
10785   mp_print_nl(mp, "   ..controls ");
10786   mp_print_two(mp, right_x(p),right_y(p));
10787   mp_print(mp, " and ");
10788   mp_print_two(mp, left_x(q),left_y(q));
10789   mp_print_nl(mp, " ..");
10790   mp_print_two(mp, x_coord(q),y_coord(q));
10791 }
10792
10793 @ Once we have an envelope spec, the remaining task to construct the actual
10794 envelope by offsetting each cubic as determined by the |info| fields in
10795 the knots.  First we use |offset_prep| to convert the |c| into an envelope
10796 spec. Then we add the offsets so that |c| becomes a cyclic path that represents
10797 the envelope.
10798
10799 The |ljoin| and |miterlim| parameters control the treatment of points where the
10800 pen offset changes, and |lcap| controls the endpoints of a \&{doublepath}.
10801 The endpoints are easily located because |c| is given in undoubled form
10802 and then doubled in this procedure.  We use |spec_p1| and |spec_p2| to keep
10803 track of the endpoints and treat them like very sharp corners.
10804 Butt end caps are treated like beveled joins; round end caps are treated like
10805 round joins; and square end caps are achieved by setting |join_type:=3|.
10806
10807 None of these parameters apply to inside joins where the convolution tracing
10808 has retrograde lines.  In such cases we use a simple connect-the-endpoints
10809 approach that is achieved by setting |join_type:=2|.
10810
10811 @c @<Declare a function called |insert_knot|@>;
10812 pointer mp_make_envelope (MP mp,pointer c, pointer h, small_number ljoin,
10813   small_number lcap, scaled miterlim) {
10814   pointer p,q,r,q0; /* for manipulating the path */
10815   int join_type=0; /* codes |0..3| for mitered, round, beveled, or square */
10816   pointer w,w0; /* the pen knot for the current offset */
10817   scaled qx,qy; /* unshifted coordinates of |q| */
10818   halfword k,k0; /* controls pen edge insertion */
10819   @<Other local variables for |make_envelope|@>;
10820   dxin=0; dyin=0; dxout=0; dyout=0;
10821   mp->spec_p1=null; mp->spec_p2=null;
10822   @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>;
10823   @<Use |offset_prep| to compute the envelope spec then walk |h| around to
10824     the initial offset@>;
10825   w=h;
10826   p=c;
10827   do {  
10828     q=link(p); q0=q;
10829     qx=x_coord(q); qy=y_coord(q);
10830     k=info(q);
10831     k0=k; w0=w;
10832     if ( k!=zero_off ) {
10833       @<Set |join_type| to indicate how to handle offset changes at~|q|@>;
10834     }
10835     @<Add offset |w| to the cubic from |p| to |q|@>;
10836     while ( k!=zero_off ) { 
10837       @<Step |w| and move |k| one step closer to |zero_off|@>;
10838       if ( (join_type==1)||(k==zero_off) )
10839          q=mp_insert_knot(mp, q,qx+x_coord(w),qy+y_coord(w));
10840     };
10841     if ( q!=link(p) ) {
10842       @<Set |p=link(p)| and add knots between |p| and |q| as
10843         required by |join_type|@>;
10844     }
10845     p=q;
10846   } while (q0!=c);
10847   return c;
10848 }
10849
10850 @ @<Use |offset_prep| to compute the envelope spec then walk |h| around to...@>=
10851 c=mp_offset_prep(mp, c,h);
10852 if ( mp->internal[tracing_specs]>0 ) 
10853   mp_print_spec(mp, c,h,"");
10854 h=mp_pen_walk(mp, h,mp->spec_offset)
10855
10856 @ Mitered and squared-off joins depend on path directions that are difficult to
10857 compute for degenerate cubics.  The envelope spec computed by |offset_prep| can
10858 have degenerate cubics only if the entire cycle collapses to a single
10859 degenerate cubic.  Setting |join_type:=2| in this case makes the computed
10860 envelope degenerate as well.
10861
10862 @<Set |join_type| to indicate how to handle offset changes at~|q|@>=
10863 if ( k<zero_off ) {
10864   join_type=2;
10865 } else {
10866   if ( (q!=mp->spec_p1)&&(q!=mp->spec_p2) ) join_type=ljoin;
10867   else if ( lcap==2 ) join_type=3;
10868   else join_type=2-lcap;
10869   if ( (join_type==0)||(join_type==3) ) {
10870     @<Set the incoming and outgoing directions at |q|; in case of
10871       degeneracy set |join_type:=2|@>;
10872     if ( join_type==0 ) {
10873       @<If |miterlim| is less than the secant of half the angle at |q|
10874         then set |join_type:=2|@>;
10875     }
10876   }
10877 }
10878
10879 @ @<If |miterlim| is less than the secant of half the angle at |q|...@>=
10880
10881   tmp=mp_take_fraction(mp, miterlim,fraction_half+
10882       half(mp_take_fraction(mp, dxin,dxout)+mp_take_fraction(mp, dyin,dyout)));
10883   if ( tmp<unity )
10884     if ( mp_take_scaled(mp, miterlim,tmp)<unity ) join_type=2;
10885 }
10886
10887 @ @<Other local variables for |make_envelope|@>=
10888 fraction dxin,dyin,dxout,dyout; /* directions at |q| when square or mitered */
10889 scaled tmp; /* a temporary value */
10890
10891 @ The coordinates of |p| have already been shifted unless |p| is the first
10892 knot in which case they get shifted at the very end.
10893
10894 @<Add offset |w| to the cubic from |p| to |q|@>=
10895 right_x(p)=right_x(p)+x_coord(w);
10896 right_y(p)=right_y(p)+y_coord(w);
10897 left_x(q)=left_x(q)+x_coord(w);
10898 left_y(q)=left_y(q)+y_coord(w);
10899 x_coord(q)=x_coord(q)+x_coord(w);
10900 y_coord(q)=y_coord(q)+y_coord(w);
10901 left_type(q)=explicit;
10902 right_type(q)=explicit
10903
10904 @ @<Step |w| and move |k| one step closer to |zero_off|@>=
10905 if ( k>zero_off ){ w=link(w); decr(k);  }
10906 else { w=knil(w); incr(k);  }
10907
10908 @ The cubic from |q| to the new knot at |(x,y)| becomes a line segment and
10909 the |right_x| and |right_y| fields of |r| are set from |q|.  This is done in
10910 case the cubic containing these control points is ``yet to be examined.''
10911
10912 @<Declare a function called |insert_knot|@>=
10913 pointer mp_insert_knot (MP mp,pointer q, scaled x, scaled y) {
10914   /* returns the inserted knot */
10915   pointer r; /* the new knot */
10916   r=mp_get_node(mp, knot_node_size);
10917   link(r)=link(q); link(q)=r;
10918   right_x(r)=right_x(q);
10919   right_y(r)=right_y(q);
10920   x_coord(r)=x;
10921   y_coord(r)=y;
10922   right_x(q)=x_coord(q);
10923   right_y(q)=y_coord(q);
10924   left_x(r)=x_coord(r);
10925   left_y(r)=y_coord(r);
10926   left_type(r)=explicit;
10927   right_type(r)=explicit;
10928   originator(r)=program_code;
10929   return r;
10930 }
10931
10932 @ After setting |p:=link(p)|, either |join_type=1| or |q=link(p)|.
10933
10934 @<Set |p=link(p)| and add knots between |p| and |q| as...@>=
10935
10936   p=link(p);
10937   if ( (join_type==0)||(join_type==3) ) {
10938     if ( join_type==0 ) {
10939       @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>
10940     } else {
10941       @<Make |r| the last of two knots inserted between |p| and |q| to form a
10942         squared join@>;
10943     }
10944     if ( r!=null ) { 
10945       right_x(r)=x_coord(r);
10946       right_y(r)=y_coord(r);
10947     }
10948   }
10949 }
10950
10951 @ For very small angles, adding a knot is unnecessary and would cause numerical
10952 problems, so we just set |r:=null| in that case.
10953
10954 @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>=
10955
10956   det=mp_take_fraction(mp, dyout,dxin)-mp_take_fraction(mp, dxout,dyin);
10957   if ( abs(det)<26844 ) { 
10958      r=null; /* sine $<10^{-4}$ */
10959   } else { 
10960     tmp=mp_take_fraction(mp, x_coord(q)-x_coord(p),dyout)-
10961         mp_take_fraction(mp, y_coord(q)-y_coord(p),dxout);
10962     tmp=mp_make_fraction(mp, tmp,det);
10963     r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
10964       y_coord(p)+mp_take_fraction(mp, tmp,dyin));
10965   }
10966 }
10967
10968 @ @<Other local variables for |make_envelope|@>=
10969 fraction det; /* a determinant used for mitered join calculations */
10970
10971 @ @<Make |r| the last of two knots inserted between |p| and |q| to form a...@>=
10972
10973   ht_x=y_coord(w)-y_coord(w0);
10974   ht_y=x_coord(w0)-x_coord(w);
10975   while ( (abs(ht_x)<fraction_half)&&(abs(ht_y)<fraction_half) ) { 
10976     ht_x+=ht_x; ht_y+=ht_y;
10977   }
10978   @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range dot
10979     product with |(ht_x,ht_y)|@>;
10980   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxin,ht_x)+
10981                                   mp_take_fraction(mp, dyin,ht_y));
10982   r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
10983                          y_coord(p)+mp_take_fraction(mp, tmp,dyin));
10984   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxout,ht_x)+
10985                                   mp_take_fraction(mp, dyout,ht_y));
10986   r=mp_insert_knot(mp, r,x_coord(q)+mp_take_fraction(mp, tmp,dxout),
10987                          y_coord(q)+mp_take_fraction(mp, tmp,dyout));
10988 }
10989
10990 @ @<Other local variables for |make_envelope|@>=
10991 fraction ht_x,ht_y; /* perpendicular to the segment from |p| to |q| */
10992 scaled max_ht; /* maximum height of the pen polygon above the |w0|-|w| line */
10993 halfword kk; /* keeps track of the pen vertices being scanned */
10994 pointer ww; /* the pen vertex being tested */
10995
10996 @ The dot product of the vector from |w0| to |ww| with |(ht_x,ht_y)| ranges
10997 from zero to |max_ht|.
10998
10999 @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range...@>=
11000 max_ht=0;
11001 kk=zero_off;
11002 ww=w;
11003 while (1)  { 
11004   @<Step |ww| and move |kk| one step closer to |k0|@>;
11005   if ( kk==k0 ) break;
11006   tmp=mp_take_fraction(mp, x_coord(ww)-x_coord(w0),ht_x)+
11007       mp_take_fraction(mp, y_coord(ww)-y_coord(w0),ht_y);
11008   if ( tmp>max_ht ) max_ht=tmp;
11009 }
11010
11011
11012 @ @<Step |ww| and move |kk| one step closer to |k0|@>=
11013 if ( kk>k0 ) { ww=link(ww); decr(kk);  }
11014 else { ww=knil(ww); incr(kk);  }
11015
11016 @ @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>=
11017 if ( left_type(c)==endpoint ) { 
11018   mp->spec_p1=mp_htap_ypoc(mp, c);
11019   mp->spec_p2=mp->path_tail;
11020   originator(mp->spec_p1)=program_code;
11021   link(mp->spec_p2)=link(mp->spec_p1);
11022   link(mp->spec_p1)=c;
11023   mp_remove_cubic(mp, mp->spec_p1);
11024   c=mp->spec_p1;
11025   if ( c!=link(c) ) {
11026     originator(mp->spec_p2)=program_code;
11027     mp_remove_cubic(mp, mp->spec_p2);
11028   } else {
11029     @<Make |c| look like a cycle of length one@>;
11030   }
11031 }
11032
11033 @ @<Make |c| look like a cycle of length one@>=
11034
11035   left_type(c)=explicit; right_type(c)=explicit;
11036   left_x(c)=x_coord(c); left_y(c)=y_coord(c);
11037   right_x(c)=x_coord(c); right_y(c)=y_coord(c);
11038 }
11039
11040 @ In degenerate situations we might have to look at the knot preceding~|q|.
11041 That knot is |p| but if |p<>c|, its coordinates have already been offset by |w|.
11042
11043 @<Set the incoming and outgoing directions at |q|; in case of...@>=
11044 dxin=x_coord(q)-left_x(q);
11045 dyin=y_coord(q)-left_y(q);
11046 if ( (dxin==0)&&(dyin==0) ) {
11047   dxin=x_coord(q)-right_x(p);
11048   dyin=y_coord(q)-right_y(p);
11049   if ( (dxin==0)&&(dyin==0) ) {
11050     dxin=x_coord(q)-x_coord(p);
11051     dyin=y_coord(q)-y_coord(p);
11052     if ( p!=c ) { /* the coordinates of |p| have been offset by |w| */
11053       dxin=dxin+x_coord(w);
11054       dyin=dyin+y_coord(w);
11055     }
11056   }
11057 }
11058 tmp=mp_pyth_add(mp, dxin,dyin);
11059 if ( tmp==0 ) {
11060   join_type=2;
11061 } else { 
11062   dxin=mp_make_fraction(mp, dxin,tmp);
11063   dyin=mp_make_fraction(mp, dyin,tmp);
11064   @<Set the outgoing direction at |q|@>;
11065 }
11066
11067 @ If |q=c| then the coordinates of |r| and the control points between |q|
11068 and~|r| have already been offset by |h|.
11069
11070 @<Set the outgoing direction at |q|@>=
11071 dxout=right_x(q)-x_coord(q);
11072 dyout=right_y(q)-y_coord(q);
11073 if ( (dxout==0)&&(dyout==0) ) {
11074   r=link(q);
11075   dxout=left_x(r)-x_coord(q);
11076   dyout=left_y(r)-y_coord(q);
11077   if ( (dxout==0)&&(dyout==0) ) {
11078     dxout=x_coord(r)-x_coord(q);
11079     dyout=y_coord(r)-y_coord(q);
11080   }
11081 }
11082 if ( q==c ) {
11083   dxout=dxout-x_coord(h);
11084   dyout=dyout-y_coord(h);
11085 }
11086 tmp=mp_pyth_add(mp, dxout,dyout);
11087 if ( tmp==0 ) mp_confusion(mp, "degenerate spec");
11088 @:this can't happen degerate spec}{\quad degenerate spec@>
11089 dxout=mp_make_fraction(mp, dxout,tmp);
11090 dyout=mp_make_fraction(mp, dyout,tmp)
11091
11092 @* \[23] Direction and intersection times.
11093 A path of length $n$ is defined parametrically by functions $x(t)$ and
11094 $y(t)$, for |0<=t<=n|; we can regard $t$ as the ``time'' at which the path
11095 reaches the point $\bigl(x(t),y(t)\bigr)$.  In this section of the program
11096 we shall consider operations that determine special times associated with
11097 given paths: the first time that a path travels in a given direction, and
11098 a pair of times at which two paths cross each other.
11099
11100 @ Let's start with the easier task. The function |find_direction_time| is
11101 given a direction |(x,y)| and a path starting at~|h|. If the path never
11102 travels in direction |(x,y)|, the direction time will be~|-1|; otherwise
11103 it will be nonnegative.
11104
11105 Certain anomalous cases can arise: If |(x,y)=(0,0)|, so that the given
11106 direction is undefined, the direction time will be~0. If $\bigl(x'(t),
11107 y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be
11108 assumed to match any given direction at time~|t|.
11109
11110 The routine solves this problem in nondegenerate cases by rotating the path
11111 and the given direction so that |(x,y)=(1,0)|; i.e., the main task will be
11112 to find when a given path first travels ``due east.''
11113
11114 @c 
11115 scaled mp_find_direction_time (MP mp,scaled x, scaled y, pointer h) {
11116   scaled max; /* $\max\bigl(\vert x\vert,\vert y\vert\bigr)$ */
11117   pointer p,q; /* for list traversal */
11118   scaled n; /* the direction time at knot |p| */
11119   scaled tt; /* the direction time within a cubic */
11120   @<Other local variables for |find_direction_time|@>;
11121   @<Normalize the given direction for better accuracy;
11122     but |return| with zero result if it's zero@>;
11123   n=0; p=h; phi=0;
11124   while (1) { 
11125     if ( right_type(p)==endpoint ) break;
11126     q=link(p);
11127     @<Rotate the cubic between |p| and |q|; then
11128       |goto found| if the rotated cubic travels due east at some time |tt|;
11129       but |break| if an entire cyclic path has been traversed@>;
11130     p=q; n=n+unity;
11131   }
11132   return (-unity);
11133 FOUND: 
11134   return (n+tt);
11135 }
11136
11137 @ @<Normalize the given direction for better accuracy...@>=
11138 if ( abs(x)<abs(y) ) { 
11139   x=mp_make_fraction(mp, x,abs(y));
11140   if ( y>0 ) y=fraction_one; else y=-fraction_one;
11141 } else if ( x==0 ) { 
11142   return 0;
11143 } else  { 
11144   y=mp_make_fraction(mp, y,abs(x));
11145   if ( x>0 ) x=fraction_one; else x=-fraction_one;
11146 }
11147
11148 @ Since we're interested in the tangent directions, we work with the
11149 derivative $${\textstyle1\over3}B'(x_0,x_1,x_2,x_3;t)=
11150 B(x_1-x_0,x_2-x_1,x_3-x_2;t)$$ instead of
11151 $B(x_0,x_1,x_2,x_3;t)$ itself. The derived coefficients are also scaled up
11152 in order to achieve better accuracy.
11153
11154 The given path may turn abruptly at a knot, and it might pass the critical
11155 tangent direction at such a time. Therefore we remember the direction |phi|
11156 in which the previous rotated cubic was traveling. (The value of |phi| will be
11157 undefined on the first cubic, i.e., when |n=0|.)
11158
11159 @<Rotate the cubic between |p| and |q|; then...@>=
11160 tt=0;
11161 @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples of the control
11162   points of the rotated derivatives@>;
11163 if ( y1==0 ) if ( x1>=0 ) goto FOUND;
11164 if ( n>0 ) { 
11165   @<Exit to |found| if an eastward direction occurs at knot |p|@>;
11166   if ( p==h ) break;
11167   };
11168 if ( (x3!=0)||(y3!=0) ) phi=mp_n_arg(mp, x3,y3);
11169 @<Exit to |found| if the curve whose derivatives are specified by
11170   |x1,x2,x3,y1,y2,y3| travels eastward at some time~|tt|@>
11171
11172 @ @<Other local variables for |find_direction_time|@>=
11173 scaled x1,x2,x3,y1,y2,y3;  /* multiples of rotated derivatives */
11174 angle theta,phi; /* angles of exit and entry at a knot */
11175 fraction t; /* temp storage */
11176
11177 @ @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples...@>=
11178 x1=right_x(p)-x_coord(p); x2=left_x(q)-right_x(p);
11179 x3=x_coord(q)-left_x(q);
11180 y1=right_y(p)-y_coord(p); y2=left_y(q)-right_y(p);
11181 y3=y_coord(q)-left_y(q);
11182 max=abs(x1);
11183 if ( abs(x2)>max ) max=abs(x2);
11184 if ( abs(x3)>max ) max=abs(x3);
11185 if ( abs(y1)>max ) max=abs(y1);
11186 if ( abs(y2)>max ) max=abs(y2);
11187 if ( abs(y3)>max ) max=abs(y3);
11188 if ( max==0 ) goto FOUND;
11189 while ( max<fraction_half ){ 
11190   max+=max; x1+=x1; x2+=x2; x3+=x3;
11191   y1+=y1; y2+=y2; y3+=y3;
11192 }
11193 t=x1; x1=mp_take_fraction(mp, x1,x)+mp_take_fraction(mp, y1,y);
11194 y1=mp_take_fraction(mp, y1,x)-mp_take_fraction(mp, t,y);
11195 t=x2; x2=mp_take_fraction(mp, x2,x)+mp_take_fraction(mp, y2,y);
11196 y2=mp_take_fraction(mp, y2,x)-mp_take_fraction(mp, t,y);
11197 t=x3; x3=mp_take_fraction(mp, x3,x)+mp_take_fraction(mp, y3,y);
11198 y3=mp_take_fraction(mp, y3,x)-mp_take_fraction(mp, t,y)
11199
11200 @ @<Exit to |found| if an eastward direction occurs at knot |p|@>=
11201 theta=mp_n_arg(mp, x1,y1);
11202 if ( theta>=0 ) if ( phi<=0 ) if ( phi>=theta-one_eighty_deg ) goto FOUND;
11203 if ( theta<=0 ) if ( phi>=0 ) if ( phi<=theta+one_eighty_deg ) goto FOUND
11204
11205 @ In this step we want to use the |crossing_point| routine to find the
11206 roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$.
11207 Several complications arise: If the quadratic equation has a double root,
11208 the curve never crosses zero, and |crossing_point| will find nothing;
11209 this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic
11210 equation has simple roots, or only one root, we may have to negate it
11211 so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root.
11212 And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is
11213 identically zero.
11214
11215 @ @<Exit to |found| if the curve whose derivatives are specified by...@>=
11216 if ( x1<0 ) if ( x2<0 ) if ( x3<0 ) goto DONE;
11217 if ( mp_ab_vs_cd(mp, y1,y3,y2,y2)==0 ) {
11218   @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11219     either |goto found| or |goto done|@>;
11220 }
11221 if ( y1<=0 ) {
11222   if ( y1<0 ) { y1=-y1; y2=-y2; y3=-y3; }
11223   else if ( y2>0 ){ y2=-y2; y3=-y3; };
11224 }
11225 @<Check the places where $B(y_1,y_2,y_3;t)=0$ to see if
11226   $B(x_1,x_2,x_3;t)\ge0$@>;
11227 DONE:
11228
11229 @ The quadratic polynomial $B(y_1,y_2,y_3;t)$ begins |>=0| and has at most
11230 two roots, because we know that it isn't identically zero.
11231
11232 It must be admitted that the |crossing_point| routine is not perfectly accurate;
11233 rounding errors might cause it to find a root when $y_1y_3>y_2^2$, or to
11234 miss the roots when $y_1y_3<y_2^2$. The rotation process is itself
11235 subject to rounding errors. Yet this code optimistically tries to
11236 do the right thing.
11237
11238 @d we_found_it { tt=(t+04000) / 010000; goto FOUND; }
11239
11240 @<Check the places where $B(y_1,y_2,y_3;t)=0$...@>=
11241 t=mp_crossing_point(mp, y1,y2,y3);
11242 if ( t>fraction_one ) goto DONE;
11243 y2=t_of_the_way(y2,y3);
11244 x1=t_of_the_way(x1,x2);
11245 x2=t_of_the_way(x2,x3);
11246 x1=t_of_the_way(x1,x2);
11247 if ( x1>=0 ) we_found_it;
11248 if ( y2>0 ) y2=0;
11249 tt=t; t=mp_crossing_point(mp, 0,-y2,-y3);
11250 if ( t>fraction_one ) goto DONE;
11251 x1=t_of_the_way(x1,x2);
11252 x2=t_of_the_way(x2,x3);
11253 if ( t_of_the_way(x1,x2)>=0 ) { 
11254   t=t_of_the_way(tt,fraction_one); we_found_it;
11255 }
11256
11257 @ @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11258     either |goto found| or |goto done|@>=
11259
11260   if ( mp_ab_vs_cd(mp, y1,y2,0,0)<0 ) {
11261     t=mp_make_fraction(mp, y1,y1-y2);
11262     x1=t_of_the_way(x1,x2);
11263     x2=t_of_the_way(x2,x3);
11264     if ( t_of_the_way(x1,x2)>=0 ) we_found_it;
11265   } else if ( y3==0 ) {
11266     if ( y1==0 ) {
11267       @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|@>;
11268     } else if ( x3>=0 ) {
11269       tt=unity; goto FOUND;
11270     }
11271   }
11272   goto DONE;
11273 }
11274
11275 @ At this point we know that the derivative of |y(t)| is identically zero,
11276 and that |x1<0|; but either |x2>=0| or |x3>=0|, so there's some hope of
11277 traveling east.
11278
11279 @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|...@>=
11280
11281   t=mp_crossing_point(mp, -x1,-x2,-x3);
11282   if ( t<=fraction_one ) we_found_it;
11283   if ( mp_ab_vs_cd(mp, x1,x3,x2,x2)<=0 ) { 
11284     t=mp_make_fraction(mp, x1,x1-x2); we_found_it;
11285   }
11286 }
11287
11288 @ The intersection of two cubics can be found by an interesting variant
11289 of the general bisection scheme described in the introduction to
11290 |crossing_point|.\
11291 Given $w(t)=B(w_0,w_1,w_2,w_3;t)$ and $z(t)=B(z_0,z_1,z_2,z_3;t)$,
11292 we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$,
11293 if an intersection exists. First we find the smallest rectangle that
11294 encloses the points $\{w_0,w_1,w_2,w_3\}$ and check that it overlaps
11295 the smallest rectangle that encloses
11296 $\{z_0,z_1,z_2,z_3\}$; if not, the cubics certainly don't intersect.
11297 But if the rectangles do overlap, we bisect the intervals, getting
11298 new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first
11299 tries for an intersection between $w'$ and~$z'$, then (if unsuccessful)
11300 between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$,
11301 finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful
11302 levels of bisection we will have determined the intersection times $t_1$
11303 and~$t_2$ to $l$~bits of accuracy.
11304
11305 \def\submin{_{\rm min}} \def\submax{_{\rm max}}
11306 As before, it is better to work with the numbers $W_k=2^l(w_k-w_{k-1})$
11307 and $Z_k=2^l(z_k-z_{k-1})$ rather than the coefficients $w_k$ and $z_k$
11308 themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$,
11309 to determine when the enclosing rectangles overlap. Here's why:
11310 The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$,
11311 and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$,
11312 if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin=
11313 \min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates
11314 overlap if and only if $u\submin\L x\submax$ and
11315 $x\submin\L u\submax$. Letting
11316 $$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\;
11317   U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$
11318 we have $u\submin=2^lu_0+U\submin$, etc.; the condition for overlap
11319 reduces to
11320 $$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$
11321 Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly,
11322 the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The
11323 coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases,
11324 because of the overlap condition; i.e., we know that $X\submin$,
11325 $X\submax$, and their relatives are bounded, hence $X\submax-
11326 U\submin$ and $X\submin-U\submax$ are bounded.
11327
11328 @ Incidentally, if the given cubics intersect more than once, the process
11329 just sketched will not necessarily find the lexicographically smallest pair
11330 $(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled
11331 order''; i.e., if $t_1=(.a_1a_2\ldots a_{16})_2$ and
11332 $t_2=(.b_1b_2\ldots b_{16})_2$, then we will minimize
11333 $a_1b_1a_2b_2\ldots a_{16}b_{16}$, not
11334 $a_1a_2\ldots a_{16}b_1b_2\ldots b_{16}$.
11335 Shuffled order agrees with lexicographic order if all pairs of solutions
11336 $(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff
11337 $t_2<t_2'$; but in general, lexicographic order can be quite different,
11338 and the bisection algorithm would be substantially less efficient if it were
11339 constrained by lexicographic order.
11340
11341 For example, suppose that an overlap has been found for $l=3$ and
11342 $(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by
11343 either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4.
11344 Then there is probably an intersection in one of the subintervals
11345 $(.1011,.011x)$; but lexicographic order would require us to explore
11346 $(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't
11347 want to store all of the subdivision data for the second path, so the
11348 subdivisions would have to be regenerated many times. Such inefficiencies
11349 would be associated with every `1' in the binary representation of~$t_1$.
11350
11351 @ The subdivision process introduces rounding errors, hence we need to
11352 make a more liberal test for overlap. It is not hard to show that the
11353 computed values of $U_i$ differ from the truth by at most~$l$, on
11354 level~$l$, hence $U\submin$ and $U\submax$ will be at most $3l$ in error.
11355 If $\beta$ is an upper bound on the absolute error in the computed
11356 components of $\Delta=(|delx|,|dely|)$ on level~$l$, we will replace
11357 the test `$X\submin-U\submax\L|delx|$' by the more liberal test
11358 `$X\submin-U\submax\L|delx|+|tol|$', where $|tol|=6l+\beta$.
11359
11360 More accuracy is obtained if we try the algorithm first with |tol=0|;
11361 the more liberal tolerance is used only if an exact approach fails.
11362 It is convenient to do this double-take by letting `3' in the preceding
11363 paragraph be a parameter, which is first 0, then 3.
11364
11365 @<Glob...@>=
11366 unsigned int tol_step; /* either 0 or 3, usually */
11367
11368 @ We shall use an explicit stack to implement the recursive bisection
11369 method described above. The |bisect_stack| array will contain numerous 5-word
11370 packets like $(U_1,U_2,U_3,U\submin,U\submax)$, as well as 20-word packets
11371 comprising the 5-word packets for $U$, $V$, $X$, and~$Y$.
11372
11373 The following macros define the allocation of stack positions to
11374 the quantities needed for bisection-intersection.
11375
11376 @d stack_1(A) mp->bisect_stack[(A)] /* $U_1$, $V_1$, $X_1$, or $Y_1$ */
11377 @d stack_2(A) mp->bisect_stack[(A)+1] /* $U_2$, $V_2$, $X_2$, or $Y_2$ */
11378 @d stack_3(A) mp->bisect_stack[(A)+2] /* $U_3$, $V_3$, $X_3$, or $Y_3$ */
11379 @d stack_min(A) mp->bisect_stack[(A)+3]
11380   /* $U\submin$, $V\submin$, $X\submin$, or $Y\submin$ */
11381 @d stack_max(A) mp->bisect_stack[(A)+4]
11382   /* $U\submax$, $V\submax$, $X\submax$, or $Y\submax$ */
11383 @d int_packets 20 /* number of words to represent $U_k$, $V_k$, $X_k$, and $Y_k$ */
11384 @#
11385 @d u_packet(A) ((A)-5)
11386 @d v_packet(A) ((A)-10)
11387 @d x_packet(A) ((A)-15)
11388 @d y_packet(A) ((A)-20)
11389 @d l_packets (mp->bisect_ptr-int_packets)
11390 @d r_packets mp->bisect_ptr
11391 @d ul_packet u_packet(l_packets) /* base of $U'_k$ variables */
11392 @d vl_packet v_packet(l_packets) /* base of $V'_k$ variables */
11393 @d xl_packet x_packet(l_packets) /* base of $X'_k$ variables */
11394 @d yl_packet y_packet(l_packets) /* base of $Y'_k$ variables */
11395 @d ur_packet u_packet(r_packets) /* base of $U''_k$ variables */
11396 @d vr_packet v_packet(r_packets) /* base of $V''_k$ variables */
11397 @d xr_packet x_packet(r_packets) /* base of $X''_k$ variables */
11398 @d yr_packet y_packet(r_packets) /* base of $Y''_k$ variables */
11399 @#
11400 @d u1l stack_1(ul_packet) /* $U'_1$ */
11401 @d u2l stack_2(ul_packet) /* $U'_2$ */
11402 @d u3l stack_3(ul_packet) /* $U'_3$ */
11403 @d v1l stack_1(vl_packet) /* $V'_1$ */
11404 @d v2l stack_2(vl_packet) /* $V'_2$ */
11405 @d v3l stack_3(vl_packet) /* $V'_3$ */
11406 @d x1l stack_1(xl_packet) /* $X'_1$ */
11407 @d x2l stack_2(xl_packet) /* $X'_2$ */
11408 @d x3l stack_3(xl_packet) /* $X'_3$ */
11409 @d y1l stack_1(yl_packet) /* $Y'_1$ */
11410 @d y2l stack_2(yl_packet) /* $Y'_2$ */
11411 @d y3l stack_3(yl_packet) /* $Y'_3$ */
11412 @d u1r stack_1(ur_packet) /* $U''_1$ */
11413 @d u2r stack_2(ur_packet) /* $U''_2$ */
11414 @d u3r stack_3(ur_packet) /* $U''_3$ */
11415 @d v1r stack_1(vr_packet) /* $V''_1$ */
11416 @d v2r stack_2(vr_packet) /* $V''_2$ */
11417 @d v3r stack_3(vr_packet) /* $V''_3$ */
11418 @d x1r stack_1(xr_packet) /* $X''_1$ */
11419 @d x2r stack_2(xr_packet) /* $X''_2$ */
11420 @d x3r stack_3(xr_packet) /* $X''_3$ */
11421 @d y1r stack_1(yr_packet) /* $Y''_1$ */
11422 @d y2r stack_2(yr_packet) /* $Y''_2$ */
11423 @d y3r stack_3(yr_packet) /* $Y''_3$ */
11424 @#
11425 @d stack_dx mp->bisect_stack[mp->bisect_ptr] /* stacked value of |delx| */
11426 @d stack_dy mp->bisect_stack[mp->bisect_ptr+1] /* stacked value of |dely| */
11427 @d stack_tol mp->bisect_stack[mp->bisect_ptr+2] /* stacked value of |tol| */
11428 @d stack_uv mp->bisect_stack[mp->bisect_ptr+3] /* stacked value of |uv| */
11429 @d stack_xy mp->bisect_stack[mp->bisect_ptr+4] /* stacked value of |xy| */
11430 @d int_increment (int_packets+int_packets+5) /* number of stack words per level */
11431
11432 @<Glob...@>=
11433 integer *bisect_stack;
11434 unsigned int bisect_ptr;
11435
11436 @ @<Allocate or initialize ...@>=
11437 mp->bisect_stack = xmalloc((bistack_size+1),sizeof(integer));
11438
11439 @ @<Dealloc variables@>=
11440 xfree(mp->bisect_stack);
11441
11442 @ @<Check the ``constant''...@>=
11443 if ( int_packets+17*int_increment>bistack_size ) mp->bad=19;
11444
11445 @ Computation of the min and max is a tedious but fairly fast sequence of
11446 instructions; exactly four comparisons are made in each branch.
11447
11448 @d set_min_max(A) 
11449   if ( stack_1((A))<0 ) {
11450     if ( stack_3((A))>=0 ) {
11451       if ( stack_2((A))<0 ) stack_min((A))=stack_1((A))+stack_2((A));
11452       else stack_min((A))=stack_1((A));
11453       stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11454       if ( stack_max((A))<0 ) stack_max((A))=0;
11455     } else { 
11456       stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11457       if ( stack_min((A))>stack_1((A)) ) stack_min((A))=stack_1((A));
11458       stack_max((A))=stack_1((A))+stack_2((A));
11459       if ( stack_max((A))<0 ) stack_max((A))=0;
11460     }
11461   } else if ( stack_3((A))<=0 ) {
11462     if ( stack_2((A))>0 ) stack_max((A))=stack_1((A))+stack_2((A));
11463     else stack_max((A))=stack_1((A));
11464     stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11465     if ( stack_min((A))>0 ) stack_min((A))=0;
11466   } else  { 
11467     stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11468     if ( stack_max((A))<stack_1((A)) ) stack_max((A))=stack_1((A));
11469     stack_min((A))=stack_1((A))+stack_2((A));
11470     if ( stack_min((A))>0 ) stack_min((A))=0;
11471   }
11472
11473 @ It's convenient to keep the current values of $l$, $t_1$, and $t_2$ in
11474 the integer form $2^l+2^lt_1$ and $2^l+2^lt_2$. The |cubic_intersection|
11475 routine uses global variables |cur_t| and |cur_tt| for this purpose;
11476 after successful completion, |cur_t| and |cur_tt| will contain |unity|
11477 plus the |scaled| values of $t_1$ and~$t_2$.
11478
11479 The values of |cur_t| and |cur_tt| will be set to zero if |cubic_intersection|
11480 finds no intersection. The routine gives up and gives an approximate answer
11481 if it has backtracked
11482 more than 5000 times (otherwise there are cases where several minutes
11483 of fruitless computation would be possible).
11484
11485 @d max_patience 5000
11486
11487 @<Glob...@>=
11488 integer cur_t;integer cur_tt; /* controls and results of |cubic_intersection| */
11489 integer time_to_go; /* this many backtracks before giving up */
11490 integer max_t; /* maximum of $2^{l+1}$ so far achieved */
11491
11492 @ The given cubics $B(w_0,w_1,w_2,w_3;t)$ and
11493 $B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes |(p,link(p))|
11494 and |(pp,link(pp))|, respectively.
11495
11496 @c void mp_cubic_intersection (MP mp,pointer p, pointer pp) {
11497   pointer q,qq; /* |link(p)|, |link(pp)| */
11498   mp->time_to_go=max_patience; mp->max_t=2;
11499   @<Initialize for intersections at level zero@>;
11500 CONTINUE:
11501   while (1) { 
11502     if ( mp->delx-mp->tol<=stack_max(x_packet(mp->xy))-stack_min(u_packet(mp->uv)))
11503     if ( mp->delx+mp->tol>=stack_min(x_packet(mp->xy))-stack_max(u_packet(mp->uv)))
11504     if ( mp->dely-mp->tol<=stack_max(y_packet(mp->xy))-stack_min(v_packet(mp->uv)))
11505     if ( mp->dely+mp->tol>=stack_min(y_packet(mp->xy))-stack_max(v_packet(mp->uv))) 
11506     { 
11507       if ( mp->cur_t>=mp->max_t ){ 
11508         if ( mp->max_t==two ) { /* we've done 17 bisections */ 
11509            mp->cur_t=halfp(mp->cur_t+1); mp->cur_tt=halfp(mp->cur_tt+1); return;
11510         }
11511         mp->max_t+=mp->max_t; mp->appr_t=mp->cur_t; mp->appr_tt=mp->cur_tt;
11512       }
11513       @<Subdivide for a new level of intersection@>;
11514       goto CONTINUE;
11515     }
11516     if ( mp->time_to_go>0 ) {
11517       decr(mp->time_to_go);
11518     } else { 
11519       while ( mp->appr_t<unity ) { 
11520         mp->appr_t+=mp->appr_t; mp->appr_tt+=mp->appr_tt;
11521       }
11522       mp->cur_t=mp->appr_t; mp->cur_tt=mp->appr_tt; return;
11523     }
11524     @<Advance to the next pair |(cur_t,cur_tt)|@>;
11525   }
11526 }
11527
11528 @ The following variables are global, although they are used only by
11529 |cubic_intersection|, because it is necessary on some machines to
11530 split |cubic_intersection| up into two procedures.
11531
11532 @<Glob...@>=
11533 integer delx;integer dely; /* the components of $\Delta=2^l(w_0-z_0)$ */
11534 integer tol; /* bound on the uncertainly in the overlap test */
11535 unsigned int uv;
11536 unsigned int xy; /* pointers to the current packets of interest */
11537 integer three_l; /* |tol_step| times the bisection level */
11538 integer appr_t;integer appr_tt; /* best approximations known to the answers */
11539
11540 @ We shall assume that the coordinates are sufficiently non-extreme that
11541 integer overflow will not occur.
11542
11543 @<Initialize for intersections at level zero@>=
11544 q=link(p); qq=link(pp); mp->bisect_ptr=int_packets;
11545 u1r=right_x(p)-x_coord(p); u2r=left_x(q)-right_x(p);
11546 u3r=x_coord(q)-left_x(q); set_min_max(ur_packet);
11547 v1r=right_y(p)-y_coord(p); v2r=left_y(q)-right_y(p);
11548 v3r=y_coord(q)-left_y(q); set_min_max(vr_packet);
11549 x1r=right_x(pp)-x_coord(pp); x2r=left_x(qq)-right_x(pp);
11550 x3r=x_coord(qq)-left_x(qq); set_min_max(xr_packet);
11551 y1r=right_y(pp)-y_coord(pp); y2r=left_y(qq)-right_y(pp);
11552 y3r=y_coord(qq)-left_y(qq); set_min_max(yr_packet);
11553 mp->delx=x_coord(p)-x_coord(pp); mp->dely=y_coord(p)-y_coord(pp);
11554 mp->tol=0; mp->uv=r_packets; mp->xy=r_packets; 
11555 mp->three_l=0; mp->cur_t=1; mp->cur_tt=1
11556
11557 @ @<Subdivide for a new level of intersection@>=
11558 stack_dx=mp->delx; stack_dy=mp->dely; stack_tol=mp->tol; 
11559 stack_uv=mp->uv; stack_xy=mp->xy;
11560 mp->bisect_ptr=mp->bisect_ptr+int_increment;
11561 mp->cur_t+=mp->cur_t; mp->cur_tt+=mp->cur_tt;
11562 u1l=stack_1(u_packet(mp->uv)); u3r=stack_3(u_packet(mp->uv));
11563 u2l=half(u1l+stack_2(u_packet(mp->uv)));
11564 u2r=half(u3r+stack_2(u_packet(mp->uv)));
11565 u3l=half(u2l+u2r); u1r=u3l;
11566 set_min_max(ul_packet); set_min_max(ur_packet);
11567 v1l=stack_1(v_packet(mp->uv)); v3r=stack_3(v_packet(mp->uv));
11568 v2l=half(v1l+stack_2(v_packet(mp->uv)));
11569 v2r=half(v3r+stack_2(v_packet(mp->uv)));
11570 v3l=half(v2l+v2r); v1r=v3l;
11571 set_min_max(vl_packet); set_min_max(vr_packet);
11572 x1l=stack_1(x_packet(mp->xy)); x3r=stack_3(x_packet(mp->xy));
11573 x2l=half(x1l+stack_2(x_packet(mp->xy)));
11574 x2r=half(x3r+stack_2(x_packet(mp->xy)));
11575 x3l=half(x2l+x2r); x1r=x3l;
11576 set_min_max(xl_packet); set_min_max(xr_packet);
11577 y1l=stack_1(y_packet(mp->xy)); y3r=stack_3(y_packet(mp->xy));
11578 y2l=half(y1l+stack_2(y_packet(mp->xy)));
11579 y2r=half(y3r+stack_2(y_packet(mp->xy)));
11580 y3l=half(y2l+y2r); y1r=y3l;
11581 set_min_max(yl_packet); set_min_max(yr_packet);
11582 mp->uv=l_packets; mp->xy=l_packets;
11583 mp->delx+=mp->delx; mp->dely+=mp->dely;
11584 mp->tol=mp->tol-mp->three_l+mp->tol_step; 
11585 mp->tol+=mp->tol; mp->three_l=mp->three_l+mp->tol_step
11586
11587 @ @<Advance to the next pair |(cur_t,cur_tt)|@>=
11588 NOT_FOUND: 
11589 if ( odd(mp->cur_tt) ) {
11590   if ( odd(mp->cur_t) ) {
11591      @<Descend to the previous level and |goto not_found|@>;
11592   } else { 
11593     incr(mp->cur_t);
11594     mp->delx=mp->delx+stack_1(u_packet(mp->uv))+stack_2(u_packet(mp->uv))
11595       +stack_3(u_packet(mp->uv));
11596     mp->dely=mp->dely+stack_1(v_packet(mp->uv))+stack_2(v_packet(mp->uv))
11597       +stack_3(v_packet(mp->uv));
11598     mp->uv=mp->uv+int_packets; /* switch from |l_packet| to |r_packet| */
11599     decr(mp->cur_tt); mp->xy=mp->xy-int_packets; 
11600          /* switch from |r_packet| to |l_packet| */
11601     mp->delx=mp->delx+stack_1(x_packet(mp->xy))+stack_2(x_packet(mp->xy))
11602       +stack_3(x_packet(mp->xy));
11603     mp->dely=mp->dely+stack_1(y_packet(mp->xy))+stack_2(y_packet(mp->xy))
11604       +stack_3(y_packet(mp->xy));
11605   }
11606 } else { 
11607   incr(mp->cur_tt); mp->tol=mp->tol+mp->three_l;
11608   mp->delx=mp->delx-stack_1(x_packet(mp->xy))-stack_2(x_packet(mp->xy))
11609     -stack_3(x_packet(mp->xy));
11610   mp->dely=mp->dely-stack_1(y_packet(mp->xy))-stack_2(y_packet(mp->xy))
11611     -stack_3(y_packet(mp->xy));
11612   mp->xy=mp->xy+int_packets; /* switch from |l_packet| to |r_packet| */
11613 }
11614
11615 @ @<Descend to the previous level...@>=
11616
11617   mp->cur_t=halfp(mp->cur_t); mp->cur_tt=halfp(mp->cur_tt);
11618   if ( mp->cur_t==0 ) return;
11619   mp->bisect_ptr=mp->bisect_ptr-int_increment; 
11620   mp->three_l=mp->three_l-mp->tol_step;
11621   mp->delx=stack_dx; mp->dely=stack_dy; mp->tol=stack_tol; 
11622   mp->uv=stack_uv; mp->xy=stack_xy;
11623   goto NOT_FOUND;
11624 }
11625
11626 @ The |path_intersection| procedure is much simpler.
11627 It invokes |cubic_intersection| in lexicographic order until finding a
11628 pair of cubics that intersect. The final intersection times are placed in
11629 |cur_t| and~|cur_tt|.
11630
11631 @c void mp_path_intersection (MP mp,pointer h, pointer hh) {
11632   pointer p,pp; /* link registers that traverse the given paths */
11633   integer n,nn; /* integer parts of intersection times, minus |unity| */
11634   @<Change one-point paths into dead cycles@>;
11635   mp->tol_step=0;
11636   do {  
11637     n=-unity; p=h;
11638     do {  
11639       if ( right_type(p)!=endpoint ) { 
11640         nn=-unity; pp=hh;
11641         do {  
11642           if ( right_type(pp)!=endpoint )  { 
11643             mp_cubic_intersection(mp, p,pp);
11644             if ( mp->cur_t>0 ) { 
11645               mp->cur_t=mp->cur_t+n; mp->cur_tt=mp->cur_tt+nn; 
11646               return;
11647             }
11648           }
11649           nn=nn+unity; pp=link(pp);
11650         } while (pp!=hh);
11651       }
11652       n=n+unity; p=link(p);
11653     } while (p!=h);
11654     mp->tol_step=mp->tol_step+3;
11655   } while (mp->tol_step<=3);
11656   mp->cur_t=-unity; mp->cur_tt=-unity;
11657 }
11658
11659 @ @<Change one-point paths...@>=
11660 if ( right_type(h)==endpoint ) {
11661   right_x(h)=x_coord(h); left_x(h)=x_coord(h);
11662   right_y(h)=y_coord(h); left_y(h)=y_coord(h); right_type(h)=explicit;
11663 }
11664 if ( right_type(hh)==endpoint ) {
11665   right_x(hh)=x_coord(hh); left_x(hh)=x_coord(hh);
11666   right_y(hh)=y_coord(hh); left_y(hh)=y_coord(hh); right_type(hh)=explicit;
11667 }
11668
11669 @* \[24] Dynamic linear equations.
11670 \MP\ users define variables implicitly by stating equations that should be
11671 satisfied; the computer is supposed to be smart enough to solve those equations.
11672 And indeed, the computer tries valiantly to do so, by distinguishing five
11673 different types of numeric values:
11674
11675 \smallskip\hang
11676 |type(p)=mp_known| is the nice case, when |value(p)| is the |scaled| value
11677 of the variable whose address is~|p|.
11678
11679 \smallskip\hang
11680 |type(p)=mp_dependent| means that |value(p)| is not present, but |dep_list(p)|
11681 points to a {\sl dependency list\/} that expresses the value of variable~|p|
11682 as a |scaled| number plus a sum of independent variables with |fraction|
11683 coefficients.
11684
11685 \smallskip\hang
11686 |type(p)=mp_independent| means that |value(p)=64s+m|, where |s>0| is a ``serial
11687 number'' reflecting the time this variable was first used in an equation;
11688 also |0<=m<64|, and each dependent variable
11689 that refers to this one is actually referring to the future value of
11690 this variable times~$2^m$. (Usually |m=0|, but higher degrees of
11691 scaling are sometimes needed to keep the coefficients in dependency lists
11692 from getting too large. The value of~|m| will always be even.)
11693
11694 \smallskip\hang
11695 |type(p)=mp_numeric_type| means that variable |p| hasn't appeared in an
11696 equation before, but it has been explicitly declared to be numeric.
11697
11698 \smallskip\hang
11699 |type(p)=undefined| means that variable |p| hasn't appeared before.
11700
11701 \smallskip\noindent
11702 We have actually discussed these five types in the reverse order of their
11703 history during a computation: Once |known|, a variable never again
11704 becomes |dependent|; once |dependent|, it almost never again becomes
11705 |mp_independent|; once |mp_independent|, it never again becomes |mp_numeric_type|;
11706 and once |mp_numeric_type|, it never again becomes |undefined| (except
11707 of course when the user specifically decides to scrap the old value
11708 and start again). A backward step may, however, take place: Sometimes
11709 a |dependent| variable becomes |mp_independent| again, when one of the
11710 independent variables it depends on is reverting to |undefined|.
11711
11712
11713 The next patch detects overflow of independent-variable serial
11714 numbers. Diagnosed and patched by Thorsten Dahlheimer.
11715
11716 @d s_scale 64 /* the serial numbers are multiplied by this factor */
11717 @d max_indep_vars 0177777777 /* $2^{25}-1$ */
11718 @d max_serial_no 017777777700 /* |max_indep_vars*s_scale| */
11719 @d new_indep(A)  /* create a new independent variable */
11720   { if ( mp->serial_no==max_serial_no )
11721     mp_fatal_error(mp, "variable instance identifiers exhausted");
11722   type((A))=mp_independent; mp->serial_no=mp->serial_no+s_scale;
11723   value((A))=mp->serial_no;
11724   }
11725
11726 @<Glob...@>=
11727 integer serial_no; /* the most recent serial number, times |s_scale| */
11728
11729 @ @<Make variable |q+s| newly independent@>=new_indep(q+s)
11730
11731 @ But how are dependency lists represented? It's simple: The linear combination
11732 $\alpha_1v_1+\cdots+\alpha_kv_k+\beta$ appears in |k+1| value nodes. If
11733 |q=dep_list(p)| points to this list, and if |k>0|, then |value(q)=
11734 @t$\alpha_1$@>| (which is a |fraction|); |info(q)| points to the location
11735 of $\alpha_1$; and |link(p)| points to the dependency list
11736 $\alpha_2v_2+\cdots+\alpha_kv_k+\beta$. On the other hand if |k=0|,
11737 then |value(q)=@t$\beta$@>| (which is |scaled|) and |info(q)=null|.
11738 The independent variables $v_1$, \dots,~$v_k$ have been sorted so that
11739 they appear in decreasing order of their |value| fields (i.e., of
11740 their serial numbers). \ (It is convenient to use decreasing order,
11741 since |value(null)=0|. If the independent variables were not sorted by
11742 serial number but by some other criterion, such as their location in |mem|,
11743 the equation-solving mechanism would be too system-dependent, because
11744 the ordering can affect the computed results.)
11745
11746 The |link| field in the node that contains the constant term $\beta$ is
11747 called the {\sl final link\/} of the dependency list. \MP\ maintains
11748 a doubly-linked master list of all dependency lists, in terms of a permanently
11749 allocated node
11750 in |mem| called |dep_head|. If there are no dependencies, we have
11751 |link(dep_head)=dep_head| and |prev_dep(dep_head)=dep_head|;
11752 otherwise |link(dep_head)| points to the first dependent variable, say~|p|,
11753 and |prev_dep(p)=dep_head|. We have |type(p)=mp_dependent|, and |dep_list(p)|
11754 points to its dependency list. If the final link of that dependency list
11755 occurs in location~|q|, then |link(q)| points to the next dependent
11756 variable (say~|r|); and we have |prev_dep(r)=q|, etc.
11757
11758 @d dep_list(A) link(value_loc((A)))
11759   /* half of the |value| field in a |dependent| variable */
11760 @d prev_dep(A) info(value_loc((A)))
11761   /* the other half; makes a doubly linked list */
11762 @d dep_node_size 2 /* the number of words per dependency node */
11763
11764 @<Initialize table entries...@>= mp->serial_no=0;
11765 link(dep_head)=dep_head; prev_dep(dep_head)=dep_head;
11766 info(dep_head)=null; dep_list(dep_head)=null;
11767
11768 @ Actually the description above contains a little white lie. There's
11769 another kind of variable called |mp_proto_dependent|, which is
11770 just like a |dependent| one except that the $\alpha$ coefficients
11771 in its dependency list are |scaled| instead of being fractions.
11772 Proto-dependency lists are mixed with dependency lists in the
11773 nodes reachable from |dep_head|.
11774
11775 @ Here is a procedure that prints a dependency list in symbolic form.
11776 The second parameter should be either |dependent| or |mp_proto_dependent|,
11777 to indicate the scaling of the coefficients.
11778
11779 @<Declare subroutines for printing expressions@>=
11780 void mp_print_dependency (MP mp,pointer p, small_number t) {
11781   integer v; /* a coefficient */
11782   pointer pp,q; /* for list manipulation */
11783   pp=p;
11784   while (1) { 
11785     v=abs(value(p)); q=info(p);
11786     if ( q==null ) { /* the constant term */
11787       if ( (v!=0)||(p==pp) ) {
11788          if ( value(p)>0 ) if ( p!=pp ) mp_print_char(mp, '+');
11789          mp_print_scaled(mp, value(p));
11790       }
11791       return;
11792     }
11793     @<Print the coefficient, unless it's $\pm1.0$@>;
11794     if ( type(q)!=mp_independent ) mp_confusion(mp, "dep");
11795 @:this can't happen dep}{\quad dep@>
11796     mp_print_variable_name(mp, q); v=value(q) % s_scale;
11797     while ( v>0 ) { mp_print(mp, "*4"); v=v-2; }
11798     p=link(p);
11799   }
11800 }
11801
11802 @ @<Print the coefficient, unless it's $\pm1.0$@>=
11803 if ( value(p)<0 ) mp_print_char(mp, '-');
11804 else if ( p!=pp ) mp_print_char(mp, '+');
11805 if ( t==mp_dependent ) v=mp_round_fraction(mp, v);
11806 if ( v!=unity ) mp_print_scaled(mp, v)
11807
11808 @ The maximum absolute value of a coefficient in a given dependency list
11809 is returned by the following simple function.
11810
11811 @c fraction mp_max_coef (MP mp,pointer p) {
11812   fraction x; /* the maximum so far */
11813   x=0;
11814   while ( info(p)!=null ) {
11815     if ( abs(value(p))>x ) x=abs(value(p));
11816     p=link(p);
11817   }
11818   return x;
11819 }
11820
11821 @ One of the main operations needed on dependency lists is to add a multiple
11822 of one list to the other; we call this |p_plus_fq|, where |p| and~|q| point
11823 to dependency lists and |f| is a fraction.
11824
11825 If the coefficient of any independent variable becomes |coef_bound| or
11826 more, in absolute value, this procedure changes the type of that variable
11827 to `|independent_needing_fix|', and sets the global variable |fix_needed|
11828 to~|true|. The value of $|coef_bound|=\mu$ is chosen so that
11829 $\mu^2+\mu<8$; this means that the numbers we deal with won't
11830 get too large. (Instead of the ``optimum'' $\mu=(\sqrt{33}-1)/2\approx
11831 2.3723$, the safer value 7/3 is taken as the threshold.)
11832
11833 The changes mentioned in the preceding paragraph are actually done only if
11834 the global variable |watch_coefs| is |true|. But it usually is; in fact,
11835 it is |false| only when \MP\ is making a dependency list that will soon
11836 be equated to zero.
11837
11838 Several procedures that act on dependency lists, including |p_plus_fq|,
11839 set the global variable |dep_final| to the final (constant term) node of
11840 the dependency list that they produce.
11841
11842 @d coef_bound 04525252525 /* |fraction| approximation to 7/3 */
11843 @d independent_needing_fix 0
11844
11845 @<Glob...@>=
11846 boolean fix_needed; /* does at least one |independent| variable need scaling? */
11847 boolean watch_coefs; /* should we scale coefficients that exceed |coef_bound|? */
11848 pointer dep_final; /* location of the constant term and final link */
11849
11850 @ @<Set init...@>=
11851 mp->fix_needed=false; mp->watch_coefs=true;
11852
11853 @ The |p_plus_fq| procedure has a fourth parameter, |t|, that should be
11854 set to |mp_proto_dependent| if |p| is a proto-dependency list. In this
11855 case |f| will be |scaled|, not a |fraction|. Similarly, the fifth parameter~|tt|
11856 should be |mp_proto_dependent| if |q| is a proto-dependency list.
11857
11858 List |q| is unchanged by the operation; but list |p| is totally destroyed.
11859
11860 The final link of the dependency list or proto-dependency list returned
11861 by |p_plus_fq| is the same as the original final link of~|p|. Indeed, the
11862 constant term of the result will be located in the same |mem| location
11863 as the original constant term of~|p|.
11864
11865 Coefficients of the result are assumed to be zero if they are less than
11866 a certain threshold. This compensates for inevitable rounding errors,
11867 and tends to make more variables `|known|'. The threshold is approximately
11868 $10^{-5}$ in the case of normal dependency lists, $10^{-4}$ for
11869 proto-dependencies.
11870
11871 @d fraction_threshold 2685 /* a |fraction| coefficient less than this is zeroed */
11872 @d half_fraction_threshold 1342 /* half of |fraction_threshold| */
11873 @d scaled_threshold 8 /* a |scaled| coefficient less than this is zeroed */
11874 @d half_scaled_threshold 4 /* half of |scaled_threshold| */
11875
11876 @<Declare basic dependency-list subroutines@>=
11877 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
11878                       pointer q, small_number t, small_number tt) ;
11879
11880 @ @c
11881 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
11882                       pointer q, small_number t, small_number tt) {
11883   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
11884   pointer r,s; /* for list manipulation */
11885   integer mp_threshold; /* defines a neighborhood of zero */
11886   integer v; /* temporary register */
11887   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
11888   else mp_threshold=scaled_threshold;
11889   r=temp_head; pp=info(p); qq=info(q);
11890   while (1) {
11891     if ( pp==qq ) {
11892       if ( pp==null ) {
11893        break;
11894       } else {
11895         @<Contribute a term from |p|, plus |f| times the
11896           corresponding term from |q|@>
11897       }
11898     } else if ( value(pp)<value(qq) ) {
11899       @<Contribute a term from |q|, multiplied by~|f|@>
11900     } else { 
11901      link(r)=p; r=p; p=link(p); pp=info(p);
11902     }
11903   }
11904   if ( t==mp_dependent )
11905     value(p)=mp_slow_add(mp, value(p),mp_take_fraction(mp, value(q),f));
11906   else  
11907     value(p)=mp_slow_add(mp, value(p),mp_take_scaled(mp, value(q),f));
11908   link(r)=p; mp->dep_final=p; 
11909   return link(temp_head);
11910 }
11911
11912 @ @<Contribute a term from |p|, plus |f|...@>=
11913
11914   if ( tt==mp_dependent ) v=value(p)+mp_take_fraction(mp, f,value(q));
11915   else v=value(p)+mp_take_scaled(mp, f,value(q));
11916   value(p)=v; s=p; p=link(p);
11917   if ( abs(v)<mp_threshold ) {
11918     mp_free_node(mp, s,dep_node_size);
11919   } else {
11920     if ( (abs(v)>=coef_bound)  && mp->watch_coefs ) { 
11921       type(qq)=independent_needing_fix; mp->fix_needed=true;
11922     }
11923     link(r)=s; r=s;
11924   };
11925   pp=info(p); q=link(q); qq=info(q);
11926 }
11927
11928 @ @<Contribute a term from |q|, multiplied by~|f|@>=
11929
11930   if ( tt==mp_dependent ) v=mp_take_fraction(mp, f,value(q));
11931   else v=mp_take_scaled(mp, f,value(q));
11932   if ( abs(v)>halfp(mp_threshold) ) { 
11933     s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=v;
11934     if ( (abs(v)>=coef_bound) && mp->watch_coefs ) { 
11935       type(qq)=independent_needing_fix; mp->fix_needed=true;
11936     }
11937     link(r)=s; r=s;
11938   }
11939   q=link(q); qq=info(q);
11940 }
11941
11942 @ It is convenient to have another subroutine for the special case
11943 of |p_plus_fq| when |f=1.0|. In this routine lists |p| and |q| are
11944 both of the same type~|t| (either |dependent| or |mp_proto_dependent|).
11945
11946 @c pointer mp_p_plus_q (MP mp,pointer p, pointer q, small_number t) {
11947   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
11948   pointer r,s; /* for list manipulation */
11949   integer mp_threshold; /* defines a neighborhood of zero */
11950   integer v; /* temporary register */
11951   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
11952   else mp_threshold=scaled_threshold;
11953   r=temp_head; pp=info(p); qq=info(q);
11954   while (1) {
11955     if ( pp==qq ) {
11956       if ( pp==null ) {
11957         break;
11958       } else {
11959         @<Contribute a term from |p|, plus the
11960           corresponding term from |q|@>
11961       }
11962     } else if ( value(pp)<value(qq) ) {
11963       s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=value(q);
11964       q=link(q); qq=info(q); link(r)=s; r=s;
11965     } else { 
11966       link(r)=p; r=p; p=link(p); pp=info(p);
11967     }
11968   }
11969   value(p)=mp_slow_add(mp, value(p),value(q));
11970   link(r)=p; mp->dep_final=p; 
11971   return link(temp_head);
11972 }
11973
11974 @ @<Contribute a term from |p|, plus the...@>=
11975
11976   v=value(p)+value(q);
11977   value(p)=v; s=p; p=link(p); pp=info(p);
11978   if ( abs(v)<mp_threshold ) {
11979     mp_free_node(mp, s,dep_node_size);
11980   } else { 
11981     if ( (abs(v)>=coef_bound ) && mp->watch_coefs ) {
11982       type(qq)=independent_needing_fix; mp->fix_needed=true;
11983     }
11984     link(r)=s; r=s;
11985   }
11986   q=link(q); qq=info(q);
11987 }
11988
11989 @ A somewhat simpler routine will multiply a dependency list
11990 by a given constant~|v|. The constant is either a |fraction| less than
11991 |fraction_one|, or it is |scaled|. In the latter case we might be forced to
11992 convert a dependency list to a proto-dependency list.
11993 Parameters |t0| and |t1| are the list types before and after;
11994 they should agree unless |t0=mp_dependent| and |t1=mp_proto_dependent|
11995 and |v_is_scaled=true|.
11996
11997 @c pointer mp_p_times_v (MP mp,pointer p, integer v, small_number t0,
11998                          small_number t1, boolean v_is_scaled) {
11999   pointer r,s; /* for list manipulation */
12000   integer w; /* tentative coefficient */
12001   integer mp_threshold;
12002   boolean scaling_down;
12003   if ( t0!=t1 ) scaling_down=true; else scaling_down=! v_is_scaled;
12004   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12005   else mp_threshold=half_scaled_threshold;
12006   r=temp_head;
12007   while ( info(p)!=null ) {    
12008     if ( scaling_down ) w=mp_take_fraction(mp, v,value(p));
12009     else w=mp_take_scaled(mp, v,value(p));
12010     if ( abs(w)<=mp_threshold ) { 
12011       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12012     } else {
12013       if ( abs(w)>=coef_bound ) { 
12014         mp->fix_needed=true; type(info(p))=independent_needing_fix;
12015       }
12016       link(r)=p; r=p; value(p)=w; p=link(p);
12017     }
12018   }
12019   link(r)=p;
12020   if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
12021   else value(p)=mp_take_fraction(mp, value(p),v);
12022   return link(temp_head);
12023 };
12024
12025 @ Similarly, we sometimes need to divide a dependency list
12026 by a given |scaled| constant.
12027
12028 @<Declare basic dependency-list subroutines@>=
12029 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12030   t0, small_number t1) ;
12031
12032 @ @c
12033 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12034   t0, small_number t1) {
12035   pointer r,s; /* for list manipulation */
12036   integer w; /* tentative coefficient */
12037   integer mp_threshold;
12038   boolean scaling_down;
12039   if ( t0!=t1 ) scaling_down=true; else scaling_down=false;
12040   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12041   else mp_threshold=half_scaled_threshold;
12042   r=temp_head;
12043   while ( info( p)!=null ) {
12044     if ( scaling_down ) {
12045       if ( abs(v)<02000000 ) w=mp_make_scaled(mp, value(p),v*010000);
12046       else w=mp_make_scaled(mp, mp_round_fraction(mp, value(p)),v);
12047     } else {
12048       w=mp_make_scaled(mp, value(p),v);
12049     }
12050     if ( abs(w)<=mp_threshold ) {
12051       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12052     } else { 
12053       if ( abs(w)>=coef_bound ) {
12054          mp->fix_needed=true; type(info(p))=independent_needing_fix;
12055       }
12056       link(r)=p; r=p; value(p)=w; p=link(p);
12057     }
12058   }
12059   link(r)=p; value(p)=mp_make_scaled(mp, value(p),v);
12060   return link(temp_head);
12061 };
12062
12063 @ Here's another utility routine for dependency lists. When an independent
12064 variable becomes dependent, we want to remove it from all existing
12065 dependencies. The |p_with_x_becoming_q| function computes the
12066 dependency list of~|p| after variable~|x| has been replaced by~|q|.
12067
12068 This procedure has basically the same calling conventions as |p_plus_fq|:
12069 List~|q| is unchanged; list~|p| is destroyed; the constant node and the
12070 final link are inherited from~|p|; and the fourth parameter tells whether
12071 or not |p| is |mp_proto_dependent|. However, the global variable |dep_final|
12072 is not altered if |x| does not occur in list~|p|.
12073
12074 @c pointer mp_p_with_x_becoming_q (MP mp,pointer p,
12075            pointer x, pointer q, small_number t) {
12076   pointer r,s; /* for list manipulation */
12077   integer v; /* coefficient of |x| */
12078   integer sx; /* serial number of |x| */
12079   s=p; r=temp_head; sx=value(x);
12080   while ( value(info(s))>sx ) { r=s; s=link(s); };
12081   if ( info(s)!=x ) { 
12082     return p;
12083   } else { 
12084     link(temp_head)=p; link(r)=link(s); v=value(s);
12085     mp_free_node(mp, s,dep_node_size);
12086     return mp_p_plus_fq(mp, link(temp_head),v,q,t,mp_dependent);
12087   }
12088 }
12089
12090 @ Here's a simple procedure that reports an error when a variable
12091 has just received a known value that's out of the required range.
12092
12093 @<Declare basic dependency-list subroutines@>=
12094 void mp_val_too_big (MP mp,scaled x) ;
12095
12096 @ @c void mp_val_too_big (MP mp,scaled x) { 
12097   if ( mp->internal[warning_check]>0 ) { 
12098     print_err("Value is too large ("); mp_print_scaled(mp, x); mp_print_char(mp, ')');
12099 @.Value is too large@>
12100     help4("The equation I just processed has given some variable")
12101       ("a value of 4096 or more. Continue and I'll try to cope")
12102       ("with that big value; but it might be dangerous.")
12103       ("(Set warningcheck:=0 to suppress this message.)");
12104     mp_error(mp);
12105   }
12106 }
12107
12108 @ When a dependent variable becomes known, the following routine
12109 removes its dependency list. Here |p| points to the variable, and
12110 |q| points to the dependency list (which is one node long).
12111
12112 @<Declare basic dependency-list subroutines@>=
12113 void mp_make_known (MP mp,pointer p, pointer q) ;
12114
12115 @ @c void mp_make_known (MP mp,pointer p, pointer q) {
12116   int t; /* the previous type */
12117   prev_dep(link(q))=prev_dep(p);
12118   link(prev_dep(p))=link(q); t=type(p);
12119   type(p)=mp_known; value(p)=value(q); mp_free_node(mp, q,dep_node_size);
12120   if ( abs(value(p))>=fraction_one ) mp_val_too_big(mp, value(p));
12121   if (( mp->internal[tracing_equations]>0) && mp_interesting(mp, p) ) {
12122     mp_begin_diagnostic(mp); mp_print_nl(mp, "#### ");
12123 @:]]]\#\#\#\#_}{\.{\#\#\#\#}@>
12124     mp_print_variable_name(mp, p); 
12125     mp_print_char(mp, '='); mp_print_scaled(mp, value(p));
12126     mp_end_diagnostic(mp, false);
12127   }
12128   if (( mp->cur_exp==p ) && mp->cur_type==t ) {
12129     mp->cur_type=mp_known; mp->cur_exp=value(p);
12130     mp_free_node(mp, p,value_node_size);
12131   }
12132 }
12133
12134 @ The |fix_dependencies| routine is called into action when |fix_needed|
12135 has been triggered. The program keeps a list~|s| of independent variables
12136 whose coefficients must be divided by~4.
12137
12138 In unusual cases, this fixup process might reduce one or more coefficients
12139 to zero, so that a variable will become known more or less by default.
12140
12141 @<Declare basic dependency-list subroutines@>=
12142 void mp_fix_dependencies (MP mp);
12143
12144 @ @c void mp_fix_dependencies (MP mp) {
12145   pointer p,q,r,s,t; /* list manipulation registers */
12146   pointer x; /* an independent variable */
12147   r=link(dep_head); s=null;
12148   while ( r!=dep_head ){ 
12149     t=r;
12150     @<Run through the dependency list for variable |t|, fixing
12151       all nodes, and ending with final link~|q|@>;
12152     r=link(q);
12153     if ( q==dep_list(t) ) mp_make_known(mp, t,q);
12154   }
12155   while ( s!=null ) { 
12156     p=link(s); x=info(s); free_avail(s); s=p;
12157     type(x)=mp_independent; value(x)=value(x)+2;
12158   }
12159   mp->fix_needed=false;
12160 }
12161
12162 @ @d independent_being_fixed 1 /* this variable already appears in |s| */
12163
12164 @<Run through the dependency list for variable |t|...@>=
12165 r=value_loc(t); /* |link(r)=dep_list(t)| */
12166 while (1) { 
12167   q=link(r); x=info(q);
12168   if ( x==null ) break;
12169   if ( type(x)<=independent_being_fixed ) {
12170     if ( type(x)<independent_being_fixed ) {
12171       p=mp_get_avail(mp); link(p)=s; s=p;
12172       info(s)=x; type(x)=independent_being_fixed;
12173     }
12174     value(q)=value(q) / 4;
12175     if ( value(q)==0 ) {
12176       link(r)=link(q); mp_free_node(mp, q,dep_node_size); q=r;
12177     }
12178   }
12179   r=q;
12180 }
12181
12182
12183 @ The |new_dep| routine installs a dependency list~|p| into the value node~|q|,
12184 linking it into the list of all known dependencies. We assume that
12185 |dep_final| points to the final node of list~|p|.
12186
12187 @c void mp_new_dep (MP mp,pointer q, pointer p) {
12188   pointer r; /* what used to be the first dependency */
12189   dep_list(q)=p; prev_dep(q)=dep_head;
12190   r=link(dep_head); link(mp->dep_final)=r; prev_dep(r)=mp->dep_final;
12191   link(dep_head)=q;
12192 }
12193
12194 @ Here is one of the ways a dependency list gets started.
12195 The |const_dependency| routine produces a list that has nothing but
12196 a constant term.
12197
12198 @c pointer mp_const_dependency (MP mp, scaled v) {
12199   mp->dep_final=mp_get_node(mp, dep_node_size);
12200   value(mp->dep_final)=v; info(mp->dep_final)=null;
12201   return mp->dep_final;
12202 }
12203
12204 @ And here's a more interesting way to start a dependency list from scratch:
12205 The parameter to |single_dependency| is the location of an
12206 independent variable~|x|, and the result is the simple dependency list
12207 `|x+0|'.
12208
12209 In the unlikely event that the given independent variable has been doubled so
12210 often that we can't refer to it with a nonzero coefficient,
12211 |single_dependency| returns the simple list `0'.  This case can be
12212 recognized by testing that the returned list pointer is equal to
12213 |dep_final|.
12214
12215 @c pointer mp_single_dependency (MP mp,pointer p) {
12216   pointer q; /* the new dependency list */
12217   integer m; /* the number of doublings */
12218   m=value(p) % s_scale;
12219   if ( m>28 ) {
12220     return mp_const_dependency(mp, 0);
12221   } else { 
12222     q=mp_get_node(mp, dep_node_size);
12223     value(q)=two_to_the(28-m); info(q)=p;
12224     link(q)=mp_const_dependency(mp, 0);
12225     return q;
12226   }
12227 }
12228
12229 @ We sometimes need to make an exact copy of a dependency list.
12230
12231 @c pointer mp_copy_dep_list (MP mp,pointer p) {
12232   pointer q; /* the new dependency list */
12233   q=mp_get_node(mp, dep_node_size); mp->dep_final=q;
12234   while (1) { 
12235     info(mp->dep_final)=info(p); value(mp->dep_final)=value(p);
12236     if ( info(mp->dep_final)==null ) break;
12237     link(mp->dep_final)=mp_get_node(mp, dep_node_size);
12238     mp->dep_final=link(mp->dep_final); p=link(p);
12239   }
12240   return q;
12241 }
12242
12243 @ But how do variables normally become known? Ah, now we get to the heart of the
12244 equation-solving mechanism. The |linear_eq| procedure is given a |dependent|
12245 or |mp_proto_dependent| list,~|p|, in which at least one independent variable
12246 appears. It equates this list to zero, by choosing an independent variable
12247 with the largest coefficient and making it dependent on the others. The
12248 newly dependent variable is eliminated from all current dependencies,
12249 thereby possibly making other dependent variables known.
12250
12251 The given list |p| is, of course, totally destroyed by all this processing.
12252
12253 @c void mp_linear_eq (MP mp, pointer p, small_number t) {
12254   pointer q,r,s; /* for link manipulation */
12255   pointer x; /* the variable that loses its independence */
12256   integer n; /* the number of times |x| had been halved */
12257   integer v; /* the coefficient of |x| in list |p| */
12258   pointer prev_r; /* lags one step behind |r| */
12259   pointer final_node; /* the constant term of the new dependency list */
12260   integer w; /* a tentative coefficient */
12261    @<Find a node |q| in list |p| whose coefficient |v| is largest@>;
12262   x=info(q); n=value(x) % s_scale;
12263   @<Divide list |p| by |-v|, removing node |q|@>;
12264   if ( mp->internal[tracing_equations]>0 ) {
12265     @<Display the new dependency@>;
12266   }
12267   @<Simplify all existing dependencies by substituting for |x|@>;
12268   @<Change variable |x| from |independent| to |dependent| or |known|@>;
12269   if ( mp->fix_needed ) mp_fix_dependencies(mp);
12270 }
12271
12272 @ @<Find a node |q| in list |p| whose coefficient |v| is largest@>=
12273 q=p; r=link(p); v=value(q);
12274 while ( info(r)!=null ) { 
12275   if ( abs(value(r))>abs(v) ) { q=r; v=value(r); };
12276   r=link(r);
12277 }
12278
12279 @ Here we want to change the coefficients from |scaled| to |fraction|,
12280 except in the constant term. In the common case of a trivial equation
12281 like `\.{x=3.14}', we will have |v=-fraction_one|, |q=p|, and |t=mp_dependent|.
12282
12283 @<Divide list |p| by |-v|, removing node |q|@>=
12284 s=temp_head; link(s)=p; r=p;
12285 do { 
12286   if ( r==q ) {
12287     link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12288   } else  { 
12289     w=mp_make_fraction(mp, value(r),v);
12290     if ( abs(w)<=half_fraction_threshold ) {
12291       link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12292     } else { 
12293       value(r)=-w; s=r;
12294     }
12295   }
12296   r=link(s);
12297 } while (info(r)!=null);
12298 if ( t==mp_proto_dependent ) {
12299   value(r)=-mp_make_scaled(mp, value(r),v);
12300 } else if ( v!=-fraction_one ) {
12301   value(r)=-mp_make_fraction(mp, value(r),v);
12302 }
12303 final_node=r; p=link(temp_head)
12304
12305 @ @<Display the new dependency@>=
12306 if ( mp_interesting(mp, x) ) {
12307   mp_begin_diagnostic(mp); mp_print_nl(mp, "## "); 
12308   mp_print_variable_name(mp, x);
12309 @:]]]\#\#_}{\.{\#\#}@>
12310   w=n;
12311   while ( w>0 ) { mp_print(mp, "*4"); w=w-2;  };
12312   mp_print_char(mp, '='); mp_print_dependency(mp, p,mp_dependent); 
12313   mp_end_diagnostic(mp, false);
12314 }
12315
12316 @ @<Simplify all existing dependencies by substituting for |x|@>=
12317 prev_r=dep_head; r=link(dep_head);
12318 while ( r!=dep_head ) {
12319   s=dep_list(r); q=mp_p_with_x_becoming_q(mp, s,x,p,type(r));
12320   if ( info(q)==null ) {
12321     mp_make_known(mp, r,q);
12322   } else { 
12323     dep_list(r)=q;
12324     do {  q=link(q); } while (info(q)!=null);
12325     prev_r=q;
12326   }
12327   r=link(prev_r);
12328 }
12329
12330 @ @<Change variable |x| from |independent| to |dependent| or |known|@>=
12331 if ( n>0 ) @<Divide list |p| by $2^n$@>;
12332 if ( info(p)==null ) {
12333   type(x)=mp_known;
12334   value(x)=value(p);
12335   if ( abs(value(x))>=fraction_one ) mp_val_too_big(mp, value(x));
12336   mp_free_node(mp, p,dep_node_size);
12337   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) {
12338     mp->cur_exp=value(x); mp->cur_type=mp_known;
12339     mp_free_node(mp, x,value_node_size);
12340   }
12341 } else { 
12342   type(x)=mp_dependent; mp->dep_final=final_node; mp_new_dep(mp, x,p);
12343   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) mp->cur_type=mp_dependent;
12344 }
12345
12346 @ @<Divide list |p| by $2^n$@>=
12347
12348   s=temp_head; link(temp_head)=p; r=p;
12349   do {  
12350     if ( n>30 ) w=0;
12351     else w=value(r) / two_to_the(n);
12352     if ( (abs(w)<=half_fraction_threshold)&&(info(r)!=null) ) {
12353       link(s)=link(r);
12354       mp_free_node(mp, r,dep_node_size);
12355     } else { 
12356       value(r)=w; s=r;
12357     }
12358     r=link(s);
12359   } while (info(s)!=null);
12360   p=link(temp_head);
12361 }
12362
12363 @ The |check_mem| procedure, which is used only when \MP\ is being
12364 debugged, makes sure that the current dependency lists are well formed.
12365
12366 @<Check the list of linear dependencies@>=
12367 q=dep_head; p=link(q);
12368 while ( p!=dep_head ) {
12369   if ( prev_dep(p)!=q ) {
12370     mp_print_nl(mp, "Bad PREVDEP at "); mp_print_int(mp, p);
12371 @.Bad PREVDEP...@>
12372   }
12373   p=dep_list(p);
12374   while (1) {
12375     r=info(p); q=p; p=link(q);
12376     if ( r==null ) break;
12377     if ( value(info(p))>=value(r) ) {
12378       mp_print_nl(mp, "Out of order at "); mp_print_int(mp, p);
12379 @.Out of order...@>
12380     }
12381   }
12382 }
12383
12384 @* \[25] Dynamic nonlinear equations.
12385 Variables of numeric type are maintained by the general scheme of
12386 independent, dependent, and known values that we have just studied;
12387 and the components of pair and transform variables are handled in the
12388 same way. But \MP\ also has five other types of values: \&{boolean},
12389 \&{string}, \&{pen}, \&{path}, and \&{picture}; what about them?
12390
12391 Equations are allowed between nonlinear quantities, but only in a
12392 simple form. Two variables that haven't yet been assigned values are
12393 either equal to each other, or they're not.
12394
12395 Before a boolean variable has received a value, its type is |mp_unknown_boolean|;
12396 similarly, there are variables whose type is |mp_unknown_string|, |mp_unknown_pen|,
12397 |mp_unknown_path|, and |mp_unknown_picture|. In such cases the value is either
12398 |null| (which means that no other variables are equivalent to this one), or
12399 it points to another variable of the same undefined type. The pointers in the
12400 latter case form a cycle of nodes, which we shall call a ``ring.''
12401 Rings of undefined variables may include capsules, which arise as
12402 intermediate results within expressions or as \&{expr} parameters to macros.
12403
12404 When one member of a ring receives a value, the same value is given to
12405 all the other members. In the case of paths and pictures, this implies
12406 making separate copies of a potentially large data structure; users should
12407 restrain their enthusiasm for such generality, unless they have lots and
12408 lots of memory space.
12409
12410 @ The following procedure is called when a capsule node is being
12411 added to a ring (e.g., when an unknown variable is mentioned in an expression).
12412
12413 @c pointer mp_new_ring_entry (MP mp,pointer p) {
12414   pointer q; /* the new capsule node */
12415   q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
12416   type(q)=type(p);
12417   if ( value(p)==null ) value(q)=p; else value(q)=value(p);
12418   value(p)=q;
12419   return q;
12420 }
12421
12422 @ Conversely, we might delete a capsule or a variable before it becomes known.
12423 The following procedure simply detaches a quantity from its ring,
12424 without recycling the storage.
12425
12426 @<Declare the recycling subroutines@>=
12427 void mp_ring_delete (MP mp,pointer p) {
12428   pointer q; 
12429   q=value(p);
12430   if ( q!=null ) if ( q!=p ){ 
12431     while ( value(q)!=p ) q=value(q);
12432     value(q)=value(p);
12433   }
12434 }
12435
12436 @ Eventually there might be an equation that assigns values to all of the
12437 variables in a ring. The |nonlinear_eq| subroutine does the necessary
12438 propagation of values.
12439
12440 If the parameter |flush_p| is |true|, node |p| itself needn't receive a
12441 value, it will soon be recycled.
12442
12443 @c void mp_nonlinear_eq (MP mp,integer v, pointer p, boolean flush_p) {
12444   small_number t; /* the type of ring |p| */
12445   pointer q,r; /* link manipulation registers */
12446   t=type(p)-unknown_tag; q=value(p);
12447   if ( flush_p ) type(p)=mp_vacuous; else p=q;
12448   do {  
12449     r=value(q); type(q)=t;
12450     switch (t) {
12451     case mp_boolean_type: value(q)=v; break;
12452     case mp_string_type: value(q)=v; add_str_ref(v); break;
12453     case mp_pen_type: value(q)=copy_pen(v); break;
12454     case mp_path_type: value(q)=mp_copy_path(mp, v); break;
12455     case mp_picture_type: value(q)=v; add_edge_ref(v); break;
12456     } /* there ain't no more cases */
12457     q=r;
12458   } while (q!=p);
12459 }
12460
12461 @ If two members of rings are equated, and if they have the same type,
12462 the |ring_merge| procedure is called on to make them equivalent.
12463
12464 @c void mp_ring_merge (MP mp,pointer p, pointer q) {
12465   pointer r; /* traverses one list */
12466   r=value(p);
12467   while ( r!=p ) {
12468     if ( r==q ) {
12469       @<Exclaim about a redundant equation@>;
12470       return;
12471     };
12472     r=value(r);
12473   }
12474   r=value(p); value(p)=value(q); value(q)=r;
12475 }
12476
12477 @ @<Exclaim about a redundant equation@>=
12478
12479   print_err("Redundant equation");
12480 @.Redundant equation@>
12481   help2("I already knew that this equation was true.")
12482    ("But perhaps no harm has been done; let's continue.");
12483   mp_put_get_error(mp);
12484 }
12485
12486 @* \[26] Introduction to the syntactic routines.
12487 Let's pause a moment now and try to look at the Big Picture.
12488 The \MP\ program consists of three main parts: syntactic routines,
12489 semantic routines, and output routines. The chief purpose of the
12490 syntactic routines is to deliver the user's input to the semantic routines,
12491 while parsing expressions and locating operators and operands. The
12492 semantic routines act as an interpreter responding to these operators,
12493 which may be regarded as commands. And the output routines are
12494 periodically called on to produce compact font descriptions that can be
12495 used for typesetting or for making interim proof drawings. We have
12496 discussed the basic data structures and many of the details of semantic
12497 operations, so we are good and ready to plunge into the part of \MP\ that
12498 actually controls the activities.
12499
12500 Our current goal is to come to grips with the |get_next| procedure,
12501 which is the keystone of \MP's input mechanism. Each call of |get_next|
12502 sets the value of three variables |cur_cmd|, |cur_mod|, and |cur_sym|,
12503 representing the next input token.
12504 $$\vbox{\halign{#\hfil\cr
12505   \hbox{|cur_cmd| denotes a command code from the long list of codes
12506    given earlier;}\cr
12507   \hbox{|cur_mod| denotes a modifier of the command code;}\cr
12508   \hbox{|cur_sym| is the hash address of the symbolic token that was
12509    just scanned,}\cr
12510   \hbox{\qquad or zero in the case of a numeric or string
12511    or capsule token.}\cr}}$$
12512 Underlying this external behavior of |get_next| is all the machinery
12513 necessary to convert from character files to tokens. At a given time we
12514 may be only partially finished with the reading of several files (for
12515 which \&{input} was specified), and partially finished with the expansion
12516 of some user-defined macros and/or some macro parameters, and partially
12517 finished reading some text that the user has inserted online,
12518 and so on. When reading a character file, the characters must be
12519 converted to tokens; comments and blank spaces must
12520 be removed, numeric and string tokens must be evaluated.
12521
12522 To handle these situations, which might all be present simultaneously,
12523 \MP\ uses various stacks that hold information about the incomplete
12524 activities, and there is a finite state control for each level of the
12525 input mechanism. These stacks record the current state of an implicitly
12526 recursive process, but the |get_next| procedure is not recursive.
12527
12528 @<Glob...@>=
12529 eight_bits cur_cmd; /* current command set by |get_next| */
12530 integer cur_mod; /* operand of current command */
12531 halfword cur_sym; /* hash address of current symbol */
12532
12533 @ The |print_cmd_mod| routine prints a symbolic interpretation of a
12534 command code and its modifier.
12535 It consists of a rather tedious sequence of print
12536 commands, and most of it is essentially an inverse to the |primitive|
12537 routine that enters a \MP\ primitive into |hash| and |eqtb|. Therefore almost
12538 all of this procedure appears elsewhere in the program, together with the
12539 corresponding |primitive| calls.
12540
12541 @<Declare the procedure called |print_cmd_mod|@>=
12542 void mp_print_cmd_mod (MP mp,integer c, integer m) { 
12543  switch (c) {
12544   @<Cases of |print_cmd_mod| for symbolic printing of primitives@>
12545   default: mp_print(mp, "[unknown command code!]"); break;
12546   }
12547 }
12548
12549 @ Here is a procedure that displays a given command in braces, in the
12550 user's transcript file.
12551
12552 @d show_cur_cmd_mod mp_show_cmd_mod(mp, mp->cur_cmd,mp->cur_mod)
12553
12554 @c 
12555 void mp_show_cmd_mod (MP mp,integer c, integer m) { 
12556   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
12557   mp_print_cmd_mod(mp, c,m); mp_print_char(mp, '}');
12558   mp_end_diagnostic(mp, false);
12559 }
12560
12561 @* \[27] Input stacks and states.
12562 The state of \MP's input mechanism appears in the input stack, whose
12563 entries are records with five fields, called |index|, |start|, |loc|,
12564 |limit|, and |name|. The top element of this stack is maintained in a
12565 global variable for which no subscripting needs to be done; the other
12566 elements of the stack appear in an array. Hence the stack is declared thus:
12567
12568 @<Types...@>=
12569 typedef struct {
12570   quarterword index_field;
12571   halfword start_field, loc_field, limit_field, name_field;
12572 } in_state_record;
12573
12574 @ @<Glob...@>=
12575 in_state_record *input_stack;
12576 integer input_ptr; /* first unused location of |input_stack| */
12577 integer max_in_stack; /* largest value of |input_ptr| when pushing */
12578 in_state_record cur_input; /* the ``top'' input state */
12579 int stack_size; /* maximum number of simultaneous input sources */
12580
12581 @ @<Allocate or initialize ...@>=
12582 mp->stack_size = 300;
12583 mp->input_stack = xmalloc((mp->stack_size+1),sizeof(in_state_record));
12584
12585 @ @<Dealloc variables@>=
12586 xfree(mp->input_stack);
12587
12588 @ We've already defined the special variable |loc==cur_input.loc_field|
12589 in our discussion of basic input-output routines. The other components of
12590 |cur_input| are defined in the same way:
12591
12592 @d index mp->cur_input.index_field /* reference for buffer information */
12593 @d start mp->cur_input.start_field /* starting position in |buffer| */
12594 @d limit mp->cur_input.limit_field /* end of current line in |buffer| */
12595 @d name mp->cur_input.name_field /* name of the current file */
12596
12597 @ Let's look more closely now at the five control variables
12598 (|index|,~|start|,~|loc|,~|limit|,~|name|),
12599 assuming that \MP\ is reading a line of characters that have been input
12600 from some file or from the user's terminal. There is an array called
12601 |buffer| that acts as a stack of all lines of characters that are
12602 currently being read from files, including all lines on subsidiary
12603 levels of the input stack that are not yet completed. \MP\ will return to
12604 the other lines when it is finished with the present input file.
12605
12606 (Incidentally, on a machine with byte-oriented addressing, it would be
12607 appropriate to combine |buffer| with the |str_pool| array,
12608 letting the buffer entries grow downward from the top of the string pool
12609 and checking that these two tables don't bump into each other.)
12610
12611 The line we are currently working on begins in position |start| of the
12612 buffer; the next character we are about to read is |buffer[loc]|; and
12613 |limit| is the location of the last character present. We always have
12614 |loc<=limit|. For convenience, |buffer[limit]| has been set to |"%"|, so
12615 that the end of a line is easily sensed.
12616
12617 The |name| variable is a string number that designates the name of
12618 the current file, if we are reading an ordinary text file.  Special codes
12619 |is_term..max_spec_src| indicate other sources of input text.
12620
12621 @d is_term 0 /* |name| value when reading from the terminal for normal input */
12622 @d is_read 1 /* |name| value when executing a \&{readstring} or \&{readfrom} */
12623 @d is_scantok 2 /* |name| value when reading text generated by \&{scantokens} */
12624 @d max_spec_src is_scantok
12625
12626 @ Additional information about the current line is available via the
12627 |index| variable, which counts how many lines of characters are present
12628 in the buffer below the current level. We have |index=0| when reading
12629 from the terminal and prompting the user for each line; then if the user types,
12630 e.g., `\.{input figs}', we will have |index=1| while reading
12631 the file \.{figs.mp}. However, it does not follow that |index| is the
12632 same as the input stack pointer, since many of the levels on the input
12633 stack may come from token lists and some |index| values may correspond
12634 to \.{MPX} files that are not currently on the stack.
12635
12636 The global variable |in_open| is equal to the highest |index| value counting
12637 \.{MPX} files but excluding token-list input levels.  Thus, the number of
12638 partially read lines in the buffer is |in_open+1| and we have |in_open>=index|
12639 when we are not reading a token list.
12640
12641 If we are not currently reading from the terminal,
12642 we are reading from the file variable |input_file[index]|. We use
12643 the notation |terminal_input| as a convenient abbreviation for |name=is_term|,
12644 and |cur_file| as an abbreviation for |input_file[index]|.
12645
12646 When \MP\ is not reading from the terminal, the global variable |line| contains
12647 the line number in the current file, for use in error messages. More precisely,
12648 |line| is a macro for |line_stack[index]| and the |line_stack| array gives
12649 the line number for each file in the |input_file| array.
12650
12651 When an \.{MPX} file is opened the file name is stored in the |mpx_name|
12652 array so that the name doesn't get lost when the file is temporarily removed
12653 from the input stack.
12654 Thus when |input_file[k]| is an \.{MPX} file, its name is |mpx_name[k]|
12655 and it contains translated \TeX\ pictures for |input_file[k-1]|.
12656 Since this is not an \.{MPX} file, we have
12657 $$ \hbox{|mpx_name[k-1]<=absent|}. $$
12658 This |name| field is set to |finished| when |input_file[k]| is completely
12659 read.
12660
12661 If more information about the input state is needed, it can be
12662 included in small arrays like those shown here. For example,
12663 the current page or segment number in the input file might be put
12664 into a variable |page|, that is really a macro for the current entry
12665 in `\ignorespaces|page_stack:array[0..max_in_open] of integer|\unskip'
12666 by analogy with |line_stack|.
12667 @^system dependencies@>
12668
12669 @d terminal_input (name==is_term) /* are we reading from the terminal? */
12670 @d cur_file mp->input_file[index] /* the current |FILE *| variable */
12671 @d line mp->line_stack[index] /* current line number in the current source file */
12672 @d in_name mp->iname_stack[index] /* a string used to construct \.{MPX} file names */
12673 @d in_area mp->iarea_stack[index] /* another string for naming \.{MPX} files */
12674 @d absent 1 /* |name_field| value for unused |mpx_in_stack| entries */
12675 @d mpx_reading (mp->mpx_name[index]>absent)
12676   /* when reading a file, is it an \.{MPX} file? */
12677 @d finished 0
12678   /* |name_field| value when the corresponding \.{MPX} file is finished */
12679
12680 @<Glob...@>=
12681 integer in_open; /* the number of lines in the buffer, less one */
12682 unsigned int open_parens; /* the number of open text files */
12683 FILE  * *input_file ;
12684 integer *line_stack ; /* the line number for each file */
12685 char *  *iname_stack; /* used for naming \.{MPX} files */
12686 char *  *iarea_stack; /* used for naming \.{MPX} files */
12687 halfword*mpx_name  ;
12688
12689 @ @<Allocate or ...@>=
12690 mp->input_file  = xmalloc((mp->max_in_open+1),sizeof(FILE *));
12691 mp->line_stack  = xmalloc((mp->max_in_open+1),sizeof(integer));
12692 mp->iname_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12693 mp->iarea_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12694 mp->mpx_name    = xmalloc((mp->max_in_open+1),sizeof(halfword));
12695 {
12696   int k;
12697   for (k=0;k<=mp->max_in_open;k++) {
12698     mp->iname_stack[k] =NULL;
12699     mp->iarea_stack[k] =NULL;
12700   }
12701 }
12702
12703 @ @<Dealloc variables@>=
12704 {
12705   int l;
12706   for (l=0;l<=mp->max_in_open;l++) {
12707     xfree(mp->iname_stack[l]);
12708     xfree(mp->iarea_stack[l]);
12709   }
12710 }
12711 xfree(mp->input_file);
12712 xfree(mp->line_stack);
12713 xfree(mp->iname_stack);
12714 xfree(mp->iarea_stack);
12715 xfree(mp->mpx_name);
12716
12717
12718 @ However, all this discussion about input state really applies only to the
12719 case that we are inputting from a file. There is another important case,
12720 namely when we are currently getting input from a token list. In this case
12721 |index>max_in_open|, and the conventions about the other state variables
12722 are different:
12723
12724 \yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
12725 the node that will be read next. If |loc=null|, the token list has been
12726 fully read.
12727
12728 \yskip\hang|start| points to the first node of the token list; this node
12729 may or may not contain a reference count, depending on the type of token
12730 list involved.
12731
12732 \yskip\hang|token_type|, which takes the place of |index| in the
12733 discussion above, is a code number that explains what kind of token list
12734 is being scanned.
12735
12736 \yskip\hang|name| points to the |eqtb| address of the control sequence
12737 being expanded, if the current token list is a macro not defined by
12738 \&{vardef}. Macros defined by \&{vardef} have |name=null|; their name
12739 can be deduced by looking at their first two parameters.
12740
12741 \yskip\hang|param_start|, which takes the place of |limit|, tells where
12742 the parameters of the current macro or loop text begin in the |param_stack|.
12743
12744 \yskip\noindent The |token_type| can take several values, depending on
12745 where the current token list came from:
12746
12747 \yskip
12748 \indent|forever_text|, if the token list being scanned is the body of
12749 a \&{forever} loop;
12750
12751 \indent|loop_text|, if the token list being scanned is the body of
12752 a \&{for} or \&{forsuffixes} loop;
12753
12754 \indent|parameter|, if a \&{text} or \&{suffix} parameter is being scanned;
12755
12756 \indent|backed_up|, if the token list being scanned has been inserted as
12757 `to be read again'.
12758
12759 \indent|inserted|, if the token list being scanned has been inserted as
12760 part of error recovery;
12761
12762 \indent|macro|, if the expansion of a user-defined symbolic token is being
12763 scanned.
12764
12765 \yskip\noindent
12766 The token list begins with a reference count if and only if |token_type=
12767 macro|.
12768 @^reference counts@>
12769
12770 @d token_type index /* type of current token list */
12771 @d token_state (index>(int)mp->max_in_open) /* are we scanning a token list? */
12772 @d file_state (index<=(int)mp->max_in_open) /* are we scanning a file line? */
12773 @d param_start limit /* base of macro parameters in |param_stack| */
12774 @d forever_text (mp->max_in_open+1) /* |token_type| code for loop texts */
12775 @d loop_text (mp->max_in_open+2) /* |token_type| code for loop texts */
12776 @d parameter (mp->max_in_open+3) /* |token_type| code for parameter texts */
12777 @d backed_up (mp->max_in_open+4) /* |token_type| code for texts to be reread */
12778 @d inserted (mp->max_in_open+5) /* |token_type| code for inserted texts */
12779 @d macro (mp->max_in_open+6) /* |token_type| code for macro replacement texts */
12780
12781 @ The |param_stack| is an auxiliary array used to hold pointers to the token
12782 lists for parameters at the current level and subsidiary levels of input.
12783 This stack grows at a different rate from the others.
12784
12785 @<Glob...@>=
12786 pointer *param_stack;  /* token list pointers for parameters */
12787 integer param_ptr; /* first unused entry in |param_stack| */
12788 integer max_param_stack;  /* largest value of |param_ptr| */
12789
12790 @ @<Allocate or initialize ...@>=
12791 mp->param_stack = xmalloc((mp->param_size+1),sizeof(pointer));
12792
12793 @ @<Dealloc variables@>=
12794 xfree(mp->param_stack);
12795
12796 @ Notice that the |line| isn't valid when |token_state| is true because it
12797 depends on |index|.  If we really need to know the line number for the
12798 topmost file in the index stack we use the following function.  If a page
12799 number or other information is needed, this routine should be modified to
12800 compute it as well.
12801 @^system dependencies@>
12802
12803 @<Declare a function called |true_line|@>=
12804 integer mp_true_line (MP mp) {
12805   int k; /* an index into the input stack */
12806   if ( file_state && (name>max_spec_src) ) {
12807      return line;
12808   } else { 
12809     k=mp->input_ptr;
12810     while ((k>0) &&
12811            ((mp->input_stack[(k-1)].index_field>mp->max_in_open)||
12812             (mp->input_stack[(k-1)].name_field<=max_spec_src))) {
12813       decr(k);
12814     }
12815     return mp->line_stack[(k-1)];
12816   }
12817   return 0; 
12818 }
12819
12820 @ Thus, the ``current input state'' can be very complicated indeed; there
12821 can be many levels and each level can arise in a variety of ways. The
12822 |show_context| procedure, which is used by \MP's error-reporting routine to
12823 print out the current input state on all levels down to the most recent
12824 line of characters from an input file, illustrates most of these conventions.
12825 The global variable |file_ptr| contains the lowest level that was
12826 displayed by this procedure.
12827
12828 @<Glob...@>=
12829 integer file_ptr; /* shallowest level shown by |show_context| */
12830
12831 @ The status at each level is indicated by printing two lines, where the first
12832 line indicates what was read so far and the second line shows what remains
12833 to be read. The context is cropped, if necessary, so that the first line
12834 contains at most |half_error_line| characters, and the second contains
12835 at most |error_line|. Non-current input levels whose |token_type| is
12836 `|backed_up|' are shown only if they have not been fully read.
12837
12838 @c void mp_show_context (MP mp) { /* prints where the scanner is */
12839   int old_setting; /* saved |selector| setting */
12840   @<Local variables for formatting calculations@>
12841   mp->file_ptr=mp->input_ptr; mp->input_stack[mp->file_ptr]=mp->cur_input;
12842   /* store current state */
12843   while (1) { 
12844     mp->cur_input=mp->input_stack[mp->file_ptr]; /* enter into the context */
12845     @<Display the current context@>;
12846     if ( file_state )
12847       if ( (name>max_spec_src) || (mp->file_ptr==0) ) break;
12848     decr(mp->file_ptr);
12849   }
12850   mp->cur_input=mp->input_stack[mp->input_ptr]; /* restore original state */
12851 }
12852
12853 @ @<Display the current context@>=
12854 if ( (mp->file_ptr==mp->input_ptr) || file_state ||
12855    (token_type!=backed_up) || (loc!=null) ) {
12856     /* we omit backed-up token lists that have already been read */
12857   mp->tally=0; /* get ready to count characters */
12858   old_setting=mp->selector;
12859   if ( file_state ) {
12860     @<Print location of current line@>;
12861     @<Pseudoprint the line@>;
12862   } else { 
12863     @<Print type of token list@>;
12864     @<Pseudoprint the token list@>;
12865   }
12866   mp->selector=old_setting; /* stop pseudoprinting */
12867   @<Print two lines using the tricky pseudoprinted information@>;
12868 }
12869
12870 @ This routine should be changed, if necessary, to give the best possible
12871 indication of where the current line resides in the input file.
12872 For example, on some systems it is best to print both a page and line number.
12873 @^system dependencies@>
12874
12875 @<Print location of current line@>=
12876 if ( name>max_spec_src ) {
12877   mp_print_nl(mp, "l."); mp_print_int(mp, mp_true_line(mp));
12878 } else if ( terminal_input ) {
12879   if ( mp->file_ptr==0 ) mp_print_nl(mp, "<*>");
12880   else mp_print_nl(mp, "<insert>");
12881 } else if ( name==is_scantok ) {
12882   mp_print_nl(mp, "<scantokens>");
12883 } else {
12884   mp_print_nl(mp, "<read>");
12885 }
12886 mp_print_char(mp, ' ')
12887
12888 @ Can't use case statement here because the |token_type| is not
12889 a constant expression.
12890
12891 @<Print type of token list@>=
12892 {
12893   if(token_type==forever_text) {
12894     mp_print_nl(mp, "<forever> ");
12895   } else if (token_type==loop_text) {
12896     @<Print the current loop value@>;
12897   } else if (token_type==parameter) {
12898     mp_print_nl(mp, "<argument> "); 
12899   } else if (token_type==backed_up) { 
12900     if ( loc==null ) mp_print_nl(mp, "<recently read> ");
12901     else mp_print_nl(mp, "<to be read again> ");
12902   } else if (token_type==inserted) {
12903     mp_print_nl(mp, "<inserted text> ");
12904   } else if (token_type==macro) {
12905     mp_print_ln(mp);
12906     if ( name!=null ) mp_print_text(name);
12907     else @<Print the name of a \&{vardef}'d macro@>;
12908     mp_print(mp, "->");
12909   } else {
12910     mp_print_nl(mp, "?");/* this should never happen */
12911 @.?\relax@>
12912   }
12913 }
12914
12915 @ The parameter that corresponds to a loop text is either a token list
12916 (in the case of \&{forsuffixes}) or a ``capsule'' (in the case of \&{for}).
12917 We'll discuss capsules later; for now, all we need to know is that
12918 the |link| field in a capsule parameter is |void| and that
12919 |print_exp(p,0)| displays the value of capsule~|p| in abbreviated form.
12920
12921 @d diov (null+1) /* a null pointer different from |null| */
12922
12923 @<Print the current loop value@>=
12924 { mp_print_nl(mp, "<for("); p=mp->param_stack[param_start];
12925   if ( p!=null ) {
12926     if ( link(p)==diov ) mp_print_exp(mp, p,0); /* we're in a \&{for} loop */
12927     else mp_show_token_list(mp, p,null,20,mp->tally);
12928   }
12929   mp_print(mp, ")> ");
12930 }
12931
12932 @ The first two parameters of a macro defined by \&{vardef} will be token
12933 lists representing the macro's prefix and ``at point.'' By putting these
12934 together, we get the macro's full name.
12935
12936 @<Print the name of a \&{vardef}'d macro@>=
12937 { p=mp->param_stack[param_start];
12938   if ( p==null ) {
12939     mp_show_token_list(mp, mp->param_stack[param_start+1],null,20,mp->tally);
12940   } else { 
12941     q=p;
12942     while ( link(q)!=null ) q=link(q);
12943     link(q)=mp->param_stack[param_start+1];
12944     mp_show_token_list(mp, p,null,20,mp->tally);
12945     link(q)=null;
12946   }
12947 }
12948
12949 @ Now it is necessary to explain a little trick. We don't want to store a long
12950 string that corresponds to a token list, because that string might take up
12951 lots of memory; and we are printing during a time when an error message is
12952 being given, so we dare not do anything that might overflow one of \MP's
12953 tables. So `pseudoprinting' is the answer: We enter a mode of printing
12954 that stores characters into a buffer of length |error_line|, where character
12955 $k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
12956 |k<trick_count|, otherwise character |k| is dropped. Initially we set
12957 |tally:=0| and |trick_count:=1000000|; then when we reach the
12958 point where transition from line 1 to line 2 should occur, we
12959 set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
12960 tally+1+error_line-half_error_line)|. At the end of the
12961 pseudoprinting, the values of |first_count|, |tally|, and
12962 |trick_count| give us all the information we need to print the two lines,
12963 and all of the necessary text is in |trick_buf|.
12964
12965 Namely, let |l| be the length of the descriptive information that appears
12966 on the first line. The length of the context information gathered for that
12967 line is |k=first_count|, and the length of the context information
12968 gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
12969 where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
12970 descriptive information on line~1, and set |n:=l+k|; here |n| is the
12971 length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
12972 and print `\.{...}' followed by
12973 $$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
12974 where subscripts of |trick_buf| are circular modulo |error_line|. The
12975 second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
12976 unless |n+m>error_line|; in the latter case, further cropping is done.
12977 This is easier to program than to explain.
12978
12979 @<Local variables for formatting...@>=
12980 int i; /* index into |buffer| */
12981 integer l; /* length of descriptive information on line 1 */
12982 integer m; /* context information gathered for line 2 */
12983 int n; /* length of line 1 */
12984 integer p; /* starting or ending place in |trick_buf| */
12985 integer q; /* temporary index */
12986
12987 @ The following code tells the print routines to gather
12988 the desired information.
12989
12990 @d begin_pseudoprint { 
12991   l=mp->tally; mp->tally=0; mp->selector=pseudo;
12992   mp->trick_count=1000000;
12993 }
12994 @d set_trick_count {
12995   mp->first_count=mp->tally;
12996   mp->trick_count=mp->tally+1+mp->error_line-mp->half_error_line;
12997   if ( mp->trick_count<mp->error_line ) mp->trick_count=mp->error_line;
12998 }
12999
13000 @ And the following code uses the information after it has been gathered.
13001
13002 @<Print two lines using the tricky pseudoprinted information@>=
13003 if ( mp->trick_count==1000000 ) set_trick_count;
13004   /* |set_trick_count| must be performed */
13005 if ( mp->tally<mp->trick_count ) m=mp->tally-mp->first_count;
13006 else m=mp->trick_count-mp->first_count; /* context on line 2 */
13007 if ( l+mp->first_count<=mp->half_error_line ) {
13008   p=0; n=l+mp->first_count;
13009 } else  { 
13010   mp_print(mp, "..."); p=l+mp->first_count-mp->half_error_line+3;
13011   n=mp->half_error_line;
13012 }
13013 for (q=p;q<=mp->first_count-1;q++) {
13014   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13015 }
13016 mp_print_ln(mp);
13017 for (q=1;q<=n;q++) {
13018   mp_print_char(mp, ' '); /* print |n| spaces to begin line~2 */
13019 }
13020 if ( m+n<=mp->error_line ) p=mp->first_count+m; 
13021 else p=mp->first_count+(mp->error_line-n-3);
13022 for (q=mp->first_count;q<=p-1;q++) {
13023   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13024 }
13025 if ( m+n>mp->error_line ) mp_print(mp, "...")
13026
13027 @ But the trick is distracting us from our current goal, which is to
13028 understand the input state. So let's concentrate on the data structures that
13029 are being pseudoprinted as we finish up the |show_context| procedure.
13030
13031 @<Pseudoprint the line@>=
13032 begin_pseudoprint;
13033 if ( limit>0 ) {
13034   for (i=start;i<=limit-1;i++) {
13035     if ( i==loc ) set_trick_count;
13036     mp_print_str(mp, mp->buffer[i]);
13037   }
13038 }
13039
13040 @ @<Pseudoprint the token list@>=
13041 begin_pseudoprint;
13042 if ( token_type!=macro ) mp_show_token_list(mp, start,loc,100000,0);
13043 else mp_show_macro(mp, start,loc,100000)
13044
13045 @ Here is the missing piece of |show_token_list| that is activated when the
13046 token beginning line~2 is about to be shown:
13047
13048 @<Do magic computation@>=set_trick_count
13049
13050 @* \[28] Maintaining the input stacks.
13051 The following subroutines change the input status in commonly needed ways.
13052
13053 First comes |push_input|, which stores the current state and creates a
13054 new level (having, initially, the same properties as the old).
13055
13056 @d push_input  { /* enter a new input level, save the old */
13057   if ( mp->input_ptr>mp->max_in_stack ) {
13058     mp->max_in_stack=mp->input_ptr;
13059     if ( mp->input_ptr==mp->stack_size ) {
13060       int l = (mp->stack_size+(mp->stack_size>>2));
13061       XREALLOC(mp->input_stack, l, in_state_record);
13062       mp->stack_size = l;
13063     }         
13064   }
13065   mp->input_stack[mp->input_ptr]=mp->cur_input; /* stack the record */
13066   incr(mp->input_ptr);
13067 }
13068
13069 @ And of course what goes up must come down.
13070
13071 @d pop_input { /* leave an input level, re-enter the old */
13072     decr(mp->input_ptr); mp->cur_input=mp->input_stack[mp->input_ptr];
13073   }
13074
13075 @ Here is a procedure that starts a new level of token-list input, given
13076 a token list |p| and its type |t|. If |t=macro|, the calling routine should
13077 set |name|, reset~|loc|, and increase the macro's reference count.
13078
13079 @d back_list(A) mp_begin_token_list(mp, (A),backed_up) /* backs up a simple token list */
13080
13081 @c void mp_begin_token_list (MP mp,pointer p, quarterword t)  { 
13082   push_input; start=p; token_type=t;
13083   param_start=mp->param_ptr; loc=p;
13084 }
13085
13086 @ When a token list has been fully scanned, the following computations
13087 should be done as we leave that level of input.
13088 @^inner loop@>
13089
13090 @c void mp_end_token_list (MP mp) { /* leave a token-list input level */
13091   pointer p; /* temporary register */
13092   if ( token_type>=backed_up ) { /* token list to be deleted */
13093     if ( token_type<=inserted ) { 
13094       mp_flush_token_list(mp, start); goto DONE;
13095     } else {
13096       mp_delete_mac_ref(mp, start); /* update reference count */
13097     }
13098   }
13099   while ( mp->param_ptr>param_start ) { /* parameters must be flushed */
13100     decr(mp->param_ptr);
13101     p=mp->param_stack[mp->param_ptr];
13102     if ( p!=null ) {
13103       if ( link(p)==diov ) { /* it's an \&{expr} parameter */
13104         mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
13105       } else {
13106         mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
13107       }
13108     }
13109   }
13110 DONE: 
13111   pop_input; check_interrupt;
13112 }
13113
13114 @ The contents of |cur_cmd,cur_mod,cur_sym| are placed into an equivalent
13115 token by the |cur_tok| routine.
13116 @^inner loop@>
13117
13118 @c @<Declare the procedure called |make_exp_copy|@>;
13119 pointer mp_cur_tok (MP mp) {
13120   pointer p; /* a new token node */
13121   small_number save_type; /* |cur_type| to be restored */
13122   integer save_exp; /* |cur_exp| to be restored */
13123   if ( mp->cur_sym==0 ) {
13124     if ( mp->cur_cmd==capsule_token ) {
13125       save_type=mp->cur_type; save_exp=mp->cur_exp;
13126       mp_make_exp_copy(mp, mp->cur_mod); p=mp_stash_cur_exp(mp); link(p)=null;
13127       mp->cur_type=save_type; mp->cur_exp=save_exp;
13128     } else { 
13129       p=mp_get_node(mp, token_node_size);
13130       value(p)=mp->cur_mod; name_type(p)=mp_token;
13131       if ( mp->cur_cmd==numeric_token ) type(p)=mp_known;
13132       else type(p)=mp_string_type;
13133     }
13134   } else { 
13135     fast_get_avail(p); info(p)=mp->cur_sym;
13136   }
13137   return p;
13138 }
13139
13140 @ Sometimes \MP\ has read too far and wants to ``unscan'' what it has
13141 seen. The |back_input| procedure takes care of this by putting the token
13142 just scanned back into the input stream, ready to be read again.
13143 If |cur_sym<>0|, the values of |cur_cmd| and |cur_mod| are irrelevant.
13144
13145 @<Declarations@>= 
13146 void mp_back_input (MP mp);
13147
13148 @ @c void mp_back_input (MP mp) {/* undoes one token of input */
13149   pointer p; /* a token list of length one */
13150   p=mp_cur_tok(mp);
13151   while ( token_state &&(loc==null) ) 
13152     mp_end_token_list(mp); /* conserve stack space */
13153   back_list(p);
13154 }
13155
13156 @ The |back_error| routine is used when we want to restore or replace an
13157 offending token just before issuing an error message.  We disable interrupts
13158 during the call of |back_input| so that the help message won't be lost.
13159
13160 @<Declarations@>=
13161 void mp_error (MP mp);
13162 void mp_back_error (MP mp);
13163
13164 @ @c void mp_back_error (MP mp) { /* back up one token and call |error| */
13165   mp->OK_to_interrupt=false; 
13166   mp_back_input(mp); 
13167   mp->OK_to_interrupt=true; mp_error(mp);
13168 }
13169 void mp_ins_error (MP mp) { /* back up one inserted token and call |error| */
13170   mp->OK_to_interrupt=false; 
13171   mp_back_input(mp); token_type=inserted;
13172   mp->OK_to_interrupt=true; mp_error(mp);
13173 }
13174
13175 @ The |begin_file_reading| procedure starts a new level of input for lines
13176 of characters to be read from a file, or as an insertion from the
13177 terminal. It does not take care of opening the file, nor does it set |loc|
13178 or |limit| or |line|.
13179 @^system dependencies@>
13180
13181 @c void mp_begin_file_reading (MP mp) { 
13182   if ( mp->in_open==mp->max_in_open ) 
13183     mp_overflow(mp, "text input levels",mp->max_in_open);
13184 @:MetaPost capacity exceeded text input levels}{\quad text input levels@>
13185   if ( mp->first==mp->buf_size ) 
13186     mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13187   incr(mp->in_open); push_input; index=mp->in_open;
13188   mp->mpx_name[index]=absent;
13189   start=mp->first;
13190   name=is_term; /* |terminal_input| is now |true| */
13191 }
13192
13193 @ Conversely, the variables must be downdated when such a level of input
13194 is finished.  Any associated \.{MPX} file must also be closed and popped
13195 off the file stack.
13196
13197 @c void mp_end_file_reading (MP mp) { 
13198   if ( mp->in_open>index ) {
13199     if ( (mp->mpx_name[mp->in_open]==absent)||(name<=max_spec_src) ) {
13200       mp_confusion(mp, "endinput");
13201 @:this can't happen endinput}{\quad endinput@>
13202     } else { 
13203       fclose(mp->input_file[mp->in_open]); /* close an \.{MPX} file */
13204       delete_str_ref(mp->mpx_name[mp->in_open]);
13205       decr(mp->in_open);
13206     }
13207   }
13208   mp->first=start;
13209   if ( index!=mp->in_open ) mp_confusion(mp, "endinput");
13210   if ( name>max_spec_src ) {
13211     fclose(cur_file);
13212     delete_str_ref(name);
13213     xfree(in_name); in_name=NULL;
13214     xfree(in_area); in_area=NULL;
13215   }
13216   pop_input; decr(mp->in_open);
13217 }
13218
13219 @ Here is a function that tries to resume input from an \.{MPX} file already
13220 associated with the current input file.  It returns |false| if this doesn't
13221 work.
13222
13223 @c boolean mp_begin_mpx_reading (MP mp) { 
13224   if ( mp->in_open!=index+1 ) {
13225      return false;
13226   } else { 
13227     if ( mp->mpx_name[mp->in_open]<=absent ) mp_confusion(mp, "mpx");
13228 @:this can't happen mpx}{\quad mpx@>
13229     if ( mp->first==mp->buf_size ) 
13230       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13231     push_input; index=mp->in_open;
13232     start=mp->first;
13233     name=mp->mpx_name[mp->in_open]; add_str_ref(name);
13234     @<Put an empty line in the input buffer@>;
13235     return true;
13236   }
13237 }
13238
13239 @ This procedure temporarily stops reading an \.{MPX} file.
13240
13241 @c void mp_end_mpx_reading (MP mp) { 
13242   if ( mp->in_open!=index ) mp_confusion(mp, "mpx");
13243 @:this can't happen mpx}{\quad mpx@>
13244   if ( loc<limit ) {
13245     @<Complain that we are not at the end of a line in the \.{MPX} file@>;
13246   }
13247   mp->first=start;
13248   pop_input;
13249 }
13250
13251 @ Here we enforce a restriction that simplifies the input stacks considerably.
13252 This should not inconvenience the user because \.{MPX} files are generated
13253 by an auxiliary program called \.{DVItoMP}.
13254
13255 @ @<Complain that we are not at the end of a line in the \.{MPX} file@>=
13256
13257 print_err("`mpxbreak' must be at the end of a line");
13258 help4("This file contains picture expressions for btex...etex")
13259   ("blocks.  Such files are normally generated automatically")
13260   ("but this one seems to be messed up.  I'm going to ignore")
13261   ("the rest of this line.");
13262 mp_error(mp);
13263 }
13264
13265 @ In order to keep the stack from overflowing during a long sequence of
13266 inserted `\.{show}' commands, the following routine removes completed
13267 error-inserted lines from memory.
13268
13269 @c void mp_clear_for_error_prompt (MP mp) { 
13270   while ( file_state && terminal_input &&
13271     (mp->input_ptr>0)&&(loc==limit) ) mp_end_file_reading(mp);
13272   mp_print_ln(mp); clear_terminal;
13273 }
13274
13275 @ To get \MP's whole input mechanism going, we perform the following
13276 actions.
13277
13278 @<Initialize the input routines@>=
13279 { mp->input_ptr=0; mp->max_in_stack=0;
13280   mp->in_open=0; mp->open_parens=0; mp->max_buf_stack=0;
13281   mp->param_ptr=0; mp->max_param_stack=0;
13282   mp->first=1;
13283   start=1; index=0; line=0; name=is_term;
13284   mp->mpx_name[0]=absent;
13285   mp->force_eof=false;
13286   if ( ! mp_init_terminal(mp) ) exit(EXIT_FAILURE);
13287   limit=mp->last; mp->first=mp->last+1; 
13288   /* |init_terminal| has set |loc| and |last| */
13289 }
13290
13291 @* \[29] Getting the next token.
13292 The heart of \MP's input mechanism is the |get_next| procedure, which
13293 we shall develop in the next few sections of the program. Perhaps we
13294 shouldn't actually call it the ``heart,'' however; it really acts as \MP's
13295 eyes and mouth, reading the source files and gobbling them up. And it also
13296 helps \MP\ to regurgitate stored token lists that are to be processed again.
13297
13298 The main duty of |get_next| is to input one token and to set |cur_cmd|
13299 and |cur_mod| to that token's command code and modifier. Furthermore, if
13300 the input token is a symbolic token, that token's |hash| address
13301 is stored in |cur_sym|; otherwise |cur_sym| is set to zero.
13302
13303 Underlying this simple description is a certain amount of complexity
13304 because of all the cases that need to be handled.
13305 However, the inner loop of |get_next| is reasonably short and fast.
13306
13307 @ Before getting into |get_next|, we need to consider a mechanism by which
13308 \MP\ helps keep errors from propagating too far. Whenever the program goes
13309 into a mode where it keeps calling |get_next| repeatedly until a certain
13310 condition is met, it sets |scanner_status| to some value other than |normal|.
13311 Then if an input file ends, or if an `\&{outer}' symbol appears,
13312 an appropriate error recovery will be possible.
13313
13314 The global variable |warning_info| helps in this error recovery by providing
13315 additional information. For example, |warning_info| might indicate the
13316 name of a macro whose replacement text is being scanned.
13317
13318 @d normal 0 /* |scanner_status| at ``quiet times'' */
13319 @d skipping 1 /* |scanner_status| when false conditional text is being skipped */
13320 @d flushing 2 /* |scanner_status| when junk after a statement is being ignored */
13321 @d absorbing 3 /* |scanner_status| when a \&{text} parameter is being scanned */
13322 @d var_defining 4 /* |scanner_status| when a \&{vardef} is being scanned */
13323 @d op_defining 5 /* |scanner_status| when a macro \&{def} is being scanned */
13324 @d loop_defining 6 /* |scanner_status| when a \&{for} loop is being scanned */
13325 @d tex_flushing 7 /* |scanner_status| when skipping \TeX\ material */
13326
13327 @<Glob...@>=
13328 integer scanner_status; /* are we scanning at high speed? */
13329 integer warning_info; /* if so, what else do we need to know,
13330     in case an error occurs? */
13331
13332 @ @<Initialize the input routines@>=
13333 mp->scanner_status=normal;
13334
13335 @ The following subroutine
13336 is called when an `\&{outer}' symbolic token has been scanned or
13337 when the end of a file has been reached. These two cases are distinguished
13338 by |cur_sym|, which is zero at the end of a file.
13339
13340 @c boolean mp_check_outer_validity (MP mp) {
13341   pointer p; /* points to inserted token list */
13342   if ( mp->scanner_status==normal ) {
13343     return true;
13344   } else if ( mp->scanner_status==tex_flushing ) {
13345     @<Check if the file has ended while flushing \TeX\ material and set the
13346       result value for |check_outer_validity|@>;
13347   } else { 
13348     mp->deletions_allowed=false;
13349     @<Back up an outer symbolic token so that it can be reread@>;
13350     if ( mp->scanner_status>skipping ) {
13351       @<Tell the user what has run away and try to recover@>;
13352     } else { 
13353       print_err("Incomplete if; all text was ignored after line ");
13354 @.Incomplete if...@>
13355       mp_print_int(mp, mp->warning_info);
13356       help3("A forbidden `outer' token occurred in skipped text.")
13357         ("This kind of error happens when you say `if...' and forget")
13358         ("the matching `fi'. I've inserted a `fi'; this might work.");
13359       if ( mp->cur_sym==0 ) 
13360         mp->help_line[2]="The file ended while I was skipping conditional text.";
13361       mp->cur_sym=frozen_fi; mp_ins_error(mp);
13362     }
13363     mp->deletions_allowed=true; 
13364         return false;
13365   }
13366 }
13367
13368 @ @<Check if the file has ended while flushing \TeX\ material and set...@>=
13369 if ( mp->cur_sym!=0 ) { 
13370    return true;
13371 } else { 
13372   mp->deletions_allowed=false;
13373   print_err("TeX mode didn't end; all text was ignored after line ");
13374   mp_print_int(mp, mp->warning_info);
13375   help2("The file ended while I was looking for the `etex' to")
13376     ("finish this TeX material.  I've inserted `etex' now.");
13377   mp->cur_sym = frozen_etex;
13378   mp_ins_error(mp);
13379   mp->deletions_allowed=true;
13380   return false;
13381 }
13382
13383 @ @<Back up an outer symbolic token so that it can be reread@>=
13384 if ( mp->cur_sym!=0 ) {
13385   p=mp_get_avail(mp); info(p)=mp->cur_sym;
13386   back_list(p); /* prepare to read the symbolic token again */
13387 }
13388
13389 @ @<Tell the user what has run away...@>=
13390
13391   mp_runaway(mp); /* print the definition-so-far */
13392   if ( mp->cur_sym==0 ) {
13393     print_err("File ended");
13394 @.File ended while scanning...@>
13395   } else { 
13396     print_err("Forbidden token found");
13397 @.Forbidden token found...@>
13398   }
13399   mp_print(mp, " while scanning ");
13400   help4("I suspect you have forgotten an `enddef',")
13401     ("causing me to read past where you wanted me to stop.")
13402     ("I'll try to recover; but if the error is serious,")
13403     ("you'd better type `E' or `X' now and fix your file.");
13404   switch (mp->scanner_status) {
13405     @<Complete the error message,
13406       and set |cur_sym| to a token that might help recover from the error@>
13407   } /* there are no other cases */
13408   mp_ins_error(mp);
13409 }
13410
13411 @ As we consider various kinds of errors, it is also appropriate to
13412 change the first line of the help message just given; |help_line[3]|
13413 points to the string that might be changed.
13414
13415 @<Complete the error message,...@>=
13416 case flushing: 
13417   mp_print(mp, "to the end of the statement");
13418   mp->help_line[3]="A previous error seems to have propagated,";
13419   mp->cur_sym=frozen_semicolon;
13420   break;
13421 case absorbing: 
13422   mp_print(mp, "a text argument");
13423   mp->help_line[3]="It seems that a right delimiter was left out,";
13424   if ( mp->warning_info==0 ) {
13425     mp->cur_sym=frozen_end_group;
13426   } else { 
13427     mp->cur_sym=frozen_right_delimiter;
13428     equiv(frozen_right_delimiter)=mp->warning_info;
13429   }
13430   break;
13431 case var_defining:
13432 case op_defining: 
13433   mp_print(mp, "the definition of ");
13434   if ( mp->scanner_status==op_defining ) 
13435      mp_print_text(mp->warning_info);
13436   else 
13437      mp_print_variable_name(mp, mp->warning_info);
13438   mp->cur_sym=frozen_end_def;
13439   break;
13440 case loop_defining: 
13441   mp_print(mp, "the text of a "); 
13442   mp_print_text(mp->warning_info);
13443   mp_print(mp, " loop");
13444   mp->help_line[3]="I suspect you have forgotten an `endfor',";
13445   mp->cur_sym=frozen_end_for;
13446   break;
13447
13448 @ The |runaway| procedure displays the first part of the text that occurred
13449 when \MP\ began its special |scanner_status|, if that text has been saved.
13450
13451 @<Declare the procedure called |runaway|@>=
13452 void mp_runaway (MP mp) { 
13453   if ( mp->scanner_status>flushing ) { 
13454      mp_print_nl(mp, "Runaway ");
13455          switch (mp->scanner_status) { 
13456          case absorbing: mp_print(mp, "text?"); break;
13457          case var_defining: 
13458      case op_defining: mp_print(mp,"definition?"); break;
13459      case loop_defining: mp_print(mp, "loop?"); break;
13460      } /* there are no other cases */
13461      mp_print_ln(mp); 
13462      mp_show_token_list(mp, link(hold_head),null,mp->error_line-10,0);
13463   }
13464 }
13465
13466 @ We need to mention a procedure that may be called by |get_next|.
13467
13468 @<Declarations@>= 
13469 void mp_firm_up_the_line (MP mp);
13470
13471 @ And now we're ready to take the plunge into |get_next| itself.
13472 Note that the behavior depends on the |scanner_status| because percent signs
13473 and double quotes need to be passed over when skipping TeX material.
13474
13475 @c 
13476 void mp_get_next (MP mp) {
13477   /* sets |cur_cmd|, |cur_mod|, |cur_sym| to next token */
13478 @^inner loop@>
13479   /*restart*/ /* go here to get the next input token */
13480   /*exit*/ /* go here when the next input token has been got */
13481   /*|common_ending|*/ /* go here to finish getting a symbolic token */
13482   /*found*/ /* go here when the end of a symbolic token has been found */
13483   /*switch*/ /* go here to branch on the class of an input character */
13484   /*|start_numeric_token|,|start_decimal_token|,|fin_numeric_token|,|done|*/
13485     /* go here at crucial stages when scanning a number */
13486   int k; /* an index into |buffer| */
13487   ASCII_code c; /* the current character in the buffer */
13488   ASCII_code class; /* its class number */
13489   integer n,f; /* registers for decimal-to-binary conversion */
13490 RESTART: 
13491   mp->cur_sym=0;
13492   if ( file_state ) {
13493     @<Input from external file; |goto restart| if no input found,
13494     or |return| if a non-symbolic token is found@>;
13495   } else {
13496     @<Input from token list; |goto restart| if end of list or
13497       if a parameter needs to be expanded,
13498       or |return| if a non-symbolic token is found@>;
13499   }
13500 COMMON_ENDING: 
13501   @<Finish getting the symbolic token in |cur_sym|;
13502    |goto restart| if it is illegal@>;
13503 }
13504
13505 @ When a symbolic token is declared to be `\&{outer}', its command code
13506 is increased by |outer_tag|.
13507 @^inner loop@>
13508
13509 @<Finish getting the symbolic token in |cur_sym|...@>=
13510 mp->cur_cmd=eq_type(mp->cur_sym); mp->cur_mod=equiv(mp->cur_sym);
13511 if ( mp->cur_cmd>=outer_tag ) {
13512   if ( mp_check_outer_validity(mp) ) 
13513     mp->cur_cmd=mp->cur_cmd-outer_tag;
13514   else 
13515     goto RESTART;
13516 }
13517
13518 @ A percent sign appears in |buffer[limit]|; this makes it unnecessary
13519 to have a special test for end-of-line.
13520 @^inner loop@>
13521
13522 @<Input from external file;...@>=
13523
13524 SWITCH: 
13525   c=mp->buffer[loc]; incr(loc); class=mp->char_class[c];
13526   switch (class) {
13527   case digit_class: goto START_NUMERIC_TOKEN; break;
13528   case period_class: 
13529     class=mp->char_class[mp->buffer[loc]];
13530     if ( class>period_class ) {
13531       goto SWITCH;
13532     } else if ( class<period_class ) { /* |class=digit_class| */
13533       n=0; goto START_DECIMAL_TOKEN;
13534     }
13535 @:. }{\..\ token@>
13536     break;
13537   case space_class: goto SWITCH; break;
13538   case percent_class: 
13539     if ( mp->scanner_status==tex_flushing ) {
13540       if ( loc<limit ) goto SWITCH;
13541     }
13542     @<Move to next line of file, or |goto restart| if there is no next line@>;
13543     check_interrupt;
13544     goto SWITCH;
13545     break;
13546   case string_class: 
13547     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13548     else @<Get a string token and |return|@>;
13549     break;
13550   case isolated_classes: 
13551     k=loc-1; goto FOUND; break;
13552   case invalid_class: 
13553     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13554     else @<Decry the invalid character and |goto restart|@>;
13555     break;
13556   default: break; /* letters, etc. */
13557   }
13558   k=loc-1;
13559   while ( mp->char_class[mp->buffer[loc]]==class ) incr(loc);
13560   goto FOUND;
13561 START_NUMERIC_TOKEN:
13562   @<Get the integer part |n| of a numeric token;
13563     set |f:=0| and |goto fin_numeric_token| if there is no decimal point@>;
13564 START_DECIMAL_TOKEN:
13565   @<Get the fraction part |f| of a numeric token@>;
13566 FIN_NUMERIC_TOKEN:
13567   @<Pack the numeric and fraction parts of a numeric token
13568     and |return|@>;
13569 FOUND: 
13570   mp->cur_sym=mp_id_lookup(mp, k,loc-k);
13571 }
13572
13573 @ We go to |restart| instead of to |SWITCH|, because |state| might equal
13574 |token_list| after the error has been dealt with
13575 (cf.\ |clear_for_error_prompt|).
13576
13577 @<Decry the invalid...@>=
13578
13579   print_err("Text line contains an invalid character");
13580 @.Text line contains...@>
13581   help2("A funny symbol that I can\'t read has just been input.")
13582     ("Continue, and I'll forget that it ever happened.");
13583   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13584   goto RESTART;
13585 }
13586
13587 @ @<Get a string token and |return|@>=
13588
13589   if ( mp->buffer[loc]=='"' ) {
13590     mp->cur_mod=rts("");
13591   } else { 
13592     k=loc; mp->buffer[limit+1]='"';
13593     do {  
13594      incr(loc);
13595     } while (mp->buffer[loc]!='"');
13596     if ( loc>limit ) {
13597       @<Decry the missing string delimiter and |goto restart|@>;
13598     }
13599     if ( loc==k+1 ) {
13600       mp->cur_mod=mp->buffer[k];
13601     } else { 
13602       str_room(loc-k);
13603       do {  
13604         append_char(mp->buffer[k]); incr(k);
13605       } while (k!=loc);
13606       mp->cur_mod=mp_make_string(mp);
13607     }
13608   }
13609   incr(loc); mp->cur_cmd=string_token; 
13610   return;
13611 }
13612
13613 @ We go to |restart| after this error message, not to |SWITCH|,
13614 because the |clear_for_error_prompt| routine might have reinstated
13615 |token_state| after |error| has finished.
13616
13617 @<Decry the missing string delimiter and |goto restart|@>=
13618
13619   loc=limit; /* the next character to be read on this line will be |"%"| */
13620   print_err("Incomplete string token has been flushed");
13621 @.Incomplete string token...@>
13622   help3("Strings should finish on the same line as they began.")
13623     ("I've deleted the partial string; you might want to")
13624     ("insert another by typing, e.g., `I\"new string\"'.");
13625   mp->deletions_allowed=false; mp_error(mp);
13626   mp->deletions_allowed=true; 
13627   goto RESTART;
13628 }
13629
13630 @ @<Get the integer part |n| of a numeric token...@>=
13631 n=c-'0';
13632 while ( mp->char_class[mp->buffer[loc]]==digit_class ) {
13633   if ( n<32768 ) n=10*n+mp->buffer[loc]-'0';
13634   incr(loc);
13635 }
13636 if ( mp->buffer[loc]=='.' ) 
13637   if ( mp->char_class[mp->buffer[loc+1]]==digit_class ) 
13638     goto DONE;
13639 f=0; 
13640 goto FIN_NUMERIC_TOKEN;
13641 DONE: incr(loc)
13642
13643 @ @<Get the fraction part |f| of a numeric token@>=
13644 k=0;
13645 do { 
13646   if ( k<17 ) { /* digits for |k>=17| cannot affect the result */
13647     mp->dig[k]=mp->buffer[loc]-'0'; incr(k);
13648   }
13649   incr(loc);
13650 } while (mp->char_class[mp->buffer[loc]]==digit_class);
13651 f=mp_round_decimals(mp, k);
13652 if ( f==unity ) {
13653   incr(n); f=0;
13654 }
13655
13656 @ @<Pack the numeric and fraction parts of a numeric token and |return|@>=
13657 if ( n<32768 ) {
13658   @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>;
13659 } else if ( mp->scanner_status!=tex_flushing ) {
13660   print_err("Enormous number has been reduced");
13661 @.Enormous number...@>
13662   help2("I can\'t handle numbers bigger than 32767.99998;")
13663     ("so I've changed your constant to that maximum amount.");
13664   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13665   mp->cur_mod=el_gordo;
13666 }
13667 mp->cur_cmd=numeric_token; return
13668
13669 @ @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>=
13670
13671   mp->cur_mod=n*unity+f;
13672   if ( mp->cur_mod>=fraction_one ) {
13673     if ( (mp->internal[warning_check]>0) &&
13674          (mp->scanner_status!=tex_flushing) ) {
13675       print_err("Number is too large (");
13676       mp_print_scaled(mp, mp->cur_mod);
13677       mp_print_char(mp, ')');
13678       help3("It is at least 4096. Continue and I'll try to cope")
13679       ("with that big value; but it might be dangerous.")
13680       ("(Set warningcheck:=0 to suppress this message.)");
13681       mp_error(mp);
13682     }
13683   }
13684 }
13685
13686 @ Let's consider now what happens when |get_next| is looking at a token list.
13687 @^inner loop@>
13688
13689 @<Input from token list;...@>=
13690 if ( loc>=mp->hi_mem_min ) { /* one-word token */
13691   mp->cur_sym=info(loc); loc=link(loc); /* move to next */
13692   if ( mp->cur_sym>=expr_base ) {
13693     if ( mp->cur_sym>=suffix_base ) {
13694       @<Insert a suffix or text parameter and |goto restart|@>;
13695     } else { 
13696       mp->cur_cmd=capsule_token;
13697       mp->cur_mod=mp->param_stack[param_start+mp->cur_sym-(expr_base)];
13698       mp->cur_sym=0; return;
13699     }
13700   }
13701 } else if ( loc>null ) {
13702   @<Get a stored numeric or string or capsule token and |return|@>
13703 } else { /* we are done with this token list */
13704   mp_end_token_list(mp); goto RESTART; /* resume previous level */
13705 }
13706
13707 @ @<Insert a suffix or text parameter...@>=
13708
13709   if ( mp->cur_sym>=text_base ) mp->cur_sym=mp->cur_sym-mp->param_size;
13710   /* |param_size=text_base-suffix_base| */
13711   mp_begin_token_list(mp,
13712                       mp->param_stack[param_start+mp->cur_sym-(suffix_base)],
13713                       parameter);
13714   goto RESTART;
13715 }
13716
13717 @ @<Get a stored numeric or string or capsule token...@>=
13718
13719   if ( name_type(loc)==mp_token ) {
13720     mp->cur_mod=value(loc);
13721     if ( type(loc)==mp_known ) {
13722       mp->cur_cmd=numeric_token;
13723     } else { 
13724       mp->cur_cmd=string_token; add_str_ref(mp->cur_mod);
13725     }
13726   } else { 
13727     mp->cur_mod=loc; mp->cur_cmd=capsule_token;
13728   };
13729   loc=link(loc); return;
13730 }
13731
13732 @ All of the easy branches of |get_next| have now been taken care of.
13733 There is one more branch.
13734
13735 @<Move to next line of file, or |goto restart|...@>=
13736 if ( name>max_spec_src ) {
13737   @<Read next line of file into |buffer|, or
13738     |goto restart| if the file has ended@>;
13739 } else { 
13740   if ( mp->input_ptr>0 ) {
13741      /* text was inserted during error recovery or by \&{scantokens} */
13742     mp_end_file_reading(mp); goto RESTART; /* resume previous level */
13743   }
13744   if ( mp->selector<log_only || mp->selector>=write_file) mp_open_log_file(mp);
13745   if ( mp->interaction>mp_nonstop_mode ) {
13746     if ( limit==start ) /* previous line was empty */
13747       mp_print_nl(mp, "(Please type a command or say `end')");
13748 @.Please type...@>
13749     mp_print_ln(mp); mp->first=start;
13750     prompt_input("*"); /* input on-line into |buffer| */
13751 @.*\relax@>
13752     limit=mp->last; mp->buffer[limit]='%';
13753     mp->first=limit+1; loc=start;
13754   } else {
13755     mp_fatal_error(mp, "*** (job aborted, no legal end found)");
13756 @.job aborted@>
13757     /* nonstop mode, which is intended for overnight batch processing,
13758     never waits for on-line input */
13759   }
13760 }
13761
13762 @ The global variable |force_eof| is normally |false|; it is set |true|
13763 by an \&{endinput} command.
13764
13765 @<Glob...@>=
13766 boolean force_eof; /* should the next \&{input} be aborted early? */
13767
13768 @ We must decrement |loc| in order to leave the buffer in a valid state
13769 when an error condition causes us to |goto restart| without calling
13770 |end_file_reading|.
13771
13772 @<Read next line of file into |buffer|, or
13773   |goto restart| if the file has ended@>=
13774
13775   incr(line); mp->first=start;
13776   if ( ! mp->force_eof ) {
13777     if ( mp_input_ln(mp, cur_file,true) ) /* not end of file */
13778       mp_firm_up_the_line(mp); /* this sets |limit| */
13779     else 
13780       mp->force_eof=true;
13781   };
13782   if ( mp->force_eof ) {
13783     mp->force_eof=false;
13784     decr(loc);
13785     if ( mpx_reading ) {
13786       @<Complain that the \.{MPX} file ended unexpectly; then set
13787         |cur_sym:=frozen_mpx_break| and |goto comon_ending|@>;
13788     } else { 
13789       mp_print_char(mp, ')'); decr(mp->open_parens);
13790       update_terminal; /* show user that file has been read */
13791       mp_end_file_reading(mp); /* resume previous level */
13792       if ( mp_check_outer_validity(mp) ) goto  RESTART;  
13793       else goto RESTART;
13794     }
13795   }
13796   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; /* ready to read */
13797 }
13798
13799 @ We should never actually come to the end of an \.{MPX} file because such
13800 files should have an \&{mpxbreak} after the translation of the last
13801 \&{btex}$\,\ldots\,$\&{etex} block.
13802
13803 @<Complain that the \.{MPX} file ended unexpectly; then set...@>=
13804
13805   mp->mpx_name[index]=finished;
13806   print_err("mpx file ended unexpectedly");
13807   help4("The file had too few picture expressions for btex...etex")
13808     ("blocks.  Such files are normally generated automatically")
13809     ("but this one got messed up.  You might want to insert a")
13810     ("picture expression now.");
13811   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13812   mp->cur_sym=frozen_mpx_break; goto COMMON_ENDING;
13813 }
13814
13815 @ Sometimes we want to make it look as though we have just read a blank line
13816 without really doing so.
13817
13818 @<Put an empty line in the input buffer@>=
13819 mp->last=mp->first; limit=mp->last; /* simulate |input_ln| and |firm_up_the_line| */
13820 mp->buffer[limit]='%'; mp->first=limit+1; loc=start
13821
13822 @ If the user has set the |pausing| parameter to some positive value,
13823 and if nonstop mode has not been selected, each line of input is displayed
13824 on the terminal and the transcript file, followed by `\.{=>}'.
13825 \MP\ waits for a response. If the response is null (i.e., if nothing is
13826 typed except perhaps a few blank spaces), the original
13827 line is accepted as it stands; otherwise the line typed is
13828 used instead of the line in the file.
13829
13830 @c void mp_firm_up_the_line (MP mp) {
13831   size_t k; /* an index into |buffer| */
13832   limit=mp->last;
13833   if ( mp->internal[pausing]>0 ) if ( mp->interaction>mp_nonstop_mode ) {
13834     wake_up_terminal; mp_print_ln(mp);
13835     if ( start<limit ) {
13836       for (k=(size_t)start;k<=(size_t)(limit-1);k++) {
13837         mp_print_str(mp, mp->buffer[k]);
13838       } 
13839     }
13840     mp->first=limit; prompt_input("=>"); /* wait for user response */
13841 @.=>@>
13842     if ( mp->last>mp->first ) {
13843       for (k=mp->first;k<=mp->last-1;k++) { /* move line down in buffer */
13844         mp->buffer[k+start-mp->first]=mp->buffer[k];
13845       }
13846       limit=start+mp->last-mp->first;
13847     }
13848   }
13849 }
13850
13851 @* \[30] Dealing with \TeX\ material.
13852 The \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}$\,\ldots\,$\&{etex}
13853 features need to be implemented at a low level in the scanning process
13854 so that \MP\ can stay in synch with the a preprocessor that treats
13855 blocks of \TeX\ material as they occur in the input file without trying
13856 to expand \MP\ macros.  Thus we need a special version of |get_next|
13857 that does not expand macros and such but does handle \&{btex},
13858 \&{verbatimtex}, etc.
13859
13860 The special version of |get_next| is called |get_t_next|.  It works by flushing
13861 \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}\allowbreak
13862 $\,\ldots\,$\&{etex} blocks, switching to the \.{MPX} file when it sees
13863 \&{btex}, and switching back when it sees \&{mpxbreak}.
13864
13865 @d btex_code 0
13866 @d verbatim_code 1
13867
13868 @ @<Put each...@>=
13869 mp_primitive(mp, "btex",start_tex,btex_code);
13870 @:btex_}{\&{btex} primitive@>
13871 mp_primitive(mp, "verbatimtex",start_tex,verbatim_code);
13872 @:verbatimtex_}{\&{verbatimtex} primitive@>
13873 mp_primitive(mp, "etex",etex_marker,0); mp->eqtb[frozen_etex]=mp->eqtb[mp->cur_sym];
13874 @:etex_}{\&{etex} primitive@>
13875 mp_primitive(mp, "mpxbreak",mpx_break,0); mp->eqtb[frozen_mpx_break]=mp->eqtb[mp->cur_sym];
13876 @:mpx_break_}{\&{mpxbreak} primitive@>
13877
13878 @ @<Cases of |print_cmd...@>=
13879 case start_tex: if ( m==btex_code ) mp_print(mp, "btex");
13880   else mp_print(mp, "verbatimtex"); break;
13881 case etex_marker: mp_print(mp, "etex"); break;
13882 case mpx_break: mp_print(mp, "mpxbreak"); break;
13883
13884 @ Actually, |get_t_next| is a macro that avoids procedure overhead except
13885 in the unusual case where \&{btex}, \&{verbatimtex}, \&{etex}, or \&{mpxbreak}
13886 is encountered.
13887
13888 @d get_t_next {mp_get_next(mp); if ( mp->cur_cmd<=max_pre_command ) mp_t_next(mp); }
13889
13890 @<Declarations@>=
13891 void mp_start_mpx_input (MP mp);
13892
13893 @ @c 
13894 void mp_t_next (MP mp) {
13895   int old_status; /* saves the |scanner_status| */
13896   integer old_info; /* saves the |warning_info| */
13897   while ( mp->cur_cmd<=max_pre_command ) {
13898     if ( mp->cur_cmd==mpx_break ) {
13899       if ( ! file_state || (mp->mpx_name[index]==absent) ) {
13900         @<Complain about a misplaced \&{mpxbreak}@>;
13901       } else { 
13902         mp_end_mpx_reading(mp); 
13903         goto TEX_FLUSH;
13904       }
13905     } else if ( mp->cur_cmd==start_tex ) {
13906       if ( token_state || (name<=max_spec_src) ) {
13907         @<Complain that we are not reading a file@>;
13908       } else if ( mpx_reading ) {
13909         @<Complain that \.{MPX} files cannot contain \TeX\ material@>;
13910       } else if ( (mp->cur_mod!=verbatim_code)&&
13911                   (mp->mpx_name[index]!=finished) ) {
13912         if ( ! mp_begin_mpx_reading(mp) ) mp_start_mpx_input(mp);
13913       } else {
13914         goto TEX_FLUSH;
13915       }
13916     } else {
13917        @<Complain about a misplaced \&{etex}@>;
13918     }
13919     goto COMMON_ENDING;
13920   TEX_FLUSH: 
13921     @<Flush the \TeX\ material@>;
13922   COMMON_ENDING: 
13923     mp_get_next(mp);
13924   }
13925 }
13926
13927 @ We could be in the middle of an operation such as skipping false conditional
13928 text when \TeX\ material is encountered, so we must be careful to save the
13929 |scanner_status|.
13930
13931 @<Flush the \TeX\ material@>=
13932 old_status=mp->scanner_status;
13933 old_info=mp->warning_info;
13934 mp->scanner_status=tex_flushing;
13935 mp->warning_info=line;
13936 do {  mp_get_next(mp); } while (mp->cur_cmd!=etex_marker);
13937 mp->scanner_status=old_status;
13938 mp->warning_info=old_info
13939
13940 @ @<Complain that \.{MPX} files cannot contain \TeX\ material@>=
13941 { print_err("An mpx file cannot contain btex or verbatimtex blocks");
13942 help4("This file contains picture expressions for btex...etex")
13943   ("blocks.  Such files are normally generated automatically")
13944   ("but this one seems to be messed up.  I'll just keep going")
13945   ("and hope for the best.");
13946 mp_error(mp);
13947 }
13948
13949 @ @<Complain that we are not reading a file@>=
13950 { print_err("You can only use `btex' or `verbatimtex' in a file");
13951 help3("I'll have to ignore this preprocessor command because it")
13952   ("only works when there is a file to preprocess.  You might")
13953   ("want to delete everything up to the next `etex`.");
13954 mp_error(mp);
13955 }
13956
13957 @ @<Complain about a misplaced \&{mpxbreak}@>=
13958 { print_err("Misplaced mpxbreak");
13959 help2("I'll ignore this preprocessor command because it")
13960   ("doesn't belong here");
13961 mp_error(mp);
13962 }
13963
13964 @ @<Complain about a misplaced \&{etex}@>=
13965 { print_err("Extra etex will be ignored");
13966 help1("There is no btex or verbatimtex for this to match");
13967 mp_error(mp);
13968 }
13969
13970 @* \[31] Scanning macro definitions.
13971 \MP\ has a variety of ways to tuck tokens away into token lists for later
13972 use: Macros can be defined with \&{def}, \&{vardef}, \&{primarydef}, etc.;
13973 repeatable code can be defined with \&{for}, \&{forever}, \&{forsuffixes}.
13974 All such operations are handled by the routines in this part of the program.
13975
13976 The modifier part of each command code is zero for the ``ending delimiters''
13977 like \&{enddef} and \&{endfor}.
13978
13979 @d start_def 1 /* command modifier for \&{def} */
13980 @d var_def 2 /* command modifier for \&{vardef} */
13981 @d end_def 0 /* command modifier for \&{enddef} */
13982 @d start_forever 1 /* command modifier for \&{forever} */
13983 @d end_for 0 /* command modifier for \&{endfor} */
13984
13985 @<Put each...@>=
13986 mp_primitive(mp, "def",macro_def,start_def);
13987 @:def_}{\&{def} primitive@>
13988 mp_primitive(mp, "vardef",macro_def,var_def);
13989 @:var_def_}{\&{vardef} primitive@>
13990 mp_primitive(mp, "primarydef",macro_def,secondary_primary_macro);
13991 @:primary_def_}{\&{primarydef} primitive@>
13992 mp_primitive(mp, "secondarydef",macro_def,tertiary_secondary_macro);
13993 @:secondary_def_}{\&{secondarydef} primitive@>
13994 mp_primitive(mp, "tertiarydef",macro_def,expression_tertiary_macro);
13995 @:tertiary_def_}{\&{tertiarydef} primitive@>
13996 mp_primitive(mp, "enddef",macro_def,end_def); mp->eqtb[frozen_end_def]=mp->eqtb[mp->cur_sym];
13997 @:end_def_}{\&{enddef} primitive@>
13998 @#
13999 mp_primitive(mp, "for",iteration,expr_base);
14000 @:for_}{\&{for} primitive@>
14001 mp_primitive(mp, "forsuffixes",iteration,suffix_base);
14002 @:for_suffixes_}{\&{forsuffixes} primitive@>
14003 mp_primitive(mp, "forever",iteration,start_forever);
14004 @:forever_}{\&{forever} primitive@>
14005 mp_primitive(mp, "endfor",iteration,end_for); mp->eqtb[frozen_end_for]=mp->eqtb[mp->cur_sym];
14006 @:end_for_}{\&{endfor} primitive@>
14007
14008 @ @<Cases of |print_cmd...@>=
14009 case macro_def:
14010   if ( m<=var_def ) {
14011     if ( m==start_def ) mp_print(mp, "def");
14012     else if ( m<start_def ) mp_print(mp, "enddef");
14013     else mp_print(mp, "vardef");
14014   } else if ( m==secondary_primary_macro ) { 
14015     mp_print(mp, "primarydef");
14016   } else if ( m==tertiary_secondary_macro ) { 
14017     mp_print(mp, "secondarydef");
14018   } else { 
14019     mp_print(mp, "tertiarydef");
14020   }
14021   break;
14022 case iteration: 
14023   if ( m<=start_forever ) {
14024     if ( m==start_forever ) mp_print(mp, "forever"); 
14025     else mp_print(mp, "endfor");
14026   } else if ( m==expr_base ) {
14027     mp_print(mp, "for"); 
14028   } else { 
14029     mp_print(mp, "forsuffixes");
14030   }
14031   break;
14032
14033 @ Different macro-absorbing operations have different syntaxes, but they
14034 also have a lot in common. There is a list of special symbols that are to
14035 be replaced by parameter tokens; there is a special command code that
14036 ends the definition; the quotation conventions are identical.  Therefore
14037 it makes sense to have most of the work done by a single subroutine. That
14038 subroutine is called |scan_toks|.
14039
14040 The first parameter to |scan_toks| is the command code that will
14041 terminate scanning (either |macro_def|, |loop_repeat|, or |iteration|).
14042
14043 The second parameter, |subst_list|, points to a (possibly empty) list
14044 of two-word nodes whose |info| and |value| fields specify symbol tokens
14045 before and after replacement. The list will be returned to free storage
14046 by |scan_toks|.
14047
14048 The third parameter is simply appended to the token list that is built.
14049 And the final parameter tells how many of the special operations
14050 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#} are to be replaced by suffix parameters.
14051 When such parameters are present, they are called \.{(SUFFIX0)},
14052 \.{(SUFFIX1)}, and \.{(SUFFIX2)}.
14053
14054 @c pointer mp_scan_toks (MP mp,command_code terminator, pointer 
14055   subst_list, pointer tail_end, small_number suffix_count) {
14056   pointer p; /* tail of the token list being built */
14057   pointer q; /* temporary for link management */
14058   integer balance; /* left delimiters minus right delimiters */
14059   p=hold_head; balance=1; link(hold_head)=null;
14060   while (1) { 
14061     get_t_next;
14062     if ( mp->cur_sym>0 ) {
14063       @<Substitute for |cur_sym|, if it's on the |subst_list|@>;
14064       if ( mp->cur_cmd==terminator ) {
14065         @<Adjust the balance; |break| if it's zero@>;
14066       } else if ( mp->cur_cmd==macro_special ) {
14067         @<Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}@>;
14068       }
14069     }
14070     link(p)=mp_cur_tok(mp); p=link(p);
14071   }
14072   link(p)=tail_end; mp_flush_node_list(mp, subst_list);
14073   return link(hold_head);
14074 }
14075
14076 @ @<Substitute for |cur_sym|...@>=
14077
14078   q=subst_list;
14079   while ( q!=null ) {
14080     if ( info(q)==mp->cur_sym ) {
14081       mp->cur_sym=value(q); mp->cur_cmd=relax; break;
14082     }
14083     q=link(q);
14084   }
14085 }
14086
14087 @ @<Adjust the balance; |break| if it's zero@>=
14088 if ( mp->cur_mod>0 ) {
14089   incr(balance);
14090 } else { 
14091   decr(balance);
14092   if ( balance==0 )
14093     break;
14094 }
14095
14096 @ Four commands are intended to be used only within macro texts: \&{quote},
14097 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#}. They are variants of a single command
14098 code called |macro_special|.
14099
14100 @d quote 0 /* |macro_special| modifier for \&{quote} */
14101 @d macro_prefix 1 /* |macro_special| modifier for \.{\#\AT!} */
14102 @d macro_at 2 /* |macro_special| modifier for \.{\AT!} */
14103 @d macro_suffix 3 /* |macro_special| modifier for \.{\AT!\#} */
14104
14105 @<Put each...@>=
14106 mp_primitive(mp, "quote",macro_special,quote);
14107 @:quote_}{\&{quote} primitive@>
14108 mp_primitive(mp, "#@@",macro_special,macro_prefix);
14109 @:]]]\#\AT!_}{\.{\#\AT!} primitive@>
14110 mp_primitive(mp, "@@",macro_special,macro_at);
14111 @:]]]\AT!_}{\.{\AT!} primitive@>
14112 mp_primitive(mp, "@@#",macro_special,macro_suffix);
14113 @:]]]\AT!\#_}{\.{\AT!\#} primitive@>
14114
14115 @ @<Cases of |print_cmd...@>=
14116 case macro_special: 
14117   switch (m) {
14118   case macro_prefix: mp_print(mp, "#@@"); break;
14119   case macro_at: mp_print_char(mp, '@@'); break;
14120   case macro_suffix: mp_print(mp, "@@#"); break;
14121   default: mp_print(mp, "quote"); break;
14122   }
14123   break;
14124
14125 @ @<Handle quoted...@>=
14126
14127   if ( mp->cur_mod==quote ) { get_t_next; } 
14128   else if ( mp->cur_mod<=suffix_count ) 
14129     mp->cur_sym=suffix_base-1+mp->cur_mod;
14130 }
14131
14132 @ Here is a routine that's used whenever a token will be redefined. If
14133 the user's token is unredefinable, the `|frozen_inaccessible|' token is
14134 substituted; the latter is redefinable but essentially impossible to use,
14135 hence \MP's tables won't get fouled up.
14136
14137 @c void mp_get_symbol (MP mp) { /* sets |cur_sym| to a safe symbol */
14138 RESTART: 
14139   get_t_next;
14140   if ( (mp->cur_sym==0)||(mp->cur_sym>frozen_inaccessible) ) {
14141     print_err("Missing symbolic token inserted");
14142 @.Missing symbolic token...@>
14143     help3("Sorry: You can\'t redefine a number, string, or expr.")
14144       ("I've inserted an inaccessible symbol so that your")
14145       ("definition will be completed without mixing me up too badly.");
14146     if ( mp->cur_sym>0 )
14147       mp->help_line[2]="Sorry: You can\'t redefine my error-recovery tokens.";
14148     else if ( mp->cur_cmd==string_token ) 
14149       delete_str_ref(mp->cur_mod);
14150     mp->cur_sym=frozen_inaccessible; mp_ins_error(mp); goto RESTART;
14151   }
14152 }
14153
14154 @ Before we actually redefine a symbolic token, we need to clear away its
14155 former value, if it was a variable. The following stronger version of
14156 |get_symbol| does that.
14157
14158 @c void mp_get_clear_symbol (MP mp) { 
14159   mp_get_symbol(mp); mp_clear_symbol(mp, mp->cur_sym,false);
14160 }
14161
14162 @ Here's another little subroutine; it checks that an equals sign
14163 or assignment sign comes along at the proper place in a macro definition.
14164
14165 @c void mp_check_equals (MP mp) { 
14166   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
14167      mp_missing_err(mp, "=");
14168 @.Missing `='@>
14169     help5("The next thing in this `def' should have been `=',")
14170       ("because I've already looked at the definition heading.")
14171       ("But don't worry; I'll pretend that an equals sign")
14172       ("was present. Everything from here to `enddef'")
14173       ("will be the replacement text of this macro.");
14174     mp_back_error(mp);
14175   }
14176 }
14177
14178 @ A \&{primarydef}, \&{secondarydef}, or \&{tertiarydef} is rather easily
14179 handled now that we have |scan_toks|.  In this case there are
14180 two parameters, which will be \.{EXPR0} and \.{EXPR1} (i.e.,
14181 |expr_base| and |expr_base+1|).
14182
14183 @c void mp_make_op_def (MP mp) {
14184   command_code m; /* the type of definition */
14185   pointer p,q,r; /* for list manipulation */
14186   m=mp->cur_mod;
14187   mp_get_symbol(mp); q=mp_get_node(mp, token_node_size);
14188   info(q)=mp->cur_sym; value(q)=expr_base;
14189   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym;
14190   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
14191   info(p)=mp->cur_sym; value(p)=expr_base+1; link(p)=q;
14192   get_t_next; mp_check_equals(mp);
14193   mp->scanner_status=op_defining; q=mp_get_avail(mp); ref_count(q)=null;
14194   r=mp_get_avail(mp); link(q)=r; info(r)=general_macro;
14195   link(r)=mp_scan_toks(mp, macro_def,p,null,0);
14196   mp->scanner_status=normal; eq_type(mp->warning_info)=m;
14197   equiv(mp->warning_info)=q; mp_get_x_next(mp);
14198 }
14199
14200 @ Parameters to macros are introduced by the keywords \&{expr},
14201 \&{suffix}, \&{text}, \&{primary}, \&{secondary}, and \&{tertiary}.
14202
14203 @<Put each...@>=
14204 mp_primitive(mp, "expr",param_type,expr_base);
14205 @:expr_}{\&{expr} primitive@>
14206 mp_primitive(mp, "suffix",param_type,suffix_base);
14207 @:suffix_}{\&{suffix} primitive@>
14208 mp_primitive(mp, "text",param_type,text_base);
14209 @:text_}{\&{text} primitive@>
14210 mp_primitive(mp, "primary",param_type,primary_macro);
14211 @:primary_}{\&{primary} primitive@>
14212 mp_primitive(mp, "secondary",param_type,secondary_macro);
14213 @:secondary_}{\&{secondary} primitive@>
14214 mp_primitive(mp, "tertiary",param_type,tertiary_macro);
14215 @:tertiary_}{\&{tertiary} primitive@>
14216
14217 @ @<Cases of |print_cmd...@>=
14218 case param_type:
14219   if ( m>=expr_base ) {
14220     if ( m==expr_base ) mp_print(mp, "expr");
14221     else if ( m==suffix_base ) mp_print(mp, "suffix");
14222     else mp_print(mp, "text");
14223   } else if ( m<secondary_macro ) {
14224     mp_print(mp, "primary");
14225   } else if ( m==secondary_macro ) {
14226     mp_print(mp, "secondary");
14227   } else {
14228     mp_print(mp, "tertiary");
14229   }
14230   break;
14231
14232 @ Let's turn next to the more complex processing associated with \&{def}
14233 and \&{vardef}. When the following procedure is called, |cur_mod|
14234 should be either |start_def| or |var_def|.
14235
14236 @c @<Declare the procedure called |check_delimiter|@>;
14237 @<Declare the function called |scan_declared_variable|@>;
14238 void mp_scan_def (MP mp) {
14239   int m; /* the type of definition */
14240   int n; /* the number of special suffix parameters */
14241   int k; /* the total number of parameters */
14242   int c; /* the kind of macro we're defining */
14243   pointer r; /* parameter-substitution list */
14244   pointer q; /* tail of the macro token list */
14245   pointer p; /* temporary storage */
14246   halfword base; /* |expr_base|, |suffix_base|, or |text_base| */
14247   pointer l_delim,r_delim; /* matching delimiters */
14248   m=mp->cur_mod; c=general_macro; link(hold_head)=null;
14249   q=mp_get_avail(mp); ref_count(q)=null; r=null;
14250   @<Scan the token or variable to be defined;
14251     set |n|, |scanner_status|, and |warning_info|@>;
14252   k=n;
14253   if ( mp->cur_cmd==left_delimiter ) {
14254     @<Absorb delimited parameters, putting them into lists |q| and |r|@>;
14255   }
14256   if ( mp->cur_cmd==param_type ) {
14257     @<Absorb undelimited parameters, putting them into list |r|@>;
14258   }
14259   mp_check_equals(mp);
14260   p=mp_get_avail(mp); info(p)=c; link(q)=p;
14261   @<Attach the replacement text to the tail of node |p|@>;
14262   mp->scanner_status=normal; mp_get_x_next(mp);
14263 }
14264
14265 @ We don't put `|frozen_end_group|' into the replacement text of
14266 a \&{vardef}, because the user may want to redefine `\.{endgroup}'.
14267
14268 @<Attach the replacement text to the tail of node |p|@>=
14269 if ( m==start_def ) {
14270   link(p)=mp_scan_toks(mp, macro_def,r,null,n);
14271 } else { 
14272   q=mp_get_avail(mp); info(q)=mp->bg_loc; link(p)=q;
14273   p=mp_get_avail(mp); info(p)=mp->eg_loc;
14274   link(q)=mp_scan_toks(mp, macro_def,r,p,n);
14275 }
14276 if ( mp->warning_info==bad_vardef ) 
14277   mp_flush_token_list(mp, value(bad_vardef))
14278
14279 @ @<Glob...@>=
14280 int bg_loc;
14281 int eg_loc; /* hash addresses of `\.{begingroup}' and `\.{endgroup}' */
14282
14283 @ @<Scan the token or variable to be defined;...@>=
14284 if ( m==start_def ) {
14285   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym; get_t_next;
14286   mp->scanner_status=op_defining; n=0;
14287   eq_type(mp->warning_info)=defined_macro; equiv(mp->warning_info)=q;
14288 } else { 
14289   p=mp_scan_declared_variable(mp);
14290   mp_flush_variable(mp, equiv(info(p)),link(p),true);
14291   mp->warning_info=mp_find_variable(mp, p); mp_flush_list(mp, p);
14292   if ( mp->warning_info==null ) @<Change to `\.{a bad variable}'@>;
14293   mp->scanner_status=var_defining; n=2;
14294   if ( mp->cur_cmd==macro_special ) if ( mp->cur_mod==macro_suffix ) {/* \.{\AT!\#} */
14295     n=3; get_t_next;
14296   }
14297   type(mp->warning_info)=mp_unsuffixed_macro-2+n; value(mp->warning_info)=q;
14298 } /* |mp_suffixed_macro=mp_unsuffixed_macro+1| */
14299
14300 @ @<Change to `\.{a bad variable}'@>=
14301
14302   print_err("This variable already starts with a macro");
14303 @.This variable already...@>
14304   help2("After `vardef a' you can\'t say `vardef a.b'.")
14305     ("So I'll have to discard this definition.");
14306   mp_error(mp); mp->warning_info=bad_vardef;
14307 }
14308
14309 @ @<Initialize table entries...@>=
14310 name_type(bad_vardef)=mp_root; link(bad_vardef)=frozen_bad_vardef;
14311 equiv(frozen_bad_vardef)=bad_vardef; eq_type(frozen_bad_vardef)=tag_token;
14312
14313 @ @<Absorb delimited parameters, putting them into lists |q| and |r|@>=
14314 do {  
14315   l_delim=mp->cur_sym; r_delim=mp->cur_mod; get_t_next;
14316   if ( (mp->cur_cmd==param_type)&&(mp->cur_mod>=expr_base) ) {
14317    base=mp->cur_mod;
14318   } else { 
14319     print_err("Missing parameter type; `expr' will be assumed");
14320 @.Missing parameter type@>
14321     help1("You should've had `expr' or `suffix' or `text' here.");
14322     mp_back_error(mp); base=expr_base;
14323   }
14324   @<Absorb parameter tokens for type |base|@>;
14325   mp_check_delimiter(mp, l_delim,r_delim);
14326   get_t_next;
14327 } while (mp->cur_cmd==left_delimiter)
14328
14329 @ @<Absorb parameter tokens for type |base|@>=
14330 do { 
14331   link(q)=mp_get_avail(mp); q=link(q); info(q)=base+k;
14332   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size); 
14333   value(p)=base+k; info(p)=mp->cur_sym;
14334   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14335 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14336   incr(k); link(p)=r; r=p; get_t_next;
14337 } while (mp->cur_cmd==comma)
14338
14339 @ @<Absorb undelimited parameters, putting them into list |r|@>=
14340
14341   p=mp_get_node(mp, token_node_size);
14342   if ( mp->cur_mod<expr_base ) {
14343     c=mp->cur_mod; value(p)=expr_base+k;
14344   } else { 
14345     value(p)=mp->cur_mod+k;
14346     if ( mp->cur_mod==expr_base ) c=expr_macro;
14347     else if ( mp->cur_mod==suffix_base ) c=suffix_macro;
14348     else c=text_macro;
14349   }
14350   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14351   incr(k); mp_get_symbol(mp); info(p)=mp->cur_sym; link(p)=r; r=p; get_t_next;
14352   if ( c==expr_macro ) if ( mp->cur_cmd==of_token ) {
14353     c=of_macro; p=mp_get_node(mp, token_node_size);
14354     if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14355     value(p)=expr_base+k; mp_get_symbol(mp); info(p)=mp->cur_sym;
14356     link(p)=r; r=p; get_t_next;
14357   }
14358 }
14359
14360 @* \[32] Expanding the next token.
14361 Only a few command codes |<min_command| can possibly be returned by
14362 |get_t_next|; in increasing order, they are
14363 |if_test|, |fi_or_else|, |input|, |iteration|, |repeat_loop|,
14364 |exit_test|, |relax|, |scan_tokens|, |expand_after|, and |defined_macro|.
14365
14366 \MP\ usually gets the next token of input by saying |get_x_next|. This is
14367 like |get_t_next| except that it keeps getting more tokens until
14368 finding |cur_cmd>=min_command|. In other words, |get_x_next| expands
14369 macros and removes conditionals or iterations or input instructions that
14370 might be present.
14371
14372 It follows that |get_x_next| might invoke itself recursively. In fact,
14373 there is massive recursion, since macro expansion can involve the
14374 scanning of arbitrarily complex expressions, which in turn involve
14375 macro expansion and conditionals, etc.
14376 @^recursion@>
14377
14378 Therefore it's necessary to declare a whole bunch of |forward|
14379 procedures at this point, and to insert some other procedures
14380 that will be invoked by |get_x_next|.
14381
14382 @<Declarations@>= 
14383 void mp_scan_primary (MP mp);
14384 void mp_scan_secondary (MP mp);
14385 void mp_scan_tertiary (MP mp);
14386 void mp_scan_expression (MP mp);
14387 void mp_scan_suffix (MP mp);
14388 @<Declare the procedure called |macro_call|@>;
14389 void mp_get_boolean (MP mp);
14390 void mp_pass_text (MP mp);
14391 void mp_conditional (MP mp);
14392 void mp_start_input (MP mp);
14393 void mp_begin_iteration (MP mp);
14394 void mp_resume_iteration (MP mp);
14395 void mp_stop_iteration (MP mp);
14396
14397 @ An auxiliary subroutine called |expand| is used by |get_x_next|
14398 when it has to do exotic expansion commands.
14399
14400 @c void mp_expand (MP mp) {
14401   pointer p; /* for list manipulation */
14402   size_t k; /* something that we hope is |<=buf_size| */
14403   pool_pointer j; /* index into |str_pool| */
14404   if ( mp->internal[tracing_commands]>unity ) 
14405     if ( mp->cur_cmd!=defined_macro )
14406       show_cur_cmd_mod;
14407   switch (mp->cur_cmd)  {
14408   case if_test:
14409     mp_conditional(mp); /* this procedure is discussed in Part 36 below */
14410     break;
14411   case fi_or_else:
14412     @<Terminate the current conditional and skip to \&{fi}@>;
14413     break;
14414   case input:
14415     @<Initiate or terminate input from a file@>;
14416     break;
14417   case iteration:
14418     if ( mp->cur_mod==end_for ) {
14419       @<Scold the user for having an extra \&{endfor}@>;
14420     } else {
14421       mp_begin_iteration(mp); /* this procedure is discussed in Part 37 below */
14422     }
14423     break;
14424   case repeat_loop: 
14425     @<Repeat a loop@>;
14426     break;
14427   case exit_test: 
14428     @<Exit a loop if the proper time has come@>;
14429     break;
14430   case relax: 
14431     break;
14432   case expand_after: 
14433     @<Expand the token after the next token@>;
14434     break;
14435   case scan_tokens: 
14436     @<Put a string into the input buffer@>;
14437     break;
14438   case defined_macro:
14439    mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14440    break;
14441   }; /* there are no other cases */
14442 };
14443
14444 @ @<Scold the user...@>=
14445
14446   print_err("Extra `endfor'");
14447 @.Extra `endfor'@>
14448   help2("I'm not currently working on a for loop,")
14449     ("so I had better not try to end anything.");
14450   mp_error(mp);
14451 }
14452
14453 @ The processing of \&{input} involves the |start_input| subroutine,
14454 which will be declared later; the processing of \&{endinput} is trivial.
14455
14456 @<Put each...@>=
14457 mp_primitive(mp, "input",input,0);
14458 @:input_}{\&{input} primitive@>
14459 mp_primitive(mp, "endinput",input,1);
14460 @:end_input_}{\&{endinput} primitive@>
14461
14462 @ @<Cases of |print_cmd_mod|...@>=
14463 case input: 
14464   if ( m==0 ) mp_print(mp, "input");
14465   else mp_print(mp, "endinput");
14466   break;
14467
14468 @ @<Initiate or terminate input...@>=
14469 if ( mp->cur_mod>0 ) mp->force_eof=true;
14470 else mp_start_input(mp)
14471
14472 @ We'll discuss the complicated parts of loop operations later. For now
14473 it suffices to know that there's a global variable called |loop_ptr|
14474 that will be |null| if no loop is in progress.
14475
14476 @<Repeat a loop@>=
14477 { while ( token_state &&(loc==null) ) 
14478     mp_end_token_list(mp); /* conserve stack space */
14479   if ( mp->loop_ptr==null ) {
14480     print_err("Lost loop");
14481 @.Lost loop@>
14482     help2("I'm confused; after exiting from a loop, I still seem")
14483       ("to want to repeat it. I'll try to forget the problem.");
14484     mp_error(mp);
14485   } else {
14486     mp_resume_iteration(mp); /* this procedure is in Part 37 below */
14487   }
14488 }
14489
14490 @ @<Exit a loop if the proper time has come@>=
14491 { mp_get_boolean(mp);
14492   if ( mp->internal[tracing_commands]>unity ) 
14493     mp_show_cmd_mod(mp, nullary,mp->cur_exp);
14494   if ( mp->cur_exp==true_code ) {
14495     if ( mp->loop_ptr==null ) {
14496       print_err("No loop is in progress");
14497 @.No loop is in progress@>
14498       help1("Why say `exitif' when there's nothing to exit from?");
14499       if ( mp->cur_cmd==semicolon ) mp_error(mp); else mp_back_error(mp);
14500     } else {
14501      @<Exit prematurely from an iteration@>;
14502     }
14503   } else if ( mp->cur_cmd!=semicolon ) {
14504     mp_missing_err(mp, ";");
14505 @.Missing `;'@>
14506     help2("After `exitif <boolean exp>' I expect to see a semicolon.")
14507     ("I shall pretend that one was there."); mp_back_error(mp);
14508   }
14509 }
14510
14511 @ Here we use the fact that |forever_text| is the only |token_type| that
14512 is less than |loop_text|.
14513
14514 @<Exit prematurely...@>=
14515 { p=null;
14516   do {  
14517     if ( file_state ) {
14518       mp_end_file_reading(mp);
14519     } else { 
14520       if ( token_type<=loop_text ) p=start;
14521       mp_end_token_list(mp);
14522     }
14523   } while (p==null);
14524   if ( p!=info(mp->loop_ptr) ) mp_fatal_error(mp, "*** (loop confusion)");
14525 @.loop confusion@>
14526   mp_stop_iteration(mp); /* this procedure is in Part 34 below */
14527 }
14528
14529 @ @<Expand the token after the next token@>=
14530 { get_t_next;
14531   p=mp_cur_tok(mp); get_t_next;
14532   if ( mp->cur_cmd<min_command ) mp_expand(mp); 
14533   else mp_back_input(mp);
14534   back_list(p);
14535 }
14536
14537 @ @<Put a string into the input buffer@>=
14538 { mp_get_x_next(mp); mp_scan_primary(mp);
14539   if ( mp->cur_type!=mp_string_type ) {
14540     mp_disp_err(mp, null,"Not a string");
14541 @.Not a string@>
14542     help2("I'm going to flush this expression, since")
14543        ("scantokens should be followed by a known string.");
14544     mp_put_get_flush_error(mp, 0);
14545   } else { 
14546     mp_back_input(mp);
14547     if ( length(mp->cur_exp)>0 )
14548        @<Pretend we're reading a new one-line file@>;
14549   }
14550 }
14551
14552 @ @<Pretend we're reading a new one-line file@>=
14553 { mp_begin_file_reading(mp); name=is_scantok;
14554   k=mp->first+length(mp->cur_exp);
14555   if ( k>=mp->max_buf_stack ) {
14556     while ( k>=mp->buf_size ) {
14557       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
14558     }
14559     mp->max_buf_stack=k+1;
14560   }
14561   j=mp->str_start[mp->cur_exp]; limit=k;
14562   while ( mp->first<(size_t)limit ) {
14563     mp->buffer[mp->first]=mp->str_pool[j]; incr(j); incr(mp->first);
14564   }
14565   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; 
14566   mp_flush_cur_exp(mp, 0);
14567 }
14568
14569 @ Here finally is |get_x_next|.
14570
14571 The expression scanning routines to be considered later
14572 communicate via the global quantities |cur_type| and |cur_exp|;
14573 we must be very careful to save and restore these quantities while
14574 macros are being expanded.
14575 @^inner loop@>
14576
14577 @<Declarations@>=
14578 void mp_get_x_next (MP mp);
14579
14580 @ @c void mp_get_x_next (MP mp) {
14581   pointer save_exp; /* a capsule to save |cur_type| and |cur_exp| */
14582   get_t_next;
14583   if ( mp->cur_cmd<min_command ) {
14584     save_exp=mp_stash_cur_exp(mp);
14585     do {  
14586       if ( mp->cur_cmd==defined_macro ) 
14587         mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14588       else 
14589         mp_expand(mp);
14590       get_t_next;
14591      } while (mp->cur_cmd<min_command);
14592      mp_unstash_cur_exp(mp, save_exp); /* that restores |cur_type| and |cur_exp| */
14593   }
14594 }
14595
14596 @ Now let's consider the |macro_call| procedure, which is used to start up
14597 all user-defined macros. Since the arguments to a macro might be expressions,
14598 |macro_call| is recursive.
14599 @^recursion@>
14600
14601 The first parameter to |macro_call| points to the reference count of the
14602 token list that defines the macro. The second parameter contains any
14603 arguments that have already been parsed (see below).  The third parameter
14604 points to the symbolic token that names the macro. If the third parameter
14605 is |null|, the macro was defined by \&{vardef}, so its name can be
14606 reconstructed from the prefix and ``at'' arguments found within the
14607 second parameter.
14608
14609 What is this second parameter? It's simply a linked list of one-word items,
14610 whose |info| fields point to the arguments. In other words, if |arg_list=null|,
14611 no arguments have been scanned yet; otherwise |info(arg_list)| points to
14612 the first scanned argument, and |link(arg_list)| points to the list of
14613 further arguments (if any).
14614
14615 Arguments of type \&{expr} are so-called capsules, which we will
14616 discuss later when we concentrate on expressions; they can be
14617 recognized easily because their |link| field is |void|. Arguments of type
14618 \&{suffix} and \&{text} are token lists without reference counts.
14619
14620 @ After argument scanning is complete, the arguments are moved to the
14621 |param_stack|. (They can't be put on that stack any sooner, because
14622 the stack is growing and shrinking in unpredictable ways as more arguments
14623 are being acquired.)  Then the macro body is fed to the scanner; i.e.,
14624 the replacement text of the macro is placed at the top of the \MP's
14625 input stack, so that |get_t_next| will proceed to read it next.
14626
14627 @<Declare the procedure called |macro_call|@>=
14628 @<Declare the procedure called |print_macro_name|@>;
14629 @<Declare the procedure called |print_arg|@>;
14630 @<Declare the procedure called |scan_text_arg|@>;
14631 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14632                     pointer macro_name) ;
14633
14634 @ @c
14635 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14636                     pointer macro_name) {
14637   /* invokes a user-defined control sequence */
14638   pointer r; /* current node in the macro's token list */
14639   pointer p,q; /* for list manipulation */
14640   integer n; /* the number of arguments */
14641   pointer tail = 0; /* tail of the argument list */
14642   pointer l_delim=0,r_delim=0; /* a delimiter pair */
14643   r=link(def_ref); add_mac_ref(def_ref);
14644   if ( arg_list==null ) {
14645     n=0;
14646   } else {
14647    @<Determine the number |n| of arguments already supplied,
14648     and set |tail| to the tail of |arg_list|@>;
14649   }
14650   if ( mp->internal[tracing_macros]>0 ) {
14651     @<Show the text of the macro being expanded, and the existing arguments@>;
14652   }
14653   @<Scan the remaining arguments, if any; set |r| to the first token
14654     of the replacement text@>;
14655   @<Feed the arguments and replacement text to the scanner@>;
14656 }
14657
14658 @ @<Show the text of the macro...@>=
14659 mp_begin_diagnostic(mp); mp_print_ln(mp); 
14660 mp_print_macro_name(mp, arg_list,macro_name);
14661 if ( n==3 ) mp_print(mp, "@@#"); /* indicate a suffixed macro */
14662 mp_show_macro(mp, def_ref,null,100000);
14663 if ( arg_list!=null ) {
14664   n=0; p=arg_list;
14665   do {  
14666     q=info(p);
14667     mp_print_arg(mp, q,n,0);
14668     incr(n); p=link(p);
14669   } while (p!=null);
14670 }
14671 mp_end_diagnostic(mp, false)
14672
14673
14674 @ @<Declare the procedure called |print_macro_name|@>=
14675 void mp_print_macro_name (MP mp,pointer a, pointer n);
14676
14677 @ @c
14678 void mp_print_macro_name (MP mp,pointer a, pointer n) {
14679   pointer p,q; /* they traverse the first part of |a| */
14680   if ( n!=null ) {
14681     mp_print_text(n);
14682   } else  { 
14683     p=info(a);
14684     if ( p==null ) {
14685       mp_print_text(info(info(link(a))));
14686     } else { 
14687       q=p;
14688       while ( link(q)!=null ) q=link(q);
14689       link(q)=info(link(a));
14690       mp_show_token_list(mp, p,null,1000,0);
14691       link(q)=null;
14692     }
14693   }
14694 }
14695
14696 @ @<Declare the procedure called |print_arg|@>=
14697 void mp_print_arg (MP mp,pointer q, integer n, pointer b) ;
14698
14699 @ @c
14700 void mp_print_arg (MP mp,pointer q, integer n, pointer b) {
14701   if ( link(q)==diov ) mp_print_nl(mp, "(EXPR");
14702   else if ( (b<text_base)&&(b!=text_macro) ) mp_print_nl(mp, "(SUFFIX");
14703   else mp_print_nl(mp, "(TEXT");
14704   mp_print_int(mp, n); mp_print(mp, ")<-");
14705   if ( link(q)==diov ) mp_print_exp(mp, q,1);
14706   else mp_show_token_list(mp, q,null,1000,0);
14707 }
14708
14709 @ @<Determine the number |n| of arguments already supplied...@>=
14710 {  
14711   n=1; tail=arg_list;
14712   while ( link(tail)!=null ) { 
14713     incr(n); tail=link(tail);
14714   }
14715 }
14716
14717 @ @<Scan the remaining arguments, if any; set |r|...@>=
14718 mp->cur_cmd=comma+1; /* anything |<>comma| will do */
14719 while ( info(r)>=expr_base ) { 
14720   @<Scan the delimited argument represented by |info(r)|@>;
14721   r=link(r);
14722 };
14723 if ( mp->cur_cmd==comma ) {
14724   print_err("Too many arguments to ");
14725 @.Too many arguments...@>
14726   mp_print_macro_name(mp, arg_list,macro_name); mp_print_char(mp, ';');
14727   mp_print_nl(mp, "  Missing `"); mp_print_text(r_delim);
14728 @.Missing `)'...@>
14729   mp_print(mp, "' has been inserted");
14730   help3("I'm going to assume that the comma I just read was a")
14731    ("right delimiter, and then I'll begin expanding the macro.")
14732    ("You might want to delete some tokens before continuing.");
14733   mp_error(mp);
14734 }
14735 if ( info(r)!=general_macro ) {
14736   @<Scan undelimited argument(s)@>;
14737 }
14738 r=link(r)
14739
14740 @ At this point, the reader will find it advisable to review the explanation
14741 of token list format that was presented earlier, paying special attention to
14742 the conventions that apply only at the beginning of a macro's token list.
14743
14744 On the other hand, the reader will have to take the expression-parsing
14745 aspects of the following program on faith; we will explain |cur_type|
14746 and |cur_exp| later. (Several things in this program depend on each other,
14747 and it's necessary to jump into the circle somewhere.)
14748
14749 @<Scan the delimited argument represented by |info(r)|@>=
14750 if ( mp->cur_cmd!=comma ) {
14751   mp_get_x_next(mp);
14752   if ( mp->cur_cmd!=left_delimiter ) {
14753     print_err("Missing argument to ");
14754 @.Missing argument...@>
14755     mp_print_macro_name(mp, arg_list,macro_name);
14756     help3("That macro has more parameters than you thought.")
14757      ("I'll continue by pretending that each missing argument")
14758      ("is either zero or null.");
14759     if ( info(r)>=suffix_base ) {
14760       mp->cur_exp=null; mp->cur_type=mp_token_list;
14761     } else { 
14762       mp->cur_exp=0; mp->cur_type=mp_known;
14763     }
14764     mp_back_error(mp); mp->cur_cmd=right_delimiter; 
14765     goto FOUND;
14766   }
14767   l_delim=mp->cur_sym; r_delim=mp->cur_mod;
14768 }
14769 @<Scan the argument represented by |info(r)|@>;
14770 if ( mp->cur_cmd!=comma ) 
14771   @<Check that the proper right delimiter was present@>;
14772 FOUND:  
14773 @<Append the current expression to |arg_list|@>
14774
14775 @ @<Check that the proper right delim...@>=
14776 if ( (mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
14777   if ( info(link(r))>=expr_base ) {
14778     mp_missing_err(mp, ",");
14779 @.Missing `,'@>
14780     help3("I've finished reading a macro argument and am about to")
14781       ("read another; the arguments weren't delimited correctly.")
14782        ("You might want to delete some tokens before continuing.");
14783     mp_back_error(mp); mp->cur_cmd=comma;
14784   } else { 
14785     mp_missing_err(mp, str(text(r_delim)));
14786 @.Missing `)'@>
14787     help2("I've gotten to the end of the macro parameter list.")
14788        ("You might want to delete some tokens before continuing.");
14789     mp_back_error(mp);
14790   }
14791 }
14792
14793 @ A \&{suffix} or \&{text} parameter will be have been scanned as
14794 a token list pointed to by |cur_exp|, in which case we will have
14795 |cur_type=token_list|.
14796
14797 @<Append the current expression to |arg_list|@>=
14798
14799   p=mp_get_avail(mp);
14800   if ( mp->cur_type==mp_token_list ) info(p)=mp->cur_exp;
14801   else info(p)=mp_stash_cur_exp(mp);
14802   if ( mp->internal[tracing_macros]>0 ) {
14803     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,info(r)); 
14804     mp_end_diagnostic(mp, false);
14805   }
14806   if ( arg_list==null ) arg_list=p;
14807   else link(tail)=p;
14808   tail=p; incr(n);
14809 }
14810
14811 @ @<Scan the argument represented by |info(r)|@>=
14812 if ( info(r)>=text_base ) {
14813   mp_scan_text_arg(mp, l_delim,r_delim);
14814 } else { 
14815   mp_get_x_next(mp);
14816   if ( info(r)>=suffix_base ) mp_scan_suffix(mp);
14817   else mp_scan_expression(mp);
14818 }
14819
14820 @ The parameters to |scan_text_arg| are either a pair of delimiters
14821 or zero; the latter case is for undelimited text arguments, which
14822 end with the first semicolon or \&{endgroup} or \&{end} that is not
14823 contained in a group.
14824
14825 @<Declare the procedure called |scan_text_arg|@>=
14826 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) ;
14827
14828 @ @c
14829 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) {
14830   integer balance; /* excess of |l_delim| over |r_delim| */
14831   pointer p; /* list tail */
14832   mp->warning_info=l_delim; mp->scanner_status=absorbing;
14833   p=hold_head; balance=1; link(hold_head)=null;
14834   while (1)  { 
14835     get_t_next;
14836     if ( l_delim==0 ) {
14837       @<Adjust the balance for an undelimited argument; |break| if done@>;
14838     } else {
14839           @<Adjust the balance for a delimited argument; |break| if done@>;
14840     }
14841     link(p)=mp_cur_tok(mp); p=link(p);
14842   }
14843   mp->cur_exp=link(hold_head); mp->cur_type=mp_token_list;
14844   mp->scanner_status=normal;
14845 };
14846
14847 @ @<Adjust the balance for a delimited argument...@>=
14848 if ( mp->cur_cmd==right_delimiter ) { 
14849   if ( mp->cur_mod==l_delim ) { 
14850     decr(balance);
14851     if ( balance==0 ) break;
14852   }
14853 } else if ( mp->cur_cmd==left_delimiter ) {
14854   if ( mp->cur_mod==r_delim ) incr(balance);
14855 }
14856
14857 @ @<Adjust the balance for an undelimited...@>=
14858 if ( end_of_statement ) { /* |cur_cmd=semicolon|, |end_group|, or |stop| */
14859   if ( balance==1 ) { break; }
14860   else  { if ( mp->cur_cmd==end_group ) decr(balance); }
14861 } else if ( mp->cur_cmd==begin_group ) { 
14862   incr(balance); 
14863 }
14864
14865 @ @<Scan undelimited argument(s)@>=
14866
14867   if ( info(r)<text_macro ) {
14868     mp_get_x_next(mp);
14869     if ( info(r)!=suffix_macro ) {
14870       if ( (mp->cur_cmd==equals)||(mp->cur_cmd==assignment) ) mp_get_x_next(mp);
14871     }
14872   }
14873   switch (info(r)) {
14874   case primary_macro:mp_scan_primary(mp); break;
14875   case secondary_macro:mp_scan_secondary(mp); break;
14876   case tertiary_macro:mp_scan_tertiary(mp); break;
14877   case expr_macro:mp_scan_expression(mp); break;
14878   case of_macro:
14879     @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>;
14880     break;
14881   case suffix_macro:
14882     @<Scan a suffix with optional delimiters@>;
14883     break;
14884   case text_macro:mp_scan_text_arg(mp, 0,0); break;
14885   } /* there are no other cases */
14886   mp_back_input(mp); 
14887   @<Append the current expression to |arg_list|@>;
14888 }
14889
14890 @ @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>=
14891
14892   mp_scan_expression(mp); p=mp_get_avail(mp); info(p)=mp_stash_cur_exp(mp);
14893   if ( mp->internal[tracing_macros]>0 ) { 
14894     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,0); 
14895     mp_end_diagnostic(mp, false);
14896   }
14897   if ( arg_list==null ) arg_list=p; else link(tail)=p;
14898   tail=p;incr(n);
14899   if ( mp->cur_cmd!=of_token ) {
14900     mp_missing_err(mp, "of"); mp_print(mp, " for ");
14901 @.Missing `of'@>
14902     mp_print_macro_name(mp, arg_list,macro_name);
14903     help1("I've got the first argument; will look now for the other.");
14904     mp_back_error(mp);
14905   }
14906   mp_get_x_next(mp); mp_scan_primary(mp);
14907 }
14908
14909 @ @<Scan a suffix with optional delimiters@>=
14910
14911   if ( mp->cur_cmd!=left_delimiter ) {
14912     l_delim=null;
14913   } else { 
14914     l_delim=mp->cur_sym; r_delim=mp->cur_mod; mp_get_x_next(mp);
14915   };
14916   mp_scan_suffix(mp);
14917   if ( l_delim!=null ) {
14918     if ((mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
14919       mp_missing_err(mp, str(text(r_delim)));
14920 @.Missing `)'@>
14921       help2("I've gotten to the end of the macro parameter list.")
14922          ("You might want to delete some tokens before continuing.");
14923       mp_back_error(mp);
14924     }
14925     mp_get_x_next(mp);
14926   }
14927 }
14928
14929 @ Before we put a new token list on the input stack, it is wise to clean off
14930 all token lists that have recently been depleted. Then a user macro that ends
14931 with a call to itself will not require unbounded stack space.
14932
14933 @<Feed the arguments and replacement text to the scanner@>=
14934 while ( token_state &&(loc==null) ) mp_end_token_list(mp); /* conserve stack space */
14935 if ( mp->param_ptr+n>mp->max_param_stack ) {
14936   mp->max_param_stack=mp->param_ptr+n;
14937   if ( mp->max_param_stack>mp->param_size )
14938     mp_overflow(mp, "parameter stack size",mp->param_size);
14939 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14940 }
14941 mp_begin_token_list(mp, def_ref,macro); name=macro_name; loc=r;
14942 if ( n>0 ) {
14943   p=arg_list;
14944   do {  
14945    mp->param_stack[mp->param_ptr]=info(p); incr(mp->param_ptr); p=link(p);
14946   } while (p!=null);
14947   mp_flush_list(mp, arg_list);
14948 }
14949
14950 @ It's sometimes necessary to put a single argument onto |param_stack|.
14951 The |stack_argument| subroutine does this.
14952
14953 @c void mp_stack_argument (MP mp,pointer p) { 
14954   if ( mp->param_ptr==mp->max_param_stack ) {
14955     incr(mp->max_param_stack);
14956     if ( mp->max_param_stack>mp->param_size )
14957       mp_overflow(mp, "parameter stack size",mp->param_size);
14958 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14959   }
14960   mp->param_stack[mp->param_ptr]=p; incr(mp->param_ptr);
14961 }
14962
14963 @* \[33] Conditional processing.
14964 Let's consider now the way \&{if} commands are handled.
14965
14966 Conditions can be inside conditions, and this nesting has a stack
14967 that is independent of other stacks.
14968 Four global variables represent the top of the condition stack:
14969 |cond_ptr| points to pushed-down entries, if~any; |cur_if| tells whether
14970 we are processing \&{if} or \&{elseif}; |if_limit| specifies
14971 the largest code of a |fi_or_else| command that is syntactically legal;
14972 and |if_line| is the line number at which the current conditional began.
14973
14974 If no conditions are currently in progress, the condition stack has the
14975 special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
14976 Otherwise |cond_ptr| points to a two-word node; the |type|, |name_type|, and
14977 |link| fields of the first word contain |if_limit|, |cur_if|, and
14978 |cond_ptr| at the next level, and the second word contains the
14979 corresponding |if_line|.
14980
14981 @d if_node_size 2 /* number of words in stack entry for conditionals */
14982 @d if_line_field(A) mp->mem[(A)+1].cint
14983 @d if_code 1 /* code for \&{if} being evaluated */
14984 @d fi_code 2 /* code for \&{fi} */
14985 @d else_code 3 /* code for \&{else} */
14986 @d else_if_code 4 /* code for \&{elseif} */
14987
14988 @<Glob...@>=
14989 pointer cond_ptr; /* top of the condition stack */
14990 integer if_limit; /* upper bound on |fi_or_else| codes */
14991 small_number cur_if; /* type of conditional being worked on */
14992 integer if_line; /* line where that conditional began */
14993
14994 @ @<Set init...@>=
14995 mp->cond_ptr=null; mp->if_limit=normal; mp->cur_if=0; mp->if_line=0;
14996
14997 @ @<Put each...@>=
14998 mp_primitive(mp, "if",if_test,if_code);
14999 @:if_}{\&{if} primitive@>
15000 mp_primitive(mp, "fi",fi_or_else,fi_code); mp->eqtb[frozen_fi]=mp->eqtb[mp->cur_sym];
15001 @:fi_}{\&{fi} primitive@>
15002 mp_primitive(mp, "else",fi_or_else,else_code);
15003 @:else_}{\&{else} primitive@>
15004 mp_primitive(mp, "elseif",fi_or_else,else_if_code);
15005 @:else_if_}{\&{elseif} primitive@>
15006
15007 @ @<Cases of |print_cmd_mod|...@>=
15008 case if_test:
15009 case fi_or_else: 
15010   switch (m) {
15011   case if_code:mp_print(mp, "if"); break;
15012   case fi_code:mp_print(mp, "fi");  break;
15013   case else_code:mp_print(mp, "else"); break;
15014   default: mp_print(mp, "elseif"); break;
15015   }
15016   break;
15017
15018 @ Here is a procedure that ignores text until coming to an \&{elseif},
15019 \&{else}, or \&{fi} at level zero of $\&{if}\ldots\&{fi}$
15020 nesting. After it has acted, |cur_mod| will indicate the token that
15021 was found.
15022
15023 \MP's smallest two command codes are |if_test| and |fi_or_else|; this
15024 makes the skipping process a bit simpler.
15025
15026 @c 
15027 void mp_pass_text (MP mp) {
15028   integer l = 0;
15029   mp->scanner_status=skipping;
15030   mp->warning_info=mp_true_line(mp);
15031   while (1)  { 
15032     get_t_next;
15033     if ( mp->cur_cmd<=fi_or_else ) {
15034       if ( mp->cur_cmd<fi_or_else ) {
15035         incr(l);
15036       } else { 
15037         if ( l==0 ) break;
15038         if ( mp->cur_mod==fi_code ) decr(l);
15039       }
15040     } else {
15041       @<Decrease the string reference count,
15042        if the current token is a string@>;
15043     }
15044   }
15045   mp->scanner_status=normal;
15046 }
15047
15048 @ @<Decrease the string reference count...@>=
15049 if ( mp->cur_cmd==string_token ) { delete_str_ref(mp->cur_mod); }
15050
15051 @ When we begin to process a new \&{if}, we set |if_limit:=if_code|; then
15052 if \&{elseif} or \&{else} or \&{fi} occurs before the current \&{if}
15053 condition has been evaluated, a colon will be inserted.
15054 A construction like `\.{if fi}' would otherwise get \MP\ confused.
15055
15056 @<Push the condition stack@>=
15057 { p=mp_get_node(mp, if_node_size); link(p)=mp->cond_ptr; type(p)=mp->if_limit;
15058   name_type(p)=mp->cur_if; if_line_field(p)=mp->if_line;
15059   mp->cond_ptr=p; mp->if_limit=if_code; mp->if_line=mp_true_line(mp); 
15060   mp->cur_if=if_code;
15061 }
15062
15063 @ @<Pop the condition stack@>=
15064 { p=mp->cond_ptr; mp->if_line=if_line_field(p);
15065   mp->cur_if=name_type(p); mp->if_limit=type(p); mp->cond_ptr=link(p);
15066   mp_free_node(mp, p,if_node_size);
15067 }
15068
15069 @ Here's a procedure that changes the |if_limit| code corresponding to
15070 a given value of |cond_ptr|.
15071
15072 @c void mp_change_if_limit (MP mp,small_number l, pointer p) {
15073   pointer q;
15074   if ( p==mp->cond_ptr ) {
15075     mp->if_limit=l; /* that's the easy case */
15076   } else  { 
15077     q=mp->cond_ptr;
15078     while (1) { 
15079       if ( q==null ) mp_confusion(mp, "if");
15080 @:this can't happen if}{\quad if@>
15081       if ( link(q)==p ) { 
15082         type(q)=l; return;
15083       }
15084       q=link(q);
15085     }
15086   }
15087 }
15088
15089 @ The user is supposed to put colons into the proper parts of conditional
15090 statements. Therefore, \MP\ has to check for their presence.
15091
15092 @c 
15093 void mp_check_colon (MP mp) { 
15094   if ( mp->cur_cmd!=colon ) { 
15095     mp_missing_err(mp, ":");
15096 @.Missing `:'@>
15097     help2("There should've been a colon after the condition.")
15098          ("I shall pretend that one was there.");;
15099     mp_back_error(mp);
15100   }
15101 }
15102
15103 @ A condition is started when the |get_x_next| procedure encounters
15104 an |if_test| command; in that case |get_x_next| calls |conditional|,
15105 which is a recursive procedure.
15106 @^recursion@>
15107
15108 @c void mp_conditional (MP mp) {
15109   pointer save_cond_ptr; /* |cond_ptr| corresponding to this conditional */
15110   int new_if_limit; /* future value of |if_limit| */
15111   pointer p; /* temporary register */
15112   @<Push the condition stack@>; 
15113   save_cond_ptr=mp->cond_ptr;
15114 RESWITCH: 
15115   mp_get_boolean(mp); new_if_limit=else_if_code;
15116   if ( mp->internal[tracing_commands]>unity ) {
15117     @<Display the boolean value of |cur_exp|@>;
15118   }
15119 FOUND: 
15120   mp_check_colon(mp);
15121   if ( mp->cur_exp==true_code ) {
15122     mp_change_if_limit(mp, new_if_limit,save_cond_ptr);
15123     return; /* wait for \&{elseif}, \&{else}, or \&{fi} */
15124   };
15125   @<Skip to \&{elseif} or \&{else} or \&{fi}, then |goto done|@>;
15126 DONE: 
15127   mp->cur_if=mp->cur_mod; mp->if_line=mp_true_line(mp);
15128   if ( mp->cur_mod==fi_code ) {
15129     @<Pop the condition stack@>
15130   } else if ( mp->cur_mod==else_if_code ) {
15131     goto RESWITCH;
15132   } else  { 
15133     mp->cur_exp=true_code; new_if_limit=fi_code; mp_get_x_next(mp); 
15134     goto FOUND;
15135   }
15136 }
15137
15138 @ In a construction like `\&{if} \&{if} \&{true}: $0=1$: \\{foo}
15139 \&{else}: \\{bar} \&{fi}', the first \&{else}
15140 that we come to after learning that the \&{if} is false is not the
15141 \&{else} we're looking for. Hence the following curious logic is needed.
15142
15143 @<Skip to \&{elseif}...@>=
15144 while (1) { 
15145   mp_pass_text(mp);
15146   if ( mp->cond_ptr==save_cond_ptr ) goto DONE;
15147   else if ( mp->cur_mod==fi_code ) @<Pop the condition stack@>;
15148 }
15149
15150
15151 @ @<Display the boolean value...@>=
15152 { mp_begin_diagnostic(mp);
15153   if ( mp->cur_exp==true_code ) mp_print(mp, "{true}");
15154   else mp_print(mp, "{false}");
15155   mp_end_diagnostic(mp, false);
15156 }
15157
15158 @ The processing of conditionals is complete except for the following
15159 code, which is actually part of |get_x_next|. It comes into play when
15160 \&{elseif}, \&{else}, or \&{fi} is scanned.
15161
15162 @<Terminate the current conditional and skip to \&{fi}@>=
15163 if ( mp->cur_mod>mp->if_limit ) {
15164   if ( mp->if_limit==if_code ) { /* condition not yet evaluated */
15165     mp_missing_err(mp, ":");
15166 @.Missing `:'@>
15167     mp_back_input(mp); mp->cur_sym=frozen_colon; mp_ins_error(mp);
15168   } else  { 
15169     print_err("Extra "); mp_print_cmd_mod(mp, fi_or_else,mp->cur_mod);
15170 @.Extra else@>
15171 @.Extra elseif@>
15172 @.Extra fi@>
15173     help1("I'm ignoring this; it doesn't match any if.");
15174     mp_error(mp);
15175   }
15176 } else  { 
15177   while ( mp->cur_mod!=fi_code ) mp_pass_text(mp); /* skip to \&{fi} */
15178   @<Pop the condition stack@>;
15179 }
15180
15181 @* \[34] Iterations.
15182 To bring our treatment of |get_x_next| to a close, we need to consider what
15183 \MP\ does when it sees \&{for}, \&{forsuffixes}, and \&{forever}.
15184
15185 There's a global variable |loop_ptr| that keeps track of the \&{for} loops
15186 that are currently active. If |loop_ptr=null|, no loops are in progress;
15187 otherwise |info(loop_ptr)| points to the iterative text of the current
15188 (innermost) loop, and |link(loop_ptr)| points to the data for any other
15189 loops that enclose the current one.
15190
15191 A loop-control node also has two other fields, called |loop_type| and
15192 |loop_list|, whose contents depend on the type of loop:
15193
15194 \yskip\indent|loop_type(loop_ptr)=null| means that |loop_list(loop_ptr)|
15195 points to a list of one-word nodes whose |info| fields point to the
15196 remaining argument values of a suffix list and expression list.
15197
15198 \yskip\indent|loop_type(loop_ptr)=diov| means that the current loop is
15199 `\&{forever}'.
15200
15201 \yskip\indent|loop_type(loop_ptr)=progression_flag| means that
15202 |p=loop_list(loop_ptr)| points to a ``progression node'' and |value(p)|,
15203 |step_size(p)|, and |final_value(p)| contain the data for an arithmetic
15204 progression.
15205
15206 \yskip\indent|loop_type(loop_ptr)=p>diov| means that |p| points to an edge
15207 header and |loop_list(loop_ptr)| points into the graphical object list for
15208 that edge header.
15209
15210 \yskip\noindent In the case of a progression node, the first word is not used
15211 because the link field of words in the dynamic memory area cannot be arbitrary.
15212
15213 @d loop_list_loc(A) ((A)+1) /* where the |loop_list| field resides */
15214 @d loop_type(A) info(loop_list_loc((A))) /* the type of \&{for} loop */
15215 @d loop_list(A) link(loop_list_loc((A))) /* the remaining list elements */
15216 @d loop_node_size 2 /* the number of words in a loop control node */
15217 @d progression_node_size 4 /* the number of words in a progression node */
15218 @d step_size(A) mp->mem[(A)+2].sc /* the step size in an arithmetic progression */
15219 @d final_value(A) mp->mem[(A)+3].sc /* the final value in an arithmetic progression */
15220 @d progression_flag (null+2)
15221   /* |loop_type| value when |loop_list| points to a progression node */
15222
15223 @<Glob...@>=
15224 pointer loop_ptr; /* top of the loop-control-node stack */
15225
15226 @ @<Set init...@>=
15227 mp->loop_ptr=null;
15228
15229 @ If the expressions that define an arithmetic progression in
15230 a \&{for} loop don't have known numeric values, the |bad_for|
15231 subroutine screams at the user.
15232
15233 @c void mp_bad_for (MP mp, char * s) {
15234   mp_disp_err(mp, null,"Improper "); /* show the bad expression above the message */
15235 @.Improper...replaced by 0@>
15236   mp_print(mp, s); mp_print(mp, " has been replaced by 0");
15237   help4("When you say `for x=a step b until c',")
15238     ("the initial value `a' and the step size `b'")
15239     ("and the final value `c' must have known numeric values.")
15240     ("I'm zeroing this one. Proceed, with fingers crossed.");
15241   mp_put_get_flush_error(mp, 0);
15242 };
15243
15244 @ Here's what \MP\ does when \&{for}, \&{forsuffixes}, or \&{forever}
15245 has just been scanned. (This code requires slight familiarity with
15246 expression-parsing routines that we have not yet discussed; but it seems
15247 to belong in the present part of the program, even though the original author
15248 didn't write it until later. The reader may wish to come back to it.)
15249
15250 @c void mp_begin_iteration (MP mp) {
15251   halfword m; /* |expr_base| (\&{for}) or |suffix_base| (\&{forsuffixes}) */
15252   halfword n; /* hash address of the current symbol */
15253   pointer s; /* the new loop-control node */
15254   pointer p; /* substitution list for |scan_toks| */
15255   pointer q;  /* link manipulation register */
15256   pointer pp; /* a new progression node */
15257   m=mp->cur_mod; n=mp->cur_sym; s=mp_get_node(mp, loop_node_size);
15258   if ( m==start_forever ){ 
15259     loop_type(s)=diov; p=null; mp_get_x_next(mp);
15260   } else { 
15261     mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
15262     info(p)=mp->cur_sym; value(p)=m;
15263     mp_get_x_next(mp);
15264     if ( mp->cur_cmd==within_token ) {
15265       @<Set up a picture iteration@>;
15266     } else { 
15267       @<Check for the |"="| or |":="| in a loop header@>;
15268       @<Scan the values to be used in the loop@>;
15269     }
15270   }
15271   @<Check for the presence of a colon@>;
15272   @<Scan the loop text and put it on the loop control stack@>;
15273   mp_resume_iteration(mp);
15274 }
15275
15276 @ @<Check for the |"="| or |":="| in a loop header@>=
15277 if ( (mp->cur_cmd!=equals)&&(mp->cur_cmd!=assignment) ) { 
15278   mp_missing_err(mp, "=");
15279 @.Missing `='@>
15280   help3("The next thing in this loop should have been `=' or `:='.")
15281     ("But don't worry; I'll pretend that an equals sign")
15282     ("was present, and I'll look for the values next.");
15283   mp_back_error(mp);
15284 }
15285
15286 @ @<Check for the presence of a colon@>=
15287 if ( mp->cur_cmd!=colon ) { 
15288   mp_missing_err(mp, ":");
15289 @.Missing `:'@>
15290   help3("The next thing in this loop should have been a `:'.")
15291     ("So I'll pretend that a colon was present;")
15292     ("everything from here to `endfor' will be iterated.");
15293   mp_back_error(mp);
15294 }
15295
15296 @ We append a special |frozen_repeat_loop| token in place of the
15297 `\&{endfor}' at the end of the loop. This will come through \MP's scanner
15298 at the proper time to cause the loop to be repeated.
15299
15300 (If the user tries some shenanigan like `\&{for} $\ldots$ \&{let} \&{endfor}',
15301 he will be foiled by the |get_symbol| routine, which keeps frozen
15302 tokens unchanged. Furthermore the |frozen_repeat_loop| is an \&{outer}
15303 token, so it won't be lost accidentally.)
15304
15305 @ @<Scan the loop text...@>=
15306 q=mp_get_avail(mp); info(q)=frozen_repeat_loop;
15307 mp->scanner_status=loop_defining; mp->warning_info=n;
15308 info(s)=mp_scan_toks(mp, iteration,p,q,0); mp->scanner_status=normal;
15309 link(s)=mp->loop_ptr; mp->loop_ptr=s
15310
15311 @ @<Initialize table...@>=
15312 eq_type(frozen_repeat_loop)=repeat_loop+outer_tag;
15313 text(frozen_repeat_loop)=intern(" ENDFOR");
15314
15315 @ The loop text is inserted into \MP's scanning apparatus by the
15316 |resume_iteration| routine.
15317
15318 @c void mp_resume_iteration (MP mp) {
15319   pointer p,q; /* link registers */
15320   p=loop_type(mp->loop_ptr);
15321   if ( p==progression_flag ) { 
15322     p=loop_list(mp->loop_ptr); /* now |p| points to a progression node */
15323     mp->cur_exp=value(p);
15324     if ( @<The arithmetic progression has ended@> ) {
15325       mp_stop_iteration(mp);
15326       return;
15327     }
15328     mp->cur_type=mp_known; q=mp_stash_cur_exp(mp); /* make |q| an \&{expr} argument */
15329     value(p)=mp->cur_exp+step_size(p); /* set |value(p)| for the next iteration */
15330   } else if ( p==null ) { 
15331     p=loop_list(mp->loop_ptr);
15332     if ( p==null ) {
15333       mp_stop_iteration(mp);
15334       return;
15335     }
15336     loop_list(mp->loop_ptr)=link(p); q=info(p); free_avail(p);
15337   } else if ( p==diov ) { 
15338     mp_begin_token_list(mp, info(mp->loop_ptr),forever_text); return;
15339   } else {
15340     @<Make |q| a capsule containing the next picture component from
15341       |loop_list(loop_ptr)| or |goto not_found|@>;
15342   }
15343   mp_begin_token_list(mp, info(mp->loop_ptr),loop_text);
15344   mp_stack_argument(mp, q);
15345   if ( mp->internal[tracing_commands]>unity ) {
15346      @<Trace the start of a loop@>;
15347   }
15348   return;
15349 NOT_FOUND:
15350   mp_stop_iteration(mp);
15351 }
15352
15353 @ @<The arithmetic progression has ended@>=
15354 ((step_size(p)>0)&&(mp->cur_exp>final_value(p)))||
15355  ((step_size(p)<0)&&(mp->cur_exp<final_value(p)))
15356
15357 @ @<Trace the start of a loop@>=
15358
15359   mp_begin_diagnostic(mp); mp_print_nl(mp, "{loop value=");
15360 @.loop value=n@>
15361   if ( (q!=null)&&(link(q)==diov) ) mp_print_exp(mp, q,1);
15362   else mp_show_token_list(mp, q,null,50,0);
15363   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
15364 }
15365
15366 @ @<Make |q| a capsule containing the next picture component from...@>=
15367 { q=loop_list(mp->loop_ptr);
15368   if ( q==null ) goto NOT_FOUND;
15369   skip_component(q) goto NOT_FOUND;
15370   mp->cur_exp=mp_copy_objects(mp, loop_list(mp->loop_ptr),q);
15371   mp_init_bbox(mp, mp->cur_exp);
15372   mp->cur_type=mp_picture_type;
15373   loop_list(mp->loop_ptr)=q;
15374   q=mp_stash_cur_exp(mp);
15375 }
15376
15377 @ A level of loop control disappears when |resume_iteration| has decided
15378 not to resume, or when an \&{exitif} construction has removed the loop text
15379 from the input stack.
15380
15381 @c void mp_stop_iteration (MP mp) {
15382   pointer p,q; /* the usual */
15383   p=loop_type(mp->loop_ptr);
15384   if ( p==progression_flag )  {
15385     mp_free_node(mp, loop_list(mp->loop_ptr),progression_node_size);
15386   } else if ( p==null ){ 
15387     q=loop_list(mp->loop_ptr);
15388     while ( q!=null ) {
15389       p=info(q);
15390       if ( p!=null ) {
15391         if ( link(p)==diov ) { /* it's an \&{expr} parameter */
15392           mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
15393         } else {
15394           mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
15395         }
15396       }
15397       p=q; q=link(q); free_avail(p);
15398     }
15399   } else if ( p>progression_flag ) {
15400     delete_edge_ref(p);
15401   }
15402   p=mp->loop_ptr; mp->loop_ptr=link(p); mp_flush_token_list(mp, info(p));
15403   mp_free_node(mp, p,loop_node_size);
15404 }
15405
15406 @ Now that we know all about loop control, we can finish up
15407 the missing portion of |begin_iteration| and we'll be done.
15408
15409 The following code is performed after the `\.=' has been scanned in
15410 a \&{for} construction (if |m=expr_base|) or a \&{forsuffixes} construction
15411 (if |m=suffix_base|).
15412
15413 @<Scan the values to be used in the loop@>=
15414 loop_type(s)=null; q=loop_list_loc(s); link(q)=null; /* |link(q)=loop_list(s)| */
15415 do {  
15416   mp_get_x_next(mp);
15417   if ( m!=expr_base ) {
15418     mp_scan_suffix(mp);
15419   } else { 
15420     if ( mp->cur_cmd>=colon ) if ( mp->cur_cmd<=comma ) 
15421           goto CONTINUE;
15422     mp_scan_expression(mp);
15423     if ( mp->cur_cmd==step_token ) if ( q==loop_list_loc(s) ) {
15424       @<Prepare for step-until construction and |break|@>;
15425     }
15426     mp->cur_exp=mp_stash_cur_exp(mp);
15427   }
15428   link(q)=mp_get_avail(mp); q=link(q); 
15429   info(q)=mp->cur_exp; mp->cur_type=mp_vacuous;
15430 CONTINUE:
15431   ;
15432 } while (mp->cur_cmd==comma)
15433
15434 @ @<Prepare for step-until construction and |break|@>=
15435
15436   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "initial value");
15437   pp=mp_get_node(mp, progression_node_size); value(pp)=mp->cur_exp;
15438   mp_get_x_next(mp); mp_scan_expression(mp);
15439   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "step size");
15440   step_size(pp)=mp->cur_exp;
15441   if ( mp->cur_cmd!=until_token ) { 
15442     mp_missing_err(mp, "until");
15443 @.Missing `until'@>
15444     help2("I assume you meant to say `until' after `step'.")
15445       ("So I'll look for the final value and colon next.");
15446     mp_back_error(mp);
15447   }
15448   mp_get_x_next(mp); mp_scan_expression(mp);
15449   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "final value");
15450   final_value(pp)=mp->cur_exp; loop_list(s)=pp;
15451   loop_type(s)=progression_flag; 
15452   break;
15453 }
15454
15455 @ The last case is when we have just seen ``\&{within}'', and we need to
15456 parse a picture expression and prepare to iterate over it.
15457
15458 @<Set up a picture iteration@>=
15459 { mp_get_x_next(mp);
15460   mp_scan_expression(mp);
15461   @<Make sure the current expression is a known picture@>;
15462   loop_type(s)=mp->cur_exp; mp->cur_type=mp_vacuous;
15463   q=link(dummy_loc(mp->cur_exp));
15464   if ( q!= null ) 
15465     if ( is_start_or_stop(q) )
15466       if ( mp_skip_1component(mp, q)==null ) q=link(q);
15467   loop_list(s)=q;
15468 }
15469
15470 @ @<Make sure the current expression is a known picture@>=
15471 if ( mp->cur_type!=mp_picture_type ) {
15472   mp_disp_err(mp, null,"Improper iteration spec has been replaced by nullpicture");
15473   help1("When you say `for x in p', p must be a known picture.");
15474   mp_put_get_flush_error(mp, mp_get_node(mp, edge_header_size));
15475   mp_init_edges(mp, mp->cur_exp); mp->cur_type=mp_picture_type;
15476 }
15477
15478 @* \[35] File names.
15479 It's time now to fret about file names.  Besides the fact that different
15480 operating systems treat files in different ways, we must cope with the
15481 fact that completely different naming conventions are used by different
15482 groups of people. The following programs show what is required for one
15483 particular operating system; similar routines for other systems are not
15484 difficult to devise.
15485 @^system dependencies@>
15486
15487 \MP\ assumes that a file name has three parts: the name proper; its
15488 ``extension''; and a ``file area'' where it is found in an external file
15489 system.  The extension of an input file is assumed to be
15490 `\.{.mp}' unless otherwise specified; it is `\.{.log}' on the
15491 transcript file that records each run of \MP; it is `\.{.tfm}' on the font
15492 metric files that describe characters in any fonts created by \MP; it is
15493 `\.{.ps}' or `.{\it nnn}' for some number {\it nnn} on the \ps\ output files;
15494 and it is `\.{.mem}' on the mem files written by \.{INIMP} to initialize \MP.
15495 The file area can be arbitrary on input files, but files are usually
15496 output to the user's current area.  If an input file cannot be
15497 found on the specified area, \MP\ will look for it on a special system
15498 area; this special area is intended for commonly used input files.
15499
15500 Simple uses of \MP\ refer only to file names that have no explicit
15501 extension or area. For example, a person usually says `\.{input} \.{cmr10}'
15502 instead of `\.{input} \.{cmr10.new}'. Simple file
15503 names are best, because they make the \MP\ source files portable;
15504 whenever a file name consists entirely of letters and digits, it should be
15505 treated in the same way by all implementations of \MP. However, users
15506 need the ability to refer to other files in their environment, especially
15507 when responding to error messages concerning unopenable files; therefore
15508 we want to let them use the syntax that appears in their favorite
15509 operating system.
15510
15511 @ \MP\ uses the same conventions that have proved to be satisfactory for
15512 \TeX\ and \MF. In order to isolate the system-dependent aspects of file names,
15513 @^system dependencies@>
15514 the system-independent parts of \MP\ are expressed in terms
15515 of three system-dependent
15516 procedures called |begin_name|, |more_name|, and |end_name|. In
15517 essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
15518 the system-independent driver program does the operations
15519 $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;|more_name|(c_n);
15520 \,|end_name|.$$
15521 These three procedures communicate with each other via global variables.
15522 Afterwards the file name will appear in the string pool as three strings
15523 called |cur_name|\penalty10000\hskip-.05em,
15524 |cur_area|, and |cur_ext|; the latter two are null (i.e.,
15525 |""|), unless they were explicitly specified by the user.
15526
15527 Actually the situation is slightly more complicated, because \MP\ needs
15528 to know when the file name ends. The |more_name| routine is a function
15529 (with side effects) that returns |true| on the calls |more_name|$(c_1)$,
15530 \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
15531 returns |false|; or, it returns |true| and $c_n$ is the last character
15532 on the current input line. In other words,
15533 |more_name| is supposed to return |true| unless it is sure that the
15534 file name has been completely scanned; and |end_name| is supposed to be able
15535 to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
15536 whether $|more_name|(c_n)$ returned |true| or |false|.
15537
15538 @<Glob...@>=
15539 char * cur_name; /* name of file just scanned */
15540 char * cur_area; /* file area just scanned, or \.{""} */
15541 char * cur_ext; /* file extension just scanned, or \.{""} */
15542
15543 @ It is easier to maintain reference counts if we assign initial values.
15544
15545 @<Set init...@>=
15546 mp->cur_name=xstrdup(""); 
15547 mp->cur_area=xstrdup(""); 
15548 mp->cur_ext=xstrdup("");
15549
15550 @ @<Dealloc variables@>=
15551 xfree(mp->cur_area);
15552 xfree(mp->cur_name);
15553 xfree(mp->cur_ext);
15554
15555 @ The file names we shall deal with for illustrative purposes have the
15556 following structure:  If the name contains `\.>' or `\.:', the file area
15557 consists of all characters up to and including the final such character;
15558 otherwise the file area is null.  If the remaining file name contains
15559 `\..', the file extension consists of all such characters from the first
15560 remaining `\..' to the end, otherwise the file extension is null.
15561 @^system dependencies@>
15562
15563 We can scan such file names easily by using two global variables that keep track
15564 of the occurrences of area and extension delimiters.  Note that these variables
15565 cannot be of type |pool_pointer| because a string pool compaction could occur
15566 while scanning a file name.
15567
15568 @<Glob...@>=
15569 integer area_delimiter;
15570   /* most recent `\.>' or `\.:' relative to |str_start[str_ptr]| */
15571 integer ext_delimiter; /* the relevant `\..', if any */
15572
15573 @ Input files that can't be found in the user's area may appear in standard
15574 system areas called |MP_area| and |MF_area|.  (The latter is used when the file
15575 extension is |".mf"|.)  The standard system area for font metric files
15576 to be read is |MP_font_area|.
15577 This system area name will, of course, vary from place to place.
15578 @^system dependencies@>
15579
15580 @d MP_area "MPinputs:"
15581 @.MPinputs@>
15582 @d MF_area "MFinputs:"
15583 @.MFinputs@>
15584 @d MP_font_area ""
15585 @.TeXfonts@>
15586
15587 @ Here now is the first of the system-dependent routines for file name scanning.
15588 @^system dependencies@>
15589
15590 @<Declare subroutines for parsing file names@>=
15591 void mp_begin_name (MP mp) { 
15592   xfree(mp->cur_name); 
15593   xfree(mp->cur_area); 
15594   xfree(mp->cur_ext);
15595   mp->area_delimiter=-1; 
15596   mp->ext_delimiter=-1;
15597 }
15598
15599 @ And here's the second.
15600 @^system dependencies@>
15601
15602 @<Declare subroutines for parsing file names@>=
15603 boolean mp_more_name (MP mp, ASCII_code c) { 
15604   if (c==' ') {
15605     return false;
15606   } else { 
15607     if ( (c=='>')||(c==':') ) { 
15608       mp->area_delimiter=mp->pool_ptr; 
15609       mp->ext_delimiter=-1;
15610     } else if ( (c=='.')&&(mp->ext_delimiter<0) ) {
15611       mp->ext_delimiter=mp->pool_ptr;
15612     }
15613     str_room(1); append_char(c); /* contribute |c| to the current string */
15614     return true;
15615   }
15616 }
15617
15618 @ The third.
15619 @^system dependencies@>
15620
15621 @d copy_pool_segment(A,B,C) { 
15622       A = xmalloc(C+1,sizeof(char)); 
15623       strncpy(A,(char *)(mp->str_pool+B),C);  
15624       A[C] = 0;}
15625
15626 @<Declare subroutines for parsing file names@>=
15627 void mp_end_name (MP mp) {
15628   pool_pointer s; /* length of area, name, and extension */
15629   unsigned int len;
15630   /* "my/w.mp" */
15631   s = mp->str_start[mp->str_ptr];
15632   if ( mp->area_delimiter<0 ) {    
15633     mp->cur_area=xstrdup("");
15634   } else {
15635     len = mp->area_delimiter-s; 
15636     copy_pool_segment(mp->cur_area,s,len);
15637     s += len+1;
15638   }
15639   if ( mp->ext_delimiter<0 ) {
15640     mp->cur_ext=xstrdup("");
15641     len = mp->pool_ptr-s; 
15642   } else {
15643     copy_pool_segment(mp->cur_ext,mp->ext_delimiter,(mp->pool_ptr-mp->ext_delimiter));
15644     len = mp->ext_delimiter-s;
15645   }
15646   copy_pool_segment(mp->cur_name,s,len);
15647   mp->pool_ptr=s; /* don't need this partial string */
15648 }
15649
15650 @ Conversely, here is a routine that takes three strings and prints a file
15651 name that might have produced them. (The routine is system dependent, because
15652 some operating systems put the file area last instead of first.)
15653 @^system dependencies@>
15654
15655 @<Basic printing...@>=
15656 void mp_print_file_name (MP mp, char * n, char * a, char * e) { 
15657   mp_print(mp, a); mp_print(mp, n); mp_print(mp, e);
15658 };
15659
15660 @ Another system-dependent routine is needed to convert three internal
15661 \MP\ strings
15662 to the |name_of_file| value that is used to open files. The present code
15663 allows both lowercase and uppercase letters in the file name.
15664 @^system dependencies@>
15665
15666 @d append_to_name(A) { c=(A); 
15667   if ( k<file_name_size ) {
15668     mp->name_of_file[k]=xchr(c);
15669     incr(k);
15670   }
15671 }
15672
15673 @<Declare subroutines for parsing file names@>=
15674 void mp_pack_file_name (MP mp, char *n, char *a, char *e) {
15675   integer k; /* number of positions filled in |name_of_file| */
15676   ASCII_code c; /* character being packed */
15677   char *j; /* a character  index */
15678   k=0;
15679   assert(n);
15680   if (a!=NULL) {
15681     for (j=a;*j;j++) { append_to_name(*j); }
15682   }
15683   for (j=n;*j;j++) { append_to_name(*j); }
15684   if (e!=NULL) {
15685     for (j=e;*j;j++) { append_to_name(*j); }
15686   }
15687   mp->name_of_file[k]=0;
15688   mp->name_length=k; 
15689 }
15690
15691 @ @<Exported...@>=
15692 void mp_pack_file_name (MP mp, char *n, char *a, char *e) ;
15693
15694 @ A messier routine is also needed, since mem file names must be scanned
15695 before \MP's string mechanism has been initialized. We shall use the
15696 global variable |MP_mem_default| to supply the text for default system areas
15697 and extensions related to mem files.
15698 @^system dependencies@>
15699
15700 @d mem_default_length 9 /* length of the |MP_mem_default| string */
15701 @d mem_ext_length 4 /* length of its `\.{.mem}' part */
15702 @d mem_extension ".mem" /* the extension, as a \.{WEB} constant */
15703
15704 @<Glob...@>=
15705 char *MP_mem_default;
15706 char *mem_name; /* for commandline */
15707
15708 @ @<Option variables@>=
15709 char *mem_name; /* for commandline */
15710
15711 @ @<Allocate or initialize ...@>=
15712 mp->MP_mem_default = xstrdup("plain.mem");
15713 mp->mem_name = mp_xstrdup(opt->mem_name);
15714 @.plain@>
15715 @^system dependencies@>
15716
15717 @ @<Dealloc variables@>=
15718 xfree(mp->MP_mem_default);
15719 xfree(mp->mem_name);
15720
15721 @ @<Check the ``constant'' values for consistency@>=
15722 if ( mem_default_length>file_name_size ) mp->bad=20;
15723
15724 @ Here is the messy routine that was just mentioned. It sets |name_of_file|
15725 from the first |n| characters of |MP_mem_default|, followed by
15726 |buffer[a..b]|, followed by the last |mem_ext_length| characters of
15727 |MP_mem_default|.
15728
15729 We dare not give error messages here, since \MP\ calls this routine before
15730 the |error| routine is ready to roll. Instead, we simply drop excess characters,
15731 since the error will be detected in another way when a strange file name
15732 isn't found.
15733 @^system dependencies@>
15734
15735 @c void mp_pack_buffered_name (MP mp,small_number n, integer a,
15736                                integer b) {
15737   integer k; /* number of positions filled in |name_of_file| */
15738   ASCII_code c; /* character being packed */
15739   integer j; /* index into |buffer| or |MP_mem_default| */
15740   if ( n+b-a+1+mem_ext_length>file_name_size )
15741     b=a+file_name_size-n-1-mem_ext_length;
15742   k=0;
15743   for (j=0;j<n;j++) {
15744     append_to_name(xord((int)mp->MP_mem_default[j]));
15745   }
15746   for (j=a;j<=b;j++) {
15747     append_to_name(mp->buffer[j]);
15748   }
15749   for (j=mem_default_length-mem_ext_length;
15750       j<mem_default_length;j++) {
15751     append_to_name(xord((int)mp->MP_mem_default[j]));
15752   } 
15753   mp->name_of_file[k]=0;
15754   mp->name_length=k; 
15755 }
15756
15757 @ Here is the only place we use |pack_buffered_name|. This part of the program
15758 becomes active when a ``virgin'' \MP\ is trying to get going, just after
15759 the preliminary initialization, or when the user is substituting another
15760 mem file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
15761 contains the first line of input in |buffer[loc..(last-1)]|, where
15762 |loc<last| and |buffer[loc]<>" "|.
15763
15764 @<Declarations@>=
15765 boolean mp_open_mem_file (MP mp) ;
15766
15767 @ @c
15768 boolean mp_open_mem_file (MP mp) {
15769   int j; /* the first space after the file name */
15770   if (mp->mem_name!=NULL) {
15771     mp->mem_file = mp_open_file(mp, mp->mem_name, "rb", mp_filetype_memfile);
15772     if ( mp->mem_file ) return true;
15773   }
15774   j=loc;
15775   if ( mp->buffer[loc]=='&' ) {
15776     incr(loc); j=loc; mp->buffer[mp->last]=' ';
15777     while ( mp->buffer[j]!=' ' ) incr(j);
15778     mp_pack_buffered_name(mp, 0,loc,j-1); /* try first without the system file area */
15779     if ( mp_w_open_in(mp, &mp->mem_file) ) goto FOUND;
15780     wake_up_terminal;
15781     wterm_ln("Sorry, I can\'t find that mem file; will try PLAIN.");
15782 @.Sorry, I can't find...@>
15783     update_terminal;
15784   }
15785   /* now pull out all the stops: try for the system \.{plain} file */
15786   mp_pack_buffered_name(mp, mem_default_length-mem_ext_length,0,0);
15787   if ( ! mp_w_open_in(mp, &mp->mem_file) ) {
15788     wake_up_terminal;
15789     wterm_ln("I can\'t find the PLAIN mem file!\n");
15790 @.I can't find PLAIN...@>
15791 @.plain@>
15792     return false;
15793   }
15794 FOUND:
15795   loc=j; return true;
15796 }
15797
15798 @ Operating systems often make it possible to determine the exact name (and
15799 possible version number) of a file that has been opened. The following routine,
15800 which simply makes a \MP\ string from the value of |name_of_file|, should
15801 ideally be changed to deduce the full name of file~|f|, which is the file
15802 most recently opened, if it is possible to do this in a \PASCAL\ program.
15803 @^system dependencies@>
15804
15805 @<Declarations@>=
15806 #define mp_a_make_name_string(A,B)  mp_make_name_string(A)
15807 #define mp_b_make_name_string(A,B)  mp_make_name_string(A)
15808 #define mp_w_make_name_string(A,B)  mp_make_name_string(A)
15809
15810 @ @c 
15811 str_number mp_make_name_string (MP mp) {
15812   int k; /* index into |name_of_file| */
15813   str_room(mp->name_length);
15814   for (k=0;k<mp->name_length;k++) {
15815     append_char(xord((int)mp->name_of_file[k]));
15816   }
15817   return mp_make_string(mp);
15818 }
15819
15820 @ Now let's consider the ``driver''
15821 routines by which \MP\ deals with file names
15822 in a system-independent manner.  First comes a procedure that looks for a
15823 file name in the input by taking the information from the input buffer.
15824 (We can't use |get_next|, because the conversion to tokens would
15825 destroy necessary information.)
15826
15827 This procedure doesn't allow semicolons or percent signs to be part of
15828 file names, because of other conventions of \MP.
15829 {\sl The {\logos METAFONT\/}book} doesn't
15830 use semicolons or percents immediately after file names, but some users
15831 no doubt will find it natural to do so; therefore system-dependent
15832 changes to allow such characters in file names should probably
15833 be made with reluctance, and only when an entire file name that
15834 includes special characters is ``quoted'' somehow.
15835 @^system dependencies@>
15836
15837 @c void mp_scan_file_name (MP mp) { 
15838   mp_begin_name(mp);
15839   while ( mp->buffer[loc]==' ' ) incr(loc);
15840   while (1) { 
15841     if ( (mp->buffer[loc]==';')||(mp->buffer[loc]=='%') ) break;
15842     if ( ! mp_more_name(mp, mp->buffer[loc]) ) break;
15843     incr(loc);
15844   }
15845   mp_end_name(mp);
15846 }
15847
15848 @ Here is another version that takes its input from a string.
15849
15850 @<Declare subroutines for parsing file names@>=
15851 void mp_str_scan_file (MP mp,  str_number s) {
15852   pool_pointer p,q; /* current position and stopping point */
15853   mp_begin_name(mp);
15854   p=mp->str_start[s]; q=str_stop(s);
15855   while ( p<q ){ 
15856     if ( ! mp_more_name(mp, mp->str_pool[p]) ) break;
15857     incr(p);
15858   }
15859   mp_end_name(mp);
15860 }
15861
15862 @ And one that reads from a |char*|.
15863
15864 @<Declare subroutines for parsing file names@>=
15865 void mp_ptr_scan_file (MP mp,  char *s) {
15866   char *p, *q; /* current position and stopping point */
15867   mp_begin_name(mp);
15868   p=s; q=p+strlen(s);
15869   while ( p<q ){ 
15870     if ( ! mp_more_name(mp, *p)) break;
15871     p++;
15872   }
15873   mp_end_name(mp);
15874 }
15875
15876
15877 @ The global variable |job_name| contains the file name that was first
15878 \&{input} by the user. This name is extended by `\.{.log}' and `\.{ps}' and
15879 `\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's output files.
15880
15881 @<Glob...@>=
15882 char *job_name; /* principal file name */
15883 boolean log_opened; /* has the transcript file been opened? */
15884 char *log_name; /* full name of the log file */
15885
15886 @ @<Option variables@>=
15887 char *job_name; /* principal file name */
15888
15889 @ Initially |job_name=NULL|; it becomes nonzero as soon as the true name is known.
15890 We have |job_name=NULL| if and only if the `\.{log}' file has not been opened,
15891 except of course for a short time just after |job_name| has become nonzero.
15892
15893 @<Allocate or ...@>=
15894 mp->job_name=opt->job_name; 
15895 mp->log_opened=false;
15896
15897 @ @<Dealloc variables@>=
15898 xfree(mp->job_name);
15899
15900 @ Here is a routine that manufactures the output file names, assuming that
15901 |job_name<>0|. It ignores and changes the current settings of |cur_area|
15902 and |cur_ext|.
15903
15904 @d pack_cur_name mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext)
15905
15906 @<Declarations@>=
15907 void mp_pack_job_name (MP mp, char *s) ;
15908
15909 @ @c void mp_pack_job_name (MP mp, char  *s) { /* |s = ".log"|, |".mem"|, |".ps"|, or .\\{nnn} */
15910   xfree(mp->cur_name); mp->cur_name=xstrdup(mp->job_name);
15911   xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
15912   xfree(mp->cur_ext);  mp->cur_ext=xstrdup(s);
15913   pack_cur_name;
15914 }
15915
15916 @ If some trouble arises when \MP\ tries to open a file, the following
15917 routine calls upon the user to supply another file name. Parameter~|s|
15918 is used in the error message to identify the type of file; parameter~|e|
15919 is the default extension if none is given. Upon exit from the routine,
15920 variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
15921 ready for another attempt at file opening.
15922
15923 @<Declarations@>=
15924 void mp_prompt_file_name (MP mp,char * s, char * e) ;
15925
15926 @ @c void mp_prompt_file_name (MP mp,char * s, char * e) {
15927   size_t k; /* index into |buffer| */
15928   char * saved_cur_name;
15929   if ( mp->interaction==mp_scroll_mode ) 
15930         wake_up_terminal;
15931   if (strcmp(s,"input file name")==0) {
15932         print_err("I can\'t find file `");
15933 @.I can't find file x@>
15934   } else {
15935         print_err("I can\'t write on file `");
15936   }
15937 @.I can't write on file x@>
15938   mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext); 
15939   mp_print(mp, "'.");
15940   if (strcmp(e,"")==0) 
15941         mp_show_context(mp);
15942   mp_print_nl(mp, "Please type another "); mp_print(mp, s);
15943 @.Please type...@>
15944   if ( mp->interaction<mp_scroll_mode )
15945     mp_fatal_error(mp, "*** (job aborted, file error in nonstop mode)");
15946 @.job aborted, file error...@>
15947   saved_cur_name = xstrdup(mp->cur_name);
15948   clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
15949   if (strcmp(mp->cur_ext,"")==0) 
15950         mp->cur_ext=e;
15951   if (strlen(mp->cur_name)==0) {
15952     mp->cur_name=saved_cur_name;
15953   } else {
15954     xfree(saved_cur_name);
15955   }
15956   pack_cur_name;
15957 }
15958
15959 @ @<Scan file name in the buffer@>=
15960
15961   mp_begin_name(mp); k=mp->first;
15962   while ( (mp->buffer[k]==' ')&&(k<mp->last) ) incr(k);
15963   while (1) { 
15964     if ( k==mp->last ) break;
15965     if ( ! mp_more_name(mp, mp->buffer[k]) ) break;
15966     incr(k);
15967   }
15968   mp_end_name(mp);
15969 }
15970
15971 @ The |open_log_file| routine is used to open the transcript file and to help
15972 it catch up to what has previously been printed on the terminal.
15973
15974 @c void mp_open_log_file (MP mp) {
15975   int old_setting; /* previous |selector| setting */
15976   int k; /* index into |months| and |buffer| */
15977   int l; /* end of first input line */
15978   integer m; /* the current month */
15979   char *months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 
15980     /* abbreviations of month names */
15981   old_setting=mp->selector;
15982   if ( mp->job_name==NULL ) {
15983      mp->job_name=xstrdup("mpout");
15984   }
15985   mp_pack_job_name(mp,".log");
15986   while ( ! mp_a_open_out(mp, &mp->log_file, mp_filetype_log) ) {
15987     @<Try to get a different log file name@>;
15988   }
15989   mp->log_name=xstrdup(mp->name_of_file);
15990   mp->selector=log_only; mp->log_opened=true;
15991   @<Print the banner line, including the date and time@>;
15992   mp->input_stack[mp->input_ptr]=mp->cur_input; 
15993     /* make sure bottom level is in memory */
15994   mp_print_nl(mp, "**");
15995 @.**@>
15996   l=mp->input_stack[0].limit_field-1; /* last position of first line */
15997   for (k=0;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
15998   mp_print_ln(mp); /* now the transcript file contains the first line of input */
15999   mp->selector=old_setting+2; /* |log_only| or |term_and_log| */
16000 }
16001
16002 @ @<Dealloc variables@>=
16003 xfree(mp->log_name);
16004
16005 @ Sometimes |open_log_file| is called at awkward moments when \MP\ is
16006 unable to print error messages or even to |show_context|.
16007 The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
16008 routine will not be invoked because |log_opened| will be false.
16009
16010 The normal idea of |mp_batch_mode| is that nothing at all should be written
16011 on the terminal. However, in the unusual case that
16012 no log file could be opened, we make an exception and allow
16013 an explanatory message to be seen.
16014
16015 Incidentally, the program always refers to the log file as a `\.{transcript
16016 file}', because some systems cannot use the extension `\.{.log}' for
16017 this file.
16018
16019 @<Try to get a different log file name@>=
16020 {  
16021   mp->selector=term_only;
16022   mp_prompt_file_name(mp, "transcript file name",".log");
16023 }
16024
16025 @ @<Print the banner...@>=
16026
16027   wlog(banner);
16028   mp_print(mp, mp->mem_ident); mp_print(mp, "  ");
16029   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[day])); 
16030   mp_print_char(mp, ' ');
16031   m=mp_round_unscaled(mp, mp->internal[month]);
16032   for (k=3*m-3;k<3*m;k++) { wlog_chr(months[k]); }
16033   mp_print_char(mp, ' '); 
16034   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[year])); 
16035   mp_print_char(mp, ' ');
16036   m=mp_round_unscaled(mp, mp->internal[mp_time]);
16037   mp_print_dd(mp, m / 60); mp_print_char(mp, ':'); mp_print_dd(mp, m % 60);
16038 }
16039
16040 @ The |try_extension| function tries to open an input file determined by
16041 |cur_name|, |cur_area|, and the argument |ext|.  It returns |false| if it
16042 can't find the file in |cur_area| or the appropriate system area.
16043
16044 @c boolean mp_try_extension (MP mp,char *ext) { 
16045   mp_pack_file_name(mp, mp->cur_name,mp->cur_area, ext);
16046   in_name=xstrdup(mp->cur_name); 
16047   in_area=xstrdup(mp->cur_area);
16048   if ( mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16049     return true;
16050   } else { 
16051     if (strcmp(ext,".mf")==0 ) in_area=xstrdup(MF_area);
16052     else in_area=xstrdup(MP_area);
16053     mp_pack_file_name(mp, mp->cur_name,in_area,ext);
16054     return mp_a_open_in(mp, &cur_file, mp_filetype_program);
16055   }
16056   return false;
16057 }
16058
16059 @ Let's turn now to the procedure that is used to initiate file reading
16060 when an `\.{input}' command is being processed.
16061
16062 @c void mp_start_input (MP mp) { /* \MP\ will \.{input} something */
16063   char *fname = NULL;
16064   @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>;
16065   while (1) { 
16066     mp_begin_file_reading(mp); /* set up |cur_file| and new level of input */
16067     if ( strlen(mp->cur_ext)==0 ) {
16068       if ( mp_try_extension(mp, ".mp") ) break;
16069       else if ( mp_try_extension(mp, "") ) break;
16070       else if ( mp_try_extension(mp, ".mf") ) break;
16071       /* |else do_nothing; | */
16072     } else if ( mp_try_extension(mp, mp->cur_ext) ) {
16073       break;
16074     }
16075     mp_end_file_reading(mp); /* remove the level that didn't work */
16076     mp_prompt_file_name(mp, "input file name","");
16077   }
16078   name=mp_a_make_name_string(mp, cur_file);
16079   fname = xstrdup(mp->name_of_file);
16080   if ( mp->job_name==NULL ) {
16081     mp->job_name=xstrdup(mp->cur_name); 
16082     mp_open_log_file(mp);
16083   } /* |open_log_file| doesn't |show_context|, so |limit|
16084         and |loc| needn't be set to meaningful values yet */
16085   if ( ((int)mp->term_offset+(int)strlen(fname)) > (mp->max_print_line-2)) mp_print_ln(mp);
16086   else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
16087   mp_print_char(mp, '('); incr(mp->open_parens); mp_print(mp, fname); 
16088   xfree(fname);
16089   update_terminal;
16090   @<Flush |name| and replace it with |cur_name| if it won't be needed@>;
16091   @<Read the first line of the new file@>;
16092 }
16093
16094 @ This code should be omitted if |a_make_name_string| returns something other
16095 than just a copy of its argument and the full file name is needed for opening
16096 \.{MPX} files or implementing the switch-to-editor option.
16097 @^system dependencies@>
16098
16099 @<Flush |name| and replace it with |cur_name| if it won't be needed@>=
16100 mp_flush_string(mp, name); name=rts(mp->cur_name); xfree(mp->cur_name)
16101
16102 @ Here we have to remember to tell the |input_ln| routine not to
16103 start with a |get|. If the file is empty, it is considered to
16104 contain a single blank line.
16105 @^system dependencies@>
16106
16107 @<Read the first line...@>=
16108
16109   line=1;
16110   (void)mp_input_ln(mp, cur_file,false); 
16111   mp_firm_up_the_line(mp);
16112   mp->buffer[limit]='%'; mp->first=limit+1; loc=start;
16113 }
16114
16115 @ @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>=
16116 while ( token_state &&(loc==null) ) mp_end_token_list(mp);
16117 if ( token_state ) { 
16118   print_err("File names can't appear within macros");
16119 @.File names can't...@>
16120   help3("Sorry...I've converted what follows to tokens,")
16121     ("possibly garbaging the name you gave.")
16122     ("Please delete the tokens and insert the name again.");
16123   mp_error(mp);
16124 }
16125 if ( file_state ) {
16126   mp_scan_file_name(mp);
16127 } else { 
16128    xfree(mp->cur_name); mp->cur_name=xstrdup(""); 
16129    xfree(mp->cur_ext);  mp->cur_ext =xstrdup(""); 
16130    xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16131 }
16132
16133 @ Sometimes we need to deal with two file names at once.  This procedure
16134 copies the given string into a special array for an old file name.
16135
16136 @c void mp_copy_old_name (MP mp,str_number s) {
16137   integer k; /* number of positions filled in |old_file_name| */
16138   pool_pointer j; /* index into |str_pool| */
16139   k=0;
16140   for (j=mp->str_start[s];j<=str_stop(s)-1;j++) { 
16141     incr(k);
16142     if ( k<=file_name_size ) 
16143       mp->old_file_name[k]=xchr(mp->str_pool[j]);
16144   }
16145   mp->old_file_name[++k] = 0;
16146 }
16147
16148 @ @<Glob...@>=
16149 char old_file_name[file_name_size+1];  /* analogous to |name_of_file| */
16150
16151 @ The following simple routine starts reading the \.{MPX} file associated
16152 with the current input file.
16153
16154 @c void mp_start_mpx_input (MP mp) {
16155   mp_pack_file_name(mp, in_name, in_area, ".mpx");
16156   @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16157     |goto not_found| if there is a problem@>;
16158   mp_begin_file_reading(mp);
16159   if ( ! mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16160     mp_end_file_reading(mp);
16161     goto NOT_FOUND;
16162   }
16163   name=mp_a_make_name_string(mp, cur_file);
16164   mp->mpx_name[index]=name; add_str_ref(name);
16165   @<Read the first line of the new file@>;
16166   return;
16167 NOT_FOUND: 
16168     @<Explain that the \.{MPX} file can't be read and |succumb|@>;
16169 }
16170
16171 @ This should ideally be changed to do whatever is necessary to create the
16172 \.{MPX} file given by |name_of_file| if it does not exist or if it is out
16173 of date.  This requires invoking \.{MPtoTeX} on the |old_file_name| and passing
16174 the results through \TeX\ and \.{DVItoMP}.  (It is possible to use a
16175 completely different typesetting program if suitable postprocessor is
16176 available to perform the function of \.{DVItoMP}.)
16177 @^system dependencies@>
16178
16179 @ @<Types...@>=
16180 typedef boolean (*run_make_mpx_command)(MP mp, char *origname, char *mtxname);
16181
16182 @ @<Glob...@>=
16183 run_make_mpx_command run_make_mpx;
16184
16185 @ @<Option variables@>=
16186 run_make_mpx_command run_make_mpx;
16187
16188 @ @<Allocate or initialize ...@>=
16189 set_callback_option(run_make_mpx);
16190
16191 @ @<Exported function headers@>=
16192 boolean mp_run_make_mpx (MP mp, char *origname, char *mtxname);
16193
16194 @ The default does nothing.
16195 @c 
16196 boolean mp_run_make_mpx (MP mp, char *origname, char *mtxname) {
16197   if (mp && origname && mtxname) /* for -W */
16198     return false;
16199   return false;
16200 }
16201
16202
16203
16204 @ @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16205   |goto not_found| if there is a problem@>=
16206 mp_copy_old_name(mp, name);
16207 if (!(mp->run_make_mpx)(mp, mp->old_file_name, mp->name_of_file))
16208    goto NOT_FOUND
16209
16210 @ @<Explain that the \.{MPX} file can't be read and |succumb|@>=
16211 if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16212 mp_print_nl(mp, ">> ");
16213 mp_print(mp, mp->old_file_name);
16214 mp_print_nl(mp, ">> ");
16215 mp_print(mp, mp->name_of_file);
16216 mp_print_nl(mp, "! Unable to make mpx file");
16217 help4("The two files given above are one of your source files")
16218   ("and an auxiliary file I need to read to find out what your")
16219   ("btex..etex blocks mean. If you don't know why I had trouble,")
16220   ("try running it manually through MPtoTeX, TeX, and DVItoMP");
16221 succumb;
16222
16223 @ The last file-opening commands are for files accessed via the \&{readfrom}
16224 @:read_from_}{\&{readfrom} primitive@>
16225 operator and the \&{write} command.  Such files are stored in separate arrays.
16226 @:write_}{\&{write} primitive@>
16227
16228 @<Types in the outer block@>=
16229 typedef unsigned int readf_index; /* |0..max_read_files| */
16230 typedef unsigned int write_index;  /* |0..max_write_files| */
16231
16232 @ @<Glob...@>=
16233 readf_index max_read_files; /* maximum number of simultaneously open \&{readfrom} files */
16234 FILE ** rd_file; /* \&{readfrom} files */
16235 char ** rd_fname; /* corresponding file name or 0 if file not open */
16236 readf_index read_files; /* number of valid entries in the above arrays */
16237 write_index max_write_files; /* maximum number of simultaneously open \&{write} */
16238 FILE ** wr_file; /* \&{write} files */
16239 char ** wr_fname; /* corresponding file name or 0 if file not open */
16240 write_index write_files; /* number of valid entries in the above arrays */
16241
16242 @ @<Allocate or initialize ...@>=
16243 mp->max_read_files=8;
16244 mp->rd_file = xmalloc((mp->max_read_files+1),sizeof(FILE *));
16245 mp->rd_fname = xmalloc((mp->max_read_files+1),sizeof(char *));
16246 memset(mp->rd_fname, 0, sizeof(char *)*(mp->max_read_files+1));
16247 mp->read_files=0;
16248 mp->max_write_files=8;
16249 mp->wr_file = xmalloc((mp->max_write_files+1),sizeof(FILE *));
16250 mp->wr_fname = xmalloc((mp->max_write_files+1),sizeof(char *));
16251 memset(mp->wr_fname, 0, sizeof(char *)*(mp->max_write_files+1));
16252 mp->write_files=0;
16253
16254
16255 @ This routine starts reading the file named by string~|s| without setting
16256 |loc|, |limit|, or |name|.  It returns |false| if the file is empty or cannot
16257 be opened.  Otherwise it updates |rd_file[n]| and |rd_fname[n]|.
16258
16259 @c boolean mp_start_read_input (MP mp,char *s, readf_index  n) {
16260   mp_ptr_scan_file(mp, s);
16261   pack_cur_name;
16262   mp_begin_file_reading(mp);
16263   if ( ! mp_a_open_in(mp, &mp->rd_file[n], mp_filetype_text) ) 
16264         goto NOT_FOUND;
16265   if ( ! mp_input_ln(mp, mp->rd_file[n], false) ) {
16266     fclose(mp->rd_file[n]); 
16267         goto NOT_FOUND; 
16268   }
16269   mp->rd_fname[n]=xstrdup(mp->name_of_file);
16270   return true;
16271 NOT_FOUND: 
16272   mp_end_file_reading(mp);
16273   return false;
16274 }
16275
16276 @ Open |wr_file[n]| using file name~|s| and update |wr_fname[n]|.
16277
16278 @<Declarations@>=
16279 void mp_open_write_file (MP mp, char *s, readf_index  n) ;
16280
16281 @ @c void mp_open_write_file (MP mp,char *s, readf_index  n) {
16282   mp_ptr_scan_file(mp, s);
16283   pack_cur_name;
16284   while ( ! mp_a_open_out(mp, &mp->wr_file[n], mp_filetype_text) )
16285     mp_prompt_file_name(mp, "file name for write output","");
16286   mp->wr_fname[n]=xstrdup(mp->name_of_file);
16287 }
16288
16289
16290 @* \[36] Introduction to the parsing routines.
16291 We come now to the central nervous system that sparks many of \MP's activities.
16292 By evaluating expressions, from their primary constituents to ever larger
16293 subexpressions, \MP\ builds the structures that ultimately define complete
16294 pictures or fonts of type.
16295
16296 Four mutually recursive subroutines are involved in this process: We call them
16297 $$\hbox{|scan_primary|, |scan_secondary|, |scan_tertiary|,
16298 and |scan_expression|.}$$
16299 @^recursion@>
16300 Each of them is parameterless and begins with the first token to be scanned
16301 already represented in |cur_cmd|, |cur_mod|, and |cur_sym|. After execution,
16302 the value of the primary or secondary or tertiary or expression that was
16303 found will appear in the global variables |cur_type| and |cur_exp|. The
16304 token following the expression will be represented in |cur_cmd|, |cur_mod|,
16305 and |cur_sym|.
16306
16307 Technically speaking, the parsing algorithms are ``LL(1),'' more or less;
16308 backup mechanisms have been added in order to provide reasonable error
16309 recovery.
16310
16311 @<Glob...@>=
16312 small_number cur_type; /* the type of the expression just found */
16313 integer cur_exp; /* the value of the expression just found */
16314
16315 @ @<Set init...@>=
16316 mp->cur_exp=0;
16317
16318 @ Many different kinds of expressions are possible, so it is wise to have
16319 precise descriptions of what |cur_type| and |cur_exp| mean in all cases:
16320
16321 \smallskip\hang
16322 |cur_type=mp_vacuous| means that this expression didn't turn out to have a
16323 value at all, because it arose from a \&{begingroup}$\,\ldots\,$\&{endgroup}
16324 construction in which there was no expression before the \&{endgroup}.
16325 In this case |cur_exp| has some irrelevant value.
16326
16327 \smallskip\hang
16328 |cur_type=mp_boolean_type| means that |cur_exp| is either |true_code|
16329 or |false_code|.
16330
16331 \smallskip\hang
16332 |cur_type=mp_unknown_boolean| means that |cur_exp| points to a capsule
16333 node that is in the ring of variables equivalent
16334 to at least one undefined boolean variable.
16335
16336 \smallskip\hang
16337 |cur_type=mp_string_type| means that |cur_exp| is a string number (i.e., an
16338 integer in the range |0<=cur_exp<str_ptr|). That string's reference count
16339 includes this particular reference.
16340
16341 \smallskip\hang
16342 |cur_type=mp_unknown_string| means that |cur_exp| points to a capsule
16343 node that is in the ring of variables equivalent
16344 to at least one undefined string variable.
16345
16346 \smallskip\hang
16347 |cur_type=mp_pen_type| means that |cur_exp| points to a node in a pen.  Nobody
16348 else points to any of the nodes in this pen.  The pen may be polygonal or
16349 elliptical.
16350
16351 \smallskip\hang
16352 |cur_type=mp_unknown_pen| means that |cur_exp| points to a capsule
16353 node that is in the ring of variables equivalent
16354 to at least one undefined pen variable.
16355
16356 \smallskip\hang
16357 |cur_type=mp_path_type| means that |cur_exp| points to a the first node of
16358 a path; nobody else points to this particular path. The control points of
16359 the path will have been chosen.
16360
16361 \smallskip\hang
16362 |cur_type=mp_unknown_path| means that |cur_exp| points to a capsule
16363 node that is in the ring of variables equivalent
16364 to at least one undefined path variable.
16365
16366 \smallskip\hang
16367 |cur_type=mp_picture_type| means that |cur_exp| points to an edge header node.
16368 There may be other pointers to this particular set of edges.  The header node
16369 contains a reference count that includes this particular reference.
16370
16371 \smallskip\hang
16372 |cur_type=mp_unknown_picture| means that |cur_exp| points to a capsule
16373 node that is in the ring of variables equivalent
16374 to at least one undefined picture variable.
16375
16376 \smallskip\hang
16377 |cur_type=mp_transform_type| means that |cur_exp| points to a |mp_transform_type|
16378 capsule node. The |value| part of this capsule
16379 points to a transform node that contains six numeric values,
16380 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16381
16382 \smallskip\hang
16383 |cur_type=mp_color_type| means that |cur_exp| points to a |color_type|
16384 capsule node. The |value| part of this capsule
16385 points to a color node that contains three numeric values,
16386 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16387
16388 \smallskip\hang
16389 |cur_type=mp_cmykcolor_type| means that |cur_exp| points to a |mp_cmykcolor_type|
16390 capsule node. The |value| part of this capsule
16391 points to a color node that contains four numeric values,
16392 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16393
16394 \smallskip\hang
16395 |cur_type=mp_pair_type| means that |cur_exp| points to a capsule
16396 node whose type is |mp_pair_type|. The |value| part of this capsule
16397 points to a pair node that contains two numeric values,
16398 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16399
16400 \smallskip\hang
16401 |cur_type=mp_known| means that |cur_exp| is a |scaled| value.
16402
16403 \smallskip\hang
16404 |cur_type=mp_dependent| means that |cur_exp| points to a capsule node whose type
16405 is |dependent|. The |dep_list| field in this capsule points to the associated
16406 dependency list.
16407
16408 \smallskip\hang
16409 |cur_type=mp_proto_dependent| means that |cur_exp| points to a |mp_proto_dependent|
16410 capsule node. The |dep_list| field in this capsule
16411 points to the associated dependency list.
16412
16413 \smallskip\hang
16414 |cur_type=independent| means that |cur_exp| points to a capsule node
16415 whose type is |independent|. This somewhat unusual case can arise, for
16416 example, in the expression
16417 `$x+\&{begingroup}\penalty0\,\&{string}\,x; 0\,\&{endgroup}$'.
16418
16419 \smallskip\hang
16420 |cur_type=mp_token_list| means that |cur_exp| points to a linked list of
16421 tokens. This case arises only on the left-hand side of an assignment
16422 (`\.{:=}') operation, under very special circumstances.
16423
16424 \smallskip\noindent
16425 The possible settings of |cur_type| have been listed here in increasing
16426 numerical order. Notice that |cur_type| will never be |mp_numeric_type| or
16427 |suffixed_macro| or |mp_unsuffixed_macro|, although variables of those types
16428 are allowed.  Conversely, \MP\ has no variables of type |mp_vacuous| or
16429 |token_list|.
16430
16431 @ Capsules are two-word nodes that have a similar meaning
16432 to |cur_type| and |cur_exp|. Such nodes have |name_type=capsule|
16433 and |link<=diov|; and their |type| field is one of the possibilities for
16434 |cur_type| listed above.
16435
16436 The |value| field of a capsule is, in most cases, the value that
16437 corresponds to its |type|, as |cur_exp| corresponds to |cur_type|.
16438 However, when |cur_exp| would point to a capsule,
16439 no extra layer of indirection is present; the |value|
16440 field is what would have been called |value(cur_exp)| if it had not been
16441 encapsulated.  Furthermore, if the type is |dependent| or
16442 |mp_proto_dependent|, the |value| field of a capsule is replaced by
16443 |dep_list| and |prev_dep| fields, since dependency lists in capsules are
16444 always part of the general |dep_list| structure.
16445
16446 The |get_x_next| routine is careful not to change the values of |cur_type|
16447 and |cur_exp| when it gets an expanded token. However, |get_x_next| might
16448 call a macro, which might parse an expression, which might execute lots of
16449 commands in a group; hence it's possible that |cur_type| might change
16450 from, say, |mp_unknown_boolean| to |mp_boolean_type|, or from |dependent| to
16451 |known| or |independent|, during the time |get_x_next| is called. The
16452 programs below are careful to stash sensitive intermediate results in
16453 capsules, so that \MP's generality doesn't cause trouble.
16454
16455 Here's a procedure that illustrates these conventions. It takes
16456 the contents of $(|cur_type|\kern-.3pt,|cur_exp|\kern-.3pt)$
16457 and stashes them away in a
16458 capsule. It is not used when |cur_type=mp_token_list|.
16459 After the operation, |cur_type=mp_vacuous|; hence there is no need to
16460 copy path lists or to update reference counts, etc.
16461
16462 The special link |diov| is put on the capsule returned by
16463 |stash_cur_exp|, because this procedure is used to store macro parameters
16464 that must be easily distinguishable from token lists.
16465
16466 @<Declare the stashing/unstashing routines@>=
16467 pointer mp_stash_cur_exp (MP mp) {
16468   pointer p; /* the capsule that will be returned */
16469   switch (mp->cur_type) {
16470   case unknown_types:
16471   case mp_transform_type:
16472   case mp_color_type:
16473   case mp_pair_type:
16474   case mp_dependent:
16475   case mp_proto_dependent:
16476   case mp_independent: 
16477   case mp_cmykcolor_type:
16478     p=mp->cur_exp;
16479     break;
16480   default: 
16481     p=mp_get_node(mp, value_node_size); name_type(p)=mp_capsule;
16482     type(p)=mp->cur_type; value(p)=mp->cur_exp;
16483     break;
16484   }
16485   mp->cur_type=mp_vacuous; link(p)=diov; 
16486   return p;
16487 }
16488
16489 @ The inverse of |stash_cur_exp| is the following procedure, which
16490 deletes an unnecessary capsule and puts its contents into |cur_type|
16491 and |cur_exp|.
16492
16493 The program steps of \MP\ can be divided into two categories: those in
16494 which |cur_type| and |cur_exp| are ``alive'' and those in which they are
16495 ``dead,'' in the sense that |cur_type| and |cur_exp| contain relevant
16496 information or not. It's important not to ignore them when they're alive,
16497 and it's important not to pay attention to them when they're dead.
16498
16499 There's also an intermediate category: If |cur_type=mp_vacuous|, then
16500 |cur_exp| is irrelevant, hence we can proceed without caring if |cur_type|
16501 and |cur_exp| are alive or dead. In such cases we say that |cur_type|
16502 and |cur_exp| are {\sl dormant}. It is permissible to call |get_x_next|
16503 only when they are alive or dormant.
16504
16505 The \\{stash} procedure above assumes that |cur_type| and |cur_exp|
16506 are alive or dormant. The \\{unstash} procedure assumes that they are
16507 dead or dormant; it resuscitates them.
16508
16509 @<Declare the stashing/unstashing...@>=
16510 void mp_unstash_cur_exp (MP mp,pointer p) ;
16511
16512 @ @c
16513 void mp_unstash_cur_exp (MP mp,pointer p) { 
16514   mp->cur_type=type(p);
16515   switch (mp->cur_type) {
16516   case unknown_types:
16517   case mp_transform_type:
16518   case mp_color_type:
16519   case mp_pair_type:
16520   case mp_dependent: 
16521   case mp_proto_dependent:
16522   case mp_independent:
16523   case mp_cmykcolor_type: 
16524     mp->cur_exp=p;
16525     break;
16526   default:
16527     mp->cur_exp=value(p);
16528     mp_free_node(mp, p,value_node_size);
16529     break;
16530   }
16531 }
16532
16533 @ The following procedure prints the values of expressions in an
16534 abbreviated format. If its first parameter |p| is null, the value of
16535 |(cur_type,cur_exp)| is displayed; otherwise |p| should be a capsule
16536 containing the desired value. The second parameter controls the amount of
16537 output. If it is~0, dependency lists will be abbreviated to
16538 `\.{linearform}' unless they consist of a single term.  If it is greater
16539 than~1, complicated structures (pens, pictures, and paths) will be displayed
16540 in full.
16541
16542 @<Declare subroutines for printing expressions@>=
16543 @<Declare the procedure called |print_dp|@>;
16544 @<Declare the stashing/unstashing routines@>;
16545 void mp_print_exp (MP mp,pointer p, small_number verbosity) {
16546   boolean restore_cur_exp; /* should |cur_exp| be restored? */
16547   small_number t; /* the type of the expression */
16548   pointer q; /* a big node being displayed */
16549   integer v=0; /* the value of the expression */
16550   if ( p!=null ) {
16551     restore_cur_exp=false;
16552   } else { 
16553     p=mp_stash_cur_exp(mp); restore_cur_exp=true;
16554   }
16555   t=type(p);
16556   if ( t<mp_dependent ) v=value(p); else if ( t<mp_independent ) v=dep_list(p);
16557   @<Print an abbreviated value of |v| with format depending on |t|@>;
16558   if ( restore_cur_exp ) mp_unstash_cur_exp(mp, p);
16559 }
16560
16561 @ @<Print an abbreviated value of |v| with format depending on |t|@>=
16562 switch (t) {
16563 case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
16564 case mp_boolean_type:
16565   if ( v==true_code ) mp_print(mp, "true"); else mp_print(mp, "false");
16566   break;
16567 case unknown_types: case mp_numeric_type:
16568   @<Display a variable that's been declared but not defined@>;
16569   break;
16570 case mp_string_type:
16571   mp_print_char(mp, '"'); mp_print_str(mp, v); mp_print_char(mp, '"');
16572   break;
16573 case mp_pen_type: case mp_path_type: case mp_picture_type:
16574   @<Display a complex type@>;
16575   break;
16576 case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_cmykcolor_type:
16577   if ( v==null ) mp_print_type(mp, t);
16578   else @<Display a big node@>;
16579   break;
16580 case mp_known:mp_print_scaled(mp, v); break;
16581 case mp_dependent: case mp_proto_dependent:
16582   mp_print_dp(mp, t,v,verbosity);
16583   break;
16584 case mp_independent:mp_print_variable_name(mp, p); break;
16585 default: mp_confusion(mp, "exp"); break;
16586 @:this can't happen exp}{\quad exp@>
16587 }
16588
16589 @ @<Display a big node@>=
16590
16591   mp_print_char(mp, '('); q=v+mp->big_node_size[t];
16592   do {  
16593     if ( type(v)==mp_known ) mp_print_scaled(mp, value(v));
16594     else if ( type(v)==mp_independent ) mp_print_variable_name(mp, v);
16595     else mp_print_dp(mp, type(v),dep_list(v),verbosity);
16596     v=v+2;
16597     if ( v!=q ) mp_print_char(mp, ',');
16598   } while (v!=q);
16599   mp_print_char(mp, ')');
16600 }
16601
16602 @ Values of type \&{picture}, \&{path}, and \&{pen} are displayed verbosely
16603 in the log file only, unless the user has given a positive value to
16604 \\{tracingonline}.
16605
16606 @<Display a complex type@>=
16607 if ( verbosity<=1 ) {
16608   mp_print_type(mp, t);
16609 } else { 
16610   if ( mp->selector==term_and_log )
16611    if ( mp->internal[tracing_online]<=0 ) {
16612     mp->selector=term_only;
16613     mp_print_type(mp, t); mp_print(mp, " (see the transcript file)");
16614     mp->selector=term_and_log;
16615   };
16616   switch (t) {
16617   case mp_pen_type:mp_print_pen(mp, v,"",false); break;
16618   case mp_path_type:mp_print_path(mp, v,"",false); break;
16619   case mp_picture_type:mp_print_edges(mp, v,"",false); break;
16620   } /* there are no other cases */
16621 }
16622
16623 @ @<Declare the procedure called |print_dp|@>=
16624 void mp_print_dp (MP mp,small_number t, pointer p, 
16625                   small_number verbosity)  {
16626   pointer q; /* the node following |p| */
16627   q=link(p);
16628   if ( (info(q)==null) || (verbosity>0) ) mp_print_dependency(mp, p,t);
16629   else mp_print(mp, "linearform");
16630 }
16631
16632 @ The displayed name of a variable in a ring will not be a capsule unless
16633 the ring consists entirely of capsules.
16634
16635 @<Display a variable that's been declared but not defined@>=
16636 { mp_print_type(mp, t);
16637 if ( v!=null )
16638   { mp_print_char(mp, ' ');
16639   while ( (name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
16640   mp_print_variable_name(mp, v);
16641   };
16642 }
16643
16644 @ When errors are detected during parsing, it is often helpful to
16645 display an expression just above the error message, using |exp_err|
16646 or |disp_err| instead of |print_err|.
16647
16648 @d exp_err(A) mp_disp_err(mp, null,(A)) /* displays the current expression */
16649
16650 @<Declare subroutines for printing expressions@>=
16651 void mp_disp_err (MP mp,pointer p, char *s) { 
16652   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16653   mp_print_nl(mp, ">> ");
16654 @.>>@>
16655   mp_print_exp(mp, p,1); /* ``medium verbose'' printing of the expression */
16656   if (strlen(s)) { 
16657     mp_print_nl(mp, "! "); mp_print(mp, s);
16658 @.!\relax@>
16659   }
16660 }
16661
16662 @ If |cur_type| and |cur_exp| contain relevant information that should
16663 be recycled, we will use the following procedure, which changes |cur_type|
16664 to |known| and stores a given value in |cur_exp|. We can think of |cur_type|
16665 and |cur_exp| as either alive or dormant after this has been done,
16666 because |cur_exp| will not contain a pointer value.
16667
16668 @ @c void mp_flush_cur_exp (MP mp,scaled v) { 
16669   switch (mp->cur_type) {
16670   case unknown_types: case mp_transform_type: case mp_color_type: case mp_pair_type:
16671   case mp_dependent: case mp_proto_dependent: case mp_independent: case mp_cmykcolor_type:
16672     mp_recycle_value(mp, mp->cur_exp); 
16673     mp_free_node(mp, mp->cur_exp,value_node_size);
16674     break;
16675   case mp_string_type:
16676     delete_str_ref(mp->cur_exp); break;
16677   case mp_pen_type: case mp_path_type: 
16678     mp_toss_knot_list(mp, mp->cur_exp); break;
16679   case mp_picture_type:
16680     delete_edge_ref(mp->cur_exp); break;
16681   default: 
16682     break;
16683   }
16684   mp->cur_type=mp_known; mp->cur_exp=v;
16685 }
16686
16687 @ There's a much more general procedure that is capable of releasing
16688 the storage associated with any two-word value packet.
16689
16690 @<Declare the recycling subroutines@>=
16691 void mp_recycle_value (MP mp,pointer p) ;
16692
16693 @ @c void mp_recycle_value (MP mp,pointer p) {
16694   small_number t; /* a type code */
16695   integer vv; /* another value */
16696   pointer q,r,s,pp; /* link manipulation registers */
16697   integer v=0; /* a value */
16698   t=type(p);
16699   if ( t<mp_dependent ) v=value(p);
16700   switch (t) {
16701   case undefined: case mp_vacuous: case mp_boolean_type: case mp_known:
16702   case mp_numeric_type:
16703     break;
16704   case unknown_types:
16705     mp_ring_delete(mp, p); break;
16706   case mp_string_type:
16707     delete_str_ref(v); break;
16708   case mp_path_type: case mp_pen_type:
16709     mp_toss_knot_list(mp, v); break;
16710   case mp_picture_type:
16711     delete_edge_ref(v); break;
16712   case mp_cmykcolor_type: case mp_pair_type: case mp_color_type:
16713   case mp_transform_type:
16714     @<Recycle a big node@>; break; 
16715   case mp_dependent: case mp_proto_dependent:
16716     @<Recycle a dependency list@>; break;
16717   case mp_independent:
16718     @<Recycle an independent variable@>; break;
16719   case mp_token_list: case mp_structured:
16720     mp_confusion(mp, "recycle"); break;
16721 @:this can't happen recycle}{\quad recycle@>
16722   case mp_unsuffixed_macro: case mp_suffixed_macro:
16723     mp_delete_mac_ref(mp, value(p)); break;
16724   } /* there are no other cases */
16725   type(p)=undefined;
16726 }
16727
16728 @ @<Recycle a big node@>=
16729 if ( v!=null ){ 
16730   q=v+mp->big_node_size[t];
16731   do {  
16732     q=q-2; mp_recycle_value(mp, q);
16733   } while (q!=v);
16734   mp_free_node(mp, v,mp->big_node_size[t]);
16735 }
16736
16737 @ @<Recycle a dependency list@>=
16738
16739   q=dep_list(p);
16740   while ( info(q)!=null ) q=link(q);
16741   link(prev_dep(p))=link(q);
16742   prev_dep(link(q))=prev_dep(p);
16743   link(q)=null; mp_flush_node_list(mp, dep_list(p));
16744 }
16745
16746 @ When an independent variable disappears, it simply fades away, unless
16747 something depends on it. In the latter case, a dependent variable whose
16748 coefficient of dependence is maximal will take its place.
16749 The relevant algorithm is due to Ignacio~A. Zabala, who implemented it
16750 as part of his Ph.D. thesis (Stanford University, December 1982).
16751 @^Zabala Salelles, Ignacio Andres@>
16752
16753 For example, suppose that variable $x$ is being recycled, and that the
16754 only variables depending on~$x$ are $y=2x+a$ and $z=x+b$. In this case
16755 we want to make $y$ independent and $z=.5y-.5a+b$; no other variables
16756 will depend on~$y$. If $\\{tracingequations}>0$ in this situation,
16757 we will print `\.{\#\#\# -2x=-y+a}'.
16758
16759 There's a slight complication, however: An independent variable $x$
16760 can occur both in dependency lists and in proto-dependency lists.
16761 This makes it necessary to be careful when deciding which coefficient
16762 is maximal.
16763
16764 Furthermore, this complication is not so slight when
16765 a proto-dependent variable is chosen to become independent. For example,
16766 suppose that $y=2x+100a$ is proto-dependent while $z=x+b$ is dependent;
16767 then we must change $z=.5y-50a+b$ to a proto-dependency, because of the
16768 large coefficient `50'.
16769
16770 In order to deal with these complications without wasting too much time,
16771 we shall link together the occurrences of~$x$ among all the linear
16772 dependencies, maintaining separate lists for the dependent and
16773 proto-dependent cases.
16774
16775 @<Recycle an independent variable@>=
16776
16777   mp->max_c[mp_dependent]=0; mp->max_c[mp_proto_dependent]=0;
16778   mp->max_link[mp_dependent]=null; mp->max_link[mp_proto_dependent]=null;
16779   q=link(dep_head);
16780   while ( q!=dep_head ) { 
16781     s=value_loc(q); /* now |link(s)=dep_list(q)| */
16782     while (1) { 
16783       r=link(s);
16784       if ( info(r)==null ) break;;
16785       if ( info(r)!=p ) { 
16786        s=r;
16787       } else  { 
16788         t=type(q); link(s)=link(r); info(r)=q;
16789         if ( abs(value(r))>mp->max_c[t] ) {
16790           @<Record a new maximum coefficient of type |t|@>;
16791         } else { 
16792           link(r)=mp->max_link[t]; mp->max_link[t]=r;
16793         }
16794       }
16795     }   
16796     q=link(r);
16797   }
16798   if ( (mp->max_c[mp_dependent]>0)||(mp->max_c[mp_proto_dependent]>0) ) {
16799     @<Choose a dependent variable to take the place of the disappearing
16800     independent variable, and change all remaining dependencies
16801     accordingly@>;
16802   }
16803 }
16804
16805 @ The code for independency removal makes use of three two-word arrays.
16806
16807 @<Glob...@>=
16808 integer max_c[mp_proto_dependent+1];  /* max coefficient magnitude */
16809 pointer max_ptr[mp_proto_dependent+1]; /* where |p| occurs with |max_c| */
16810 pointer max_link[mp_proto_dependent+1]; /* other occurrences of |p| */
16811
16812 @ @<Record a new maximum coefficient...@>=
16813
16814   if ( mp->max_c[t]>0 ) {
16815     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
16816   }
16817   mp->max_c[t]=abs(value(r)); mp->max_ptr[t]=r;
16818 }
16819
16820 @ @<Choose a dependent...@>=
16821
16822   if ( (mp->max_c[mp_dependent] / 010000 >= mp->max_c[mp_proto_dependent]) )
16823     t=mp_dependent;
16824   else 
16825     t=mp_proto_dependent;
16826   @<Determine the dependency list |s| to substitute for the independent
16827     variable~|p|@>;
16828   t=mp_dependent+mp_proto_dependent-t; /* complement |t| */
16829   if ( mp->max_c[t]>0 ) { /* we need to pick up an unchosen dependency */ 
16830     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
16831   }
16832   if ( t!=mp_dependent ) { @<Substitute new dependencies in place of |p|@>; }
16833   else { @<Substitute new proto-dependencies in place of |p|@>;}
16834   mp_flush_node_list(mp, s);
16835   if ( mp->fix_needed ) mp_fix_dependencies(mp);
16836   check_arith;
16837 }
16838
16839 @ Let |s=max_ptr[t]|. At this point we have $|value|(s)=\pm|max_c|[t]$,
16840 and |info(s)| points to the dependent variable~|pp| of type~|t| from
16841 whose dependency list we have removed node~|s|. We must reinsert
16842 node~|s| into the dependency list, with coefficient $-1.0$, and with
16843 |pp| as the new independent variable. Since |pp| will have a larger serial
16844 number than any other variable, we can put node |s| at the head of the
16845 list.
16846
16847 @<Determine the dep...@>=
16848 s=mp->max_ptr[t]; pp=info(s); v=value(s);
16849 if ( t==mp_dependent ) value(s)=-fraction_one; else value(s)=-unity;
16850 r=dep_list(pp); link(s)=r;
16851 while ( info(r)!=null ) r=link(r);
16852 q=link(r); link(r)=null;
16853 prev_dep(q)=prev_dep(pp); link(prev_dep(pp))=q;
16854 new_indep(pp);
16855 if ( mp->cur_exp==pp ) if ( mp->cur_type==t ) mp->cur_type=mp_independent;
16856 if ( mp->internal[tracing_equations]>0 ) { 
16857   @<Show the transformed dependency@>; 
16858 }
16859
16860 @ Now $(-v)$ times the formerly independent variable~|p| is being replaced
16861 by the dependency list~|s|.
16862
16863 @<Show the transformed...@>=
16864 if ( mp_interesting(mp, p) ) {
16865   mp_begin_diagnostic(mp); mp_print_nl(mp, "### ");
16866 @:]]]\#\#\#_}{\.{\#\#\#}@>
16867   if ( v>0 ) mp_print_char(mp, '-');
16868   if ( t==mp_dependent ) vv=mp_round_fraction(mp, mp->max_c[mp_dependent]);
16869   else vv=mp->max_c[mp_proto_dependent];
16870   if ( vv!=unity ) mp_print_scaled(mp, vv);
16871   mp_print_variable_name(mp, p);
16872   while ( value(p) % s_scale>0 ) {
16873     mp_print(mp, "*4"); value(p)=value(p)-2;
16874   }
16875   if ( t==mp_dependent ) mp_print_char(mp, '='); else mp_print(mp, " = ");
16876   mp_print_dependency(mp, s,t);
16877   mp_end_diagnostic(mp, false);
16878 }
16879
16880 @ Finally, there are dependent and proto-dependent variables whose
16881 dependency lists must be brought up to date.
16882
16883 @<Substitute new dependencies...@>=
16884 for (t=mp_dependent;t<=mp_proto_dependent;t++){ 
16885   r=mp->max_link[t];
16886   while ( r!=null ) {
16887     q=info(r);
16888     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
16889      mp_make_fraction(mp, value(r),-v),s,t,mp_dependent);
16890     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
16891     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
16892   }
16893 }
16894
16895 @ @<Substitute new proto...@>=
16896 for (t=mp_dependent;t<=mp_proto_dependent;t++) {
16897   r=mp->max_link[t];
16898   while ( r!=null ) {
16899     q=info(r);
16900     if ( t==mp_dependent ) { /* for safety's sake, we change |q| to |mp_proto_dependent| */
16901       if ( mp->cur_exp==q ) if ( mp->cur_type==mp_dependent )
16902         mp->cur_type=mp_proto_dependent;
16903       dep_list(q)=mp_p_over_v(mp, dep_list(q),unity,mp_dependent,mp_proto_dependent);
16904       type(q)=mp_proto_dependent; value(r)=mp_round_fraction(mp, value(r));
16905     }
16906     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
16907       mp_make_scaled(mp, value(r),-v),s,mp_proto_dependent,mp_proto_dependent);
16908     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
16909     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
16910   }
16911 }
16912
16913 @ Here are some routines that provide handy combinations of actions
16914 that are often needed during error recovery. For example,
16915 `|flush_error|' flushes the current expression, replaces it by
16916 a given value, and calls |error|.
16917
16918 Errors often are detected after an extra token has already been scanned.
16919 The `\\{put\_get}' routines put that token back before calling |error|;
16920 then they get it back again. (Or perhaps they get another token, if
16921 the user has changed things.)
16922
16923 @<Declarations@>=
16924 void mp_flush_error (MP mp,scaled v);
16925 void mp_put_get_error (MP mp);
16926 void mp_put_get_flush_error (MP mp,scaled v) ;
16927
16928 @ @c
16929 void mp_flush_error (MP mp,scaled v) { 
16930   mp_error(mp); mp_flush_cur_exp(mp, v); 
16931 }
16932 void mp_put_get_error (MP mp) { 
16933   mp_back_error(mp); mp_get_x_next(mp); 
16934 }
16935 void mp_put_get_flush_error (MP mp,scaled v) { 
16936   mp_put_get_error(mp);
16937   mp_flush_cur_exp(mp, v); 
16938 }
16939
16940 @ A global variable |var_flag| is set to a special command code
16941 just before \MP\ calls |scan_expression|, if the expression should be
16942 treated as a variable when this command code immediately follows. For
16943 example, |var_flag| is set to |assignment| at the beginning of a
16944 statement, because we want to know the {\sl location\/} of a variable at
16945 the left of `\.{:=}', not the {\sl value\/} of that variable.
16946
16947 The |scan_expression| subroutine calls |scan_tertiary|,
16948 which calls |scan_secondary|, which calls |scan_primary|, which sets
16949 |var_flag:=0|. In this way each of the scanning routines ``knows''
16950 when it has been called with a special |var_flag|, but |var_flag| is
16951 usually zero.
16952
16953 A variable preceding a command that equals |var_flag| is converted to a
16954 token list rather than a value. Furthermore, an `\.{=}' sign following an
16955 expression with |var_flag=assignment| is not considered to be a relation
16956 that produces boolean expressions.
16957
16958
16959 @<Glob...@>=
16960 int var_flag; /* command that wants a variable */
16961
16962 @ @<Set init...@>=
16963 mp->var_flag=0;
16964
16965 @* \[37] Parsing primary expressions.
16966 The first parsing routine, |scan_primary|, is also the most complicated one,
16967 since it involves so many different cases. But each case---with one
16968 exception---is fairly simple by itself.
16969
16970 When |scan_primary| begins, the first token of the primary to be scanned
16971 should already appear in |cur_cmd|, |cur_mod|, and |cur_sym|. The values
16972 of |cur_type| and |cur_exp| should be either dead or dormant, as explained
16973 earlier. If |cur_cmd| is not between |min_primary_command| and
16974 |max_primary_command|, inclusive, a syntax error will be signaled.
16975
16976 @<Declare the basic parsing subroutines@>=
16977 void mp_scan_primary (MP mp) {
16978   pointer p,q,r; /* for list manipulation */
16979   quarterword c; /* a primitive operation code */
16980   int my_var_flag; /* initial value of |my_var_flag| */
16981   pointer l_delim,r_delim; /* hash addresses of a delimiter pair */
16982   @<Other local variables for |scan_primary|@>;
16983   my_var_flag=mp->var_flag; mp->var_flag=0;
16984 RESTART:
16985   check_arith;
16986   @<Supply diagnostic information, if requested@>;
16987   switch (mp->cur_cmd) {
16988   case left_delimiter:
16989     @<Scan a delimited primary@>; break;
16990   case begin_group:
16991     @<Scan a grouped primary@>; break;
16992   case string_token:
16993     @<Scan a string constant@>; break;
16994   case numeric_token:
16995     @<Scan a primary that starts with a numeric token@>; break;
16996   case nullary:
16997     @<Scan a nullary operation@>; break;
16998   case unary: case type_name: case cycle: case plus_or_minus:
16999     @<Scan a unary operation@>; break;
17000   case primary_binary:
17001     @<Scan a binary operation with `\&{of}' between its operands@>; break;
17002   case str_op:
17003     @<Convert a suffix to a string@>; break;
17004   case internal_quantity:
17005     @<Scan an internal numeric quantity@>; break;
17006   case capsule_token:
17007     mp_make_exp_copy(mp, mp->cur_mod); break;
17008   case tag_token:
17009     @<Scan a variable primary; |goto restart| if it turns out to be a macro@>; break;
17010   default: 
17011     mp_bad_exp(mp, "A primary"); goto RESTART; break;
17012 @.A primary expression...@>
17013   }
17014   mp_get_x_next(mp); /* the routines |goto done| if they don't want this */
17015 DONE: 
17016   if ( mp->cur_cmd==left_bracket ) {
17017     if ( mp->cur_type>=mp_known ) {
17018       @<Scan a mediation construction@>;
17019     }
17020   }
17021 }
17022
17023
17024
17025 @ Errors at the beginning of expressions are flagged by |bad_exp|.
17026
17027 @c void mp_bad_exp (MP mp,char * s) {
17028   int save_flag;
17029   print_err(s); mp_print(mp, " expression can't begin with `");
17030   mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); 
17031   mp_print_char(mp, '\'');
17032   help4("I'm afraid I need some sort of value in order to continue,")
17033     ("so I've tentatively inserted `0'. You may want to")
17034     ("delete this zero and insert something else;")
17035     ("see Chapter 27 of The METAFONTbook for an example.");
17036 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17037   mp_back_input(mp); mp->cur_sym=0; mp->cur_cmd=numeric_token; 
17038   mp->cur_mod=0; mp_ins_error(mp);
17039   save_flag=mp->var_flag; mp->var_flag=0; mp_get_x_next(mp);
17040   mp->var_flag=save_flag;
17041 }
17042
17043 @ @<Supply diagnostic information, if requested@>=
17044 #ifdef DEBUG
17045 if ( mp->panicking ) mp_check_mem(mp, false);
17046 #endif
17047 if ( mp->interrupt!=0 ) if ( mp->OK_to_interrupt ) {
17048   mp_back_input(mp); check_interrupt; mp_get_x_next(mp);
17049 }
17050
17051 @ @<Scan a delimited primary@>=
17052
17053   l_delim=mp->cur_sym; r_delim=mp->cur_mod; 
17054   mp_get_x_next(mp); mp_scan_expression(mp);
17055   if ( (mp->cur_cmd==comma) && (mp->cur_type>=mp_known) ) {
17056     @<Scan the rest of a delimited set of numerics@>;
17057   } else {
17058     mp_check_delimiter(mp, l_delim,r_delim);
17059   }
17060 }
17061
17062 @ The |stash_in| subroutine puts the current (numeric) expression into a field
17063 within a ``big node.''
17064
17065 @c void mp_stash_in (MP mp,pointer p) {
17066   pointer q; /* temporary register */
17067   type(p)=mp->cur_type;
17068   if ( mp->cur_type==mp_known ) {
17069     value(p)=mp->cur_exp;
17070   } else { 
17071     if ( mp->cur_type==mp_independent ) {
17072       @<Stash an independent |cur_exp| into a big node@>;
17073     } else { 
17074       mp->mem[value_loc(p)]=mp->mem[value_loc(mp->cur_exp)];
17075       /* |dep_list(p):=dep_list(cur_exp)| and |prev_dep(p):=prev_dep(cur_exp)| */
17076       link(prev_dep(p))=p;
17077     }
17078     mp_free_node(mp, mp->cur_exp,value_node_size);
17079   }
17080   mp->cur_type=mp_vacuous;
17081 }
17082
17083 @ In rare cases the current expression can become |independent|. There
17084 may be many dependency lists pointing to such an independent capsule,
17085 so we can't simply move it into place within a big node. Instead,
17086 we copy it, then recycle it.
17087
17088 @ @<Stash an independent |cur_exp|...@>=
17089
17090   q=mp_single_dependency(mp, mp->cur_exp);
17091   if ( q==mp->dep_final ){ 
17092     type(p)=mp_known; value(p)=0; mp_free_node(mp, q,dep_node_size);
17093   } else { 
17094     type(p)=mp_dependent; mp_new_dep(mp, p,q);
17095   }
17096   mp_recycle_value(mp, mp->cur_exp);
17097 }
17098
17099 @ This code uses the fact that |red_part_loc| and |green_part_loc|
17100 are synonymous with |x_part_loc| and |y_part_loc|.
17101
17102 @<Scan the rest of a delimited set of numerics@>=
17103
17104 p=mp_stash_cur_exp(mp);
17105 mp_get_x_next(mp); mp_scan_expression(mp);
17106 @<Make sure the second part of a pair or color has a numeric type@>;
17107 q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
17108 if ( mp->cur_cmd==comma ) type(q)=mp_color_type;
17109 else type(q)=mp_pair_type;
17110 mp_init_big_node(mp, q); r=value(q);
17111 mp_stash_in(mp, y_part_loc(r));
17112 mp_unstash_cur_exp(mp, p);
17113 mp_stash_in(mp, x_part_loc(r));
17114 if ( mp->cur_cmd==comma ) {
17115   @<Scan the last of a triplet of numerics@>;
17116 }
17117 if ( mp->cur_cmd==comma ) {
17118   type(q)=mp_cmykcolor_type;
17119   mp_init_big_node(mp, q); t=value(q);
17120   mp->mem[cyan_part_loc(t)]=mp->mem[red_part_loc(r)];
17121   value(cyan_part_loc(t))=value(red_part_loc(r));
17122   mp->mem[magenta_part_loc(t)]=mp->mem[green_part_loc(r)];
17123   value(magenta_part_loc(t))=value(green_part_loc(r));
17124   mp->mem[yellow_part_loc(t)]=mp->mem[blue_part_loc(r)];
17125   value(yellow_part_loc(t))=value(blue_part_loc(r));
17126   mp_recycle_value(mp, r);
17127   r=t;
17128   @<Scan the last of a quartet of numerics@>;
17129 }
17130 mp_check_delimiter(mp, l_delim,r_delim);
17131 mp->cur_type=type(q);
17132 mp->cur_exp=q;
17133 }
17134
17135 @ @<Make sure the second part of a pair or color has a numeric type@>=
17136 if ( mp->cur_type<mp_known ) {
17137   exp_err("Nonnumeric ypart has been replaced by 0");
17138 @.Nonnumeric...replaced by 0@>
17139   help4("I've started to scan a pair `(a,b)' or a color `(a,b,c)';")
17140     ("but after finding a nice `a' I found a `b' that isn't")
17141     ("of numeric type. So I've changed that part to zero.")
17142     ("(The b that I didn't like appears above the error message.)");
17143   mp_put_get_flush_error(mp, 0);
17144 }
17145
17146 @ @<Scan the last of a triplet of numerics@>=
17147
17148   mp_get_x_next(mp); mp_scan_expression(mp);
17149   if ( mp->cur_type<mp_known ) {
17150     exp_err("Nonnumeric third part has been replaced by 0");
17151 @.Nonnumeric...replaced by 0@>
17152     help3("I've just scanned a color `(a,b,c)' or cmykcolor(a,b,c,d); but the `c'")
17153       ("isn't of numeric type. So I've changed that part to zero.")
17154       ("(The c that I didn't like appears above the error message.)");
17155     mp_put_get_flush_error(mp, 0);
17156   }
17157   mp_stash_in(mp, blue_part_loc(r));
17158 }
17159
17160 @ @<Scan the last of a quartet of numerics@>=
17161
17162   mp_get_x_next(mp); mp_scan_expression(mp);
17163   if ( mp->cur_type<mp_known ) {
17164     exp_err("Nonnumeric blackpart has been replaced by 0");
17165 @.Nonnumeric...replaced by 0@>
17166     help3("I've just scanned a cmykcolor `(c,m,y,k)'; but the `k' isn't")
17167       ("of numeric type. So I've changed that part to zero.")
17168       ("(The k that I didn't like appears above the error message.)");
17169     mp_put_get_flush_error(mp, 0);
17170   }
17171   mp_stash_in(mp, black_part_loc(r));
17172 }
17173
17174 @ The local variable |group_line| keeps track of the line
17175 where a \&{begingroup} command occurred; this will be useful
17176 in an error message if the group doesn't actually end.
17177
17178 @<Other local variables for |scan_primary|@>=
17179 integer group_line; /* where a group began */
17180
17181 @ @<Scan a grouped primary@>=
17182
17183   group_line=mp_true_line(mp);
17184   if ( mp->internal[tracing_commands]>0 ) show_cur_cmd_mod;
17185   save_boundary_item(p);
17186   do {  
17187     mp_do_statement(mp); /* ends with |cur_cmd>=semicolon| */
17188   } while (! (mp->cur_cmd!=semicolon));
17189   if ( mp->cur_cmd!=end_group ) {
17190     print_err("A group begun on line ");
17191 @.A group...never ended@>
17192     mp_print_int(mp, group_line);
17193     mp_print(mp, " never ended");
17194     help2("I saw a `begingroup' back there that hasn't been matched")
17195          ("by `endgroup'. So I've inserted `endgroup' now.");
17196     mp_back_error(mp); mp->cur_cmd=end_group;
17197   }
17198   mp_unsave(mp); 
17199     /* this might change |cur_type|, if independent variables are recycled */
17200   if ( mp->internal[tracing_commands]>0 ) show_cur_cmd_mod;
17201 }
17202
17203 @ @<Scan a string constant@>=
17204
17205   mp->cur_type=mp_string_type; mp->cur_exp=mp->cur_mod;
17206 }
17207
17208 @ Later we'll come to procedures that perform actual operations like
17209 addition, square root, and so on; our purpose now is to do the parsing.
17210 But we might as well mention those future procedures now, so that the
17211 suspense won't be too bad:
17212
17213 \smallskip
17214 |do_nullary(c)| does primitive operations that have no operands (e.g.,
17215 `\&{true}' or `\&{pencircle}');
17216
17217 \smallskip
17218 |do_unary(c)| applies a primitive operation to the current expression;
17219
17220 \smallskip
17221 |do_binary(p,c)| applies a primitive operation to the capsule~|p|
17222 and the current expression.
17223
17224 @<Scan a nullary operation@>=mp_do_nullary(mp, mp->cur_mod)
17225
17226 @ @<Scan a unary operation@>=
17227
17228   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_primary(mp); 
17229   mp_do_unary(mp, c); goto DONE;
17230 }
17231
17232 @ A numeric token might be a primary by itself, or it might be the
17233 numerator of a fraction composed solely of numeric tokens, or it might
17234 multiply the primary that follows (provided that the primary doesn't begin
17235 with a plus sign or a minus sign). The code here uses the facts that
17236 |max_primary_command=plus_or_minus| and
17237 |max_primary_command-1=numeric_token|. If a fraction is found that is less
17238 than unity, we try to retain higher precision when we use it in scalar
17239 multiplication.
17240
17241 @<Other local variables for |scan_primary|@>=
17242 scaled num,denom; /* for primaries that are fractions, like `1/2' */
17243
17244 @ @<Scan a primary that starts with a numeric token@>=
17245
17246   mp->cur_exp=mp->cur_mod; mp->cur_type=mp_known; mp_get_x_next(mp);
17247   if ( mp->cur_cmd!=slash ) { 
17248     num=0; denom=0;
17249   } else { 
17250     mp_get_x_next(mp);
17251     if ( mp->cur_cmd!=numeric_token ) { 
17252       mp_back_input(mp);
17253       mp->cur_cmd=slash; mp->cur_mod=over; mp->cur_sym=frozen_slash;
17254       goto DONE;
17255     }
17256     num=mp->cur_exp; denom=mp->cur_mod;
17257     if ( denom==0 ) { @<Protest division by zero@>; }
17258     else { mp->cur_exp=mp_make_scaled(mp, num,denom); }
17259     check_arith; mp_get_x_next(mp);
17260   }
17261   if ( mp->cur_cmd>=min_primary_command ) {
17262    if ( mp->cur_cmd<numeric_token ) { /* in particular, |cur_cmd<>plus_or_minus| */
17263      p=mp_stash_cur_exp(mp); mp_scan_primary(mp);
17264      if ( (abs(num)>=abs(denom))||(mp->cur_type<mp_color_type) ) {
17265        mp_do_binary(mp, p,times);
17266      } else {
17267        mp_frac_mult(mp, num,denom);
17268        mp_free_node(mp, p,value_node_size);
17269      }
17270     }
17271   }
17272   goto DONE;
17273 }
17274
17275 @ @<Protest division...@>=
17276
17277   print_err("Division by zero");
17278 @.Division by zero@>
17279   help1("I'll pretend that you meant to divide by 1."); mp_error(mp);
17280 }
17281
17282 @ @<Scan a binary operation with `\&{of}' between its operands@>=
17283
17284   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
17285   if ( mp->cur_cmd!=of_token ) {
17286     mp_missing_err(mp, "of"); mp_print(mp, " for "); 
17287     mp_print_cmd_mod(mp, primary_binary,c);
17288 @.Missing `of'@>
17289     help1("I've got the first argument; will look now for the other.");
17290     mp_back_error(mp);
17291   }
17292   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_primary(mp); 
17293   mp_do_binary(mp, p,c); goto DONE;
17294 }
17295
17296 @ @<Convert a suffix to a string@>=
17297
17298   mp_get_x_next(mp); mp_scan_suffix(mp); 
17299   mp->old_setting=mp->selector; mp->selector=new_string;
17300   mp_show_token_list(mp, mp->cur_exp,null,100000,0); 
17301   mp_flush_token_list(mp, mp->cur_exp);
17302   mp->cur_exp=mp_make_string(mp); mp->selector=mp->old_setting; 
17303   mp->cur_type=mp_string_type;
17304   goto DONE;
17305 }
17306
17307 @ If an internal quantity appears all by itself on the left of an
17308 assignment, we return a token list of length one, containing the address
17309 of the internal quantity plus |hash_end|. (This accords with the conventions
17310 of the save stack, as described earlier.)
17311
17312 @<Scan an internal...@>=
17313
17314   q=mp->cur_mod;
17315   if ( my_var_flag==assignment ) {
17316     mp_get_x_next(mp);
17317     if ( mp->cur_cmd==assignment ) {
17318       mp->cur_exp=mp_get_avail(mp);
17319       info(mp->cur_exp)=q+hash_end; mp->cur_type=mp_token_list; 
17320       goto DONE;
17321     }
17322     mp_back_input(mp);
17323   }
17324   mp->cur_type=mp_known; mp->cur_exp=mp->internal[q];
17325 }
17326
17327 @ The most difficult part of |scan_primary| has been saved for last, since
17328 it was necessary to build up some confidence first. We can now face the task
17329 of scanning a variable.
17330
17331 As we scan a variable, we build a token list containing the relevant
17332 names and subscript values, simultaneously following along in the
17333 ``collective'' structure to see if we are actually dealing with a macro
17334 instead of a value.
17335
17336 The local variables |pre_head| and |post_head| will point to the beginning
17337 of the prefix and suffix lists; |tail| will point to the end of the list
17338 that is currently growing.
17339
17340 Another local variable, |tt|, contains partial information about the
17341 declared type of the variable-so-far. If |tt>=mp_unsuffixed_macro|, the
17342 relation |tt=type(q)| will always hold. If |tt=undefined|, the routine
17343 doesn't bother to update its information about type. And if
17344 |undefined<tt<mp_unsuffixed_macro|, the precise value of |tt| isn't critical.
17345
17346 @ @<Other local variables for |scan_primary|@>=
17347 pointer pre_head,post_head,tail;
17348   /* prefix and suffix list variables */
17349 small_number tt; /* approximation to the type of the variable-so-far */
17350 pointer t; /* a token */
17351 pointer macro_ref = 0; /* reference count for a suffixed macro */
17352
17353 @ @<Scan a variable primary...@>=
17354
17355   fast_get_avail(pre_head); tail=pre_head; post_head=null; tt=mp_vacuous;
17356   while (1) { 
17357     t=mp_cur_tok(mp); link(tail)=t;
17358     if ( tt!=undefined ) {
17359        @<Find the approximate type |tt| and corresponding~|q|@>;
17360       if ( tt>=mp_unsuffixed_macro ) {
17361         @<Either begin an unsuffixed macro call or
17362           prepare for a suffixed one@>;
17363       }
17364     }
17365     mp_get_x_next(mp); tail=t;
17366     if ( mp->cur_cmd==left_bracket ) {
17367       @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>;
17368     }
17369     if ( mp->cur_cmd>max_suffix_token ) break;
17370     if ( mp->cur_cmd<min_suffix_token ) break;
17371   } /* now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| */
17372   @<Handle unusual cases that masquerade as variables, and |goto restart|
17373     or |goto done| if appropriate;
17374     otherwise make a copy of the variable and |goto done|@>;
17375 }
17376
17377 @ @<Either begin an unsuffixed macro call or...@>=
17378
17379   link(tail)=null;
17380   if ( tt>mp_unsuffixed_macro ) { /* |tt=mp_suffixed_macro| */
17381     post_head=mp_get_avail(mp); tail=post_head; link(tail)=t;
17382     tt=undefined; macro_ref=value(q); add_mac_ref(macro_ref);
17383   } else {
17384     @<Set up unsuffixed macro call and |goto restart|@>;
17385   }
17386 }
17387
17388 @ @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>=
17389
17390   mp_get_x_next(mp); mp_scan_expression(mp);
17391   if ( mp->cur_cmd!=right_bracket ) {
17392     @<Put the left bracket and the expression back to be rescanned@>;
17393   } else { 
17394     if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17395     mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp; mp->cur_sym=0;
17396   }
17397 }
17398
17399 @ The left bracket that we thought was introducing a subscript might have
17400 actually been the left bracket in a mediation construction like `\.{x[a,b]}'.
17401 So we don't issue an error message at this point; but we do want to back up
17402 so as to avoid any embarrassment about our incorrect assumption.
17403
17404 @<Put the left bracket and the expression back to be rescanned@>=
17405
17406   mp_back_input(mp); /* that was the token following the current expression */
17407   mp_back_expr(mp); mp->cur_cmd=left_bracket; 
17408   mp->cur_mod=0; mp->cur_sym=frozen_left_bracket;
17409 }
17410
17411 @ Here's a routine that puts the current expression back to be read again.
17412
17413 @c void mp_back_expr (MP mp) {
17414   pointer p; /* capsule token */
17415   p=mp_stash_cur_exp(mp); link(p)=null; back_list(p);
17416 }
17417
17418 @ Unknown subscripts lead to the following error message.
17419
17420 @c void mp_bad_subscript (MP mp) { 
17421   exp_err("Improper subscript has been replaced by zero");
17422 @.Improper subscript...@>
17423   help3("A bracketed subscript must have a known numeric value;")
17424     ("unfortunately, what I found was the value that appears just")
17425     ("above this error message. So I'll try a zero subscript.");
17426   mp_flush_error(mp, 0);
17427 }
17428
17429 @ Every time we call |get_x_next|, there's a chance that the variable we've
17430 been looking at will disappear. Thus, we cannot safely keep |q| pointing
17431 into the variable structure; we need to start searching from the root each time.
17432
17433 @<Find the approximate type |tt| and corresponding~|q|@>=
17434 @^inner loop@>
17435
17436   p=link(pre_head); q=info(p); tt=undefined;
17437   if ( eq_type(q) % outer_tag==tag_token ) {
17438     q=equiv(q);
17439     if ( q==null ) goto DONE2;
17440     while (1) { 
17441       p=link(p);
17442       if ( p==null ) {
17443         tt=type(q); goto DONE2;
17444       };
17445       if ( type(q)!=mp_structured ) goto DONE2;
17446       q=link(attr_head(q)); /* the |collective_subscript| attribute */
17447       if ( p>=mp->hi_mem_min ) { /* it's not a subscript */
17448         do {  q=link(q); } while (! (attr_loc(q)>=info(p)));
17449         if ( attr_loc(q)>info(p) ) goto DONE2;
17450       }
17451     }
17452   }
17453 DONE2:
17454   ;
17455 }
17456
17457 @ How do things stand now? Well, we have scanned an entire variable name,
17458 including possible subscripts and/or attributes; |cur_cmd|, |cur_mod|, and
17459 |cur_sym| represent the token that follows. If |post_head=null|, a
17460 token list for this variable name starts at |link(pre_head)|, with all
17461 subscripts evaluated. But if |post_head<>null|, the variable turned out
17462 to be a suffixed macro; |pre_head| is the head of the prefix list, while
17463 |post_head| is the head of a token list containing both `\.{\AT!}' and
17464 the suffix.
17465
17466 Our immediate problem is to see if this variable still exists. (Variable
17467 structures can change drastically whenever we call |get_x_next|; users
17468 aren't supposed to do this, but the fact that it is possible means that
17469 we must be cautious.)
17470
17471 The following procedure prints an error message when a variable
17472 unexpectedly disappears. Its help message isn't quite right for
17473 our present purposes, but we'll be able to fix that up.
17474
17475 @c 
17476 void mp_obliterated (MP mp,pointer q) { 
17477   print_err("Variable "); mp_show_token_list(mp, q,null,1000,0);
17478   mp_print(mp, " has been obliterated");
17479 @.Variable...obliterated@>
17480   help5("It seems you did a nasty thing---probably by accident,")
17481     ("but nevertheless you nearly hornswoggled me...")
17482     ("While I was evaluating the right-hand side of this")
17483     ("command, something happened, and the left-hand side")
17484     ("is no longer a variable! So I won't change anything.");
17485 }
17486
17487 @ If the variable does exist, we also need to check
17488 for a few other special cases before deciding that a plain old ordinary
17489 variable has, indeed, been scanned.
17490
17491 @<Handle unusual cases that masquerade as variables...@>=
17492 if ( post_head!=null ) {
17493   @<Set up suffixed macro call and |goto restart|@>;
17494 }
17495 q=link(pre_head); free_avail(pre_head);
17496 if ( mp->cur_cmd==my_var_flag ) { 
17497   mp->cur_type=mp_token_list; mp->cur_exp=q; goto DONE;
17498 }
17499 p=mp_find_variable(mp, q);
17500 if ( p!=null ) {
17501   mp_make_exp_copy(mp, p);
17502 } else { 
17503   mp_obliterated(mp, q);
17504   mp->help_line[2]="While I was evaluating the suffix of this variable,";
17505   mp->help_line[1]="something was redefined, and it's no longer a variable!";
17506   mp->help_line[0]="In order to get back on my feet, I've inserted `0' instead.";
17507   mp_put_get_flush_error(mp, 0);
17508 }
17509 mp_flush_node_list(mp, q); 
17510 goto DONE
17511
17512 @ The only complication associated with macro calling is that the prefix
17513 and ``at'' parameters must be packaged in an appropriate list of lists.
17514
17515 @<Set up unsuffixed macro call and |goto restart|@>=
17516
17517   p=mp_get_avail(mp); info(pre_head)=link(pre_head); link(pre_head)=p;
17518   info(p)=t; mp_macro_call(mp, value(q),pre_head,null);
17519   mp_get_x_next(mp); 
17520   goto RESTART;
17521 }
17522
17523 @ If the ``variable'' that turned out to be a suffixed macro no longer exists,
17524 we don't care, because we have reserved a pointer (|macro_ref|) to its
17525 token list.
17526
17527 @<Set up suffixed macro call and |goto restart|@>=
17528
17529   mp_back_input(mp); p=mp_get_avail(mp); q=link(post_head);
17530   info(pre_head)=link(pre_head); link(pre_head)=post_head;
17531   info(post_head)=q; link(post_head)=p; info(p)=link(q); link(q)=null;
17532   mp_macro_call(mp, macro_ref,pre_head,null); decr(ref_count(macro_ref));
17533   mp_get_x_next(mp); goto RESTART;
17534 }
17535
17536 @ Our remaining job is simply to make a copy of the value that has been
17537 found. Some cases are harder than others, but complexity arises solely
17538 because of the multiplicity of possible cases.
17539
17540 @<Declare the procedure called |make_exp_copy|@>=
17541 @<Declare subroutines needed by |make_exp_copy|@>;
17542 void mp_make_exp_copy (MP mp,pointer p) {
17543   pointer q,r,t; /* registers for list manipulation */
17544 RESTART: 
17545   mp->cur_type=type(p);
17546   switch (mp->cur_type) {
17547   case mp_vacuous: case mp_boolean_type: case mp_known:
17548     mp->cur_exp=value(p); break;
17549   case unknown_types:
17550     mp->cur_exp=mp_new_ring_entry(mp, p);
17551     break;
17552   case mp_string_type: 
17553     mp->cur_exp=value(p); add_str_ref(mp->cur_exp);
17554     break;
17555   case mp_picture_type:
17556     mp->cur_exp=value(p);add_edge_ref(mp->cur_exp);
17557     break;
17558   case mp_pen_type:
17559     mp->cur_exp=copy_pen(value(p));
17560     break; 
17561   case mp_path_type:
17562     mp->cur_exp=mp_copy_path(mp, value(p));
17563     break;
17564   case mp_transform_type: case mp_color_type: 
17565   case mp_cmykcolor_type: case mp_pair_type:
17566     @<Copy the big node |p|@>;
17567     break;
17568   case mp_dependent: case mp_proto_dependent:
17569     mp_encapsulate(mp, mp_copy_dep_list(mp, dep_list(p)));
17570     break;
17571   case mp_numeric_type: 
17572     new_indep(p); goto RESTART;
17573     break;
17574   case mp_independent: 
17575     q=mp_single_dependency(mp, p);
17576     if ( q==mp->dep_final ){ 
17577       mp->cur_type=mp_known; mp->cur_exp=0; mp_free_node(mp, q,value_node_size);
17578     } else { 
17579       mp->cur_type=mp_dependent; mp_encapsulate(mp, q);
17580     }
17581     break;
17582   default: 
17583     mp_confusion(mp, "copy");
17584 @:this can't happen copy}{\quad copy@>
17585     break;
17586   }
17587 }
17588
17589 @ The |encapsulate| subroutine assumes that |dep_final| is the
17590 tail of dependency list~|p|.
17591
17592 @<Declare subroutines needed by |make_exp_copy|@>=
17593 void mp_encapsulate (MP mp,pointer p) { 
17594   mp->cur_exp=mp_get_node(mp, value_node_size); type(mp->cur_exp)=mp->cur_type;
17595   name_type(mp->cur_exp)=mp_capsule; mp_new_dep(mp, mp->cur_exp,p);
17596 }
17597
17598 @ The most tedious case arises when the user refers to a
17599 \&{pair}, \&{color}, or \&{transform} variable; we must copy several fields,
17600 each of which can be |independent|, |dependent|, |mp_proto_dependent|,
17601 or |known|.
17602
17603 @<Copy the big node |p|@>=
17604
17605   if ( value(p)==null ) 
17606     mp_init_big_node(mp, p);
17607   t=mp_get_node(mp, value_node_size); name_type(t)=mp_capsule; type(t)=mp->cur_type;
17608   mp_init_big_node(mp, t);
17609   q=value(p)+mp->big_node_size[mp->cur_type]; 
17610   r=value(t)+mp->big_node_size[mp->cur_type];
17611   do {  
17612     q=q-2; r=r-2; mp_install(mp, r,q);
17613   } while (q!=value(p));
17614   mp->cur_exp=t;
17615 }
17616
17617 @ The |install| procedure copies a numeric field~|q| into field~|r| of
17618 a big node that will be part of a capsule.
17619
17620 @<Declare subroutines needed by |make_exp_copy|@>=
17621 void mp_install (MP mp,pointer r, pointer q) {
17622   pointer p; /* temporary register */
17623   if ( type(q)==mp_known ){ 
17624     value(r)=value(q); type(r)=mp_known;
17625   } else  if ( type(q)==mp_independent ) {
17626     p=mp_single_dependency(mp, q);
17627     if ( p==mp->dep_final ) {
17628       type(r)=mp_known; value(r)=0; mp_free_node(mp, p,value_node_size);
17629     } else  { 
17630       type(r)=mp_dependent; mp_new_dep(mp, r,p);
17631     }
17632   } else {
17633     type(r)=type(q); mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(q)));
17634   }
17635 }
17636
17637 @ Expressions of the form `\.{a[b,c]}' are converted into
17638 `\.{b+a*(c-b)}', without checking the types of \.b~or~\.c,
17639 provided that \.a is numeric.
17640
17641 @<Scan a mediation...@>=
17642
17643   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17644   if ( mp->cur_cmd!=comma ) {
17645     @<Put the left bracket and the expression back...@>;
17646     mp_unstash_cur_exp(mp, p);
17647   } else { 
17648     q=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17649     if ( mp->cur_cmd!=right_bracket ) {
17650       mp_missing_err(mp, "]");
17651 @.Missing `]'@>
17652       help3("I've scanned an expression of the form `a[b,c',")
17653       ("so a right bracket should have come next.")
17654       ("I shall pretend that one was there.");
17655       mp_back_error(mp);
17656     }
17657     r=mp_stash_cur_exp(mp); mp_make_exp_copy(mp, q);
17658     mp_do_binary(mp, r,minus); mp_do_binary(mp, p,times); 
17659     mp_do_binary(mp, q,plus); mp_get_x_next(mp);
17660   }
17661 }
17662
17663 @ Here is a comparatively simple routine that is used to scan the
17664 \&{suffix} parameters of a macro.
17665
17666 @<Declare the basic parsing subroutines@>=
17667 void mp_scan_suffix (MP mp) {
17668   pointer h,t; /* head and tail of the list being built */
17669   pointer p; /* temporary register */
17670   h=mp_get_avail(mp); t=h;
17671   while (1) { 
17672     if ( mp->cur_cmd==left_bracket ) {
17673       @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>;
17674     }
17675     if ( mp->cur_cmd==numeric_token ) {
17676       p=mp_new_num_tok(mp, mp->cur_mod);
17677     } else if ((mp->cur_cmd==tag_token)||(mp->cur_cmd==internal_quantity) ) {
17678        p=mp_get_avail(mp); info(p)=mp->cur_sym;
17679     } else {
17680       break;
17681     }
17682     link(t)=p; t=p; mp_get_x_next(mp);
17683   }
17684   mp->cur_exp=link(h); free_avail(h); mp->cur_type=mp_token_list;
17685 }
17686
17687 @ @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>=
17688
17689   mp_get_x_next(mp); mp_scan_expression(mp);
17690   if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17691   if ( mp->cur_cmd!=right_bracket ) {
17692      mp_missing_err(mp, "]");
17693 @.Missing `]'@>
17694     help3("I've seen a `[' and a subscript value, in a suffix,")
17695       ("so a right bracket should have come next.")
17696       ("I shall pretend that one was there.");
17697     mp_back_error(mp);
17698   }
17699   mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp;
17700 }
17701
17702 @* \[38] Parsing secondary and higher expressions.
17703 After the intricacies of |scan_primary|\kern-1pt,
17704 the |scan_secondary| routine is
17705 refreshingly simple. It's not trivial, but the operations are relatively
17706 straightforward; the main difficulty is, again, that expressions and data
17707 structures might change drastically every time we call |get_x_next|, so a
17708 cautious approach is mandatory. For example, a macro defined by
17709 \&{primarydef} might have disappeared by the time its second argument has
17710 been scanned; we solve this by increasing the reference count of its token
17711 list, so that the macro can be called even after it has been clobbered.
17712
17713 @<Declare the basic parsing subroutines@>=
17714 void mp_scan_secondary (MP mp) {
17715   pointer p; /* for list manipulation */
17716   halfword c,d; /* operation codes or modifiers */
17717   pointer mac_name; /* token defined with \&{primarydef} */
17718 RESTART:
17719   if ((mp->cur_cmd<min_primary_command)||
17720       (mp->cur_cmd>max_primary_command) )
17721     mp_bad_exp(mp, "A secondary");
17722 @.A secondary expression...@>
17723   mp_scan_primary(mp);
17724 CONTINUE: 
17725   if ( mp->cur_cmd<=max_secondary_command )
17726     if ( mp->cur_cmd>=min_secondary_command ) {
17727       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17728       if ( d==secondary_primary_macro ) { 
17729         mac_name=mp->cur_sym; add_mac_ref(c);
17730      }
17731      mp_get_x_next(mp); mp_scan_primary(mp);
17732      if ( d!=secondary_primary_macro ) {
17733        mp_do_binary(mp, p,c);
17734      } else  { 
17735        mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17736        decr(ref_count(c)); mp_get_x_next(mp); 
17737        goto RESTART;
17738     }
17739     goto CONTINUE;
17740   }
17741 }
17742
17743 @ The following procedure calls a macro that has two parameters,
17744 |p| and |cur_exp|.
17745
17746 @c void mp_binary_mac (MP mp,pointer p, pointer c, pointer n) {
17747   pointer q,r; /* nodes in the parameter list */
17748   q=mp_get_avail(mp); r=mp_get_avail(mp); link(q)=r;
17749   info(q)=p; info(r)=mp_stash_cur_exp(mp);
17750   mp_macro_call(mp, c,q,n);
17751 }
17752
17753 @ The next procedure, |scan_tertiary|, is pretty much the same deal.
17754
17755 @<Declare the basic parsing subroutines@>=
17756 void mp_scan_tertiary (MP mp) {
17757   pointer p; /* for list manipulation */
17758   halfword c,d; /* operation codes or modifiers */
17759   pointer mac_name; /* token defined with \&{secondarydef} */
17760 RESTART:
17761   if ((mp->cur_cmd<min_primary_command)||
17762       (mp->cur_cmd>max_primary_command) )
17763     mp_bad_exp(mp, "A tertiary");
17764 @.A tertiary expression...@>
17765   mp_scan_secondary(mp);
17766 CONTINUE: 
17767   if ( mp->cur_cmd<=max_tertiary_command ) {
17768     if ( mp->cur_cmd>=min_tertiary_command ) {
17769       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17770       if ( d==tertiary_secondary_macro ) { 
17771         mac_name=mp->cur_sym; add_mac_ref(c);
17772       };
17773       mp_get_x_next(mp); mp_scan_secondary(mp);
17774       if ( d!=tertiary_secondary_macro ) {
17775         mp_do_binary(mp, p,c);
17776       } else { 
17777         mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17778         decr(ref_count(c)); mp_get_x_next(mp); 
17779         goto RESTART;
17780       }
17781       goto CONTINUE;
17782     }
17783   }
17784 }
17785
17786 @ Finally we reach the deepest level in our quartet of parsing routines.
17787 This one is much like the others; but it has an extra complication from
17788 paths, which materialize here.
17789
17790 @d continue_path 25 /* a label inside of |scan_expression| */
17791 @d finish_path 26 /* another */
17792
17793 @<Declare the basic parsing subroutines@>=
17794 void mp_scan_expression (MP mp) {
17795   pointer p,q,r,pp,qq; /* for list manipulation */
17796   halfword c,d; /* operation codes or modifiers */
17797   int my_var_flag; /* initial value of |var_flag| */
17798   pointer mac_name; /* token defined with \&{tertiarydef} */
17799   boolean cycle_hit; /* did a path expression just end with `\&{cycle}'? */
17800   scaled x,y; /* explicit coordinates or tension at a path join */
17801   int t; /* knot type following a path join */
17802   t=0; y=0; x=0;
17803   my_var_flag=mp->var_flag; mac_name=null;
17804 RESTART:
17805   if ((mp->cur_cmd<min_primary_command)||
17806       (mp->cur_cmd>max_primary_command) )
17807     mp_bad_exp(mp, "An");
17808 @.An expression...@>
17809   mp_scan_tertiary(mp);
17810 CONTINUE: 
17811   if ( mp->cur_cmd<=max_expression_command )
17812     if ( mp->cur_cmd>=min_expression_command ) {
17813       if ( (mp->cur_cmd!=equals)||(my_var_flag!=assignment) ) {
17814         p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17815         if ( d==expression_tertiary_macro ) {
17816           mac_name=mp->cur_sym; add_mac_ref(c);
17817         }
17818         if ( (d<ampersand)||((d==ampersand)&&
17819              ((type(p)==mp_pair_type)||(type(p)==mp_path_type))) ) {
17820           @<Scan a path construction operation;
17821             but |return| if |p| has the wrong type@>;
17822         } else { 
17823           mp_get_x_next(mp); mp_scan_tertiary(mp);
17824           if ( d!=expression_tertiary_macro ) {
17825             mp_do_binary(mp, p,c);
17826           } else  { 
17827             mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17828             decr(ref_count(c)); mp_get_x_next(mp); 
17829             goto RESTART;
17830           }
17831         }
17832         goto CONTINUE;
17833      }
17834   }
17835 }
17836
17837 @ The reader should review the data structure conventions for paths before
17838 hoping to understand the next part of this code.
17839
17840 @<Scan a path construction operation...@>=
17841
17842   cycle_hit=false;
17843   @<Convert the left operand, |p|, into a partial path ending at~|q|;
17844     but |return| if |p| doesn't have a suitable type@>;
17845 CONTINUE_PATH: 
17846   @<Determine the path join parameters;
17847     but |goto finish_path| if there's only a direction specifier@>;
17848   if ( mp->cur_cmd==cycle ) {
17849     @<Get ready to close a cycle@>;
17850   } else { 
17851     mp_scan_tertiary(mp);
17852     @<Convert the right operand, |cur_exp|,
17853       into a partial path from |pp| to~|qq|@>;
17854   }
17855   @<Join the partial paths and reset |p| and |q| to the head and tail
17856     of the result@>;
17857   if ( mp->cur_cmd>=min_expression_command )
17858     if ( mp->cur_cmd<=ampersand ) if ( ! cycle_hit ) goto CONTINUE_PATH;
17859 FINISH_PATH:
17860   @<Choose control points for the path and put the result into |cur_exp|@>;
17861 }
17862
17863 @ @<Convert the left operand, |p|, into a partial path ending at~|q|...@>=
17864
17865   mp_unstash_cur_exp(mp, p);
17866   if ( mp->cur_type==mp_pair_type ) p=mp_new_knot(mp);
17867   else if ( mp->cur_type==mp_path_type ) p=mp->cur_exp;
17868   else return;
17869   q=p;
17870   while ( link(q)!=p ) q=link(q);
17871   if ( left_type(p)!=endpoint ) { /* open up a cycle */
17872     r=mp_copy_knot(mp, p); link(q)=r; q=r;
17873   }
17874   left_type(p)=open; right_type(q)=open;
17875 }
17876
17877 @ A pair of numeric values is changed into a knot node for a one-point path
17878 when \MP\ discovers that the pair is part of a path.
17879
17880 @c@<Declare the procedure called |known_pair|@>;
17881 pointer mp_new_knot (MP mp) { /* convert a pair to a knot with two endpoints */
17882   pointer q; /* the new node */
17883   q=mp_get_node(mp, knot_node_size); left_type(q)=endpoint;
17884   right_type(q)=endpoint; originator(q)=metapost_user; link(q)=q;
17885   mp_known_pair(mp); x_coord(q)=mp->cur_x; y_coord(q)=mp->cur_y;
17886   return q;
17887 }
17888
17889 @ The |known_pair| subroutine sets |cur_x| and |cur_y| to the components
17890 of the current expression, assuming that the current expression is a
17891 pair of known numerics. Unknown components are zeroed, and the
17892 current expression is flushed.
17893
17894 @<Declare the procedure called |known_pair|@>=
17895 void mp_known_pair (MP mp) {
17896   pointer p; /* the pair node */
17897   if ( mp->cur_type!=mp_pair_type ) {
17898     exp_err("Undefined coordinates have been replaced by (0,0)");
17899 @.Undefined coordinates...@>
17900     help5("I need x and y numbers for this part of the path.")
17901       ("The value I found (see above) was no good;")
17902       ("so I'll try to keep going by using zero instead.")
17903       ("(Chapter 27 of The METAFONTbook explains that")
17904 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17905       ("you might want to type `I ??" "?' now.)");
17906     mp_put_get_flush_error(mp, 0); mp->cur_x=0; mp->cur_y=0;
17907   } else { 
17908     p=value(mp->cur_exp);
17909      @<Make sure that both |x| and |y| parts of |p| are known;
17910        copy them into |cur_x| and |cur_y|@>;
17911     mp_flush_cur_exp(mp, 0);
17912   }
17913 }
17914
17915 @ @<Make sure that both |x| and |y| parts of |p| are known...@>=
17916 if ( type(x_part_loc(p))==mp_known ) {
17917   mp->cur_x=value(x_part_loc(p));
17918 } else { 
17919   mp_disp_err(mp, x_part_loc(p),
17920     "Undefined x coordinate has been replaced by 0");
17921 @.Undefined coordinates...@>
17922   help5("I need a `known' x value for this part of the path.")
17923     ("The value I found (see above) was no good;")
17924     ("so I'll try to keep going by using zero instead.")
17925     ("(Chapter 27 of The METAFONTbook explains that")
17926 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17927     ("you might want to type `I ??" "?' now.)");
17928   mp_put_get_error(mp); mp_recycle_value(mp, x_part_loc(p)); mp->cur_x=0;
17929 }
17930 if ( type(y_part_loc(p))==mp_known ) {
17931   mp->cur_y=value(y_part_loc(p));
17932 } else { 
17933   mp_disp_err(mp, y_part_loc(p),
17934     "Undefined y coordinate has been replaced by 0");
17935   help5("I need a `known' y value for this part of the path.")
17936     ("The value I found (see above) was no good;")
17937     ("so I'll try to keep going by using zero instead.")
17938     ("(Chapter 27 of The METAFONTbook explains that")
17939     ("you might want to type `I ??" "?' now.)");
17940   mp_put_get_error(mp); mp_recycle_value(mp, y_part_loc(p)); mp->cur_y=0;
17941 }
17942
17943 @ At this point |cur_cmd| is either |ampersand|, |left_brace|, or |path_join|.
17944
17945 @<Determine the path join parameters...@>=
17946 if ( mp->cur_cmd==left_brace ) {
17947   @<Put the pre-join direction information into node |q|@>;
17948 }
17949 d=mp->cur_cmd;
17950 if ( d==path_join ) {
17951   @<Determine the tension and/or control points@>;
17952 } else if ( d!=ampersand ) {
17953   goto FINISH_PATH;
17954 }
17955 mp_get_x_next(mp);
17956 if ( mp->cur_cmd==left_brace ) {
17957   @<Put the post-join direction information into |x| and |t|@>;
17958 } else if ( right_type(q)!=explicit ) {
17959   t=open; x=0;
17960 }
17961
17962 @ The |scan_direction| subroutine looks at the directional information
17963 that is enclosed in braces, and also scans ahead to the following character.
17964 A type code is returned, either |open| (if the direction was $(0,0)$),
17965 or |curl| (if the direction was a curl of known value |cur_exp|), or
17966 |given| (if the direction is given by the |angle| value that now
17967 appears in |cur_exp|).
17968
17969 There's nothing difficult about this subroutine, but the program is rather
17970 lengthy because a variety of potential errors need to be nipped in the bud.
17971
17972 @c small_number mp_scan_direction (MP mp) {
17973   int t; /* the type of information found */
17974   scaled x; /* an |x| coordinate */
17975   mp_get_x_next(mp);
17976   if ( mp->cur_cmd==curl_command ) {
17977      @<Scan a curl specification@>;
17978   } else {
17979     @<Scan a given direction@>;
17980   }
17981   if ( mp->cur_cmd!=right_brace ) {
17982     mp_missing_err(mp, "}");
17983 @.Missing `\char`\}'@>
17984     help3("I've scanned a direction spec for part of a path,")
17985       ("so a right brace should have come next.")
17986       ("I shall pretend that one was there.");
17987     mp_back_error(mp);
17988   }
17989   mp_get_x_next(mp); 
17990   return t;
17991 }
17992
17993 @ @<Scan a curl specification@>=
17994 { mp_get_x_next(mp); mp_scan_expression(mp);
17995 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<0) ){ 
17996   exp_err("Improper curl has been replaced by 1");
17997 @.Improper curl@>
17998   help1("A curl must be a known, nonnegative number.");
17999   mp_put_get_flush_error(mp, unity);
18000 }
18001 t=curl;
18002 }
18003
18004 @ @<Scan a given direction@>=
18005 { mp_scan_expression(mp);
18006   if ( mp->cur_type>mp_pair_type ) {
18007     @<Get given directions separated by commas@>;
18008   } else {
18009     mp_known_pair(mp);
18010   }
18011   if ( (mp->cur_x==0)&&(mp->cur_y==0) )  t=open;
18012   else  { t=given; mp->cur_exp=mp_n_arg(mp, mp->cur_x,mp->cur_y);}
18013 }
18014
18015 @ @<Get given directions separated by commas@>=
18016
18017   if ( mp->cur_type!=mp_known ) {
18018     exp_err("Undefined x coordinate has been replaced by 0");
18019 @.Undefined coordinates...@>
18020     help5("I need a `known' x value for this part of the path.")
18021       ("The value I found (see above) was no good;")
18022       ("so I'll try to keep going by using zero instead.")
18023       ("(Chapter 27 of The METAFONTbook explains that")
18024 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18025       ("you might want to type `I ??" "?' now.)");
18026     mp_put_get_flush_error(mp, 0);
18027   }
18028   x=mp->cur_exp;
18029   if ( mp->cur_cmd!=comma ) {
18030     mp_missing_err(mp, ",");
18031 @.Missing `,'@>
18032     help2("I've got the x coordinate of a path direction;")
18033       ("will look for the y coordinate next.");
18034     mp_back_error(mp);
18035   }
18036   mp_get_x_next(mp); mp_scan_expression(mp);
18037   if ( mp->cur_type!=mp_known ) {
18038      exp_err("Undefined y coordinate has been replaced by 0");
18039     help5("I need a `known' y value for this part of the path.")
18040       ("The value I found (see above) was no good;")
18041       ("so I'll try to keep going by using zero instead.")
18042       ("(Chapter 27 of The METAFONTbook explains that")
18043       ("you might want to type `I ??" "?' now.)");
18044     mp_put_get_flush_error(mp, 0);
18045   }
18046   mp->cur_y=mp->cur_exp; mp->cur_x=x;
18047 }
18048
18049 @ At this point |right_type(q)| is usually |open|, but it may have been
18050 set to some other value by a previous splicing operation. We must maintain
18051 the value of |right_type(q)| in unusual cases such as
18052 `\.{..z1\{z2\}\&\{z3\}z1\{0,0\}..}'.
18053
18054 @<Put the pre-join...@>=
18055
18056   t=mp_scan_direction(mp);
18057   if ( t!=open ) {
18058     right_type(q)=t; right_given(q)=mp->cur_exp;
18059     if ( left_type(q)==open ) {
18060       left_type(q)=t; left_given(q)=mp->cur_exp;
18061     } /* note that |left_given(q)=left_curl(q)| */
18062   }
18063 }
18064
18065 @ Since |left_tension| and |left_y| share the same position in knot nodes,
18066 and since |left_given| is similarly equivalent to |left_x|, we use
18067 |x| and |y| to hold the given direction and tension information when
18068 there are no explicit control points.
18069
18070 @<Put the post-join...@>=
18071
18072   t=mp_scan_direction(mp);
18073   if ( right_type(q)!=explicit ) x=mp->cur_exp;
18074   else t=explicit; /* the direction information is superfluous */
18075 }
18076
18077 @ @<Determine the tension and/or...@>=
18078
18079   mp_get_x_next(mp);
18080   if ( mp->cur_cmd==tension ) {
18081     @<Set explicit tensions@>;
18082   } else if ( mp->cur_cmd==controls ) {
18083     @<Set explicit control points@>;
18084   } else  { 
18085     right_tension(q)=unity; y=unity; mp_back_input(mp); /* default tension */
18086     goto DONE;
18087   };
18088   if ( mp->cur_cmd!=path_join ) {
18089      mp_missing_err(mp, "..");
18090 @.Missing `..'@>
18091     help1("A path join command should end with two dots.");
18092     mp_back_error(mp);
18093   }
18094 DONE:
18095   ;
18096 }
18097
18098 @ @<Set explicit tensions@>=
18099
18100   mp_get_x_next(mp); y=mp->cur_cmd;
18101   if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18102   mp_scan_primary(mp);
18103   @<Make sure that the current expression is a valid tension setting@>;
18104   if ( y==at_least ) negate(mp->cur_exp);
18105   right_tension(q)=mp->cur_exp;
18106   if ( mp->cur_cmd==and_command ) {
18107     mp_get_x_next(mp); y=mp->cur_cmd;
18108     if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18109     mp_scan_primary(mp);
18110     @<Make sure that the current expression is a valid tension setting@>;
18111     if ( y==at_least ) negate(mp->cur_exp);
18112   }
18113   y=mp->cur_exp;
18114 }
18115
18116 @ @d min_tension three_quarter_unit
18117
18118 @<Make sure that the current expression is a valid tension setting@>=
18119 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<min_tension) ) {
18120   exp_err("Improper tension has been set to 1");
18121 @.Improper tension@>
18122   help1("The expression above should have been a number >=3/4.");
18123   mp_put_get_flush_error(mp, unity);
18124 }
18125
18126 @ @<Set explicit control points@>=
18127
18128   right_type(q)=explicit; t=explicit; mp_get_x_next(mp); mp_scan_primary(mp);
18129   mp_known_pair(mp); right_x(q)=mp->cur_x; right_y(q)=mp->cur_y;
18130   if ( mp->cur_cmd!=and_command ) {
18131     x=right_x(q); y=right_y(q);
18132   } else { 
18133     mp_get_x_next(mp); mp_scan_primary(mp);
18134     mp_known_pair(mp); x=mp->cur_x; y=mp->cur_y;
18135   }
18136 }
18137
18138 @ @<Convert the right operand, |cur_exp|, into a partial path...@>=
18139
18140   if ( mp->cur_type!=mp_path_type ) pp=mp_new_knot(mp);
18141   else pp=mp->cur_exp;
18142   qq=pp;
18143   while ( link(qq)!=pp ) qq=link(qq);
18144   if ( left_type(pp)!=endpoint ) { /* open up a cycle */
18145     r=mp_copy_knot(mp, pp); link(qq)=r; qq=r;
18146   }
18147   left_type(pp)=open; right_type(qq)=open;
18148 }
18149
18150 @ If a person tries to define an entire path by saying `\.{(x,y)\&cycle}',
18151 we silently change the specification to `\.{(x,y)..cycle}', since a cycle
18152 shouldn't have length zero.
18153
18154 @<Get ready to close a cycle@>=
18155
18156   cycle_hit=true; mp_get_x_next(mp); pp=p; qq=p;
18157   if ( d==ampersand ) if ( p==q ) {
18158     d=path_join; right_tension(q)=unity; y=unity;
18159   }
18160 }
18161
18162 @ @<Join the partial paths and reset |p| and |q|...@>=
18163
18164 if ( d==ampersand ) {
18165   if ( (x_coord(q)!=x_coord(pp))||(y_coord(q)!=y_coord(pp)) ) {
18166     print_err("Paths don't touch; `&' will be changed to `..'");
18167 @.Paths don't touch@>
18168     help3("When you join paths `p&q', the ending point of p")
18169       ("must be exactly equal to the starting point of q.")
18170       ("So I'm going to pretend that you said `p..q' instead.");
18171     mp_put_get_error(mp); d=path_join; right_tension(q)=unity; y=unity;
18172   }
18173 }
18174 @<Plug an opening in |right_type(pp)|, if possible@>;
18175 if ( d==ampersand ) {
18176   @<Splice independent paths together@>;
18177 } else  { 
18178   @<Plug an opening in |right_type(q)|, if possible@>;
18179   link(q)=pp; left_y(pp)=y;
18180   if ( t!=open ) { left_x(pp)=x; left_type(pp)=t;  };
18181 }
18182 q=qq;
18183 }
18184
18185 @ @<Plug an opening in |right_type(q)|...@>=
18186 if ( right_type(q)==open ) {
18187   if ( (left_type(q)==curl)||(left_type(q)==given) ) {
18188     right_type(q)=left_type(q); right_given(q)=left_given(q);
18189   }
18190 }
18191
18192 @ @<Plug an opening in |right_type(pp)|...@>=
18193 if ( right_type(pp)==open ) {
18194   if ( (t==curl)||(t==given) ) {
18195     right_type(pp)=t; right_given(pp)=x;
18196   }
18197 }
18198
18199 @ @<Splice independent paths together@>=
18200
18201   if ( left_type(q)==open ) if ( right_type(q)==open ) {
18202     left_type(q)=curl; left_curl(q)=unity;
18203   }
18204   if ( right_type(pp)==open ) if ( t==open ) {
18205     right_type(pp)=curl; right_curl(pp)=unity;
18206   }
18207   right_type(q)=right_type(pp); link(q)=link(pp);
18208   right_x(q)=right_x(pp); right_y(q)=right_y(pp);
18209   mp_free_node(mp, pp,knot_node_size);
18210   if ( qq==pp ) qq=q;
18211 }
18212
18213 @ @<Choose control points for the path...@>=
18214 if ( cycle_hit ) { 
18215   if ( d==ampersand ) p=q;
18216 } else  { 
18217   left_type(p)=endpoint;
18218   if ( right_type(p)==open ) { 
18219     right_type(p)=curl; right_curl(p)=unity;
18220   }
18221   right_type(q)=endpoint;
18222   if ( left_type(q)==open ) { 
18223     left_type(q)=curl; left_curl(q)=unity;
18224   }
18225   link(q)=p;
18226 }
18227 mp_make_choices(mp, p);
18228 mp->cur_type=mp_path_type; mp->cur_exp=p
18229
18230 @ Finally, we sometimes need to scan an expression whose value is
18231 supposed to be either |true_code| or |false_code|.
18232
18233 @<Declare the basic parsing subroutines@>=
18234 void mp_get_boolean (MP mp) { 
18235   mp_get_x_next(mp); mp_scan_expression(mp);
18236   if ( mp->cur_type!=mp_boolean_type ) {
18237     exp_err("Undefined condition will be treated as `false'");
18238 @.Undefined condition...@>
18239     help2("The expression shown above should have had a definite")
18240       ("true-or-false value. I'm changing it to `false'.");
18241     mp_put_get_flush_error(mp, false_code); mp->cur_type=mp_boolean_type;
18242   }
18243 }
18244
18245 @* \[39] Doing the operations.
18246 The purpose of parsing is primarily to permit people to avoid piles of
18247 parentheses. But the real work is done after the structure of an expression
18248 has been recognized; that's when new expressions are generated. We
18249 turn now to the guts of \MP, which handles individual operators that
18250 have come through the parsing mechanism.
18251
18252 We'll start with the easy ones that take no operands, then work our way
18253 up to operators with one and ultimately two arguments. In other words,
18254 we will write the three procedures |do_nullary|, |do_unary|, and |do_binary|
18255 that are invoked periodically by the expression scanners.
18256
18257 First let's make sure that all of the primitive operators are in the
18258 hash table. Although |scan_primary| and its relatives made use of the
18259 \\{cmd} code for these operators, the \\{do} routines base everything
18260 on the \\{mod} code. For example, |do_binary| doesn't care whether the
18261 operation it performs is a |primary_binary| or |secondary_binary|, etc.
18262
18263 @<Put each...@>=
18264 mp_primitive(mp, "true",nullary,true_code);
18265 @:true_}{\&{true} primitive@>
18266 mp_primitive(mp, "false",nullary,false_code);
18267 @:false_}{\&{false} primitive@>
18268 mp_primitive(mp, "nullpicture",nullary,null_picture_code);
18269 @:null_picture_}{\&{nullpicture} primitive@>
18270 mp_primitive(mp, "nullpen",nullary,null_pen_code);
18271 @:null_pen_}{\&{nullpen} primitive@>
18272 mp_primitive(mp, "jobname",nullary,job_name_op);
18273 @:job_name_}{\&{jobname} primitive@>
18274 mp_primitive(mp, "readstring",nullary,read_string_op);
18275 @:read_string_}{\&{readstring} primitive@>
18276 mp_primitive(mp, "pencircle",nullary,pen_circle);
18277 @:pen_circle_}{\&{pencircle} primitive@>
18278 mp_primitive(mp, "normaldeviate",nullary,normal_deviate);
18279 @:normal_deviate_}{\&{normaldeviate} primitive@>
18280 mp_primitive(mp, "readfrom",unary,read_from_op);
18281 @:read_from_}{\&{readfrom} primitive@>
18282 mp_primitive(mp, "closefrom",unary,close_from_op);
18283 @:close_from_}{\&{closefrom} primitive@>
18284 mp_primitive(mp, "odd",unary,odd_op);
18285 @:odd_}{\&{odd} primitive@>
18286 mp_primitive(mp, "known",unary,known_op);
18287 @:known_}{\&{known} primitive@>
18288 mp_primitive(mp, "unknown",unary,unknown_op);
18289 @:unknown_}{\&{unknown} primitive@>
18290 mp_primitive(mp, "not",unary,not_op);
18291 @:not_}{\&{not} primitive@>
18292 mp_primitive(mp, "decimal",unary,decimal);
18293 @:decimal_}{\&{decimal} primitive@>
18294 mp_primitive(mp, "reverse",unary,reverse);
18295 @:reverse_}{\&{reverse} primitive@>
18296 mp_primitive(mp, "makepath",unary,make_path_op);
18297 @:make_path_}{\&{makepath} primitive@>
18298 mp_primitive(mp, "makepen",unary,make_pen_op);
18299 @:make_pen_}{\&{makepen} primitive@>
18300 mp_primitive(mp, "oct",unary,oct_op);
18301 @:oct_}{\&{oct} primitive@>
18302 mp_primitive(mp, "hex",unary,hex_op);
18303 @:hex_}{\&{hex} primitive@>
18304 mp_primitive(mp, "ASCII",unary,ASCII_op);
18305 @:ASCII_}{\&{ASCII} primitive@>
18306 mp_primitive(mp, "char",unary,char_op);
18307 @:char_}{\&{char} primitive@>
18308 mp_primitive(mp, "length",unary,length_op);
18309 @:length_}{\&{length} primitive@>
18310 mp_primitive(mp, "turningnumber",unary,turning_op);
18311 @:turning_number_}{\&{turningnumber} primitive@>
18312 mp_primitive(mp, "xpart",unary,x_part);
18313 @:x_part_}{\&{xpart} primitive@>
18314 mp_primitive(mp, "ypart",unary,y_part);
18315 @:y_part_}{\&{ypart} primitive@>
18316 mp_primitive(mp, "xxpart",unary,xx_part);
18317 @:xx_part_}{\&{xxpart} primitive@>
18318 mp_primitive(mp, "xypart",unary,xy_part);
18319 @:xy_part_}{\&{xypart} primitive@>
18320 mp_primitive(mp, "yxpart",unary,yx_part);
18321 @:yx_part_}{\&{yxpart} primitive@>
18322 mp_primitive(mp, "yypart",unary,yy_part);
18323 @:yy_part_}{\&{yypart} primitive@>
18324 mp_primitive(mp, "redpart",unary,red_part);
18325 @:red_part_}{\&{redpart} primitive@>
18326 mp_primitive(mp, "greenpart",unary,green_part);
18327 @:green_part_}{\&{greenpart} primitive@>
18328 mp_primitive(mp, "bluepart",unary,blue_part);
18329 @:blue_part_}{\&{bluepart} primitive@>
18330 mp_primitive(mp, "cyanpart",unary,cyan_part);
18331 @:cyan_part_}{\&{cyanpart} primitive@>
18332 mp_primitive(mp, "magentapart",unary,magenta_part);
18333 @:magenta_part_}{\&{magentapart} primitive@>
18334 mp_primitive(mp, "yellowpart",unary,yellow_part);
18335 @:yellow_part_}{\&{yellowpart} primitive@>
18336 mp_primitive(mp, "blackpart",unary,black_part);
18337 @:black_part_}{\&{blackpart} primitive@>
18338 mp_primitive(mp, "greypart",unary,grey_part);
18339 @:grey_part_}{\&{greypart} primitive@>
18340 mp_primitive(mp, "colormodel",unary,color_model_part);
18341 @:color_model_part_}{\&{colormodel} primitive@>
18342 mp_primitive(mp, "fontpart",unary,font_part);
18343 @:font_part_}{\&{fontpart} primitive@>
18344 mp_primitive(mp, "textpart",unary,text_part);
18345 @:text_part_}{\&{textpart} primitive@>
18346 mp_primitive(mp, "pathpart",unary,path_part);
18347 @:path_part_}{\&{pathpart} primitive@>
18348 mp_primitive(mp, "penpart",unary,pen_part);
18349 @:pen_part_}{\&{penpart} primitive@>
18350 mp_primitive(mp, "dashpart",unary,dash_part);
18351 @:dash_part_}{\&{dashpart} primitive@>
18352 mp_primitive(mp, "sqrt",unary,sqrt_op);
18353 @:sqrt_}{\&{sqrt} primitive@>
18354 mp_primitive(mp, "mexp",unary,m_exp_op);
18355 @:m_exp_}{\&{mexp} primitive@>
18356 mp_primitive(mp, "mlog",unary,m_log_op);
18357 @:m_log_}{\&{mlog} primitive@>
18358 mp_primitive(mp, "sind",unary,sin_d_op);
18359 @:sin_d_}{\&{sind} primitive@>
18360 mp_primitive(mp, "cosd",unary,cos_d_op);
18361 @:cos_d_}{\&{cosd} primitive@>
18362 mp_primitive(mp, "floor",unary,floor_op);
18363 @:floor_}{\&{floor} primitive@>
18364 mp_primitive(mp, "uniformdeviate",unary,uniform_deviate);
18365 @:uniform_deviate_}{\&{uniformdeviate} primitive@>
18366 mp_primitive(mp, "charexists",unary,char_exists_op);
18367 @:char_exists_}{\&{charexists} primitive@>
18368 mp_primitive(mp, "fontsize",unary,font_size);
18369 @:font_size_}{\&{fontsize} primitive@>
18370 mp_primitive(mp, "llcorner",unary,ll_corner_op);
18371 @:ll_corner_}{\&{llcorner} primitive@>
18372 mp_primitive(mp, "lrcorner",unary,lr_corner_op);
18373 @:lr_corner_}{\&{lrcorner} primitive@>
18374 mp_primitive(mp, "ulcorner",unary,ul_corner_op);
18375 @:ul_corner_}{\&{ulcorner} primitive@>
18376 mp_primitive(mp, "urcorner",unary,ur_corner_op);
18377 @:ur_corner_}{\&{urcorner} primitive@>
18378 mp_primitive(mp, "arclength",unary,arc_length);
18379 @:arc_length_}{\&{arclength} primitive@>
18380 mp_primitive(mp, "angle",unary,angle_op);
18381 @:angle_}{\&{angle} primitive@>
18382 mp_primitive(mp, "cycle",cycle,cycle_op);
18383 @:cycle_}{\&{cycle} primitive@>
18384 mp_primitive(mp, "stroked",unary,stroked_op);
18385 @:stroked_}{\&{stroked} primitive@>
18386 mp_primitive(mp, "filled",unary,filled_op);
18387 @:filled_}{\&{filled} primitive@>
18388 mp_primitive(mp, "textual",unary,textual_op);
18389 @:textual_}{\&{textual} primitive@>
18390 mp_primitive(mp, "clipped",unary,clipped_op);
18391 @:clipped_}{\&{clipped} primitive@>
18392 mp_primitive(mp, "bounded",unary,bounded_op);
18393 @:bounded_}{\&{bounded} primitive@>
18394 mp_primitive(mp, "+",plus_or_minus,plus);
18395 @:+ }{\.{+} primitive@>
18396 mp_primitive(mp, "-",plus_or_minus,minus);
18397 @:- }{\.{-} primitive@>
18398 mp_primitive(mp, "*",secondary_binary,times);
18399 @:* }{\.{*} primitive@>
18400 mp_primitive(mp, "/",slash,over); mp->eqtb[frozen_slash]=mp->eqtb[mp->cur_sym];
18401 @:/ }{\.{/} primitive@>
18402 mp_primitive(mp, "++",tertiary_binary,pythag_add);
18403 @:++_}{\.{++} primitive@>
18404 mp_primitive(mp, "+-+",tertiary_binary,pythag_sub);
18405 @:+-+_}{\.{+-+} primitive@>
18406 mp_primitive(mp, "or",tertiary_binary,or_op);
18407 @:or_}{\&{or} primitive@>
18408 mp_primitive(mp, "and",and_command,and_op);
18409 @:and_}{\&{and} primitive@>
18410 mp_primitive(mp, "<",expression_binary,less_than);
18411 @:< }{\.{<} primitive@>
18412 mp_primitive(mp, "<=",expression_binary,less_or_equal);
18413 @:<=_}{\.{<=} primitive@>
18414 mp_primitive(mp, ">",expression_binary,greater_than);
18415 @:> }{\.{>} primitive@>
18416 mp_primitive(mp, ">=",expression_binary,greater_or_equal);
18417 @:>=_}{\.{>=} primitive@>
18418 mp_primitive(mp, "=",equals,equal_to);
18419 @:= }{\.{=} primitive@>
18420 mp_primitive(mp, "<>",expression_binary,unequal_to);
18421 @:<>_}{\.{<>} primitive@>
18422 mp_primitive(mp, "substring",primary_binary,substring_of);
18423 @:substring_}{\&{substring} primitive@>
18424 mp_primitive(mp, "subpath",primary_binary,subpath_of);
18425 @:subpath_}{\&{subpath} primitive@>
18426 mp_primitive(mp, "directiontime",primary_binary,direction_time_of);
18427 @:direction_time_}{\&{directiontime} primitive@>
18428 mp_primitive(mp, "point",primary_binary,point_of);
18429 @:point_}{\&{point} primitive@>
18430 mp_primitive(mp, "precontrol",primary_binary,precontrol_of);
18431 @:precontrol_}{\&{precontrol} primitive@>
18432 mp_primitive(mp, "postcontrol",primary_binary,postcontrol_of);
18433 @:postcontrol_}{\&{postcontrol} primitive@>
18434 mp_primitive(mp, "penoffset",primary_binary,pen_offset_of);
18435 @:pen_offset_}{\&{penoffset} primitive@>
18436 mp_primitive(mp, "arctime",primary_binary,arc_time_of);
18437 @:arc_time_of_}{\&{arctime} primitive@>
18438 mp_primitive(mp, "mpversion",nullary,mp_version);
18439 @:mp_verison_}{\&{mpversion} primitive@>
18440 mp_primitive(mp, "&",ampersand,concatenate);
18441 @:!!!}{\.{\&} primitive@>
18442 mp_primitive(mp, "rotated",secondary_binary,rotated_by);
18443 @:rotated_}{\&{rotated} primitive@>
18444 mp_primitive(mp, "slanted",secondary_binary,slanted_by);
18445 @:slanted_}{\&{slanted} primitive@>
18446 mp_primitive(mp, "scaled",secondary_binary,scaled_by);
18447 @:scaled_}{\&{scaled} primitive@>
18448 mp_primitive(mp, "shifted",secondary_binary,shifted_by);
18449 @:shifted_}{\&{shifted} primitive@>
18450 mp_primitive(mp, "transformed",secondary_binary,transformed_by);
18451 @:transformed_}{\&{transformed} primitive@>
18452 mp_primitive(mp, "xscaled",secondary_binary,x_scaled);
18453 @:x_scaled_}{\&{xscaled} primitive@>
18454 mp_primitive(mp, "yscaled",secondary_binary,y_scaled);
18455 @:y_scaled_}{\&{yscaled} primitive@>
18456 mp_primitive(mp, "zscaled",secondary_binary,z_scaled);
18457 @:z_scaled_}{\&{zscaled} primitive@>
18458 mp_primitive(mp, "infont",secondary_binary,in_font);
18459 @:in_font_}{\&{infont} primitive@>
18460 mp_primitive(mp, "intersectiontimes",tertiary_binary,intersect);
18461 @:intersection_times_}{\&{intersectiontimes} primitive@>
18462
18463 @ @<Cases of |print_cmd...@>=
18464 case nullary:
18465 case unary:
18466 case primary_binary:
18467 case secondary_binary:
18468 case tertiary_binary:
18469 case expression_binary:
18470 case cycle:
18471 case plus_or_minus:
18472 case slash:
18473 case ampersand:
18474 case equals:
18475 case and_command:
18476   mp_print_op(mp, m);
18477   break;
18478
18479 @ OK, let's look at the simplest \\{do} procedure first.
18480
18481 @c @<Declare nullary action procedure@>;
18482 void mp_do_nullary (MP mp,quarterword c) { 
18483   check_arith;
18484   if ( mp->internal[tracing_commands]>two )
18485     mp_show_cmd_mod(mp, nullary,c);
18486   switch (c) {
18487   case true_code: case false_code: 
18488     mp->cur_type=mp_boolean_type; mp->cur_exp=c;
18489     break;
18490   case null_picture_code: 
18491     mp->cur_type=mp_picture_type;
18492     mp->cur_exp=mp_get_node(mp, edge_header_size); 
18493     mp_init_edges(mp, mp->cur_exp);
18494     break;
18495   case null_pen_code: 
18496     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, 0);
18497     break;
18498   case normal_deviate: 
18499     mp->cur_type=mp_known; mp->cur_exp=mp_norm_rand(mp);
18500     break;
18501   case pen_circle: 
18502     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, unity);
18503     break;
18504   case job_name_op:  
18505     if ( mp->job_name==NULL ) mp_open_log_file(mp);
18506     mp->cur_type=mp_string_type; mp->cur_exp=rts(mp->job_name);
18507     break;
18508   case mp_version: 
18509     mp->cur_type=mp_string_type; 
18510     mp->cur_exp=intern(metapost_version) ;
18511     break;
18512   case read_string_op:
18513     @<Read a string from the terminal@>;
18514     break;
18515   } /* there are no other cases */
18516   check_arith;
18517 }
18518
18519 @ @<Read a string...@>=
18520
18521   if ( mp->interaction<=mp_nonstop_mode )
18522     mp_fatal_error(mp, "*** (cannot readstring in nonstop modes)");
18523   mp_begin_file_reading(mp); name=is_read;
18524   limit=start; prompt_input("");
18525   mp_finish_read(mp);
18526 }
18527
18528 @ @<Declare nullary action procedure@>=
18529 void mp_finish_read (MP mp) { /* copy |buffer| line to |cur_exp| */
18530   size_t k;
18531   str_room((int)mp->last-start);
18532   for (k=start;k<=mp->last-1;k++) {
18533    append_char(mp->buffer[k]);
18534   }
18535   mp_end_file_reading(mp); mp->cur_type=mp_string_type; 
18536   mp->cur_exp=mp_make_string(mp);
18537 }
18538
18539 @ Things get a bit more interesting when there's an operand. The
18540 operand to |do_unary| appears in |cur_type| and |cur_exp|.
18541
18542 @c @<Declare unary action procedures@>;
18543 void mp_do_unary (MP mp,quarterword c) {
18544   pointer p,q,r; /* for list manipulation */
18545   integer x; /* a temporary register */
18546   check_arith;
18547   if ( mp->internal[tracing_commands]>two )
18548     @<Trace the current unary operation@>;
18549   switch (c) {
18550   case plus:
18551     if ( mp->cur_type<mp_color_type ) mp_bad_unary(mp, plus);
18552     break;
18553   case minus:
18554     @<Negate the current expression@>;
18555     break;
18556   @<Additional cases of unary operators@>;
18557   } /* there are no other cases */
18558   check_arith;
18559 };
18560
18561 @ The |nice_pair| function returns |true| if both components of a pair
18562 are known.
18563
18564 @<Declare unary action procedures@>=
18565 boolean mp_nice_pair (MP mp,integer p, quarterword t) { 
18566   if ( t==mp_pair_type ) {
18567     p=value(p);
18568     if ( type(x_part_loc(p))==mp_known )
18569       if ( type(y_part_loc(p))==mp_known )
18570         return true;
18571   }
18572   return false;
18573 }
18574
18575 @ The |nice_color_or_pair| function is analogous except that it also accepts
18576 fully known colors.
18577
18578 @<Declare unary action procedures@>=
18579 boolean mp_nice_color_or_pair (MP mp,integer p, quarterword t) {
18580   pointer q,r; /* for scanning the big node */
18581   if ( (t!=mp_pair_type)&&(t!=mp_color_type)&&(t!=mp_cmykcolor_type) ) {
18582     return false;
18583   } else { 
18584     q=value(p);
18585     r=q+mp->big_node_size[type(p)];
18586     do {  
18587       r=r-2;
18588       if ( type(r)!=mp_known )
18589         return false;
18590     } while (r!=q);
18591     return true;
18592   }
18593 }
18594
18595 @ @<Declare unary action...@>=
18596 void mp_print_known_or_unknown_type (MP mp,small_number t, integer v) { 
18597   mp_print_char(mp, '(');
18598   if ( t>mp_known ) mp_print(mp, "unknown numeric");
18599   else { if ( (t==mp_pair_type)||(t==mp_color_type)||(t==mp_cmykcolor_type) )
18600     if ( ! mp_nice_color_or_pair(mp, v,t) ) mp_print(mp, "unknown ");
18601     mp_print_type(mp, t);
18602   }
18603   mp_print_char(mp, ')');
18604 }
18605
18606 @ @<Declare unary action...@>=
18607 void mp_bad_unary (MP mp,quarterword c) { 
18608   exp_err("Not implemented: "); mp_print_op(mp, c);
18609 @.Not implemented...@>
18610   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
18611   help3("I'm afraid I don't know how to apply that operation to that")
18612     ("particular type. Continue, and I'll simply return the")
18613     ("argument (shown above) as the result of the operation.");
18614   mp_put_get_error(mp);
18615 }
18616
18617 @ @<Trace the current unary operation@>=
18618
18619   mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); 
18620   mp_print_op(mp, c); mp_print_char(mp, '(');
18621   mp_print_exp(mp, null,0); /* show the operand, but not verbosely */
18622   mp_print(mp, ")}"); mp_end_diagnostic(mp, false);
18623 }
18624
18625 @ Negation is easy except when the current expression
18626 is of type |independent|, or when it is a pair with one or more
18627 |independent| components.
18628
18629 It is tempting to argue that the negative of an independent variable
18630 is an independent variable, hence we don't have to do anything when
18631 negating it. The fallacy is that other dependent variables pointing
18632 to the current expression must change the sign of their
18633 coefficients if we make no change to the current expression.
18634
18635 Instead, we work around the problem by copying the current expression
18636 and recycling it afterwards (cf.~the |stash_in| routine).
18637
18638 @<Negate the current expression@>=
18639 switch (mp->cur_type) {
18640 case mp_color_type:
18641 case mp_cmykcolor_type:
18642 case mp_pair_type:
18643 case mp_independent: 
18644   q=mp->cur_exp; mp_make_exp_copy(mp, q);
18645   if ( mp->cur_type==mp_dependent ) {
18646     mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18647   } else if ( mp->cur_type<=mp_pair_type ) { /* |mp_color_type| or |mp_pair_type| */
18648     p=value(mp->cur_exp);
18649     r=p+mp->big_node_size[mp->cur_type];
18650     do {  
18651       r=r-2;
18652       if ( type(r)==mp_known ) negate(value(r));
18653       else mp_negate_dep_list(mp, dep_list(r));
18654     } while (r!=p);
18655   } /* if |cur_type=mp_known| then |cur_exp=0| */
18656   mp_recycle_value(mp, q); mp_free_node(mp, q,value_node_size);
18657   break;
18658 case mp_dependent:
18659 case mp_proto_dependent:
18660   mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18661   break;
18662 case mp_known:
18663   negate(mp->cur_exp);
18664   break;
18665 default:
18666   mp_bad_unary(mp, minus);
18667   break;
18668 }
18669
18670 @ @<Declare unary action...@>=
18671 void mp_negate_dep_list (MP mp,pointer p) { 
18672   while (1) { 
18673     negate(value(p));
18674     if ( info(p)==null ) return;
18675     p=link(p);
18676   }
18677 }
18678
18679 @ @<Additional cases of unary operators@>=
18680 case not_op: 
18681   if ( mp->cur_type!=mp_boolean_type ) mp_bad_unary(mp, not_op);
18682   else mp->cur_exp=true_code+false_code-mp->cur_exp;
18683   break;
18684
18685 @ @d three_sixty_units 23592960 /* that's |360*unity| */
18686 @d boolean_reset(A) if ( (A) ) mp->cur_exp=true_code; else mp->cur_exp=false_code
18687
18688 @<Additional cases of unary operators@>=
18689 case sqrt_op:
18690 case m_exp_op:
18691 case m_log_op:
18692 case sin_d_op:
18693 case cos_d_op:
18694 case floor_op:
18695 case  uniform_deviate:
18696 case odd_op:
18697 case char_exists_op:
18698   if ( mp->cur_type!=mp_known ) {
18699     mp_bad_unary(mp, c);
18700   } else {
18701     switch (c) {
18702     case sqrt_op:mp->cur_exp=mp_square_rt(mp, mp->cur_exp);break;
18703     case m_exp_op:mp->cur_exp=mp_m_exp(mp, mp->cur_exp);break;
18704     case m_log_op:mp->cur_exp=mp_m_log(mp, mp->cur_exp);break;
18705     case sin_d_op:
18706     case cos_d_op:
18707       mp_n_sin_cos(mp, (mp->cur_exp % three_sixty_units)*16);
18708       if ( c==sin_d_op ) mp->cur_exp=mp_round_fraction(mp, mp->n_sin);
18709       else mp->cur_exp=mp_round_fraction(mp, mp->n_cos);
18710       break;
18711     case floor_op:mp->cur_exp=mp_floor_scaled(mp, mp->cur_exp);break;
18712     case uniform_deviate:mp->cur_exp=mp_unif_rand(mp, mp->cur_exp);break;
18713     case odd_op: 
18714       boolean_reset(odd(mp_round_unscaled(mp, mp->cur_exp)));
18715       mp->cur_type=mp_boolean_type;
18716       break;
18717     case char_exists_op:
18718       @<Determine if a character has been shipped out@>;
18719       break;
18720     } /* there are no other cases */
18721   }
18722   break;
18723
18724 @ @<Additional cases of unary operators@>=
18725 case angle_op:
18726   if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) ) {
18727     p=value(mp->cur_exp);
18728     x=mp_n_arg(mp, value(x_part_loc(p)),value(y_part_loc(p)));
18729     if ( x>=0 ) mp_flush_cur_exp(mp, (x+8)/ 16);
18730     else mp_flush_cur_exp(mp, -((-x+8)/ 16));
18731   } else {
18732     mp_bad_unary(mp, angle_op);
18733   }
18734   break;
18735
18736 @ If the current expression is a pair, but the context wants it to
18737 be a path, we call |pair_to_path|.
18738
18739 @<Declare unary action...@>=
18740 void mp_pair_to_path (MP mp) { 
18741   mp->cur_exp=mp_new_knot(mp); 
18742   mp->cur_type=mp_path_type;
18743 };
18744
18745 @ @<Additional cases of unary operators@>=
18746 case x_part:
18747 case y_part:
18748   if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_transform_type) )
18749     mp_take_part(mp, c);
18750   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18751   else mp_bad_unary(mp, c);
18752   break;
18753 case xx_part:
18754 case xy_part:
18755 case yx_part:
18756 case yy_part: 
18757   if ( mp->cur_type==mp_transform_type ) mp_take_part(mp, c);
18758   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18759   else mp_bad_unary(mp, c);
18760   break;
18761 case red_part:
18762 case green_part:
18763 case blue_part: 
18764   if ( mp->cur_type==mp_color_type ) mp_take_part(mp, c);
18765   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18766   else mp_bad_unary(mp, c);
18767   break;
18768 case cyan_part:
18769 case magenta_part:
18770 case yellow_part:
18771 case black_part: 
18772   if ( mp->cur_type==mp_cmykcolor_type) mp_take_part(mp, c); 
18773   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18774   else mp_bad_unary(mp, c);
18775   break;
18776 case grey_part: 
18777   if ( mp->cur_type==mp_known ) mp->cur_exp=value(c);
18778   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18779   else mp_bad_unary(mp, c);
18780   break;
18781 case color_model_part: 
18782   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18783   else mp_bad_unary(mp, c);
18784   break;
18785
18786 @ In the following procedure, |cur_exp| points to a capsule, which points to
18787 a big node. We want to delete all but one part of the big node.
18788
18789 @<Declare unary action...@>=
18790 void mp_take_part (MP mp,quarterword c) {
18791   pointer p; /* the big node */
18792   p=value(mp->cur_exp); value(temp_val)=p; type(temp_val)=mp->cur_type;
18793   link(p)=temp_val; mp_free_node(mp, mp->cur_exp,value_node_size);
18794   mp_make_exp_copy(mp, p+mp->sector_offset[c+mp_x_part_sector-x_part]);
18795   mp_recycle_value(mp, temp_val);
18796 }
18797
18798 @ @<Initialize table entries...@>=
18799 name_type(temp_val)=mp_capsule;
18800
18801 @ @<Additional cases of unary operators@>=
18802 case font_part:
18803 case text_part:
18804 case path_part:
18805 case pen_part:
18806 case dash_part:
18807   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18808   else mp_bad_unary(mp, c);
18809   break;
18810
18811 @ @<Declarations@>=
18812 void mp_scale_edges (MP mp);
18813
18814 @ @<Declare unary action...@>=
18815 void mp_take_pict_part (MP mp,quarterword c) {
18816   pointer p; /* first graphical object in |cur_exp| */
18817   p=link(dummy_loc(mp->cur_exp));
18818   if ( p!=null ) {
18819     switch (c) {
18820     case x_part: case y_part: case xx_part:
18821     case xy_part: case yx_part: case yy_part:
18822       if ( type(p)==text_code ) mp_flush_cur_exp(mp, text_trans_part(p+c));
18823       else goto NOT_FOUND;
18824       break;
18825     case red_part: case green_part: case blue_part:
18826       if ( has_color(p) ) mp_flush_cur_exp(mp, obj_color_part(p+c));
18827       else goto NOT_FOUND;
18828       break;
18829     case cyan_part: case magenta_part: case yellow_part:
18830     case black_part:
18831       if ( has_color(p) ) {
18832         if ( color_model(p)==uninitialized_model )
18833           mp_flush_cur_exp(mp, unity);
18834         else
18835           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-cyan_part)));
18836       } else goto NOT_FOUND;
18837       break;
18838     case grey_part:
18839       if ( has_color(p) )
18840           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-grey_part)));
18841       else goto NOT_FOUND;
18842       break;
18843     case color_model_part:
18844       if ( has_color(p) ) {
18845         if ( color_model(p)==uninitialized_model )
18846           mp_flush_cur_exp(mp, mp->internal[default_color_model]);
18847         else
18848           mp_flush_cur_exp(mp, color_model(p)*unity);
18849       } else goto NOT_FOUND;
18850       break;
18851     @<Handle other cases in |take_pict_part| or |goto not_found|@>;
18852     } /* all cases have been enumerated */
18853     return;
18854   };
18855 NOT_FOUND:
18856   @<Convert the current expression to a null value appropriate
18857     for |c|@>;
18858 }
18859
18860 @ @<Handle other cases in |take_pict_part| or |goto not_found|@>=
18861 case text_part: 
18862   if ( type(p)!=text_code ) goto NOT_FOUND;
18863   else { 
18864     mp_flush_cur_exp(mp, text_p(p));
18865     add_str_ref(mp->cur_exp);
18866     mp->cur_type=mp_string_type;
18867     };
18868   break;
18869 case font_part: 
18870   if ( type(p)!=text_code ) goto NOT_FOUND;
18871   else { 
18872     mp_flush_cur_exp(mp, rts(mp->font_name[font_n(p)])); 
18873     add_str_ref(mp->cur_exp);
18874     mp->cur_type=mp_string_type;
18875   };
18876   break;
18877 case path_part:
18878   if ( type(p)==text_code ) goto NOT_FOUND;
18879   else if ( is_stop(p) ) mp_confusion(mp, "pict");
18880 @:this can't happen pict}{\quad pict@>
18881   else { 
18882     mp_flush_cur_exp(mp, mp_copy_path(mp, path_p(p)));
18883     mp->cur_type=mp_path_type;
18884   }
18885   break;
18886 case pen_part: 
18887   if ( ! has_pen(p) ) goto NOT_FOUND;
18888   else {
18889     if ( pen_p(p)==null ) goto NOT_FOUND;
18890     else { mp_flush_cur_exp(mp, copy_pen(pen_p(p)));
18891       mp->cur_type=mp_pen_type;
18892     };
18893   }
18894   break;
18895 case dash_part: 
18896   if ( type(p)!=stroked_code ) goto NOT_FOUND;
18897   else { if ( dash_p(p)==null ) goto NOT_FOUND;
18898     else { add_edge_ref(dash_p(p));
18899     mp->se_sf=dash_scale(p);
18900     mp->se_pic=dash_p(p);
18901     mp_scale_edges(mp);
18902     mp_flush_cur_exp(mp, mp->se_pic);
18903     mp->cur_type=mp_picture_type;
18904     };
18905   }
18906   break;
18907
18908 @ Since |scale_edges| had to be declared |forward|, it had to be declared as a
18909 parameterless procedure even though it really takes two arguments and updates
18910 one of them.  Hence the following globals are needed.
18911
18912 @<Global...@>=
18913 pointer se_pic;  /* edge header used and updated by |scale_edges| */
18914 scaled se_sf;  /* the scale factor argument to |scale_edges| */
18915
18916 @ @<Convert the current expression to a null value appropriate...@>=
18917 switch (c) {
18918 case text_part: case font_part: 
18919   mp_flush_cur_exp(mp, rts(""));
18920   mp->cur_type=mp_string_type;
18921   break;
18922 case path_part: 
18923   mp_flush_cur_exp(mp, mp_get_node(mp, knot_node_size));
18924   left_type(mp->cur_exp)=endpoint;
18925   right_type(mp->cur_exp)=endpoint;
18926   link(mp->cur_exp)=mp->cur_exp;
18927   x_coord(mp->cur_exp)=0;
18928   y_coord(mp->cur_exp)=0;
18929   originator(mp->cur_exp)=metapost_user;
18930   mp->cur_type=mp_path_type;
18931   break;
18932 case pen_part: 
18933   mp_flush_cur_exp(mp, mp_get_pen_circle(mp, 0));
18934   mp->cur_type=mp_pen_type;
18935   break;
18936 case dash_part: 
18937   mp_flush_cur_exp(mp, mp_get_node(mp, edge_header_size));
18938   mp_init_edges(mp, mp->cur_exp);
18939   mp->cur_type=mp_picture_type;
18940   break;
18941 default: 
18942    mp_flush_cur_exp(mp, 0);
18943   break;
18944 }
18945
18946 @ @<Additional cases of unary...@>=
18947 case char_op: 
18948   if ( mp->cur_type!=mp_known ) { 
18949     mp_bad_unary(mp, char_op);
18950   } else { 
18951     mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256; 
18952     mp->cur_type=mp_string_type;
18953     if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
18954   }
18955   break;
18956 case decimal: 
18957   if ( mp->cur_type!=mp_known ) {
18958      mp_bad_unary(mp, decimal);
18959   } else { 
18960     mp->old_setting=mp->selector; mp->selector=new_string;
18961     mp_print_scaled(mp, mp->cur_exp); mp->cur_exp=mp_make_string(mp);
18962     mp->selector=mp->old_setting; mp->cur_type=mp_string_type;
18963   }
18964   break;
18965 case oct_op:
18966 case hex_op:
18967 case ASCII_op: 
18968   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
18969   else mp_str_to_num(mp, c);
18970   break;
18971 case font_size: 
18972   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, font_size);
18973   else @<Find the design size of the font whose name is |cur_exp|@>;
18974   break;
18975
18976 @ @<Declare unary action...@>=
18977 void mp_str_to_num (MP mp,quarterword c) { /* converts a string to a number */
18978   integer n; /* accumulator */
18979   ASCII_code m; /* current character */
18980   pool_pointer k; /* index into |str_pool| */
18981   int b; /* radix of conversion */
18982   boolean bad_char; /* did the string contain an invalid digit? */
18983   if ( c==ASCII_op ) {
18984     if ( length(mp->cur_exp)==0 ) n=-1;
18985     else n=mp->str_pool[mp->str_start[mp->cur_exp]];
18986   } else { 
18987     if ( c==oct_op ) b=8; else b=16;
18988     n=0; bad_char=false;
18989     for (k=mp->str_start[mp->cur_exp];k<=str_stop(mp->cur_exp)-1;k++) {
18990       m=mp->str_pool[k];
18991       if ( (m>='0')&&(m<='9') ) m=m-'0';
18992       else if ( (m>='A')&&(m<='F') ) m=m-'A'+10;
18993       else if ( (m>='a')&&(m<='f') ) m=m-'a'+10;
18994       else  { bad_char=true; m=0; };
18995       if ( m>=b ) { bad_char=true; m=0; };
18996       if ( n<32768 / b ) n=n*b+m; else n=32767;
18997     }
18998     @<Give error messages if |bad_char| or |n>=4096|@>;
18999   }
19000   mp_flush_cur_exp(mp, n*unity);
19001 }
19002
19003 @ @<Give error messages if |bad_char|...@>=
19004 if ( bad_char ) { 
19005   exp_err("String contains illegal digits");
19006 @.String contains illegal digits@>
19007   if ( c==oct_op ) {
19008     help1("I zeroed out characters that weren't in the range 0..7.");
19009   } else  {
19010     help1("I zeroed out characters that weren't hex digits.");
19011   }
19012   mp_put_get_error(mp);
19013 }
19014 if ( (n>4095) ) {
19015   if ( mp->internal[warning_check]>0 ) {
19016     print_err("Number too large ("); 
19017     mp_print_int(mp, n); mp_print_char(mp, ')');
19018 @.Number too large@>
19019     help2("I have trouble with numbers greater than 4095; watch out.")
19020       ("(Set warningcheck:=0 to suppress this message.)");
19021     mp_put_get_error(mp);
19022   }
19023 }
19024
19025 @ The length operation is somewhat unusual in that it applies to a variety
19026 of different types of operands.
19027
19028 @<Additional cases of unary...@>=
19029 case length_op: 
19030   switch (mp->cur_type) {
19031   case mp_string_type: mp_flush_cur_exp(mp, length(mp->cur_exp)*unity); break;
19032   case mp_path_type: mp_flush_cur_exp(mp, mp_path_length(mp)); break;
19033   case mp_known: mp->cur_exp=abs(mp->cur_exp); break;
19034   case mp_picture_type: mp_flush_cur_exp(mp, mp_pict_length(mp)); break;
19035   default: 
19036     if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) )
19037       mp_flush_cur_exp(mp, mp_pyth_add(mp, 
19038         value(x_part_loc(value(mp->cur_exp))),
19039         value(y_part_loc(value(mp->cur_exp)))));
19040     else mp_bad_unary(mp, c);
19041     break;
19042   }
19043   break;
19044
19045 @ @<Declare unary action...@>=
19046 scaled mp_path_length (MP mp) { /* computes the length of the current path */
19047   scaled n; /* the path length so far */
19048   pointer p; /* traverser */
19049   p=mp->cur_exp;
19050   if ( left_type(p)==endpoint ) n=-unity; else n=0;
19051   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
19052   return n;
19053 }
19054
19055 @ @<Declare unary action...@>=
19056 scaled mp_pict_length (MP mp) { 
19057   /* counts interior components in picture |cur_exp| */
19058   scaled n; /* the count so far */
19059   pointer p; /* traverser */
19060   n=0;
19061   p=link(dummy_loc(mp->cur_exp));
19062   if ( p!=null ) {
19063     if ( is_start_or_stop(p) )
19064       if ( mp_skip_1component(mp, p)==null ) p=link(p);
19065     while ( p!=null )  { 
19066       skip_component(p) return n; 
19067       n=n+unity;   
19068     }
19069   }
19070   return n;
19071 }
19072
19073 @ Implement |turningnumber|
19074
19075 @<Additional cases of unary...@>=
19076 case turning_op:
19077   if ( mp->cur_type==mp_pair_type ) mp_flush_cur_exp(mp, 0);
19078   else if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, turning_op);
19079   else if ( left_type(mp->cur_exp)==endpoint )
19080      mp_flush_cur_exp(mp, 0); /* not a cyclic path */
19081   else
19082     mp_flush_cur_exp(mp, mp_turn_cycles_wrapper(mp, mp->cur_exp));
19083   break;
19084
19085 @ The function |an_angle| returns the value of the |angle| primitive, or $0$ if the
19086 argument is |origin|.
19087
19088 @<Declare unary action...@>=
19089 angle mp_an_angle (MP mp,scaled xpar, scaled ypar) {
19090   if ( (! ((xpar==0) && (ypar==0))) )
19091     return mp_n_arg(mp, xpar,ypar);
19092   return 0;
19093 }
19094
19095
19096 @ The actual turning number is (for the moment) computed in a C function
19097 that receives eight integers corresponding to the four controlling points,
19098 and returns a single angle.  Besides those, we have to account for discrete
19099 moves at the actual points.
19100
19101 @d floor(a) (a>=0 ? a : -(int)(-a))
19102 @d bezier_error (720<<20)+1
19103 @d sign(v) ((v)>0 ? 1 : ((v)<0 ? -1 : 0 ))
19104 @d print_roots(a) { if (debuglevel>(65536*2))
19105    fprintf(stdout,"bezier_slope(): %s, i=%f, o=%f, angle=%f\n", (a),in,out,res); }
19106 @d out ((double)(xo>>20))
19107 @d mid ((double)(xm>>20))
19108 @d in  ((double)(xi>>20))
19109 @d divisor (256*256)
19110 @d double2angle(a) (int)floor(a*256.0*256.0*16.0)
19111
19112 @<Declare unary action...@>=
19113 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19114             integer CX,integer CY,integer DX,integer DY, int debuglevel);
19115
19116 @ @c 
19117 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19118             integer CX,integer CY,integer DX,integer DY, int debuglevel) {
19119   double a, b, c;
19120   integer deltax,deltay;
19121   double ax,ay,bx,by,cx,cy,dx,dy;
19122   angle xi = 0, xo = 0, xm = 0;
19123   double res = 0;
19124   ax=AX/divisor;  ay=AY/divisor;
19125   bx=BX/divisor;  by=BY/divisor;
19126   cx=CX/divisor;  cy=CY/divisor;
19127   dx=DX/divisor;  dy=DY/divisor;
19128
19129   deltax = (BX-AX); deltay = (BY-AY);
19130   if (deltax==0 && deltay == 0) { deltax=(CX-AX); deltay=(CY-AY); }
19131   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19132   xi = mp_an_angle(mp,deltax,deltay);
19133
19134   deltax = (CX-BX); deltay = (CY-BY);
19135   xm = mp_an_angle(mp,deltax,deltay);
19136
19137   deltax = (DX-CX); deltay = (DY-CY);
19138   if (deltax==0 && deltay == 0) { deltax=(DX-BX); deltay=(DY-BY); }
19139   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19140   xo = mp_an_angle(mp,deltax,deltay);
19141
19142   a = (bx-ax)*(cy-by) - (cx-bx)*(by-ay); /* a = (bp-ap)x(cp-bp); */
19143   b = (bx-ax)*(dy-cy) - (by-ay)*(dx-cx);; /* b = (bp-ap)x(dp-cp);*/
19144   c = (cx-bx)*(dy-cy) - (dx-cx)*(cy-by); /* c = (cp-bp)x(dp-cp);*/
19145
19146   if (debuglevel>(65536*2)) {
19147     fprintf(stdout,
19148       "bezier_slope(): (%.2f,%.2f),(%.2f,%.2f),(%.2f,%.2f),(%.2f,%.2f)\n",
19149               ax,ay,bx,by,cx,cy,dx,dy);
19150     fprintf(stdout,
19151       "bezier_slope(): a,b,c,b^2,4ac: (%.2f,%.2f,%.2f,%.2f,%.2f)\n",a,b,c,b*b,4*a*c);
19152   }
19153
19154   if ((a==0)&&(c==0)) {
19155     res = (b==0 ?  0 :  (out-in)); 
19156     print_roots("no roots (a)");
19157   } else if ((a==0)||(c==0)) {
19158     if ((sign(b) == sign(a)) || (sign(b) == sign(c))) {
19159       res = out-in; /* ? */
19160       if (res<-180.0) 
19161         res += 360.0;
19162       else if (res>180.0)
19163         res -= 360.0;
19164       print_roots("no roots (b)");
19165     } else {
19166       res = out-in; /* ? */
19167       print_roots("one root (a)");
19168     }
19169   } else if ((sign(a)*sign(c))<0) {
19170     res = out-in; /* ? */
19171       if (res<-180.0) 
19172         res += 360.0;
19173       else if (res>180.0)
19174         res -= 360.0;
19175     print_roots("one root (b)");
19176   } else {
19177     if (sign(a) == sign(b)) {
19178       res = out-in; /* ? */
19179       if (res<-180.0) 
19180         res += 360.0;
19181       else if (res>180.0)
19182         res -= 360.0;
19183       print_roots("no roots (d)");
19184     } else {
19185       if ((b*b) == (4*a*c)) {
19186         res = bezier_error;
19187         print_roots("double root"); /* cusp */
19188       } else if ((b*b) < (4*a*c)) {
19189         res = out-in; /* ? */
19190         if (res<=0.0 &&res>-180.0) 
19191           res += 360.0;
19192         else if (res>=0.0 && res<180.0)
19193           res -= 360.0;
19194         print_roots("no roots (e)");
19195       } else {
19196         res = out-in;
19197         if (res<-180.0) 
19198           res += 360.0;
19199         else if (res>180.0)
19200           res -= 360.0;
19201         print_roots("two roots"); /* two inflections */
19202       }
19203     }
19204   }
19205   return double2angle(res);
19206 }
19207
19208 @
19209 @d p_nextnext link(link(p))
19210 @d p_next link(p)
19211 @d seven_twenty_deg 05500000000 /* $720\cdot2^{20}$, represents $720^\circ$ */
19212
19213 @<Declare unary action...@>=
19214 scaled mp_new_turn_cycles (MP mp,pointer c) {
19215   angle res,ang; /*  the angles of intermediate results  */
19216   scaled turns;  /*  the turn counter  */
19217   pointer p;     /*  for running around the path  */
19218   integer xp,yp;   /*  coordinates of next point  */
19219   integer x,y;   /*  helper coordinates  */
19220   angle in_angle,out_angle;     /*  helper angles */
19221   int old_setting; /* saved |selector| setting */
19222   res=0;
19223   turns= 0;
19224   p=c;
19225   old_setting = mp->selector; mp->selector=term_only;
19226   if ( mp->internal[tracing_commands]>unity ) {
19227     mp_begin_diagnostic(mp);
19228     mp_print_nl(mp, "");
19229     mp_end_diagnostic(mp, false);
19230   }
19231   do { 
19232     xp = x_coord(p_next); yp = y_coord(p_next);
19233     ang  = mp_bezier_slope(mp,x_coord(p), y_coord(p), right_x(p), right_y(p),
19234              left_x(p_next), left_y(p_next), xp, yp, 
19235              mp->internal[tracing_commands]);
19236     if ( ang>seven_twenty_deg ) {
19237       print_err("Strange path");
19238       mp_error(mp);
19239       mp->selector=old_setting;
19240       return 0;
19241     }
19242     res  = res + ang;
19243     if ( res > one_eighty_deg ) {
19244       res = res - three_sixty_deg;
19245       turns = turns + unity;
19246     }
19247     if ( res <= -one_eighty_deg ) {
19248       res = res + three_sixty_deg;
19249       turns = turns - unity;
19250     }
19251     /*  incoming angle at next point  */
19252     x = left_x(p_next);  y = left_y(p_next);
19253     if ( (xp==x)&&(yp==y) ) { x = right_x(p);  y = right_y(p);  };
19254     if ( (xp==x)&&(yp==y) ) { x = x_coord(p);  y = y_coord(p);  };
19255     in_angle = mp_an_angle(mp, xp - x, yp - y);
19256     /*  outgoing angle at next point  */
19257     x = right_x(p_next);  y = right_y(p_next);
19258     if ( (xp==x)&&(yp==y) ) { x = left_x(p_nextnext);  y = left_y(p_nextnext);  };
19259     if ( (xp==x)&&(yp==y) ) { x = x_coord(p_nextnext); y = y_coord(p_nextnext); };
19260     out_angle = mp_an_angle(mp, x - xp, y- yp);
19261     ang  = (out_angle - in_angle);
19262     reduce_angle(ang);
19263     if ( ang!=0 ) {
19264       res  = res + ang;
19265       if ( res >= one_eighty_deg ) {
19266         res = res - three_sixty_deg;
19267         turns = turns + unity;
19268       };
19269       if ( res <= -one_eighty_deg ) {
19270         res = res + three_sixty_deg;
19271         turns = turns - unity;
19272       };
19273     };
19274     p = link(p);
19275   } while (p!=c);
19276   mp->selector=old_setting;
19277   return turns;
19278 }
19279
19280
19281 @ This code is based on Bogus\l{}av Jackowski's
19282 |emergency_turningnumber| macro, with some minor changes by Taco
19283 Hoekwater. The macro code looked more like this:
19284 {\obeylines
19285 vardef turning\_number primary p =
19286 ~~save res, ang, turns;
19287 ~~res := 0;
19288 ~~if length p <= 2:
19289 ~~~~if Angle ((point 0 of p) - (postcontrol 0 of p)) >= 0:  1  else: -1 fi
19290 ~~else:
19291 ~~~~for t = 0 upto length p-1 :
19292 ~~~~~~angc := Angle ((point t+1 of p)  - (point t of p))
19293 ~~~~~~~~- Angle ((point t of p) - (point t-1 of p));
19294 ~~~~~~if angc > 180: angc := angc - 360; fi;
19295 ~~~~~~if angc < -180: angc := angc + 360; fi;
19296 ~~~~~~res  := res + angc;
19297 ~~~~endfor;
19298 ~~res/360
19299 ~~fi
19300 enddef;}
19301 The general idea is to calculate only the sum of the angles of
19302 straight lines between the points, of a path, not worrying about cusps
19303 or self-intersections in the segments at all. If the segment is not
19304 well-behaved, the result is not necesarily correct. But the old code
19305 was not always correct either, and worse, it sometimes failed for
19306 well-behaved paths as well. All known bugs that were triggered by the
19307 original code no longer occur with this code, and it runs roughly 3
19308 times as fast because the algorithm is much simpler.
19309
19310 @ It is possible to overflow the return value of the |turn_cycles|
19311 function when the path is sufficiently long and winding, but I am not
19312 going to bother testing for that. In any case, it would only return
19313 the looped result value, which is not a big problem.
19314
19315 The macro code for the repeat loop was a bit nicer to look
19316 at than the pascal code, because it could use |point -1 of p|. In
19317 pascal, the fastest way to loop around the path is not to look
19318 backward once, but forward twice. These defines help hide the trick.
19319
19320 @d p_to link(link(p))
19321 @d p_here link(p)
19322 @d p_from p
19323
19324 @<Declare unary action...@>=
19325 scaled mp_turn_cycles (MP mp,pointer c) {
19326   angle res,ang; /*  the angles of intermediate results  */
19327   scaled turns;  /*  the turn counter  */
19328   pointer p;     /*  for running around the path  */
19329   res=0;  turns= 0; p=c;
19330   do { 
19331     ang  = mp_an_angle (mp, x_coord(p_to) - x_coord(p_here), 
19332                             y_coord(p_to) - y_coord(p_here))
19333         - mp_an_angle (mp, x_coord(p_here) - x_coord(p_from), 
19334                            y_coord(p_here) - y_coord(p_from));
19335     reduce_angle(ang);
19336     res  = res + ang;
19337     if ( res >= three_sixty_deg )  {
19338       res = res - three_sixty_deg;
19339       turns = turns + unity;
19340     };
19341     if ( res <= -three_sixty_deg ) {
19342       res = res + three_sixty_deg;
19343       turns = turns - unity;
19344     };
19345     p = link(p);
19346   } while (p!=c);
19347   return turns;
19348 }
19349
19350 @ @<Declare unary action...@>=
19351 scaled mp_turn_cycles_wrapper (MP mp,pointer c) {
19352   scaled nval,oval;
19353   scaled saved_t_o; /* tracing\_online saved  */
19354   if ( (link(c)==c)||(link(link(c))==c) ) {
19355     if ( mp_an_angle (mp, x_coord(c) - right_x(c),  y_coord(c) - right_y(c)) > 0 )
19356       return unity;
19357     else
19358       return -unity;
19359   } else {
19360     nval = mp_new_turn_cycles(mp, c);
19361     oval = mp_turn_cycles(mp, c);
19362     if ( nval!=oval ) {
19363       saved_t_o=mp->internal[tracing_online];
19364       mp->internal[tracing_online]=unity;
19365       mp_begin_diagnostic(mp);
19366       mp_print_nl (mp, "Warning: the turningnumber algorithms do not agree."
19367                        " The current computed value is ");
19368       mp_print_scaled(mp, nval);
19369       mp_print(mp, ", but the 'connect-the-dots' algorithm returned ");
19370       mp_print_scaled(mp, oval);
19371       mp_end_diagnostic(mp, false);
19372       mp->internal[tracing_online]=saved_t_o;
19373     }
19374     return nval;
19375   }
19376 }
19377
19378 @ @<Declare unary action...@>=
19379 scaled mp_count_turns (MP mp,pointer c) {
19380   pointer p; /* a knot in envelope spec |c| */
19381   integer t; /* total pen offset changes counted */
19382   t=0; p=c;
19383   do {  
19384     t=t+info(p)-zero_off;
19385     p=link(p);
19386   } while (p!=c);
19387   return ((t / 3)*unity);
19388 }
19389
19390 @ @d type_range(A,B) { 
19391   if ( (mp->cur_type>=(A)) && (mp->cur_type<=(B)) ) 
19392     mp_flush_cur_exp(mp, true_code);
19393   else mp_flush_cur_exp(mp, false_code);
19394   mp->cur_type=mp_boolean_type;
19395   }
19396 @d type_test(A) { 
19397   if ( mp->cur_type==(A) ) mp_flush_cur_exp(mp, true_code);
19398   else mp_flush_cur_exp(mp, false_code);
19399   mp->cur_type=mp_boolean_type;
19400   }
19401
19402 @<Additional cases of unary operators@>=
19403 case mp_boolean_type: 
19404   type_range(mp_boolean_type,mp_unknown_boolean); break;
19405 case mp_string_type: 
19406   type_range(mp_string_type,mp_unknown_string); break;
19407 case mp_pen_type: 
19408   type_range(mp_pen_type,mp_unknown_pen); break;
19409 case mp_path_type: 
19410   type_range(mp_path_type,mp_unknown_path); break;
19411 case mp_picture_type: 
19412   type_range(mp_picture_type,mp_unknown_picture); break;
19413 case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
19414 case mp_pair_type: 
19415   type_test(c); break;
19416 case mp_numeric_type: 
19417   type_range(mp_known,mp_independent); break;
19418 case known_op: case unknown_op: 
19419   mp_test_known(mp, c); break;
19420
19421 @ @<Declare unary action procedures@>=
19422 void mp_test_known (MP mp,quarterword c) {
19423   int b; /* is the current expression known? */
19424   pointer p,q; /* locations in a big node */
19425   b=false_code;
19426   switch (mp->cur_type) {
19427   case mp_vacuous: case mp_boolean_type: case mp_string_type:
19428   case mp_pen_type: case mp_path_type: case mp_picture_type:
19429   case mp_known: 
19430     b=true_code;
19431     break;
19432   case mp_transform_type:
19433   case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: 
19434     p=value(mp->cur_exp);
19435     q=p+mp->big_node_size[mp->cur_type];
19436     do {  
19437       q=q-2;
19438       if ( type(q)!=mp_known ) 
19439        goto DONE;
19440     } while (q!=p);
19441     b=true_code;
19442   DONE:  
19443     break;
19444   default: 
19445     break;
19446   }
19447   if ( c==known_op ) mp_flush_cur_exp(mp, b);
19448   else mp_flush_cur_exp(mp, true_code+false_code-b);
19449   mp->cur_type=mp_boolean_type;
19450 }
19451
19452 @ @<Additional cases of unary operators@>=
19453 case cycle_op: 
19454   if ( mp->cur_type!=mp_path_type ) mp_flush_cur_exp(mp, false_code);
19455   else if ( left_type(mp->cur_exp)!=endpoint ) mp_flush_cur_exp(mp, true_code);
19456   else mp_flush_cur_exp(mp, false_code);
19457   mp->cur_type=mp_boolean_type;
19458   break;
19459
19460 @ @<Additional cases of unary operators@>=
19461 case arc_length: 
19462   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19463   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, arc_length);
19464   else mp_flush_cur_exp(mp, mp_get_arc_length(mp, mp->cur_exp));
19465   break;
19466
19467 @ Here we use the fact that |c-filled_op+fill_code| is the desired graphical
19468 object |type|.
19469 @^data structure assumptions@>
19470
19471 @<Additional cases of unary operators@>=
19472 case filled_op:
19473 case stroked_op:
19474 case textual_op:
19475 case clipped_op:
19476 case bounded_op:
19477   if ( mp->cur_type!=mp_picture_type ) mp_flush_cur_exp(mp, false_code);
19478   else if ( link(dummy_loc(mp->cur_exp))==null ) mp_flush_cur_exp(mp, false_code);
19479   else if ( type(link(dummy_loc(mp->cur_exp)))==c+fill_code-filled_op )
19480     mp_flush_cur_exp(mp, true_code);
19481   else mp_flush_cur_exp(mp, false_code);
19482   mp->cur_type=mp_boolean_type;
19483   break;
19484
19485 @ @<Additional cases of unary operators@>=
19486 case make_pen_op: 
19487   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19488   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, make_pen_op);
19489   else { 
19490     mp->cur_type=mp_pen_type;
19491     mp->cur_exp=mp_make_pen(mp, mp->cur_exp,true);
19492   };
19493   break;
19494 case make_path_op: 
19495   if ( mp->cur_type!=mp_pen_type ) mp_bad_unary(mp, make_path_op);
19496   else  { 
19497     mp->cur_type=mp_path_type;
19498     mp_make_path(mp, mp->cur_exp);
19499   };
19500   break;
19501 case reverse: 
19502   if ( mp->cur_type==mp_path_type ) {
19503     p=mp_htap_ypoc(mp, mp->cur_exp);
19504     if ( right_type(p)==endpoint ) p=link(p);
19505     mp_toss_knot_list(mp, mp->cur_exp); mp->cur_exp=p;
19506   } else if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19507   else mp_bad_unary(mp, reverse);
19508   break;
19509
19510 @ The |pair_value| routine changes the current expression to a
19511 given ordered pair of values.
19512
19513 @<Declare unary action procedures@>=
19514 void mp_pair_value (MP mp,scaled x, scaled y) {
19515   pointer p; /* a pair node */
19516   p=mp_get_node(mp, value_node_size); 
19517   mp_flush_cur_exp(mp, p); mp->cur_type=mp_pair_type;
19518   type(p)=mp_pair_type; name_type(p)=mp_capsule; mp_init_big_node(mp, p);
19519   p=value(p);
19520   type(x_part_loc(p))=mp_known; value(x_part_loc(p))=x;
19521   type(y_part_loc(p))=mp_known; value(y_part_loc(p))=y;
19522 }
19523
19524 @ @<Additional cases of unary operators@>=
19525 case ll_corner_op: 
19526   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ll_corner_op);
19527   else mp_pair_value(mp, minx,miny);
19528   break;
19529 case lr_corner_op: 
19530   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, lr_corner_op);
19531   else mp_pair_value(mp, maxx,miny);
19532   break;
19533 case ul_corner_op: 
19534   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ul_corner_op);
19535   else mp_pair_value(mp, minx,maxy);
19536   break;
19537 case ur_corner_op: 
19538   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ur_corner_op);
19539   else mp_pair_value(mp, maxx,maxy);
19540   break;
19541
19542 @ Here is a function that sets |minx|, |maxx|, |miny|, |maxy| to the bounding
19543 box of the current expression.  The boolean result is |false| if the expression
19544 has the wrong type.
19545
19546 @<Declare unary action procedures@>=
19547 boolean mp_get_cur_bbox (MP mp) { 
19548   switch (mp->cur_type) {
19549   case mp_picture_type: 
19550     mp_set_bbox(mp, mp->cur_exp,true);
19551     if ( minx_val(mp->cur_exp)>maxx_val(mp->cur_exp) ) {
19552       minx=0; maxx=0; miny=0; maxy=0;
19553     } else { 
19554       minx=minx_val(mp->cur_exp);
19555       maxx=maxx_val(mp->cur_exp);
19556       miny=miny_val(mp->cur_exp);
19557       maxy=maxy_val(mp->cur_exp);
19558     }
19559     break;
19560   case mp_path_type: 
19561     mp_path_bbox(mp, mp->cur_exp);
19562     break;
19563   case mp_pen_type: 
19564     mp_pen_bbox(mp, mp->cur_exp);
19565     break;
19566   default: 
19567     return false;
19568   }
19569   return true;
19570 }
19571
19572 @ @<Additional cases of unary operators@>=
19573 case read_from_op:
19574 case close_from_op: 
19575   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19576   else mp_do_read_or_close(mp,c);
19577   break;
19578
19579 @ Here is a routine that interprets |cur_exp| as a file name and tries to read
19580 a line from the file or to close the file.
19581
19582 @d close_file 46 /* go here when closing the file */
19583
19584 @<Declare unary action procedures@>=
19585 void mp_do_read_or_close (MP mp,quarterword c) {
19586   readf_index n,n0; /* indices for searching |rd_fname| */
19587   @<Find the |n| where |rd_fname[n]=cur_exp|; if |cur_exp| must be inserted,
19588     call |start_read_input| and |goto found| or |not_found|@>;
19589   mp_begin_file_reading(mp);
19590   name=is_read;
19591   if ( mp_input_ln(mp, mp->rd_file[n],true) ) 
19592     goto FOUND;
19593   mp_end_file_reading(mp);
19594 NOT_FOUND:
19595   @<Record the end of file and set |cur_exp| to a dummy value@>;
19596   return;
19597 CLOSE_FILE:
19598   mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous; 
19599   return;
19600 FOUND:
19601   mp_flush_cur_exp(mp, 0);
19602   mp_finish_read(mp);
19603 }
19604
19605 @ Free slots in the |rd_file| and |rd_fname| arrays are marked with NULL's in
19606 |rd_fname|.
19607
19608 @<Find the |n| where |rd_fname[n]=cur_exp|...@>=
19609 {   
19610   char *fn;
19611   n=mp->read_files;
19612   n0=mp->read_files;
19613   fn = str(mp->cur_exp);
19614   while (mp_xstrcmp(fn,mp->rd_fname[n])!=0) { 
19615     if ( n>0 ) {
19616       decr(n);
19617     } else if ( c==close_from_op ) {
19618       goto CLOSE_FILE;
19619     } else {
19620       if ( n0==mp->read_files ) {
19621         if ( mp->read_files<mp->max_read_files ) {
19622           incr(mp->read_files);
19623         } else {
19624           FILE **rd_file;
19625           char **rd_fname;
19626               readf_index l,k;
19627           l = mp->max_read_files + (mp->max_read_files>>2);
19628           rd_file = xmalloc((l+1), sizeof(FILE *));
19629           rd_fname = xmalloc((l+1), sizeof(char *));
19630               for (k=0;k<=l;k++) {
19631             if (k<=mp->max_read_files) {
19632                   rd_file[k]=mp->rd_file[k]; 
19633               rd_fname[k]=mp->rd_fname[k];
19634             } else {
19635                   rd_file[k]=0; 
19636               rd_fname[k]=NULL;
19637             }
19638           }
19639               xfree(mp->rd_file); xfree(mp->rd_fname);
19640           mp->max_read_files = l;
19641           mp->rd_file = rd_file;
19642           mp->rd_fname = rd_fname;
19643         }
19644       }
19645       n=n0;
19646       if ( mp_start_read_input(mp,fn,n) ) 
19647         goto FOUND;
19648       else 
19649         goto NOT_FOUND;
19650     }
19651     if ( mp->rd_fname[n]==NULL ) { n0=n; }
19652   } 
19653   if ( c==close_from_op ) { 
19654     fclose(mp->rd_file[n]); 
19655     goto NOT_FOUND; 
19656   }
19657 }
19658
19659 @ @<Record the end of file and set |cur_exp| to a dummy value@>=
19660 xfree(mp->rd_fname[n]);
19661 mp->rd_fname[n]=NULL;
19662 if ( n==mp->read_files-1 ) mp->read_files=n;
19663 if ( c==close_from_op ) 
19664   goto CLOSE_FILE;
19665 mp_flush_cur_exp(mp, mp->eof_line);
19666 mp->cur_type=mp_string_type
19667
19668 @ The string denoting end-of-file is a one-byte string at position zero, by definition
19669
19670 @<Glob...@>=
19671 str_number eof_line;
19672
19673 @ @<Set init...@>=
19674 mp->eof_line=0;
19675
19676 @ Finally, we have the operations that combine a capsule~|p|
19677 with the current expression.
19678
19679 @c @<Declare binary action procedures@>;
19680 void mp_do_binary (MP mp,pointer p, quarterword c) {
19681   pointer q,r,rr; /* for list manipulation */
19682   pointer old_p,old_exp; /* capsules to recycle */
19683   integer v; /* for numeric manipulation */
19684   check_arith;
19685   if ( mp->internal[tracing_commands]>two ) {
19686     @<Trace the current binary operation@>;
19687   }
19688   @<Sidestep |independent| cases in capsule |p|@>;
19689   @<Sidestep |independent| cases in the current expression@>;
19690   switch (c) {
19691   case plus: case minus:
19692     @<Add or subtract the current expression from |p|@>;
19693     break;
19694   @<Additional cases of binary operators@>;
19695   }; /* there are no other cases */
19696   mp_recycle_value(mp, p); 
19697   mp_free_node(mp, p,value_node_size); /* |return| to avoid this */
19698   check_arith; 
19699   @<Recycle any sidestepped |independent| capsules@>;
19700 }
19701
19702 @ @<Declare binary action...@>=
19703 void mp_bad_binary (MP mp,pointer p, quarterword c) { 
19704   mp_disp_err(mp, p,"");
19705   exp_err("Not implemented: ");
19706 @.Not implemented...@>
19707   if ( c>=min_of ) mp_print_op(mp, c);
19708   mp_print_known_or_unknown_type(mp, type(p),p);
19709   if ( c>=min_of ) mp_print(mp, "of"); else mp_print_op(mp, c);
19710   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
19711   help3("I'm afraid I don't know how to apply that operation to that")
19712        ("combination of types. Continue, and I'll return the second")
19713       ("argument (see above) as the result of the operation.");
19714   mp_put_get_error(mp);
19715 }
19716
19717 @ @<Trace the current binary operation@>=
19718
19719   mp_begin_diagnostic(mp); mp_print_nl(mp, "{(");
19720   mp_print_exp(mp,p,0); /* show the operand, but not verbosely */
19721   mp_print_char(mp,')'); mp_print_op(mp,c); mp_print_char(mp,'(');
19722   mp_print_exp(mp,null,0); mp_print(mp,")}"); 
19723   mp_end_diagnostic(mp, false);
19724 }
19725
19726 @ Several of the binary operations are potentially complicated by the
19727 fact that |independent| values can sneak into capsules. For example,
19728 we've seen an instance of this difficulty in the unary operation
19729 of negation. In order to reduce the number of cases that need to be
19730 handled, we first change the two operands (if necessary)
19731 to rid them of |independent| components. The original operands are
19732 put into capsules called |old_p| and |old_exp|, which will be
19733 recycled after the binary operation has been safely carried out.
19734
19735 @<Recycle any sidestepped |independent| capsules@>=
19736 if ( old_p!=null ) { 
19737   mp_recycle_value(mp, old_p); mp_free_node(mp, old_p,value_node_size);
19738 }
19739 if ( old_exp!=null ) {
19740   mp_recycle_value(mp, old_exp); mp_free_node(mp, old_exp,value_node_size);
19741 }
19742
19743 @ A big node is considered to be ``tarnished'' if it contains at least one
19744 independent component. We will define a simple function called `|tarnished|'
19745 that returns |null| if and only if its argument is not tarnished.
19746
19747 @<Sidestep |independent| cases in capsule |p|@>=
19748 switch (type(p)) {
19749 case mp_transform_type:
19750 case mp_color_type:
19751 case mp_cmykcolor_type:
19752 case mp_pair_type: 
19753   old_p=mp_tarnished(mp, p);
19754   break;
19755 case mp_independent: old_p=diov; break;
19756 default: old_p=null; break;
19757 };
19758 if ( old_p!=null ) {
19759   q=mp_stash_cur_exp(mp); old_p=p; mp_make_exp_copy(mp, old_p);
19760   p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
19761 }
19762
19763 @ @<Sidestep |independent| cases in the current expression@>=
19764 switch (mp->cur_type) {
19765 case mp_transform_type:
19766 case mp_color_type:
19767 case mp_cmykcolor_type:
19768 case mp_pair_type: 
19769   old_exp=mp_tarnished(mp, mp->cur_exp);
19770   break;
19771 case mp_independent:old_exp=diov; break;
19772 default: old_exp=null; break;
19773 };
19774 if ( old_exp!=null ) {
19775   old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
19776 }
19777
19778 @ @<Declare binary action...@>=
19779 pointer mp_tarnished (MP mp,pointer p) {
19780   pointer q; /* beginning of the big node */
19781   pointer r; /* current position in the big node */
19782   q=value(p); r=q+mp->big_node_size[type(p)];
19783   do {  
19784    r=r-2;
19785    if ( type(r)==mp_independent ) return diov; 
19786   } while (r!=q);
19787   return null;
19788 }
19789
19790 @ @<Add or subtract the current expression from |p|@>=
19791 if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
19792   mp_bad_binary(mp, p,c);
19793 } else  {
19794   if ((mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
19795     mp_add_or_subtract(mp, p,null,c);
19796   } else {
19797     if ( mp->cur_type!=type(p) )  {
19798       mp_bad_binary(mp, p,c);
19799     } else { 
19800       q=value(p); r=value(mp->cur_exp);
19801       rr=r+mp->big_node_size[mp->cur_type];
19802       while ( r<rr ) { 
19803         mp_add_or_subtract(mp, q,r,c);
19804         q=q+2; r=r+2;
19805       }
19806     }
19807   }
19808 }
19809
19810 @ The first argument to |add_or_subtract| is the location of a value node
19811 in a capsule or pair node that will soon be recycled. The second argument
19812 is either a location within a pair or transform node of |cur_exp|,
19813 or it is null (which means that |cur_exp| itself should be the second
19814 argument).  The third argument is either |plus| or |minus|.
19815
19816 The sum or difference of the numeric quantities will replace the second
19817 operand.  Arithmetic overflow may go undetected; users aren't supposed to
19818 be monkeying around with really big values.
19819
19820 @<Declare binary action...@>=
19821 @<Declare the procedure called |dep_finish|@>;
19822 void mp_add_or_subtract (MP mp,pointer p, pointer q, quarterword c) {
19823   small_number s,t; /* operand types */
19824   pointer r; /* list traverser */
19825   integer v; /* second operand value */
19826   if ( q==null ) { 
19827     t=mp->cur_type;
19828     if ( t<mp_dependent ) v=mp->cur_exp; else v=dep_list(mp->cur_exp);
19829   } else { 
19830     t=type(q);
19831     if ( t<mp_dependent ) v=value(q); else v=dep_list(q);
19832   }
19833   if ( t==mp_known ) {
19834     if ( c==minus ) negate(v);
19835     if ( type(p)==mp_known ) {
19836       v=mp_slow_add(mp, value(p),v);
19837       if ( q==null ) mp->cur_exp=v; else value(q)=v;
19838       return;
19839     }
19840     @<Add a known value to the constant term of |dep_list(p)|@>;
19841   } else  { 
19842     if ( c==minus ) mp_negate_dep_list(mp, v);
19843     @<Add operand |p| to the dependency list |v|@>;
19844   }
19845 }
19846
19847 @ @<Add a known value to the constant term of |dep_list(p)|@>=
19848 r=dep_list(p);
19849 while ( info(r)!=null ) r=link(r);
19850 value(r)=mp_slow_add(mp, value(r),v);
19851 if ( q==null ) {
19852   q=mp_get_node(mp, value_node_size); mp->cur_exp=q; mp->cur_type=type(p);
19853   name_type(q)=mp_capsule;
19854 }
19855 dep_list(q)=dep_list(p); type(q)=type(p);
19856 prev_dep(q)=prev_dep(p); link(prev_dep(p))=q;
19857 type(p)=mp_known; /* this will keep the recycler from collecting non-garbage */
19858
19859 @ We prefer |dependent| lists to |mp_proto_dependent| ones, because it is
19860 nice to retain the extra accuracy of |fraction| coefficients.
19861 But we have to handle both kinds, and mixtures too.
19862
19863 @<Add operand |p| to the dependency list |v|@>=
19864 if ( type(p)==mp_known ) {
19865   @<Add the known |value(p)| to the constant term of |v|@>;
19866 } else { 
19867   s=type(p); r=dep_list(p);
19868   if ( t==mp_dependent ) {
19869     if ( s==mp_dependent ) {
19870       if ( mp_max_coef(mp, r)+mp_max_coef(mp, v)<coef_bound )
19871         v=mp_p_plus_q(mp, v,r,mp_dependent); goto DONE;
19872       } /* |fix_needed| will necessarily be false */
19873       t=mp_proto_dependent; 
19874       v=mp_p_over_v(mp, v,unity,mp_dependent,mp_proto_dependent);
19875     }
19876     if ( s==mp_proto_dependent ) v=mp_p_plus_q(mp, v,r,mp_proto_dependent);
19877     else v=mp_p_plus_fq(mp, v,unity,r,mp_proto_dependent,mp_dependent);
19878  DONE:  
19879     @<Output the answer, |v| (which might have become |known|)@>;
19880   }
19881
19882 @ @<Add the known |value(p)| to the constant term of |v|@>=
19883
19884   while ( info(v)!=null ) v=link(v);
19885   value(v)=mp_slow_add(mp, value(p),value(v));
19886 }
19887
19888 @ @<Output the answer, |v| (which might have become |known|)@>=
19889 if ( q!=null ) mp_dep_finish(mp, v,q,t);
19890 else  { mp->cur_type=t; mp_dep_finish(mp, v,null,t); }
19891
19892 @ Here's the current situation: The dependency list |v| of type |t|
19893 should either be put into the current expression (if |q=null|) or
19894 into location |q| within a pair node (otherwise). The destination (|cur_exp|
19895 or |q|) formerly held a dependency list with the same
19896 final pointer as the list |v|.
19897
19898 @<Declare the procedure called |dep_finish|@>=
19899 void mp_dep_finish (MP mp, pointer v, pointer q, small_number t) {
19900   pointer p; /* the destination */
19901   scaled vv; /* the value, if it is |known| */
19902   if ( q==null ) p=mp->cur_exp; else p=q;
19903   dep_list(p)=v; type(p)=t;
19904   if ( info(v)==null ) { 
19905     vv=value(v);
19906     if ( q==null ) { 
19907       mp_flush_cur_exp(mp, vv);
19908     } else  { 
19909       mp_recycle_value(mp, p); type(q)=mp_known; value(q)=vv; 
19910     }
19911   } else if ( q==null ) {
19912     mp->cur_type=t;
19913   }
19914   if ( mp->fix_needed ) mp_fix_dependencies(mp);
19915 }
19916
19917 @ Let's turn now to the six basic relations of comparison.
19918
19919 @<Additional cases of binary operators@>=
19920 case less_than: case less_or_equal: case greater_than:
19921 case greater_or_equal: case equal_to: case unequal_to:
19922   check_arith; /* at this point |arith_error| should be |false|? */
19923   if ( (mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
19924     mp_add_or_subtract(mp, p,null,minus); /* |cur_exp:=(p)-cur_exp| */
19925   } else if ( mp->cur_type!=type(p) ) {
19926     mp_bad_binary(mp, p,c); goto DONE; 
19927   } else if ( mp->cur_type==mp_string_type ) {
19928     mp_flush_cur_exp(mp, mp_str_vs_str(mp, value(p),mp->cur_exp));
19929   } else if ((mp->cur_type==mp_unknown_string)||
19930            (mp->cur_type==mp_unknown_boolean) ) {
19931     @<Check if unknowns have been equated@>;
19932   } else if ( (mp->cur_type<=mp_pair_type)&&(mp->cur_type>=mp_transform_type)) {
19933     @<Reduce comparison of big nodes to comparison of scalars@>;
19934   } else if ( mp->cur_type==mp_boolean_type ) {
19935     mp_flush_cur_exp(mp, mp->cur_exp-value(p));
19936   } else { 
19937     mp_bad_binary(mp, p,c); goto DONE;
19938   }
19939   @<Compare the current expression with zero@>;
19940 DONE:  
19941   mp->arith_error=false; /* ignore overflow in comparisons */
19942   break;
19943
19944 @ @<Compare the current expression with zero@>=
19945 if ( mp->cur_type!=mp_known ) {
19946   if ( mp->cur_type<mp_known ) {
19947     mp_disp_err(mp, p,"");
19948     help1("The quantities shown above have not been equated.")
19949   } else  {
19950     help2("Oh dear. I can\'t decide if the expression above is positive,")
19951      ("negative, or zero. So this comparison test won't be `true'.");
19952   }
19953   exp_err("Unknown relation will be considered false");
19954 @.Unknown relation...@>
19955   mp_put_get_flush_error(mp, false_code);
19956 } else {
19957   switch (c) {
19958   case less_than: boolean_reset(mp->cur_exp<0); break;
19959   case less_or_equal: boolean_reset(mp->cur_exp<=0); break;
19960   case greater_than: boolean_reset(mp->cur_exp>0); break;
19961   case greater_or_equal: boolean_reset(mp->cur_exp>=0); break;
19962   case equal_to: boolean_reset(mp->cur_exp==0); break;
19963   case unequal_to: boolean_reset(mp->cur_exp!=0); break;
19964   }; /* there are no other cases */
19965 }
19966 mp->cur_type=mp_boolean_type
19967
19968 @ When two unknown strings are in the same ring, we know that they are
19969 equal. Otherwise, we don't know whether they are equal or not, so we
19970 make no change.
19971
19972 @<Check if unknowns have been equated@>=
19973
19974   q=value(mp->cur_exp);
19975   while ( (q!=mp->cur_exp)&&(q!=p) ) q=value(q);
19976   if ( q==p ) mp_flush_cur_exp(mp, 0);
19977 }
19978
19979 @ @<Reduce comparison of big nodes to comparison of scalars@>=
19980
19981   q=value(p); r=value(mp->cur_exp);
19982   rr=r+mp->big_node_size[mp->cur_type]-2;
19983   while (1) { mp_add_or_subtract(mp, q,r,minus);
19984     if ( type(r)!=mp_known ) break;
19985     if ( value(r)!=0 ) break;
19986     if ( r==rr ) break;
19987     q=q+2; r=r+2;
19988   }
19989   mp_take_part(mp, name_type(r)+x_part-mp_x_part_sector);
19990 }
19991
19992 @ Here we use the sneaky fact that |and_op-false_code=or_op-true_code|.
19993
19994 @<Additional cases of binary operators@>=
19995 case and_op:
19996 case or_op: 
19997   if ( (type(p)!=mp_boolean_type)||(mp->cur_type!=mp_boolean_type) )
19998     mp_bad_binary(mp, p,c);
19999   else if ( value(p)==c+false_code-and_op ) mp->cur_exp=value(p);
20000   break;
20001
20002 @ @<Additional cases of binary operators@>=
20003 case times: 
20004   if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
20005    mp_bad_binary(mp, p,times);
20006   } else if ( (mp->cur_type==mp_known)||(type(p)==mp_known) ) {
20007     @<Multiply when at least one operand is known@>;
20008   } else if ( (mp_nice_color_or_pair(mp, p,type(p))&&(mp->cur_type>mp_pair_type))
20009       ||(mp_nice_color_or_pair(mp, mp->cur_exp,mp->cur_type)&&
20010           (type(p)>mp_pair_type)) ) {
20011     mp_hard_times(mp, p); return;
20012   } else {
20013     mp_bad_binary(mp, p,times);
20014   }
20015   break;
20016
20017 @ @<Multiply when at least one operand is known@>=
20018
20019   if ( type(p)==mp_known ) {
20020     v=value(p); mp_free_node(mp, p,value_node_size); 
20021   } else {
20022     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20023   }
20024   if ( mp->cur_type==mp_known ) {
20025     mp->cur_exp=mp_take_scaled(mp, mp->cur_exp,v);
20026   } else if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_color_type)||
20027               (mp->cur_type==mp_cmykcolor_type) ) {
20028     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20029     do {  
20030        p=p-2; mp_dep_mult(mp, p,v,true);
20031     } while (p!=value(mp->cur_exp));
20032   } else {
20033     mp_dep_mult(mp, null,v,true);
20034   }
20035   return;
20036 }
20037
20038 @ @<Declare binary action...@>=
20039 void mp_dep_mult (MP mp,pointer p, integer v, boolean v_is_scaled) {
20040   pointer q; /* the dependency list being multiplied by |v| */
20041   small_number s,t; /* its type, before and after */
20042   if ( p==null ) {
20043     q=mp->cur_exp;
20044   } else if ( type(p)!=mp_known ) {
20045     q=p;
20046   } else { 
20047     if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
20048     else value(p)=mp_take_fraction(mp, value(p),v);
20049     return;
20050   };
20051   t=type(q); q=dep_list(q); s=t;
20052   if ( t==mp_dependent ) if ( v_is_scaled )
20053     if (mp_ab_vs_cd(mp, mp_max_coef(mp,q),abs(v),coef_bound-1,unity)>=0 ) 
20054       t=mp_proto_dependent;
20055   q=mp_p_times_v(mp, q,v,s,t,v_is_scaled); 
20056   mp_dep_finish(mp, q,p,t);
20057 }
20058
20059 @ Here is a routine that is similar to |times|; but it is invoked only
20060 internally, when |v| is a |fraction| whose magnitude is at most~1,
20061 and when |cur_type>=mp_color_type|.
20062
20063 @c void mp_frac_mult (MP mp,scaled n, scaled d) {
20064   /* multiplies |cur_exp| by |n/d| */
20065   pointer p; /* a pair node */
20066   pointer old_exp; /* a capsule to recycle */
20067   fraction v; /* |n/d| */
20068   if ( mp->internal[tracing_commands]>two ) {
20069     @<Trace the fraction multiplication@>;
20070   }
20071   switch (mp->cur_type) {
20072   case mp_transform_type:
20073   case mp_color_type:
20074   case mp_cmykcolor_type:
20075   case mp_pair_type:
20076    old_exp=mp_tarnished(mp, mp->cur_exp);
20077    break;
20078   case mp_independent: old_exp=diov; break;
20079   default: old_exp=null; break;
20080   }
20081   if ( old_exp!=null ) { 
20082      old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20083   }
20084   v=mp_make_fraction(mp, n,d);
20085   if ( mp->cur_type==mp_known ) {
20086     mp->cur_exp=mp_take_fraction(mp, mp->cur_exp,v);
20087   } else if ( mp->cur_type<=mp_pair_type ) { 
20088     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20089     do {  
20090       p=p-2;
20091       mp_dep_mult(mp, p,v,false);
20092     } while (p!=value(mp->cur_exp));
20093   } else {
20094     mp_dep_mult(mp, null,v,false);
20095   }
20096   if ( old_exp!=null ) {
20097     mp_recycle_value(mp, old_exp); 
20098     mp_free_node(mp, old_exp,value_node_size);
20099   }
20100 }
20101
20102 @ @<Trace the fraction multiplication@>=
20103
20104   mp_begin_diagnostic(mp); 
20105   mp_print_nl(mp, "{("); mp_print_scaled(mp,n); mp_print_char(mp,'/');
20106   mp_print_scaled(mp,d); mp_print(mp,")*("); mp_print_exp(mp,null,0); 
20107   mp_print(mp,")}");
20108   mp_end_diagnostic(mp, false);
20109 }
20110
20111 @ The |hard_times| routine multiplies a nice color or pair by a dependency list.
20112
20113 @<Declare binary action procedures@>=
20114 void mp_hard_times (MP mp,pointer p) {
20115   pointer q; /* a copy of the dependent variable |p| */
20116   pointer r; /* a component of the big node for the nice color or pair */
20117   scaled v; /* the known value for |r| */
20118   if ( type(p)<=mp_pair_type ) { 
20119      q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); p=q;
20120   }; /* now |cur_type=mp_pair_type| or |cur_type=mp_color_type| */
20121   r=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20122   while (1) { 
20123     r=r-2;
20124     v=value(r);
20125     type(r)=type(p);
20126     if ( r==value(mp->cur_exp) ) 
20127       break;
20128     mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(p)));
20129     mp_dep_mult(mp, r,v,true);
20130   }
20131   mp->mem[value_loc(r)]=mp->mem[value_loc(p)];
20132   link(prev_dep(p))=r;
20133   mp_free_node(mp, p,value_node_size);
20134   mp_dep_mult(mp, r,v,true);
20135 }
20136
20137 @ @<Additional cases of binary operators@>=
20138 case over: 
20139   if ( (mp->cur_type!=mp_known)||(type(p)<mp_color_type) ) {
20140     mp_bad_binary(mp, p,over);
20141   } else { 
20142     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20143     if ( v==0 ) {
20144       @<Squeal about division by zero@>;
20145     } else { 
20146       if ( mp->cur_type==mp_known ) {
20147         mp->cur_exp=mp_make_scaled(mp, mp->cur_exp,v);
20148       } else if ( mp->cur_type<=mp_pair_type ) { 
20149         p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20150         do {  
20151           p=p-2;  mp_dep_div(mp, p,v);
20152         } while (p!=value(mp->cur_exp));
20153       } else {
20154         mp_dep_div(mp, null,v);
20155       }
20156     }
20157     return;
20158   }
20159   break;
20160
20161 @ @<Declare binary action...@>=
20162 void mp_dep_div (MP mp,pointer p, scaled v) {
20163   pointer q; /* the dependency list being divided by |v| */
20164   small_number s,t; /* its type, before and after */
20165   if ( p==null ) q=mp->cur_exp;
20166   else if ( type(p)!=mp_known ) q=p;
20167   else { value(p)=mp_make_scaled(mp, value(p),v); return; };
20168   t=type(q); q=dep_list(q); s=t;
20169   if ( t==mp_dependent )
20170     if ( mp_ab_vs_cd(mp, mp_max_coef(mp,q),unity,coef_bound-1,abs(v))>=0 ) 
20171       t=mp_proto_dependent;
20172   q=mp_p_over_v(mp, q,v,s,t); 
20173   mp_dep_finish(mp, q,p,t);
20174 }
20175
20176 @ @<Squeal about division by zero@>=
20177
20178   exp_err("Division by zero");
20179 @.Division by zero@>
20180   help2("You're trying to divide the quantity shown above the error")
20181     ("message by zero. I'm going to divide it by one instead.");
20182   mp_put_get_error(mp);
20183 }
20184
20185 @ @<Additional cases of binary operators@>=
20186 case pythag_add:
20187 case pythag_sub: 
20188    if ( (mp->cur_type==mp_known)&&(type(p)==mp_known) ) {
20189      if ( c==pythag_add ) mp->cur_exp=mp_pyth_add(mp, value(p),mp->cur_exp);
20190      else mp->cur_exp=mp_pyth_sub(mp, value(p),mp->cur_exp);
20191    } else mp_bad_binary(mp, p,c);
20192    break;
20193
20194 @ The next few sections of the program deal with affine transformations
20195 of coordinate data.
20196
20197 @<Additional cases of binary operators@>=
20198 case rotated_by: case slanted_by:
20199 case scaled_by: case shifted_by: case transformed_by:
20200 case x_scaled: case y_scaled: case z_scaled:
20201   if ( type(p)==mp_path_type ) { 
20202     path_trans(c,p); return;
20203   } else if ( type(p)==mp_pen_type ) { 
20204     pen_trans(c,p);
20205     mp->cur_exp=mp_convex_hull(mp, mp->cur_exp); 
20206       /* rounding error could destroy convexity */
20207     return;
20208   } else if ( (type(p)==mp_pair_type)||(type(p)==mp_transform_type) ) {
20209     mp_big_trans(mp, p,c);
20210   } else if ( type(p)==mp_picture_type ) {
20211     mp_do_edges_trans(mp, p,c); return;
20212   } else {
20213     mp_bad_binary(mp, p,c);
20214   }
20215   break;
20216
20217 @ Let |c| be one of the eight transform operators. The procedure call
20218 |set_up_trans(c)| first changes |cur_exp| to a transform that corresponds to
20219 |c| and the original value of |cur_exp|. (In particular, |cur_exp| doesn't
20220 change at all if |c=transformed_by|.)
20221
20222 Then, if all components of the resulting transform are |known|, they are
20223 moved to the global variables |txx|, |txy|, |tyx|, |tyy|, |tx|, |ty|;
20224 and |cur_exp| is changed to the known value zero.
20225
20226 @<Declare binary action...@>=
20227 void mp_set_up_trans (MP mp,quarterword c) {
20228   pointer p,q,r; /* list manipulation registers */
20229   if ( (c!=transformed_by)||(mp->cur_type!=mp_transform_type) ) {
20230     @<Put the current transform into |cur_exp|@>;
20231   }
20232   @<If the current transform is entirely known, stash it in global variables;
20233     otherwise |return|@>;
20234 }
20235
20236 @ @<Glob...@>=
20237 scaled txx;
20238 scaled txy;
20239 scaled tyx;
20240 scaled tyy;
20241 scaled tx;
20242 scaled ty; /* current transform coefficients */
20243
20244 @ @<Put the current transform...@>=
20245
20246   p=mp_stash_cur_exp(mp); 
20247   mp->cur_exp=mp_id_transform(mp); 
20248   mp->cur_type=mp_transform_type;
20249   q=value(mp->cur_exp);
20250   switch (c) {
20251   @<For each of the eight cases, change the relevant fields of |cur_exp|
20252     and |goto done|;
20253     but do nothing if capsule |p| doesn't have the appropriate type@>;
20254   }; /* there are no other cases */
20255   mp_disp_err(mp, p,"Improper transformation argument");
20256 @.Improper transformation argument@>
20257   help3("The expression shown above has the wrong type,")
20258        ("so I can\'t transform anything using it.")
20259        ("Proceed, and I'll omit the transformation.");
20260   mp_put_get_error(mp);
20261 DONE: 
20262   mp_recycle_value(mp, p); 
20263   mp_free_node(mp, p,value_node_size);
20264 }
20265
20266 @ @<If the current transform is entirely known, ...@>=
20267 q=value(mp->cur_exp); r=q+transform_node_size;
20268 do {  
20269   r=r-2;
20270   if ( type(r)!=mp_known ) return;
20271 } while (r!=q);
20272 mp->txx=value(xx_part_loc(q));
20273 mp->txy=value(xy_part_loc(q));
20274 mp->tyx=value(yx_part_loc(q));
20275 mp->tyy=value(yy_part_loc(q));
20276 mp->tx=value(x_part_loc(q));
20277 mp->ty=value(y_part_loc(q));
20278 mp_flush_cur_exp(mp, 0)
20279
20280 @ @<For each of the eight cases...@>=
20281 case rotated_by:
20282   if ( type(p)==mp_known )
20283     @<Install sines and cosines, then |goto done|@>;
20284   break;
20285 case slanted_by:
20286   if ( type(p)>mp_pair_type ) { 
20287    mp_install(mp, xy_part_loc(q),p); goto DONE;
20288   };
20289   break;
20290 case scaled_by:
20291   if ( type(p)>mp_pair_type ) { 
20292     mp_install(mp, xx_part_loc(q),p); mp_install(mp, yy_part_loc(q),p); 
20293     goto DONE;
20294   };
20295   break;
20296 case shifted_by:
20297   if ( type(p)==mp_pair_type ) {
20298     r=value(p); mp_install(mp, x_part_loc(q),x_part_loc(r));
20299     mp_install(mp, y_part_loc(q),y_part_loc(r)); goto DONE;
20300   };
20301   break;
20302 case x_scaled:
20303   if ( type(p)>mp_pair_type ) {
20304     mp_install(mp, xx_part_loc(q),p); goto DONE;
20305   };
20306   break;
20307 case y_scaled:
20308   if ( type(p)>mp_pair_type ) {
20309     mp_install(mp, yy_part_loc(q),p); goto DONE;
20310   };
20311   break;
20312 case z_scaled:
20313   if ( type(p)==mp_pair_type )
20314     @<Install a complex multiplier, then |goto done|@>;
20315   break;
20316 case transformed_by:
20317   break;
20318   
20319
20320 @ @<Install sines and cosines, then |goto done|@>=
20321 { mp_n_sin_cos(mp, (value(p) % three_sixty_units)*16);
20322   value(xx_part_loc(q))=mp_round_fraction(mp, mp->n_cos);
20323   value(yx_part_loc(q))=mp_round_fraction(mp, mp->n_sin);
20324   value(xy_part_loc(q))=-value(yx_part_loc(q));
20325   value(yy_part_loc(q))=value(xx_part_loc(q));
20326   goto DONE;
20327 }
20328
20329 @ @<Install a complex multiplier, then |goto done|@>=
20330
20331   r=value(p);
20332   mp_install(mp, xx_part_loc(q),x_part_loc(r));
20333   mp_install(mp, yy_part_loc(q),x_part_loc(r));
20334   mp_install(mp, yx_part_loc(q),y_part_loc(r));
20335   if ( type(y_part_loc(r))==mp_known ) negate(value(y_part_loc(r)));
20336   else mp_negate_dep_list(mp, dep_list(y_part_loc(r)));
20337   mp_install(mp, xy_part_loc(q),y_part_loc(r));
20338   goto DONE;
20339 }
20340
20341 @ Procedure |set_up_known_trans| is like |set_up_trans|, but it
20342 insists that the transformation be entirely known.
20343
20344 @<Declare binary action...@>=
20345 void mp_set_up_known_trans (MP mp,quarterword c) { 
20346   mp_set_up_trans(mp, c);
20347   if ( mp->cur_type!=mp_known ) {
20348     exp_err("Transform components aren't all known");
20349 @.Transform components...@>
20350     help3("I'm unable to apply a partially specified transformation")
20351       ("except to a fully known pair or transform.")
20352       ("Proceed, and I'll omit the transformation.");
20353     mp_put_get_flush_error(mp, 0);
20354     mp->txx=unity; mp->txy=0; mp->tyx=0; mp->tyy=unity; 
20355     mp->tx=0; mp->ty=0;
20356   }
20357 }
20358
20359 @ Here's a procedure that applies the transform |txx..ty| to a pair of
20360 coordinates in locations |p| and~|q|.
20361
20362 @<Declare binary action...@>= 
20363 void mp_trans (MP mp,pointer p, pointer q) {
20364   scaled v; /* the new |x| value */
20365   v=mp_take_scaled(mp, mp->mem[p].sc,mp->txx)+
20366   mp_take_scaled(mp, mp->mem[q].sc,mp->txy)+mp->tx;
20367   mp->mem[q].sc=mp_take_scaled(mp, mp->mem[p].sc,mp->tyx)+
20368   mp_take_scaled(mp, mp->mem[q].sc,mp->tyy)+mp->ty;
20369   mp->mem[p].sc=v;
20370 }
20371
20372 @ The simplest transformation procedure applies a transform to all
20373 coordinates of a path.  The |path_trans(c)(p)| macro applies
20374 a transformation defined by |cur_exp| and the transform operator |c|
20375 to the path~|p|.
20376
20377 @d path_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20378                      mp_unstash_cur_exp(mp, (B)); 
20379                      mp_do_path_trans(mp, mp->cur_exp); }
20380
20381 @<Declare binary action...@>=
20382 void mp_do_path_trans (MP mp,pointer p) {
20383   pointer q; /* list traverser */
20384   q=p;
20385   do { 
20386     if ( left_type(q)!=endpoint ) 
20387       mp_trans(mp, q+3,q+4); /* that's |left_x| and |left_y| */
20388     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20389     if ( right_type(q)!=endpoint ) 
20390       mp_trans(mp, q+5,q+6); /* that's |right_x| and |right_y| */
20391 @^data structure assumptions@>
20392     q=link(q);
20393   } while (q!=p);
20394 }
20395
20396 @ Transforming a pen is very similar, except that there are no |left_type|
20397 and |right_type| fields.
20398
20399 @d pen_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20400                     mp_unstash_cur_exp(mp, (B)); 
20401                     mp_do_pen_trans(mp, mp->cur_exp); }
20402
20403 @<Declare binary action...@>=
20404 void mp_do_pen_trans (MP mp,pointer p) {
20405   pointer q; /* list traverser */
20406   if ( pen_is_elliptical(p) ) {
20407     mp_trans(mp, p+3,p+4); /* that's |left_x| and |left_y| */
20408     mp_trans(mp, p+5,p+6); /* that's |right_x| and |right_y| */
20409   };
20410   q=p;
20411   do { 
20412     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20413 @^data structure assumptions@>
20414     q=link(q);
20415   } while (q!=p);
20416 }
20417
20418 @ The next transformation procedure applies to edge structures. It will do
20419 any transformation, but the results may be substandard if the picture contains
20420 text that uses downloaded bitmap fonts.  The binary action procedure is
20421 |do_edges_trans|, but we also need a function that just scales a picture.
20422 That routine is |scale_edges|.  Both it and the underlying routine |edges_trans|
20423 should be thought of as procedures that update an edge structure |h|, except
20424 that they have to return a (possibly new) structure because of the need to call
20425 |private_edges|.
20426
20427 @<Declare binary action...@>=
20428 pointer mp_edges_trans (MP mp, pointer h) {
20429   pointer q; /* the object being transformed */
20430   pointer r,s; /* for list manipulation */
20431   scaled sx,sy; /* saved transformation parameters */
20432   scaled sqdet; /* square root of determinant for |dash_scale| */
20433   integer sgndet; /* sign of the determinant */
20434   scaled v; /* a temporary value */
20435   h=mp_private_edges(mp, h);
20436   sqdet=mp_sqrt_det(mp, mp->txx,mp->txy,mp->tyx,mp->tyy);
20437   sgndet=mp_ab_vs_cd(mp, mp->txx,mp->tyy,mp->txy,mp->tyx);
20438   if ( dash_list(h)!=null_dash ) {
20439     @<Try to transform the dash list of |h|@>;
20440   }
20441   @<Make the bounding box of |h| unknown if it can't be updated properly
20442     without scanning the whole structure@>;  
20443   q=link(dummy_loc(h));
20444   while ( q!=null ) { 
20445     @<Transform graphical object |q|@>;
20446     q=link(q);
20447   }
20448   return h;
20449 }
20450 void mp_do_edges_trans (MP mp,pointer p, quarterword c) { 
20451   mp_set_up_known_trans(mp, c);
20452   value(p)=mp_edges_trans(mp, value(p));
20453   mp_unstash_cur_exp(mp, p);
20454 }
20455 void mp_scale_edges (MP mp) { 
20456   mp->txx=mp->se_sf; mp->tyy=mp->se_sf;
20457   mp->txy=0; mp->tyx=0; mp->tx=0; mp->ty=0;
20458   mp->se_pic=mp_edges_trans(mp, mp->se_pic);
20459 }
20460
20461 @ @<Try to transform the dash list of |h|@>=
20462 if ( (mp->txy!=0)||(mp->tyx!=0)||
20463      (mp->ty!=0)||(abs(mp->txx)!=abs(mp->tyy))) {
20464   mp_flush_dash_list(mp, h);
20465 } else { 
20466   if ( mp->txx<0 ) { @<Reverse the dash list of |h|@>; } 
20467   @<Scale the dash list by |txx| and shift it by |tx|@>;
20468   dash_y(h)=mp_take_scaled(mp, dash_y(h),abs(mp->tyy));
20469 }
20470
20471 @ @<Reverse the dash list of |h|@>=
20472
20473   r=dash_list(h);
20474   dash_list(h)=null_dash;
20475   while ( r!=null_dash ) {
20476     s=r; r=link(r);
20477     v=start_x(s); start_x(s)=stop_x(s); stop_x(s)=v;
20478     link(s)=dash_list(h);
20479     dash_list(h)=s;
20480   }
20481 }
20482
20483 @ @<Scale the dash list by |txx| and shift it by |tx|@>=
20484 r=dash_list(h);
20485 while ( r!=null_dash ) {
20486   start_x(r)=mp_take_scaled(mp, start_x(r),mp->txx)+mp->tx;
20487   stop_x(r)=mp_take_scaled(mp, stop_x(r),mp->txx)+mp->tx;
20488   r=link(r);
20489 }
20490
20491 @ @<Make the bounding box of |h| unknown if it can't be updated properly...@>=
20492 if ( (mp->txx==0)&&(mp->tyy==0) ) {
20493   @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>;
20494 } else if ( (mp->txy!=0)||(mp->tyx!=0) ) {
20495   mp_init_bbox(mp, h);
20496   goto DONE1;
20497 }
20498 if ( minx_val(h)<=maxx_val(h) ) {
20499   @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift by
20500    |(tx,ty)|@>;
20501 }
20502 DONE1:
20503
20504
20505
20506 @ @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>=
20507
20508   v=minx_val(h); minx_val(h)=miny_val(h); miny_val(h)=v;
20509   v=maxx_val(h); maxx_val(h)=maxy_val(h); maxy_val(h)=v;
20510 }
20511
20512 @ The sum ``|txx+txy|'' is whichever of |txx| or |txy| is nonzero.  The other
20513 sum is similar.
20514
20515 @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift...@>=
20516
20517   minx_val(h)=mp_take_scaled(mp, minx_val(h),mp->txx+mp->txy)+mp->tx;
20518   maxx_val(h)=mp_take_scaled(mp, maxx_val(h),mp->txx+mp->txy)+mp->tx;
20519   miny_val(h)=mp_take_scaled(mp, miny_val(h),mp->tyx+mp->tyy)+mp->ty;
20520   maxy_val(h)=mp_take_scaled(mp, maxy_val(h),mp->tyx+mp->tyy)+mp->ty;
20521   if ( mp->txx+mp->txy<0 ) {
20522     v=minx_val(h); minx_val(h)=maxx_val(h); maxx_val(h)=v;
20523   }
20524   if ( mp->tyx+mp->tyy<0 ) {
20525     v=miny_val(h); miny_val(h)=maxy_val(h); maxy_val(h)=v;
20526   }
20527 }
20528
20529 @ Now we ready for the main task of transforming the graphical objects in edge
20530 structure~|h|.
20531
20532 @<Transform graphical object |q|@>=
20533 switch (type(q)) {
20534 case fill_code: case stroked_code: 
20535   mp_do_path_trans(mp, path_p(q));
20536   @<Transform |pen_p(q)|, making sure polygonal pens stay counter-clockwise@>;
20537   break;
20538 case mp_start_clip_code: case mp_start_bounds_code: 
20539   mp_do_path_trans(mp, path_p(q));
20540   break;
20541 case text_code: 
20542   r=text_tx_loc(q);
20543   @<Transform the compact transformation starting at |r|@>;
20544   break;
20545 case mp_stop_clip_code: case mp_stop_bounds_code: 
20546   break;
20547 } /* there are no other cases */
20548
20549 @ Note that the shift parameters |(tx,ty)| apply only to the path being stroked.
20550 The |dash_scale| has to be adjusted  to scale the dash lengths in |dash_p(q)|
20551 since the \ps\ output procedures will try to compensate for the transformation
20552 we are applying to |pen_p(q)|.  Since this compensation is based on the square
20553 root of the determinant, |sqdet| is the appropriate factor.
20554
20555 @<Transform |pen_p(q)|, making sure...@>=
20556 if ( pen_p(q)!=null ) {
20557   sx=mp->tx; sy=mp->ty;
20558   mp->tx=0; mp->ty=0;
20559   mp_do_pen_trans(mp, pen_p(q));
20560   if ( ((type(q)==stroked_code)&&(dash_p(q)!=null)) )
20561     dash_scale(q)=mp_take_scaled(mp, dash_scale(q),sqdet);
20562   if ( ! pen_is_elliptical(pen_p(q)) )
20563     if ( sgndet<0 )
20564       pen_p(q)=mp_make_pen(mp, mp_copy_path(mp, pen_p(q)),true); 
20565          /* this unreverses the pen */
20566   mp->tx=sx; mp->ty=sy;
20567 }
20568
20569 @ This uses the fact that transformations are stored in the order
20570 |(tx,ty,txx,txy,tyx,tyy)|.
20571 @^data structure assumptions@>
20572
20573 @<Transform the compact transformation starting at |r|@>=
20574 mp_trans(mp, r,r+1);
20575 sx=mp->tx; sy=mp->ty;
20576 mp->tx=0; mp->ty=0;
20577 mp_trans(mp, r+2,r+4);
20578 mp_trans(mp, r+3,r+5);
20579 mp->tx=sx; mp->ty=sy
20580
20581 @ The hard cases of transformation occur when big nodes are involved,
20582 and when some of their components are unknown.
20583
20584 @<Declare binary action...@>=
20585 @<Declare subroutines needed by |big_trans|@>;
20586 void mp_big_trans (MP mp,pointer p, quarterword c) {
20587   pointer q,r,pp,qq; /* list manipulation registers */
20588   small_number s; /* size of a big node */
20589   s=mp->big_node_size[type(p)]; q=value(p); r=q+s;
20590   do {  
20591     r=r-2;
20592     if ( type(r)!=mp_known ) {
20593       @<Transform an unknown big node and |return|@>;
20594     }
20595   } while (r!=q);
20596   @<Transform a known big node@>;
20597 }; /* node |p| will now be recycled by |do_binary| */
20598
20599 @ @<Transform an unknown big node and |return|@>=
20600
20601   mp_set_up_known_trans(mp, c); mp_make_exp_copy(mp, p); 
20602   r=value(mp->cur_exp);
20603   if ( mp->cur_type==mp_transform_type ) {
20604     mp_bilin1(mp, yy_part_loc(r),mp->tyy,xy_part_loc(q),mp->tyx,0);
20605     mp_bilin1(mp, yx_part_loc(r),mp->tyy,xx_part_loc(q),mp->tyx,0);
20606     mp_bilin1(mp, xy_part_loc(r),mp->txx,yy_part_loc(q),mp->txy,0);
20607     mp_bilin1(mp, xx_part_loc(r),mp->txx,yx_part_loc(q),mp->txy,0);
20608   }
20609   mp_bilin1(mp, y_part_loc(r),mp->tyy,x_part_loc(q),mp->tyx,mp->ty);
20610   mp_bilin1(mp, x_part_loc(r),mp->txx,y_part_loc(q),mp->txy,mp->tx);
20611   return;
20612 }
20613
20614 @ Let |p| point to a two-word value field inside a big node of |cur_exp|,
20615 and let |q| point to a another value field. The |bilin1| procedure
20616 replaces |p| by $p\cdot t+q\cdot u+\delta$.
20617
20618 @<Declare subroutines needed by |big_trans|@>=
20619 void mp_bilin1 (MP mp, pointer p, scaled t, pointer q, 
20620                 scaled u, scaled delta) {
20621   pointer r; /* list traverser */
20622   if ( t!=unity ) mp_dep_mult(mp, p,t,true);
20623   if ( u!=0 ) {
20624     if ( type(q)==mp_known ) {
20625       delta+=mp_take_scaled(mp, value(q),u);
20626     } else { 
20627       @<Ensure that |type(p)=mp_proto_dependent|@>;
20628       dep_list(p)=mp_p_plus_fq(mp, dep_list(p),u,dep_list(q),
20629                                mp_proto_dependent,type(q));
20630     }
20631   }
20632   if ( type(p)==mp_known ) {
20633     value(p)+=delta;
20634   } else {
20635     r=dep_list(p);
20636     while ( info(r)!=null ) r=link(r);
20637     delta+=value(r);
20638     if ( r!=dep_list(p) ) value(r)=delta;
20639     else { mp_recycle_value(mp, p); type(p)=mp_known; value(p)=delta; };
20640   }
20641   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20642 }
20643
20644 @ @<Ensure that |type(p)=mp_proto_dependent|@>=
20645 if ( type(p)!=mp_proto_dependent ) {
20646   if ( type(p)==mp_known ) 
20647     mp_new_dep(mp, p,mp_const_dependency(mp, value(p)));
20648   else 
20649     dep_list(p)=mp_p_times_v(mp, dep_list(p),unity,mp_dependent,
20650                              mp_proto_dependent,true);
20651   type(p)=mp_proto_dependent;
20652 }
20653
20654 @ @<Transform a known big node@>=
20655 mp_set_up_trans(mp, c);
20656 if ( mp->cur_type==mp_known ) {
20657   @<Transform known by known@>;
20658 } else { 
20659   pp=mp_stash_cur_exp(mp); qq=value(pp);
20660   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20661   if ( mp->cur_type==mp_transform_type ) {
20662     mp_bilin2(mp, yy_part_loc(r),yy_part_loc(qq),
20663       value(xy_part_loc(q)),yx_part_loc(qq),null);
20664     mp_bilin2(mp, yx_part_loc(r),yy_part_loc(qq),
20665       value(xx_part_loc(q)),yx_part_loc(qq),null);
20666     mp_bilin2(mp, xy_part_loc(r),xx_part_loc(qq),
20667       value(yy_part_loc(q)),xy_part_loc(qq),null);
20668     mp_bilin2(mp, xx_part_loc(r),xx_part_loc(qq),
20669       value(yx_part_loc(q)),xy_part_loc(qq),null);
20670   };
20671   mp_bilin2(mp, y_part_loc(r),yy_part_loc(qq),
20672     value(x_part_loc(q)),yx_part_loc(qq),y_part_loc(qq));
20673   mp_bilin2(mp, x_part_loc(r),xx_part_loc(qq),
20674     value(y_part_loc(q)),xy_part_loc(qq),x_part_loc(qq));
20675   mp_recycle_value(mp, pp); mp_free_node(mp, pp,value_node_size);
20676 }
20677
20678 @ Let |p| be a |mp_proto_dependent| value whose dependency list ends
20679 at |dep_final|. The following procedure adds |v| times another
20680 numeric quantity to~|p|.
20681
20682 @<Declare subroutines needed by |big_trans|@>=
20683 void mp_add_mult_dep (MP mp,pointer p, scaled v, pointer r) { 
20684   if ( type(r)==mp_known ) {
20685     value(mp->dep_final)+=mp_take_scaled(mp, value(r),v);
20686   } else  { 
20687     dep_list(p)=mp_p_plus_fq(mp, dep_list(p),v,dep_list(r),
20688                                                          mp_proto_dependent,type(r));
20689     if ( mp->fix_needed ) mp_fix_dependencies(mp);
20690   }
20691 }
20692
20693 @ The |bilin2| procedure is something like |bilin1|, but with known
20694 and unknown quantities reversed. Parameter |p| points to a value field
20695 within the big node for |cur_exp|; and |type(p)=mp_known|. Parameters
20696 |t| and~|u| point to value fields elsewhere; so does parameter~|q|,
20697 unless it is |null| (which stands for zero). Location~|p| will be
20698 replaced by $p\cdot t+v\cdot u+q$.
20699
20700 @<Declare subroutines needed by |big_trans|@>=
20701 void mp_bilin2 (MP mp,pointer p, pointer t, scaled v, 
20702                 pointer u, pointer q) {
20703   scaled vv; /* temporary storage for |value(p)| */
20704   vv=value(p); type(p)=mp_proto_dependent;
20705   mp_new_dep(mp, p,mp_const_dependency(mp, 0)); /* this sets |dep_final| */
20706   if ( vv!=0 ) 
20707     mp_add_mult_dep(mp, p,vv,t); /* |dep_final| doesn't change */
20708   if ( v!=0 ) mp_add_mult_dep(mp, p,v,u);
20709   if ( q!=null ) mp_add_mult_dep(mp, p,unity,q);
20710   if ( dep_list(p)==mp->dep_final ) {
20711     vv=value(mp->dep_final); mp_recycle_value(mp, p);
20712     type(p)=mp_known; value(p)=vv;
20713   }
20714 }
20715
20716 @ @<Transform known by known@>=
20717
20718   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20719   if ( mp->cur_type==mp_transform_type ) {
20720     mp_bilin3(mp, yy_part_loc(r),mp->tyy,value(xy_part_loc(q)),mp->tyx,0);
20721     mp_bilin3(mp, yx_part_loc(r),mp->tyy,value(xx_part_loc(q)),mp->tyx,0);
20722     mp_bilin3(mp, xy_part_loc(r),mp->txx,value(yy_part_loc(q)),mp->txy,0);
20723     mp_bilin3(mp, xx_part_loc(r),mp->txx,value(yx_part_loc(q)),mp->txy,0);
20724   }
20725   mp_bilin3(mp, y_part_loc(r),mp->tyy,value(x_part_loc(q)),mp->tyx,mp->ty);
20726   mp_bilin3(mp, x_part_loc(r),mp->txx,value(y_part_loc(q)),mp->txy,mp->tx);
20727 }
20728
20729 @ Finally, in |bilin3| everything is |known|.
20730
20731 @<Declare subroutines needed by |big_trans|@>=
20732 void mp_bilin3 (MP mp,pointer p, scaled t, 
20733                scaled v, scaled u, scaled delta) { 
20734   if ( t!=unity )
20735     delta+=mp_take_scaled(mp, value(p),t);
20736   else 
20737     delta+=value(p);
20738   if ( u!=0 ) value(p)=delta+mp_take_scaled(mp, v,u);
20739   else value(p)=delta;
20740 }
20741
20742 @ @<Additional cases of binary operators@>=
20743 case concatenate: 
20744   if ( (mp->cur_type==mp_string_type)&&(type(p)==mp_string_type) ) mp_cat(mp, p);
20745   else mp_bad_binary(mp, p,concatenate);
20746   break;
20747 case substring_of: 
20748   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_string_type) )
20749     mp_chop_string(mp, value(p));
20750   else mp_bad_binary(mp, p,substring_of);
20751   break;
20752 case subpath_of: 
20753   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20754   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_path_type) )
20755     mp_chop_path(mp, value(p));
20756   else mp_bad_binary(mp, p,subpath_of);
20757   break;
20758
20759 @ @<Declare binary action...@>=
20760 void mp_cat (MP mp,pointer p) {
20761   str_number a,b; /* the strings being concatenated */
20762   pool_pointer k; /* index into |str_pool| */
20763   a=value(p); b=mp->cur_exp; str_room(length(a)+length(b));
20764   for (k=mp->str_start[a];k<=str_stop(a)-1;k++) {
20765     append_char(mp->str_pool[k]);
20766   }
20767   for (k=mp->str_start[b];k<=str_stop(b)-1;k++) {
20768     append_char(mp->str_pool[k]);
20769   }
20770   mp->cur_exp=mp_make_string(mp); delete_str_ref(b);
20771 }
20772
20773 @ @<Declare binary action...@>=
20774 void mp_chop_string (MP mp,pointer p) {
20775   integer a, b; /* start and stop points */
20776   integer l; /* length of the original string */
20777   integer k; /* runs from |a| to |b| */
20778   str_number s; /* the original string */
20779   boolean reversed; /* was |a>b|? */
20780   a=mp_round_unscaled(mp, value(x_part_loc(p)));
20781   b=mp_round_unscaled(mp, value(y_part_loc(p)));
20782   if ( a<=b ) reversed=false;
20783   else  { reversed=true; k=a; a=b; b=k; };
20784   s=mp->cur_exp; l=length(s);
20785   if ( a<0 ) { 
20786     a=0;
20787     if ( b<0 ) b=0;
20788   }
20789   if ( b>l ) { 
20790     b=l;
20791     if ( a>l ) a=l;
20792   }
20793   str_room(b-a);
20794   if ( reversed ) {
20795     for (k=mp->str_start[s]+b-1;k>=mp->str_start[s]+a;k--)  {
20796       append_char(mp->str_pool[k]);
20797     }
20798   } else  {
20799     for (k=mp->str_start[s]+a;k<=mp->str_start[s]+b-1;k++)  {
20800       append_char(mp->str_pool[k]);
20801     }
20802   }
20803   mp->cur_exp=mp_make_string(mp); delete_str_ref(s);
20804 }
20805
20806 @ @<Declare binary action...@>=
20807 void mp_chop_path (MP mp,pointer p) {
20808   pointer q; /* a knot in the original path */
20809   pointer pp,qq,rr,ss; /* link variables for copies of path nodes */
20810   scaled a,b,k,l; /* indices for chopping */
20811   boolean reversed; /* was |a>b|? */
20812   l=mp_path_length(mp); a=value(x_part_loc(p)); b=value(y_part_loc(p));
20813   if ( a<=b ) reversed=false;
20814   else  { reversed=true; k=a; a=b; b=k; };
20815   @<Dispense with the cases |a<0| and/or |b>l|@>;
20816   q=mp->cur_exp;
20817   while ( a>=unity ) {
20818     q=link(q); a=a-unity; b=b-unity;
20819   }
20820   if ( b==a ) {
20821     @<Construct a path from |pp| to |qq| of length zero@>; 
20822   } else { 
20823     @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>; 
20824   }
20825   left_type(pp)=endpoint; right_type(qq)=endpoint; link(qq)=pp;
20826   mp_toss_knot_list(mp, mp->cur_exp);
20827   if ( reversed ) {
20828     mp->cur_exp=link(mp_htap_ypoc(mp, pp)); mp_toss_knot_list(mp, pp);
20829   } else {
20830     mp->cur_exp=pp;
20831   }
20832 }
20833
20834 @ @<Dispense with the cases |a<0| and/or |b>l|@>=
20835 if ( a<0 ) {
20836   if ( left_type(mp->cur_exp)==endpoint ) {
20837     a=0; if ( b<0 ) b=0;
20838   } else  {
20839     do {  a=a+l; b=b+l; } while (a<0); /* a cycle always has length |l>0| */
20840   }
20841 }
20842 if ( b>l ) {
20843   if ( left_type(mp->cur_exp)==endpoint ) {
20844     b=l; if ( a>l ) a=l;
20845   } else {
20846     while ( a>=l ) { 
20847       a=a-l; b=b-l;
20848     }
20849   }
20850 }
20851
20852 @ @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>=
20853
20854   pp=mp_copy_knot(mp, q); qq=pp;
20855   do {  
20856     q=link(q); rr=qq; qq=mp_copy_knot(mp, q); link(rr)=qq; b=b-unity;
20857   } while (b>0);
20858   if ( a>0 ) {
20859     ss=pp; pp=link(pp);
20860     mp_split_cubic(mp, ss,a*010000); pp=link(ss);
20861     mp_free_node(mp, ss,knot_node_size);
20862     if ( rr==ss ) {
20863       b=mp_make_scaled(mp, b,unity-a); rr=pp;
20864     }
20865   }
20866   if ( b<0 ) {
20867     mp_split_cubic(mp, rr,(b+unity)*010000);
20868     mp_free_node(mp, qq,knot_node_size);
20869     qq=link(rr);
20870   }
20871 }
20872
20873 @ @<Construct a path from |pp| to |qq| of length zero@>=
20874
20875   if ( a>0 ) { mp_split_cubic(mp, q,a*010000); q=link(q); };
20876   pp=mp_copy_knot(mp, q); qq=pp;
20877 }
20878
20879 @ @<Additional cases of binary operators@>=
20880 case point_of: case precontrol_of: case postcontrol_of: 
20881   if ( mp->cur_type==mp_pair_type )
20882      mp_pair_to_path(mp);
20883   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
20884     mp_find_point(mp, value(p),c);
20885   else 
20886     mp_bad_binary(mp, p,c);
20887   break;
20888 case pen_offset_of: 
20889   if ( (mp->cur_type==mp_pen_type)&& mp_nice_pair(mp, p,type(p)) )
20890     mp_set_up_offset(mp, value(p));
20891   else 
20892     mp_bad_binary(mp, p,pen_offset_of);
20893   break;
20894 case direction_time_of: 
20895   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20896   if ( (mp->cur_type==mp_path_type)&& mp_nice_pair(mp, p,type(p)) )
20897     mp_set_up_direction_time(mp, value(p));
20898   else 
20899     mp_bad_binary(mp, p,direction_time_of);
20900   break;
20901
20902 @ @<Declare binary action...@>=
20903 void mp_set_up_offset (MP mp,pointer p) { 
20904   mp_find_offset(mp, value(x_part_loc(p)),value(y_part_loc(p)),mp->cur_exp);
20905   mp_pair_value(mp, mp->cur_x,mp->cur_y);
20906 }
20907 void mp_set_up_direction_time (MP mp,pointer p) { 
20908   mp_flush_cur_exp(mp, mp_find_direction_time(mp, value(x_part_loc(p)),
20909   value(y_part_loc(p)),mp->cur_exp));
20910 }
20911
20912 @ @<Declare binary action...@>=
20913 void mp_find_point (MP mp,scaled v, quarterword c) {
20914   pointer p; /* the path */
20915   scaled n; /* its length */
20916   p=mp->cur_exp;
20917   if ( left_type(p)==endpoint ) n=-unity; else n=0;
20918   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
20919   if ( n==0 ) { 
20920     v=0; 
20921   } else if ( v<0 ) {
20922     if ( left_type(p)==endpoint ) v=0;
20923     else v=n-1-((-v-1) % n);
20924   } else if ( v>n ) {
20925     if ( left_type(p)==endpoint ) v=n;
20926     else v=v % n;
20927   }
20928   p=mp->cur_exp;
20929   while ( v>=unity ) { p=link(p); v=v-unity;  };
20930   if ( v!=0 ) {
20931      @<Insert a fractional node by splitting the cubic@>;
20932   }
20933   @<Set the current expression to the desired path coordinates@>;
20934 }
20935
20936 @ @<Insert a fractional node...@>=
20937 { mp_split_cubic(mp, p,v*010000); p=link(p); }
20938
20939 @ @<Set the current expression to the desired path coordinates...@>=
20940 switch (c) {
20941 case point_of: 
20942   mp_pair_value(mp, x_coord(p),y_coord(p));
20943   break;
20944 case precontrol_of: 
20945   if ( left_type(p)==endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
20946   else mp_pair_value(mp, left_x(p),left_y(p));
20947   break;
20948 case postcontrol_of: 
20949   if ( right_type(p)==endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
20950   else mp_pair_value(mp, right_x(p),right_y(p));
20951   break;
20952 } /* there are no other cases */
20953
20954 @ @<Additional cases of binary operators@>=
20955 case arc_time_of: 
20956   if ( mp->cur_type==mp_pair_type )
20957      mp_pair_to_path(mp);
20958   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
20959     mp_flush_cur_exp(mp, mp_get_arc_time(mp, mp->cur_exp,value(p)));
20960   else 
20961     mp_bad_binary(mp, p,c);
20962   break;
20963
20964 @ @<Additional cases of bin...@>=
20965 case intersect: 
20966   if ( type(p)==mp_pair_type ) {
20967     q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p);
20968     mp_pair_to_path(mp); p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
20969   };
20970   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20971   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_path_type) ) {
20972     mp_path_intersection(mp, value(p),mp->cur_exp);
20973     mp_pair_value(mp, mp->cur_t,mp->cur_tt);
20974   } else {
20975     mp_bad_binary(mp, p,intersect);
20976   }
20977   break;
20978
20979 @ @<Additional cases of bin...@>=
20980 case in_font:
20981   if ( (mp->cur_type!=mp_string_type)||(type(p)!=mp_string_type)) 
20982     mp_bad_binary(mp, p,in_font);
20983   else { mp_do_infont(mp, p); return; }
20984   break;
20985
20986 @ Function |new_text_node| owns the reference count for its second argument
20987 (the text string) but not its first (the font name).
20988
20989 @<Declare binary action...@>=
20990 void mp_do_infont (MP mp,pointer p) {
20991   pointer q;
20992   q=mp_get_node(mp, edge_header_size);
20993   mp_init_edges(mp, q);
20994   link(obj_tail(q))=mp_new_text_node(mp, str(mp->cur_exp),value(p));
20995   obj_tail(q)=link(obj_tail(q));
20996   mp_free_node(mp, p,value_node_size);
20997   mp_flush_cur_exp(mp, q);
20998   mp->cur_type=mp_picture_type;
20999 }
21000
21001 @* \[40] Statements and commands.
21002 The chief executive of \MP\ is the |do_statement| routine, which
21003 contains the master switch that causes all the various pieces of \MP\
21004 to do their things, in the right order.
21005
21006 In a sense, this is the grand climax of the program: It applies all the
21007 tools that we have worked so hard to construct. In another sense, this is
21008 the messiest part of the program: It necessarily refers to other pieces
21009 of code all over the place, so that a person can't fully understand what is
21010 going on without paging back and forth to be reminded of conventions that
21011 are defined elsewhere. We are now at the hub of the web.
21012
21013 The structure of |do_statement| itself is quite simple.  The first token
21014 of the statement is fetched using |get_x_next|.  If it can be the first
21015 token of an expression, we look for an equation, an assignment, or a
21016 title. Otherwise we use a \&{case} construction to branch at high speed to
21017 the appropriate routine for various and sundry other types of commands,
21018 each of which has an ``action procedure'' that does the necessary work.
21019
21020 The program uses the fact that
21021 $$\hbox{|min_primary_command=max_statement_command=type_name|}$$
21022 to interpret a statement that starts with, e.g., `\&{string}',
21023 as a type declaration rather than a boolean expression.
21024
21025 @c void mp_do_statement (MP mp) { /* governs \MP's activities */
21026   mp->cur_type=mp_vacuous; mp_get_x_next(mp);
21027   if ( mp->cur_cmd>max_primary_command ) {
21028     @<Worry about bad statement@>;
21029   } else if ( mp->cur_cmd>max_statement_command ) {
21030     @<Do an equation, assignment, title, or
21031      `$\langle\,$expression$\,\rangle\,$\&{endgroup}'@>;
21032   } else {
21033     @<Do a statement that doesn't begin with an expression@>;
21034   }
21035   if ( mp->cur_cmd<semicolon )
21036     @<Flush unparsable junk that was found after the statement@>;
21037   mp->error_count=0;
21038 }
21039
21040 @ @<Declarations@>=
21041 @<Declare action procedures for use by |do_statement|@>;
21042
21043 @ The only command codes |>max_primary_command| that can be present
21044 at the beginning of a statement are |semicolon| and higher; these
21045 occur when the statement is null.
21046
21047 @<Worry about bad statement@>=
21048
21049   if ( mp->cur_cmd<semicolon ) {
21050     print_err("A statement can't begin with `");
21051 @.A statement can't begin with x@>
21052     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); mp_print_char(mp, '\'');
21053     help5("I was looking for the beginning of a new statement.")
21054       ("If you just proceed without changing anything, I'll ignore")
21055       ("everything up to the next `;'. Please insert a semicolon")
21056       ("now in front of anything that you don't want me to delete.")
21057       ("(See Chapter 27 of The METAFONTbook for an example.)");
21058 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21059     mp_back_error(mp); mp_get_x_next(mp);
21060   }
21061 }
21062
21063 @ The help message printed here says that everything is flushed up to
21064 a semicolon, but actually the commands |end_group| and |stop| will
21065 also terminate a statement.
21066
21067 @<Flush unparsable junk that was found after the statement@>=
21068
21069   print_err("Extra tokens will be flushed");
21070 @.Extra tokens will be flushed@>
21071   help6("I've just read as much of that statement as I could fathom,")
21072        ("so a semicolon should have been next. It's very puzzling...")
21073        ("but I'll try to get myself back together, by ignoring")
21074        ("everything up to the next `;'. Please insert a semicolon")
21075        ("now in front of anything that you don't want me to delete.")
21076        ("(See Chapter 27 of The METAFONTbook for an example.)");
21077 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21078   mp_back_error(mp); mp->scanner_status=flushing;
21079   do {  
21080     get_t_next;
21081     @<Decrease the string reference count...@>;
21082   } while (! end_of_statement); /* |cur_cmd=semicolon|, |end_group|, or |stop| */
21083   mp->scanner_status=normal;
21084 }
21085
21086 @ If |do_statement| ends with |cur_cmd=end_group|, we should have
21087 |cur_type=mp_vacuous| unless the statement was simply an expression;
21088 in the latter case, |cur_type| and |cur_exp| should represent that
21089 expression.
21090
21091 @<Do a statement that doesn't...@>=
21092
21093   if ( mp->internal[tracing_commands]>0 ) 
21094     show_cur_cmd_mod;
21095   switch (mp->cur_cmd ) {
21096   case type_name:mp_do_type_declaration(mp); break;
21097   case macro_def:
21098     if ( mp->cur_mod>var_def ) mp_make_op_def(mp);
21099     else if ( mp->cur_mod>end_def ) mp_scan_def(mp);
21100      break;
21101   @<Cases of |do_statement| that invoke particular commands@>;
21102   } /* there are no other cases */
21103   mp->cur_type=mp_vacuous;
21104 }
21105
21106 @ The most important statements begin with expressions.
21107
21108 @<Do an equation, assignment, title, or...@>=
21109
21110   mp->var_flag=assignment; mp_scan_expression(mp);
21111   if ( mp->cur_cmd<end_group ) {
21112     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21113     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21114     else if ( mp->cur_type==mp_string_type ) {@<Do a title@> ; }
21115     else if ( mp->cur_type!=mp_vacuous ){ 
21116       exp_err("Isolated expression");
21117 @.Isolated expression@>
21118       help3("I couldn't find an `=' or `:=' after the")
21119         ("expression that is shown above this error message,")
21120         ("so I guess I'll just ignore it and carry on.");
21121       mp_put_get_error(mp);
21122     }
21123     mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous;
21124   }
21125 }
21126
21127 @ @<Do a title@>=
21128
21129   if ( mp->internal[tracing_titles]>0 ) {
21130     mp_print_nl(mp, "");  mp_print_str(mp, mp->cur_exp); update_terminal;
21131   }
21132 }
21133
21134 @ Equations and assignments are performed by the pair of mutually recursive
21135 @^recursion@>
21136 routines |do_equation| and |do_assignment|. These routines are called when
21137 |cur_cmd=equals| and when |cur_cmd=assignment|, respectively; the left-hand
21138 side is in |cur_type| and |cur_exp|, while the right-hand side is yet
21139 to be scanned. After the routines are finished, |cur_type| and |cur_exp|
21140 will be equal to the right-hand side (which will normally be equal
21141 to the left-hand side).
21142
21143 @<Declare action procedures for use by |do_statement|@>=
21144 @<Declare the procedure called |try_eq|@>;
21145 @<Declare the procedure called |make_eq|@>;
21146 void mp_do_equation (MP mp) ;
21147
21148 @ @c
21149 void mp_do_equation (MP mp) {
21150   pointer lhs; /* capsule for the left-hand side */
21151   pointer p; /* temporary register */
21152   lhs=mp_stash_cur_exp(mp); mp_get_x_next(mp); 
21153   mp->var_flag=assignment; mp_scan_expression(mp);
21154   if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21155   else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21156   if ( mp->internal[tracing_commands]>two ) 
21157     @<Trace the current equation@>;
21158   if ( mp->cur_type==mp_unknown_path ) if ( type(lhs)==mp_pair_type ) {
21159     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, lhs); lhs=p;
21160   }; /* in this case |make_eq| will change the pair to a path */
21161   mp_make_eq(mp, lhs); /* equate |lhs| to |(cur_type,cur_exp)| */
21162 }
21163
21164 @ And |do_assignment| is similar to |do_expression|:
21165
21166 @<Declarations@>=
21167 void mp_do_assignment (MP mp);
21168
21169 @ @<Declare action procedures for use by |do_statement|@>=
21170 void mp_do_assignment (MP mp) ;
21171
21172 @ @c
21173 void mp_do_assignment (MP mp) {
21174   pointer lhs; /* token list for the left-hand side */
21175   pointer p; /* where the left-hand value is stored */
21176   pointer q; /* temporary capsule for the right-hand value */
21177   if ( mp->cur_type!=mp_token_list ) { 
21178     exp_err("Improper `:=' will be changed to `='");
21179 @.Improper `:='@>
21180     help2("I didn't find a variable name at the left of the `:=',")
21181       ("so I'm going to pretend that you said `=' instead.");
21182     mp_error(mp); mp_do_equation(mp);
21183   } else { 
21184     lhs=mp->cur_exp; mp->cur_type=mp_vacuous;
21185     mp_get_x_next(mp); mp->var_flag=assignment; mp_scan_expression(mp);
21186     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21187     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21188     if ( mp->internal[tracing_commands]>two ) 
21189       @<Trace the current assignment@>;
21190     if ( info(lhs)>hash_end ) {
21191       @<Assign the current expression to an internal variable@>;
21192     } else  {
21193       @<Assign the current expression to the variable |lhs|@>;
21194     }
21195     mp_flush_node_list(mp, lhs);
21196   }
21197 }
21198
21199 @ @<Trace the current equation@>=
21200
21201   mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp,lhs,0);
21202   mp_print(mp,")=("); mp_print_exp(mp,null,0); 
21203   mp_print(mp,")}"); mp_end_diagnostic(mp, false);
21204 }
21205
21206 @ @<Trace the current assignment@>=
21207
21208   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
21209   if ( info(lhs)>hash_end ) 
21210      mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21211   else 
21212      mp_show_token_list(mp, lhs,null,1000,0);
21213   mp_print(mp, ":="); mp_print_exp(mp, null,0); 
21214   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
21215 }
21216
21217 @ @<Assign the current expression to an internal variable@>=
21218 if ( mp->cur_type==mp_known )  {
21219   mp->internal[info(lhs)-(hash_end)]=mp->cur_exp;
21220 } else { 
21221   exp_err("Internal quantity `");
21222 @.Internal quantity...@>
21223   mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21224   mp_print(mp, "' must receive a known value");
21225   help2("I can\'t set an internal quantity to anything but a known")
21226     ("numeric value, so I'll have to ignore this assignment.");
21227   mp_put_get_error(mp);
21228 }
21229
21230 @ @<Assign the current expression to the variable |lhs|@>=
21231
21232   p=mp_find_variable(mp, lhs);
21233   if ( p!=null ) {
21234     q=mp_stash_cur_exp(mp); mp->cur_type=mp_und_type(mp, p); 
21235     mp_recycle_value(mp, p);
21236     type(p)=mp->cur_type; value(p)=null; mp_make_exp_copy(mp, p);
21237     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); mp_make_eq(mp, p);
21238   } else  { 
21239     mp_obliterated(mp, lhs); mp_put_get_error(mp);
21240   }
21241 }
21242
21243
21244 @ And now we get to the nitty-gritty. The |make_eq| procedure is given
21245 a pointer to a capsule that is to be equated to the current expression.
21246
21247 @<Declare the procedure called |make_eq|@>=
21248 void mp_make_eq (MP mp,pointer lhs) ;
21249
21250
21251
21252 @c void mp_make_eq (MP mp,pointer lhs) {
21253   small_number t; /* type of the left-hand side */
21254   pointer p,q; /* pointers inside of big nodes */
21255   integer v=0; /* value of the left-hand side */
21256 RESTART: 
21257   t=type(lhs);
21258   if ( t<=mp_pair_type ) v=value(lhs);
21259   switch (t) {
21260   @<For each type |t|, make an equation and |goto done| unless |cur_type|
21261     is incompatible with~|t|@>;
21262   } /* all cases have been listed */
21263   @<Announce that the equation cannot be performed@>;
21264 DONE:
21265   check_arith; mp_recycle_value(mp, lhs); 
21266   mp_free_node(mp, lhs,value_node_size);
21267 }
21268
21269 @ @<Announce that the equation cannot be performed@>=
21270 mp_disp_err(mp, lhs,""); 
21271 exp_err("Equation cannot be performed (");
21272 @.Equation cannot be performed@>
21273 if ( type(lhs)<=mp_pair_type ) mp_print_type(mp, type(lhs));
21274 else mp_print(mp, "numeric");
21275 mp_print_char(mp, '=');
21276 if ( mp->cur_type<=mp_pair_type ) mp_print_type(mp, mp->cur_type);
21277 else mp_print(mp, "numeric");
21278 mp_print_char(mp, ')');
21279 help2("I'm sorry, but I don't know how to make such things equal.")
21280      ("(See the two expressions just above the error message.)");
21281 mp_put_get_error(mp)
21282
21283 @ @<For each type |t|, make an equation and |goto done| unless...@>=
21284 case mp_boolean_type: case mp_string_type: case mp_pen_type:
21285 case mp_path_type: case mp_picture_type:
21286   if ( mp->cur_type==t+unknown_tag ) { 
21287     mp_nonlinear_eq(mp, v,mp->cur_exp,false); goto DONE;
21288   } else if ( mp->cur_type==t ) {
21289     @<Report redundant or inconsistent equation and |goto done|@>;
21290   }
21291   break;
21292 case unknown_types:
21293   if ( mp->cur_type==t-unknown_tag ) { 
21294     mp_nonlinear_eq(mp, mp->cur_exp,lhs,true); goto DONE;
21295   } else if ( mp->cur_type==t ) { 
21296     mp_ring_merge(mp, lhs,mp->cur_exp); goto DONE;
21297   } else if ( mp->cur_type==mp_pair_type ) {
21298     if ( t==mp_unknown_path ) { 
21299      mp_pair_to_path(mp); goto RESTART;
21300     };
21301   }
21302   break;
21303 case mp_transform_type: case mp_color_type:
21304 case mp_cmykcolor_type: case mp_pair_type:
21305   if ( mp->cur_type==t ) {
21306     @<Do multiple equations and |goto done|@>;
21307   }
21308   break;
21309 case mp_known: case mp_dependent:
21310 case mp_proto_dependent: case mp_independent:
21311   if ( mp->cur_type>=mp_known ) { 
21312     mp_try_eq(mp, lhs,null); goto DONE;
21313   };
21314   break;
21315 case mp_vacuous:
21316   break;
21317
21318 @ @<Report redundant or inconsistent equation and |goto done|@>=
21319
21320   if ( mp->cur_type<=mp_string_type ) {
21321     if ( mp->cur_type==mp_string_type ) {
21322       if ( mp_str_vs_str(mp, v,mp->cur_exp)!=0 ) {
21323         goto NOT_FOUND;
21324       }
21325     } else if ( v!=mp->cur_exp ) {
21326       goto NOT_FOUND;
21327     }
21328     @<Exclaim about a redundant equation@>; goto DONE;
21329   }
21330   print_err("Redundant or inconsistent equation");
21331 @.Redundant or inconsistent equation@>
21332   help2("An equation between already-known quantities can't help.")
21333        ("But don't worry; continue and I'll just ignore it.");
21334   mp_put_get_error(mp); goto DONE;
21335 NOT_FOUND: 
21336   print_err("Inconsistent equation");
21337 @.Inconsistent equation@>
21338   help2("The equation I just read contradicts what was said before.")
21339        ("But don't worry; continue and I'll just ignore it.");
21340   mp_put_get_error(mp); goto DONE;
21341 }
21342
21343 @ @<Do multiple equations and |goto done|@>=
21344
21345   p=v+mp->big_node_size[t]; 
21346   q=value(mp->cur_exp)+mp->big_node_size[t];
21347   do {  
21348     p=p-2; q=q-2; mp_try_eq(mp, p,q);
21349   } while (p!=v);
21350   goto DONE;
21351 }
21352
21353 @ The first argument to |try_eq| is the location of a value node
21354 in a capsule that will soon be recycled. The second argument is
21355 either a location within a pair or transform node pointed to by
21356 |cur_exp|, or it is |null| (which means that |cur_exp| itself
21357 serves as the second argument). The idea is to leave |cur_exp| unchanged,
21358 but to equate the two operands.
21359
21360 @<Declare the procedure called |try_eq|@>=
21361 void mp_try_eq (MP mp,pointer l, pointer r) ;
21362
21363
21364 @c void mp_try_eq (MP mp,pointer l, pointer r) {
21365   pointer p; /* dependency list for right operand minus left operand */
21366   int t; /* the type of list |p| */
21367   pointer q; /* the constant term of |p| is here */
21368   pointer pp; /* dependency list for right operand */
21369   int tt; /* the type of list |pp| */
21370   boolean copied; /* have we copied a list that ought to be recycled? */
21371   @<Remove the left operand from its container, negate it, and
21372     put it into dependency list~|p| with constant term~|q|@>;
21373   @<Add the right operand to list |p|@>;
21374   if ( info(p)==null ) {
21375     @<Deal with redundant or inconsistent equation@>;
21376   } else { 
21377     mp_linear_eq(mp, p,t);
21378     if ( r==null ) if ( mp->cur_type!=mp_known ) {
21379       if ( type(mp->cur_exp)==mp_known ) {
21380         pp=mp->cur_exp; mp->cur_exp=value(mp->cur_exp); mp->cur_type=mp_known;
21381         mp_free_node(mp, pp,value_node_size);
21382       }
21383     }
21384   }
21385 }
21386
21387 @ @<Remove the left operand from its container, negate it, and...@>=
21388 t=type(l);
21389 if ( t==mp_known ) { 
21390   t=mp_dependent; p=mp_const_dependency(mp, -value(l)); q=p;
21391 } else if ( t==mp_independent ) {
21392   t=mp_dependent; p=mp_single_dependency(mp, l); negate(value(p));
21393   q=mp->dep_final;
21394 } else { 
21395   p=dep_list(l); q=p;
21396   while (1) { 
21397     negate(value(q));
21398     if ( info(q)==null ) break;
21399     q=link(q);
21400   }
21401   link(prev_dep(l))=link(q); prev_dep(link(q))=prev_dep(l);
21402   type(l)=mp_known;
21403 }
21404
21405 @ @<Deal with redundant or inconsistent equation@>=
21406
21407   if ( abs(value(p))>64 ) { /* off by .001 or more */
21408     print_err("Inconsistent equation");
21409 @.Inconsistent equation@>
21410     mp_print(mp, " (off by "); mp_print_scaled(mp, value(p)); 
21411     mp_print_char(mp, ')');
21412     help2("The equation I just read contradicts what was said before.")
21413       ("But don't worry; continue and I'll just ignore it.");
21414     mp_put_get_error(mp);
21415   } else if ( r==null ) {
21416     @<Exclaim about a redundant equation@>;
21417   }
21418   mp_free_node(mp, p,dep_node_size);
21419 }
21420
21421 @ @<Add the right operand to list |p|@>=
21422 if ( r==null ) {
21423   if ( mp->cur_type==mp_known ) {
21424     value(q)=value(q)+mp->cur_exp; goto DONE1;
21425   } else { 
21426     tt=mp->cur_type;
21427     if ( tt==mp_independent ) pp=mp_single_dependency(mp, mp->cur_exp);
21428     else pp=dep_list(mp->cur_exp);
21429   } 
21430 } else {
21431   if ( type(r)==mp_known ) {
21432     value(q)=value(q)+value(r); goto DONE1;
21433   } else { 
21434     tt=type(r);
21435     if ( tt==mp_independent ) pp=mp_single_dependency(mp, r);
21436     else pp=dep_list(r);
21437   }
21438 }
21439 if ( tt!=mp_independent ) copied=false;
21440 else  { copied=true; tt=mp_dependent; };
21441 @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>;
21442 if ( copied ) mp_flush_node_list(mp, pp);
21443 DONE1:
21444
21445 @ @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>=
21446 mp->watch_coefs=false;
21447 if ( t==tt ) {
21448   p=mp_p_plus_q(mp, p,pp,t);
21449 } else if ( t==mp_proto_dependent ) {
21450   p=mp_p_plus_fq(mp, p,unity,pp,mp_proto_dependent,mp_dependent);
21451 } else { 
21452   q=p;
21453   while ( info(q)!=null ) {
21454     value(q)=mp_round_fraction(mp, value(q)); q=link(q);
21455   }
21456   t=mp_proto_dependent; p=mp_p_plus_q(mp, p,pp,t);
21457 }
21458 mp->watch_coefs=true;
21459
21460 @ Our next goal is to process type declarations. For this purpose it's
21461 convenient to have a procedure that scans a $\langle\,$declared
21462 variable$\,\rangle$ and returns the corresponding token list. After the
21463 following procedure has acted, the token after the declared variable
21464 will have been scanned, so it will appear in |cur_cmd|, |cur_mod|,
21465 and~|cur_sym|.
21466
21467 @<Declare the function called |scan_declared_variable|@>=
21468 pointer mp_scan_declared_variable (MP mp) {
21469   pointer x; /* hash address of the variable's root */
21470   pointer h,t; /* head and tail of the token list to be returned */
21471   pointer l; /* hash address of left bracket */
21472   mp_get_symbol(mp); x=mp->cur_sym;
21473   if ( mp->cur_cmd!=tag_token ) mp_clear_symbol(mp, x,false);
21474   h=mp_get_avail(mp); info(h)=x; t=h;
21475   while (1) { 
21476     mp_get_x_next(mp);
21477     if ( mp->cur_sym==0 ) break;
21478     if ( mp->cur_cmd!=tag_token ) if ( mp->cur_cmd!=internal_quantity)  {
21479       if ( mp->cur_cmd==left_bracket ) {
21480         @<Descend past a collective subscript@>;
21481       } else {
21482         break;
21483       }
21484     }
21485     link(t)=mp_get_avail(mp); t=link(t); info(t)=mp->cur_sym;
21486   }
21487   if ( eq_type(x)!=tag_token ) mp_clear_symbol(mp, x,false);
21488   if ( equiv(x)==null ) mp_new_root(mp, x);
21489   return h;
21490 }
21491
21492 @ If the subscript isn't collective, we don't accept it as part of the
21493 declared variable.
21494
21495 @<Descend past a collective subscript@>=
21496
21497   l=mp->cur_sym; mp_get_x_next(mp);
21498   if ( mp->cur_cmd!=right_bracket ) {
21499     mp_back_input(mp); mp->cur_sym=l; mp->cur_cmd=left_bracket; break;
21500   } else {
21501     mp->cur_sym=collective_subscript;
21502   }
21503 }
21504
21505 @ Type declarations are introduced by the following primitive operations.
21506
21507 @<Put each...@>=
21508 mp_primitive(mp, "numeric",type_name,mp_numeric_type);
21509 @:numeric_}{\&{numeric} primitive@>
21510 mp_primitive(mp, "string",type_name,mp_string_type);
21511 @:string_}{\&{string} primitive@>
21512 mp_primitive(mp, "boolean",type_name,mp_boolean_type);
21513 @:boolean_}{\&{boolean} primitive@>
21514 mp_primitive(mp, "path",type_name,mp_path_type);
21515 @:path_}{\&{path} primitive@>
21516 mp_primitive(mp, "pen",type_name,mp_pen_type);
21517 @:pen_}{\&{pen} primitive@>
21518 mp_primitive(mp, "picture",type_name,mp_picture_type);
21519 @:picture_}{\&{picture} primitive@>
21520 mp_primitive(mp, "transform",type_name,mp_transform_type);
21521 @:transform_}{\&{transform} primitive@>
21522 mp_primitive(mp, "color",type_name,mp_color_type);
21523 @:color_}{\&{color} primitive@>
21524 mp_primitive(mp, "rgbcolor",type_name,mp_color_type);
21525 @:color_}{\&{rgbcolor} primitive@>
21526 mp_primitive(mp, "cmykcolor",type_name,mp_cmykcolor_type);
21527 @:color_}{\&{cmykcolor} primitive@>
21528 mp_primitive(mp, "pair",type_name,mp_pair_type);
21529 @:pair_}{\&{pair} primitive@>
21530
21531 @ @<Cases of |print_cmd...@>=
21532 case type_name: mp_print_type(mp, m); break;
21533
21534 @ Now we are ready to handle type declarations, assuming that a
21535 |type_name| has just been scanned.
21536
21537 @<Declare action procedures for use by |do_statement|@>=
21538 void mp_do_type_declaration (MP mp) ;
21539
21540 @ @c
21541 void mp_do_type_declaration (MP mp) {
21542   small_number t; /* the type being declared */
21543   pointer p; /* token list for a declared variable */
21544   pointer q; /* value node for the variable */
21545   if ( mp->cur_mod>=mp_transform_type ) 
21546     t=mp->cur_mod;
21547   else 
21548     t=mp->cur_mod+unknown_tag;
21549   do {  
21550     p=mp_scan_declared_variable(mp);
21551     mp_flush_variable(mp, equiv(info(p)),link(p),false);
21552     q=mp_find_variable(mp, p);
21553     if ( q!=null ) { 
21554       type(q)=t; value(q)=null; 
21555     } else  { 
21556       print_err("Declared variable conflicts with previous vardef");
21557 @.Declared variable conflicts...@>
21558       help2("You can't use, e.g., `numeric foo[]' after `vardef foo'.")
21559            ("Proceed, and I'll ignore the illegal redeclaration.");
21560       mp_put_get_error(mp);
21561     }
21562     mp_flush_list(mp, p);
21563     if ( mp->cur_cmd<comma ) {
21564       @<Flush spurious symbols after the declared variable@>;
21565     }
21566   } while (! end_of_statement);
21567 }
21568
21569 @ @<Flush spurious symbols after the declared variable@>=
21570
21571   print_err("Illegal suffix of declared variable will be flushed");
21572 @.Illegal suffix...flushed@>
21573   help5("Variables in declarations must consist entirely of")
21574     ("names and collective subscripts, e.g., `x[]a'.")
21575     ("Are you trying to use a reserved word in a variable name?")
21576     ("I'm going to discard the junk I found here,")
21577     ("up to the next comma or the end of the declaration.");
21578   if ( mp->cur_cmd==numeric_token )
21579     mp->help_line[2]="Explicit subscripts like `x15a' aren't permitted.";
21580   mp_put_get_error(mp); mp->scanner_status=flushing;
21581   do {  
21582     get_t_next;
21583     @<Decrease the string reference count...@>;
21584   } while (mp->cur_cmd<comma); /* either |end_of_statement| or |cur_cmd=comma| */
21585   mp->scanner_status=normal;
21586 }
21587
21588 @ \MP's |main_control| procedure just calls |do_statement| repeatedly
21589 until coming to the end of the user's program.
21590 Each execution of |do_statement| concludes with
21591 |cur_cmd=semicolon|, |end_group|, or |stop|.
21592
21593 @c void mp_main_control (MP mp) { 
21594   do {  
21595     mp_do_statement(mp);
21596     if ( mp->cur_cmd==end_group ) {
21597       print_err("Extra `endgroup'");
21598 @.Extra `endgroup'@>
21599       help2("I'm not currently working on a `begingroup',")
21600         ("so I had better not try to end anything.");
21601       mp_flush_error(mp, 0);
21602     }
21603   } while (mp->cur_cmd!=stop);
21604 }
21605 int mp_run (MP mp) {
21606   mp_main_control(mp); /* come to life */
21607   mp_final_cleanup(mp); /* prepare for death */
21608   mp_close_files_and_terminate(mp);
21609   return mp->history;
21610 }
21611 char * mp_mplib_version (MP mp) {
21612   assert(mp);
21613   return mplib_version;
21614 }
21615 char * mp_metapost_version (MP mp) {
21616   assert(mp);
21617   return metapost_version;
21618 }
21619
21620 @ @<Exported function headers@>=
21621 int mp_run (MP mp);
21622 char * mp_mplib_version (MP mp);
21623 char * mp_metapost_version (MP mp);
21624
21625 @ @<Put each...@>=
21626 mp_primitive(mp, "end",stop,0);
21627 @:end_}{\&{end} primitive@>
21628 mp_primitive(mp, "dump",stop,1);
21629 @:dump_}{\&{dump} primitive@>
21630
21631 @ @<Cases of |print_cmd...@>=
21632 case stop:
21633   if ( m==0 ) mp_print(mp, "end");
21634   else mp_print(mp, "dump");
21635   break;
21636
21637 @* \[41] Commands.
21638 Let's turn now to statements that are classified as ``commands'' because
21639 of their imperative nature. We'll begin with simple ones, so that it
21640 will be clear how to hook command processing into the |do_statement| routine;
21641 then we'll tackle the tougher commands.
21642
21643 Here's one of the simplest:
21644
21645 @<Cases of |do_statement|...@>=
21646 case random_seed: mp_do_random_seed(mp);  break;
21647
21648 @ @<Declare action procedures for use by |do_statement|@>=
21649 void mp_do_random_seed (MP mp) ;
21650
21651 @ @c void mp_do_random_seed (MP mp) { 
21652   mp_get_x_next(mp);
21653   if ( mp->cur_cmd!=assignment ) {
21654     mp_missing_err(mp, ":=");
21655 @.Missing `:='@>
21656     help1("Always say `randomseed:=<numeric expression>'.");
21657     mp_back_error(mp);
21658   };
21659   mp_get_x_next(mp); mp_scan_expression(mp);
21660   if ( mp->cur_type!=mp_known ) {
21661     exp_err("Unknown value will be ignored");
21662 @.Unknown value...ignored@>
21663     help2("Your expression was too random for me to handle,")
21664       ("so I won't change the random seed just now.");
21665     mp_put_get_flush_error(mp, 0);
21666   } else {
21667    @<Initialize the random seed to |cur_exp|@>;
21668   }
21669 }
21670
21671 @ @<Initialize the random seed to |cur_exp|@>=
21672
21673   mp_init_randoms(mp, mp->cur_exp);
21674   if ( mp->selector>=log_only && mp->selector<write_file) {
21675     mp->old_setting=mp->selector; mp->selector=log_only;
21676     mp_print_nl(mp, "{randomseed:="); 
21677     mp_print_scaled(mp, mp->cur_exp); 
21678     mp_print_char(mp, '}');
21679     mp_print_nl(mp, ""); mp->selector=mp->old_setting;
21680   }
21681 }
21682
21683 @ And here's another simple one (somewhat different in flavor):
21684
21685 @<Cases of |do_statement|...@>=
21686 case mode_command: 
21687   mp_print_ln(mp); mp->interaction=mp->cur_mod;
21688   @<Initialize the print |selector| based on |interaction|@>;
21689   if ( mp->log_opened ) mp->selector=mp->selector+2;
21690   mp_get_x_next(mp);
21691   break;
21692
21693 @ @<Put each...@>=
21694 mp_primitive(mp, "batchmode",mode_command,mp_batch_mode);
21695 @:mp_batch_mode_}{\&{batchmode} primitive@>
21696 mp_primitive(mp, "nonstopmode",mode_command,mp_nonstop_mode);
21697 @:mp_nonstop_mode_}{\&{nonstopmode} primitive@>
21698 mp_primitive(mp, "scrollmode",mode_command,mp_scroll_mode);
21699 @:mp_scroll_mode_}{\&{scrollmode} primitive@>
21700 mp_primitive(mp, "errorstopmode",mode_command,mp_error_stop_mode);
21701 @:mp_error_stop_mode_}{\&{errorstopmode} primitive@>
21702
21703 @ @<Cases of |print_cmd_mod|...@>=
21704 case mode_command: 
21705   switch (m) {
21706   case mp_batch_mode: mp_print(mp, "batchmode"); break;
21707   case mp_nonstop_mode: mp_print(mp, "nonstopmode"); break;
21708   case mp_scroll_mode: mp_print(mp, "scrollmode"); break;
21709   default: mp_print(mp, "errorstopmode"); break;
21710   }
21711   break;
21712
21713 @ The `\&{inner}' and `\&{outer}' commands are only slightly harder.
21714
21715 @<Cases of |do_statement|...@>=
21716 case protection_command: mp_do_protection(mp); break;
21717
21718 @ @<Put each...@>=
21719 mp_primitive(mp, "inner",protection_command,0);
21720 @:inner_}{\&{inner} primitive@>
21721 mp_primitive(mp, "outer",protection_command,1);
21722 @:outer_}{\&{outer} primitive@>
21723
21724 @ @<Cases of |print_cmd...@>=
21725 case protection_command: 
21726   if ( m==0 ) mp_print(mp, "inner");
21727   else mp_print(mp, "outer");
21728   break;
21729
21730 @ @<Declare action procedures for use by |do_statement|@>=
21731 void mp_do_protection (MP mp) ;
21732
21733 @ @c void mp_do_protection (MP mp) {
21734   int m; /* 0 to unprotect, 1 to protect */
21735   halfword t; /* the |eq_type| before we change it */
21736   m=mp->cur_mod;
21737   do {  
21738     mp_get_symbol(mp); t=eq_type(mp->cur_sym);
21739     if ( m==0 ) { 
21740       if ( t>=outer_tag ) 
21741         eq_type(mp->cur_sym)=t-outer_tag;
21742     } else if ( t<outer_tag ) {
21743       eq_type(mp->cur_sym)=t+outer_tag;
21744     }
21745     mp_get_x_next(mp);
21746   } while (mp->cur_cmd==comma);
21747 }
21748
21749 @ \MP\ never defines the tokens `\.(' and `\.)' to be primitives, but
21750 plain \MP\ begins with the declaration `\&{delimiters} \.{()}'. Such a
21751 declaration assigns the command code |left_delimiter| to `\.{(}' and
21752 |right_delimiter| to `\.{)}'; the |equiv| of each delimiter is the
21753 hash address of its mate.
21754
21755 @<Cases of |do_statement|...@>=
21756 case delimiters: mp_def_delims(mp); break;
21757
21758 @ @<Declare action procedures for use by |do_statement|@>=
21759 void mp_def_delims (MP mp) ;
21760
21761 @ @c void mp_def_delims (MP mp) {
21762   pointer l_delim,r_delim; /* the new delimiter pair */
21763   mp_get_clear_symbol(mp); l_delim=mp->cur_sym;
21764   mp_get_clear_symbol(mp); r_delim=mp->cur_sym;
21765   eq_type(l_delim)=left_delimiter; equiv(l_delim)=r_delim;
21766   eq_type(r_delim)=right_delimiter; equiv(r_delim)=l_delim;
21767   mp_get_x_next(mp);
21768 }
21769
21770 @ Here is a procedure that is called when \MP\ has reached a point
21771 where some right delimiter is mandatory.
21772
21773 @<Declare the procedure called |check_delimiter|@>=
21774 void mp_check_delimiter (MP mp,pointer l_delim, pointer r_delim) {
21775   if ( mp->cur_cmd==right_delimiter ) 
21776     if ( mp->cur_mod==l_delim ) 
21777       return;
21778   if ( mp->cur_sym!=r_delim ) {
21779      mp_missing_err(mp, str(text(r_delim)));
21780 @.Missing `)'@>
21781     help2("I found no right delimiter to match a left one. So I've")
21782       ("put one in, behind the scenes; this may fix the problem.");
21783     mp_back_error(mp);
21784   } else { 
21785     print_err("The token `"); mp_print_text(r_delim);
21786 @.The token...delimiter@>
21787     mp_print(mp, "' is no longer a right delimiter");
21788     help3("Strange: This token has lost its former meaning!")
21789       ("I'll read it as a right delimiter this time;")
21790       ("but watch out, I'll probably miss it later.");
21791     mp_error(mp);
21792   }
21793 }
21794
21795 @ The next four commands save or change the values associated with tokens.
21796
21797 @<Cases of |do_statement|...@>=
21798 case save_command: 
21799   do {  
21800     mp_get_symbol(mp); mp_save_variable(mp, mp->cur_sym); mp_get_x_next(mp);
21801   } while (mp->cur_cmd==comma);
21802   break;
21803 case interim_command: mp_do_interim(mp); break;
21804 case let_command: mp_do_let(mp); break;
21805 case new_internal: mp_do_new_internal(mp); break;
21806
21807 @ @<Declare action procedures for use by |do_statement|@>=
21808 void mp_do_statement (MP mp);
21809 void mp_do_interim (MP mp);
21810
21811 @ @c void mp_do_interim (MP mp) { 
21812   mp_get_x_next(mp);
21813   if ( mp->cur_cmd!=internal_quantity ) {
21814      print_err("The token `");
21815 @.The token...quantity@>
21816     if ( mp->cur_sym==0 ) mp_print(mp, "(%CAPSULE)");
21817     else mp_print_text(mp->cur_sym);
21818     mp_print(mp, "' isn't an internal quantity");
21819     help1("Something like `tracingonline' should follow `interim'.");
21820     mp_back_error(mp);
21821   } else { 
21822     mp_save_internal(mp, mp->cur_mod); mp_back_input(mp);
21823   }
21824   mp_do_statement(mp);
21825 }
21826
21827 @ The following procedure is careful not to undefine the left-hand symbol
21828 too soon, lest commands like `{\tt let x=x}' have a surprising effect.
21829
21830 @<Declare action procedures for use by |do_statement|@>=
21831 void mp_do_let (MP mp) ;
21832
21833 @ @c void mp_do_let (MP mp) {
21834   pointer l; /* hash location of the left-hand symbol */
21835   mp_get_symbol(mp); l=mp->cur_sym; mp_get_x_next(mp);
21836   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
21837      mp_missing_err(mp, "=");
21838 @.Missing `='@>
21839     help3("You should have said `let symbol = something'.")
21840       ("But don't worry; I'll pretend that an equals sign")
21841       ("was present. The next token I read will be `something'.");
21842     mp_back_error(mp);
21843   }
21844   mp_get_symbol(mp);
21845   switch (mp->cur_cmd) {
21846   case defined_macro: case secondary_primary_macro:
21847   case tertiary_secondary_macro: case expression_tertiary_macro: 
21848     add_mac_ref(mp->cur_mod);
21849     break;
21850   default: 
21851     break;
21852   }
21853   mp_clear_symbol(mp, l,false); eq_type(l)=mp->cur_cmd;
21854   if ( mp->cur_cmd==tag_token ) equiv(l)=null;
21855   else equiv(l)=mp->cur_mod;
21856   mp_get_x_next(mp);
21857 }
21858
21859 @ @<Declarations@>=
21860 void mp_grow_internals (MP mp, int l);
21861 void mp_do_new_internal (MP mp) ;
21862
21863 @ @c
21864 void mp_grow_internals (MP mp, int l) {
21865   scaled *internal;
21866   char * *int_name; 
21867   int k;
21868   if ( hash_end+l>max_halfword ) {
21869     mp_confusion(mp, "out of memory space"); /* can't be reached */
21870   }
21871   int_name = xmalloc ((l+1),sizeof(char *));
21872   internal = xmalloc ((l+1),sizeof(scaled));
21873   for (k=0;k<=l; k++ ) { 
21874     if (k<=mp->max_internal) {
21875       internal[k]=mp->internal[k]; 
21876       int_name[k]=mp->int_name[k]; 
21877     } else {
21878       internal[k]=0; 
21879       int_name[k]=NULL; 
21880     }
21881   }
21882   xfree(mp->internal); xfree(mp->int_name);
21883   mp->int_name = int_name;
21884   mp->internal = internal;
21885   mp->max_internal = l;
21886 }
21887
21888
21889 void mp_do_new_internal (MP mp) { 
21890   do {  
21891     if ( mp->int_ptr==mp->max_internal ) {
21892       mp_grow_internals(mp, (mp->max_internal + (mp->max_internal>>2)));
21893     }
21894     mp_get_clear_symbol(mp); incr(mp->int_ptr);
21895     eq_type(mp->cur_sym)=internal_quantity; 
21896     equiv(mp->cur_sym)=mp->int_ptr;
21897     if(mp->int_name[mp->int_ptr]!=NULL)
21898       xfree(mp->int_name[mp->int_ptr]);
21899     mp->int_name[mp->int_ptr]=str(text(mp->cur_sym)); 
21900     mp->internal[mp->int_ptr]=0;
21901     mp_get_x_next(mp);
21902   } while (mp->cur_cmd==comma);
21903 }
21904
21905 @ @<Dealloc variables@>=
21906 for (k=0;k<=mp->max_internal;k++) {
21907    xfree(mp->int_name[k]);
21908 }
21909 xfree(mp->internal); 
21910 xfree(mp->int_name); 
21911
21912
21913 @ The various `\&{show}' commands are distinguished by modifier fields
21914 in the usual way.
21915
21916 @d show_token_code 0 /* show the meaning of a single token */
21917 @d show_stats_code 1 /* show current memory and string usage */
21918 @d show_code 2 /* show a list of expressions */
21919 @d show_var_code 3 /* show a variable and its descendents */
21920 @d show_dependencies_code 4 /* show dependent variables in terms of independents */
21921
21922 @<Put each...@>=
21923 mp_primitive(mp, "showtoken",show_command,show_token_code);
21924 @:show_token_}{\&{showtoken} primitive@>
21925 mp_primitive(mp, "showstats",show_command,show_stats_code);
21926 @:show_stats_}{\&{showstats} primitive@>
21927 mp_primitive(mp, "show",show_command,show_code);
21928 @:show_}{\&{show} primitive@>
21929 mp_primitive(mp, "showvariable",show_command,show_var_code);
21930 @:show_var_}{\&{showvariable} primitive@>
21931 mp_primitive(mp, "showdependencies",show_command,show_dependencies_code);
21932 @:show_dependencies_}{\&{showdependencies} primitive@>
21933
21934 @ @<Cases of |print_cmd...@>=
21935 case show_command: 
21936   switch (m) {
21937   case show_token_code:mp_print(mp, "showtoken"); break;
21938   case show_stats_code:mp_print(mp, "showstats"); break;
21939   case show_code:mp_print(mp, "show"); break;
21940   case show_var_code:mp_print(mp, "showvariable"); break;
21941   default: mp_print(mp, "showdependencies"); break;
21942   }
21943   break;
21944
21945 @ @<Cases of |do_statement|...@>=
21946 case show_command:mp_do_show_whatever(mp); break;
21947
21948 @ The value of |cur_mod| controls the |verbosity| in the |print_exp| routine:
21949 if it's |show_code|, complicated structures are abbreviated, otherwise
21950 they aren't.
21951
21952 @<Declare action procedures for use by |do_statement|@>=
21953 void mp_do_show (MP mp) ;
21954
21955 @ @c void mp_do_show (MP mp) { 
21956   do {  
21957     mp_get_x_next(mp); mp_scan_expression(mp);
21958     mp_print_nl(mp, ">> ");
21959 @.>>@>
21960     mp_print_exp(mp, null,2); mp_flush_cur_exp(mp, 0);
21961   } while (mp->cur_cmd==comma);
21962 }
21963
21964 @ @<Declare action procedures for use by |do_statement|@>=
21965 void mp_disp_token (MP mp) ;
21966
21967 @ @c void mp_disp_token (MP mp) { 
21968   mp_print_nl(mp, "> ");
21969 @.>\relax@>
21970   if ( mp->cur_sym==0 ) {
21971     @<Show a numeric or string or capsule token@>;
21972   } else { 
21973     mp_print_text(mp->cur_sym); mp_print_char(mp, '=');
21974     if ( eq_type(mp->cur_sym)>=outer_tag ) mp_print(mp, "(outer) ");
21975     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod);
21976     if ( mp->cur_cmd==defined_macro ) {
21977       mp_print_ln(mp); mp_show_macro(mp, mp->cur_mod,null,100000);
21978     } /* this avoids recursion between |show_macro| and |print_cmd_mod| */
21979 @^recursion@>
21980   }
21981 }
21982
21983 @ @<Show a numeric or string or capsule token@>=
21984
21985   if ( mp->cur_cmd==numeric_token ) {
21986     mp_print_scaled(mp, mp->cur_mod);
21987   } else if ( mp->cur_cmd==capsule_token ) {
21988     mp->g_pointer=mp->cur_mod; mp_print_capsule(mp);
21989   } else  { 
21990     mp_print_char(mp, '"'); 
21991     mp_print_str(mp, mp->cur_mod); mp_print_char(mp, '"');
21992     delete_str_ref(mp->cur_mod);
21993   }
21994 }
21995
21996 @ The following cases of |print_cmd_mod| might arise in connection
21997 with |disp_token|, although they don't correspond to any
21998 primitive tokens.
21999
22000 @<Cases of |print_cmd_...@>=
22001 case left_delimiter:
22002 case right_delimiter: 
22003   if ( c==left_delimiter ) mp_print(mp, "left");
22004   else mp_print(mp, "right");
22005   mp_print(mp, " delimiter that matches "); 
22006   mp_print_text(m);
22007   break;
22008 case tag_token:
22009   if ( m==null ) mp_print(mp, "tag");
22010    else mp_print(mp, "variable");
22011    break;
22012 case defined_macro: 
22013    mp_print(mp, "macro:");
22014    break;
22015 case secondary_primary_macro:
22016 case tertiary_secondary_macro:
22017 case expression_tertiary_macro:
22018   mp_print_cmd_mod(mp, macro_def,c); 
22019   mp_print(mp, "'d macro:");
22020   mp_print_ln(mp); mp_show_token_list(mp, link(link(m)),null,1000,0);
22021   break;
22022 case repeat_loop:
22023   mp_print(mp, "[repeat the loop]");
22024   break;
22025 case internal_quantity:
22026   mp_print(mp, mp->int_name[m]);
22027   break;
22028
22029 @ @<Declare action procedures for use by |do_statement|@>=
22030 void mp_do_show_token (MP mp) ;
22031
22032 @ @c void mp_do_show_token (MP mp) { 
22033   do {  
22034     get_t_next; mp_disp_token(mp);
22035     mp_get_x_next(mp);
22036   } while (mp->cur_cmd==comma);
22037 }
22038
22039 @ @<Declare action procedures for use by |do_statement|@>=
22040 void mp_do_show_stats (MP mp) ;
22041
22042 @ @c void mp_do_show_stats (MP mp) { 
22043   mp_print_nl(mp, "Memory usage ");
22044 @.Memory usage...@>
22045   mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used);
22046   if ( false )
22047     mp_print(mp, "unknown");
22048   mp_print(mp, " ("); mp_print_int(mp, mp->hi_mem_min-mp->lo_mem_max-1);
22049   mp_print(mp, " still untouched)"); mp_print_ln(mp);
22050   mp_print_nl(mp, "String usage ");
22051   mp_print_int(mp, mp->strs_in_use-mp->init_str_use);
22052   mp_print_char(mp, '&'); mp_print_int(mp, mp->pool_in_use-mp->init_pool_ptr);
22053   if ( false )
22054     mp_print(mp, "unknown");
22055   mp_print(mp, " (");
22056   mp_print_int(mp, mp->max_strings-1-mp->strs_used_up); mp_print_char(mp, '&');
22057   mp_print_int(mp, mp->pool_size-mp->pool_ptr); 
22058   mp_print(mp, " now untouched)"); mp_print_ln(mp);
22059   mp_get_x_next(mp);
22060 }
22061
22062 @ Here's a recursive procedure that gives an abbreviated account
22063 of a variable, for use by |do_show_var|.
22064
22065 @<Declare action procedures for use by |do_statement|@>=
22066 void mp_disp_var (MP mp,pointer p) ;
22067
22068 @ @c void mp_disp_var (MP mp,pointer p) {
22069   pointer q; /* traverses attributes and subscripts */
22070   int n; /* amount of macro text to show */
22071   if ( type(p)==mp_structured )  {
22072     @<Descend the structure@>;
22073   } else if ( type(p)>=mp_unsuffixed_macro ) {
22074     @<Display a variable macro@>;
22075   } else if ( type(p)!=undefined ){ 
22076     mp_print_nl(mp, ""); mp_print_variable_name(mp, p); 
22077     mp_print_char(mp, '=');
22078     mp_print_exp(mp, p,0);
22079   }
22080 }
22081
22082 @ @<Descend the structure@>=
22083
22084   q=attr_head(p);
22085   do {  mp_disp_var(mp, q); q=link(q); } while (q!=end_attr);
22086   q=subscr_head(p);
22087   while ( name_type(q)==mp_subscr ) { 
22088     mp_disp_var(mp, q); q=link(q);
22089   }
22090 }
22091
22092 @ @<Display a variable macro@>=
22093
22094   mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22095   if ( type(p)>mp_unsuffixed_macro ) 
22096     mp_print(mp, "@@#"); /* |suffixed_macro| */
22097   mp_print(mp, "=macro:");
22098   if ( (int)mp->file_offset>=mp->max_print_line-20 ) n=5;
22099   else n=mp->max_print_line-mp->file_offset-15;
22100   mp_show_macro(mp, value(p),null,n);
22101 }
22102
22103 @ @<Declare action procedures for use by |do_statement|@>=
22104 void mp_do_show_var (MP mp) ;
22105
22106 @ @c void mp_do_show_var (MP mp) { 
22107   do {  
22108     get_t_next;
22109     if ( mp->cur_sym>0 ) if ( mp->cur_sym<=hash_end )
22110       if ( mp->cur_cmd==tag_token ) if ( mp->cur_mod!=null ) {
22111       mp_disp_var(mp, mp->cur_mod); goto DONE;
22112     }
22113    mp_disp_token(mp);
22114   DONE:
22115    mp_get_x_next(mp);
22116   } while (mp->cur_cmd==comma);
22117 }
22118
22119 @ @<Declare action procedures for use by |do_statement|@>=
22120 void mp_do_show_dependencies (MP mp) ;
22121
22122 @ @c void mp_do_show_dependencies (MP mp) {
22123   pointer p; /* link that runs through all dependencies */
22124   p=link(dep_head);
22125   while ( p!=dep_head ) {
22126     if ( mp_interesting(mp, p) ) {
22127       mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22128       if ( type(p)==mp_dependent ) mp_print_char(mp, '=');
22129       else mp_print(mp, " = "); /* extra spaces imply proto-dependency */
22130       mp_print_dependency(mp, dep_list(p),type(p));
22131     }
22132     p=dep_list(p);
22133     while ( info(p)!=null ) p=link(p);
22134     p=link(p);
22135   }
22136   mp_get_x_next(mp);
22137 }
22138
22139 @ Finally we are ready for the procedure that governs all of the
22140 show commands.
22141
22142 @<Declare action procedures for use by |do_statement|@>=
22143 void mp_do_show_whatever (MP mp) ;
22144
22145 @ @c void mp_do_show_whatever (MP mp) { 
22146   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
22147   switch (mp->cur_mod) {
22148   case show_token_code:mp_do_show_token(mp); break;
22149   case show_stats_code:mp_do_show_stats(mp); break;
22150   case show_code:mp_do_show(mp); break;
22151   case show_var_code:mp_do_show_var(mp); break;
22152   case show_dependencies_code:mp_do_show_dependencies(mp); break;
22153   } /* there are no other cases */
22154   if ( mp->internal[showstopping]>0 ){ 
22155     print_err("OK");
22156 @.OK@>
22157     if ( mp->interaction<mp_error_stop_mode ) { 
22158       help0; decr(mp->error_count);
22159     } else {
22160       help1("This isn't an error message; I'm just showing something.");
22161     }
22162     if ( mp->cur_cmd==semicolon ) mp_error(mp);
22163      else mp_put_get_error(mp);
22164   }
22165 }
22166
22167 @ The `\&{addto}' command needs the following additional primitives:
22168
22169 @d double_path_code 0 /* command modifier for `\&{doublepath}' */
22170 @d contour_code 1 /* command modifier for `\&{contour}' */
22171 @d also_code 2 /* command modifier for `\&{also}' */
22172
22173 @ Pre and postscripts need two new identifiers:
22174
22175 @d with_pre_script 11
22176 @d with_post_script 13
22177
22178 @<Put each...@>=
22179 mp_primitive(mp, "doublepath",thing_to_add,double_path_code);
22180 @:double_path_}{\&{doublepath} primitive@>
22181 mp_primitive(mp, "contour",thing_to_add,contour_code);
22182 @:contour_}{\&{contour} primitive@>
22183 mp_primitive(mp, "also",thing_to_add,also_code);
22184 @:also_}{\&{also} primitive@>
22185 mp_primitive(mp, "withpen",with_option,mp_pen_type);
22186 @:with_pen_}{\&{withpen} primitive@>
22187 mp_primitive(mp, "dashed",with_option,mp_picture_type);
22188 @:dashed_}{\&{dashed} primitive@>
22189 mp_primitive(mp, "withprescript",with_option,with_pre_script);
22190 @:with_pre_script_}{\&{withprescript} primitive@>
22191 mp_primitive(mp, "withpostscript",with_option,with_post_script);
22192 @:with_post_script_}{\&{withpostscript} primitive@>
22193 mp_primitive(mp, "withoutcolor",with_option,no_model);
22194 @:with_color_}{\&{withoutcolor} primitive@>
22195 mp_primitive(mp, "withgreyscale",with_option,grey_model);
22196 @:with_color_}{\&{withgreyscale} primitive@>
22197 mp_primitive(mp, "withcolor",with_option,uninitialized_model);
22198 @:with_color_}{\&{withcolor} primitive@>
22199 /*  \&{withrgbcolor} is an alias for \&{withcolor} */
22200 mp_primitive(mp, "withrgbcolor",with_option,rgb_model);
22201 @:with_color_}{\&{withrgbcolor} primitive@>
22202 mp_primitive(mp, "withcmykcolor",with_option,cmyk_model);
22203 @:with_color_}{\&{withcmykcolor} primitive@>
22204
22205 @ @<Cases of |print_cmd...@>=
22206 case thing_to_add:
22207   if ( m==contour_code ) mp_print(mp, "contour");
22208   else if ( m==double_path_code ) mp_print(mp, "doublepath");
22209   else mp_print(mp, "also");
22210   break;
22211 case with_option:
22212   if ( m==mp_pen_type ) mp_print(mp, "withpen");
22213   else if ( m==with_pre_script ) mp_print(mp, "withprescript");
22214   else if ( m==with_post_script ) mp_print(mp, "withpostscript");
22215   else if ( m==no_model ) mp_print(mp, "withoutcolor");
22216   else if ( m==rgb_model ) mp_print(mp, "withrgbcolor");
22217   else if ( m==uninitialized_model ) mp_print(mp, "withcolor");
22218   else if ( m==cmyk_model ) mp_print(mp, "withcmykcolor");
22219   else if ( m==grey_model ) mp_print(mp, "withgreyscale");
22220   else mp_print(mp, "dashed");
22221   break;
22222
22223 @ The |scan_with_list| procedure parses a $\langle$with list$\rangle$ and
22224 updates the list of graphical objects starting at |p|.  Each $\langle$with
22225 clause$\rangle$ updates all graphical objects whose |type| is compatible.
22226 Other objects are ignored.
22227
22228 @<Declare action procedures for use by |do_statement|@>=
22229 void mp_scan_with_list (MP mp,pointer p) ;
22230
22231 @ @c void mp_scan_with_list (MP mp,pointer p) {
22232   small_number t; /* |cur_mod| of the |with_option| (should match |cur_type|) */
22233   pointer q; /* for list manipulation */
22234   int old_setting; /* saved |selector| setting */
22235   pointer k; /* for finding the near-last item in a list  */
22236   str_number s; /* for string cleanup after combining  */
22237   pointer cp,pp,dp,ap,bp;
22238     /* objects being updated; |void| initially; |null| to suppress update */
22239   cp=diov; pp=diov; dp=diov; ap=diov; bp=diov;
22240   k=0;
22241   while ( mp->cur_cmd==with_option ){ 
22242     t=mp->cur_mod;
22243     mp_get_x_next(mp);
22244     if ( t!=no_model ) mp_scan_expression(mp);
22245     if (((t==with_pre_script)&&(mp->cur_type!=mp_string_type))||
22246      ((t==with_post_script)&&(mp->cur_type!=mp_string_type))||
22247      ((t==uninitialized_model)&&
22248         ((mp->cur_type!=mp_cmykcolor_type)&&(mp->cur_type!=mp_color_type)
22249           &&(mp->cur_type!=mp_known)&&(mp->cur_type!=mp_boolean_type)))||
22250      ((t==cmyk_model)&&(mp->cur_type!=mp_cmykcolor_type))||
22251      ((t==rgb_model)&&(mp->cur_type!=mp_color_type))||
22252      ((t==grey_model)&&(mp->cur_type!=mp_known))||
22253      ((t==mp_pen_type)&&(mp->cur_type!=t))||
22254      ((t==mp_picture_type)&&(mp->cur_type!=t)) ) {
22255       @<Complain about improper type@>;
22256     } else if ( t==uninitialized_model ) {
22257       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22258       if ( cp!=null )
22259         @<Transfer a color from the current expression to object~|cp|@>;
22260       mp_flush_cur_exp(mp, 0);
22261     } else if ( t==rgb_model ) {
22262       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22263       if ( cp!=null )
22264         @<Transfer a rgbcolor from the current expression to object~|cp|@>;
22265       mp_flush_cur_exp(mp, 0);
22266     } else if ( t==cmyk_model ) {
22267       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22268       if ( cp!=null )
22269         @<Transfer a cmykcolor from the current expression to object~|cp|@>;
22270       mp_flush_cur_exp(mp, 0);
22271     } else if ( t==grey_model ) {
22272       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22273       if ( cp!=null )
22274         @<Transfer a greyscale from the current expression to object~|cp|@>;
22275       mp_flush_cur_exp(mp, 0);
22276     } else if ( t==no_model ) {
22277       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22278       if ( cp!=null )
22279         @<Transfer a noncolor from the current expression to object~|cp|@>;
22280     } else if ( t==mp_pen_type ) {
22281       if ( pp==diov ) @<Make |pp| an object in list~|p| that needs a pen@>;
22282       if ( pp!=null ) {
22283         if ( pen_p(pp)!=null ) mp_toss_knot_list(mp, pen_p(pp));
22284         pen_p(pp)=mp->cur_exp; mp->cur_type=mp_vacuous;
22285       }
22286     } else if ( t==with_pre_script ) {
22287       if ( ap==diov )
22288         ap=p;
22289       while ( (ap!=null)&&(! has_color(ap)) )
22290          ap=link(ap);
22291       if ( ap!=null ) {
22292         if ( pre_script(ap)!=null ) { /*  build a new,combined string  */
22293           s=pre_script(ap);
22294           old_setting=mp->selector;
22295               mp->selector=new_string;
22296           str_room(length(pre_script(ap))+length(mp->cur_exp)+2);
22297               mp_print_str(mp, mp->cur_exp);
22298           append_char(13);  /* a forced \ps\ newline  */
22299           mp_print_str(mp, pre_script(ap));
22300           pre_script(ap)=mp_make_string(mp);
22301           delete_str_ref(s);
22302           mp->selector=old_setting;
22303         } else {
22304           pre_script(ap)=mp->cur_exp;
22305         }
22306         mp->cur_type=mp_vacuous;
22307       }
22308     } else if ( t==with_post_script ) {
22309       if ( bp==diov )
22310         k=p; 
22311       bp=k;
22312       while ( link(k)!=null ) {
22313         k=link(k);
22314         if ( has_color(k) ) bp=k;
22315       }
22316       if ( bp!=null ) {
22317          if ( post_script(bp)!=null ) {
22318            s=post_script(bp);
22319            old_setting=mp->selector;
22320                mp->selector=new_string;
22321            str_room(length(post_script(bp))+length(mp->cur_exp)+2);
22322            mp_print_str(mp, post_script(bp));
22323            append_char(13); /* a forced \ps\ newline  */
22324            mp_print_str(mp, mp->cur_exp);
22325            post_script(bp)=mp_make_string(mp);
22326            delete_str_ref(s);
22327            mp->selector=old_setting;
22328          } else {
22329            post_script(bp)=mp->cur_exp;
22330          }
22331          mp->cur_type=mp_vacuous;
22332        }
22333     } else { 
22334       if ( dp==diov ) 
22335         @<Make |dp| a stroked node in list~|p|@>;
22336       if ( dp!=null ) {
22337         if ( dash_p(dp)!=null ) delete_edge_ref(dash_p(dp));
22338         dash_p(dp)=mp_make_dashes(mp, mp->cur_exp);
22339         dash_scale(dp)=unity;
22340         mp->cur_type=mp_vacuous;
22341       }
22342     }
22343   }
22344   @<Copy the information from objects |cp|, |pp|, and |dp| into the rest
22345     of the list@>;
22346 };
22347
22348 @ @<Complain about improper type@>=
22349 { exp_err("Improper type");
22350 @.Improper type@>
22351 help2("Next time say `withpen <known pen expression>';")
22352   ("I'll ignore the bad `with' clause and look for another.");
22353 if ( t==with_pre_script )
22354   mp->help_line[1]="Next time say `withprescript <known string expression>';";
22355 else if ( t==with_post_script )
22356   mp->help_line[1]="Next time say `withpostscript <known string expression>';";
22357 else if ( t==mp_picture_type )
22358   mp->help_line[1]="Next time say `dashed <known picture expression>';";
22359 else if ( t==uninitialized_model )
22360   mp->help_line[1]="Next time say `withcolor <known color expression>';";
22361 else if ( t==rgb_model )
22362   mp->help_line[1]="Next time say `withrgbcolor <known color expression>';";
22363 else if ( t==cmyk_model )
22364   mp->help_line[1]="Next time say `withcmykcolor <known cmykcolor expression>';";
22365 else if ( t==grey_model )
22366   mp->help_line[1]="Next time say `withgreyscale <known numeric expression>';";;
22367 mp_put_get_flush_error(mp, 0);
22368 }
22369
22370 @ Forcing the color to be between |0| and |unity| here guarantees that no
22371 picture will ever contain a color outside the legal range for \ps\ graphics.
22372
22373 @<Transfer a color from the current expression to object~|cp|@>=
22374 { if ( mp->cur_type==mp_color_type )
22375    @<Transfer a rgbcolor from the current expression to object~|cp|@>
22376 else if ( mp->cur_type==mp_cmykcolor_type )
22377    @<Transfer a cmykcolor from the current expression to object~|cp|@>
22378 else if ( mp->cur_type==mp_known )
22379    @<Transfer a greyscale from the current expression to object~|cp|@>
22380 else if ( mp->cur_exp==false_code )
22381    @<Transfer a noncolor from the current expression to object~|cp|@>;
22382 }
22383
22384 @ @<Transfer a rgbcolor from the current expression to object~|cp|@>=
22385 { q=value(mp->cur_exp);
22386 cyan_val(cp)=0;
22387 magenta_val(cp)=0;
22388 yellow_val(cp)=0;
22389 black_val(cp)=0;
22390 red_val(cp)=value(red_part_loc(q));
22391 green_val(cp)=value(green_part_loc(q));
22392 blue_val(cp)=value(blue_part_loc(q));
22393 color_model(cp)=rgb_model;
22394 if ( red_val(cp)<0 ) red_val(cp)=0;
22395 if ( green_val(cp)<0 ) green_val(cp)=0;
22396 if ( blue_val(cp)<0 ) blue_val(cp)=0;
22397 if ( red_val(cp)>unity ) red_val(cp)=unity;
22398 if ( green_val(cp)>unity ) green_val(cp)=unity;
22399 if ( blue_val(cp)>unity ) blue_val(cp)=unity;
22400 }
22401
22402 @ @<Transfer a cmykcolor from the current expression to object~|cp|@>=
22403 { q=value(mp->cur_exp);
22404 cyan_val(cp)=value(cyan_part_loc(q));
22405 magenta_val(cp)=value(magenta_part_loc(q));
22406 yellow_val(cp)=value(yellow_part_loc(q));
22407 black_val(cp)=value(black_part_loc(q));
22408 color_model(cp)=cmyk_model;
22409 if ( cyan_val(cp)<0 ) cyan_val(cp)=0;
22410 if ( magenta_val(cp)<0 ) magenta_val(cp)=0;
22411 if ( yellow_val(cp)<0 ) yellow_val(cp)=0;
22412 if ( black_val(cp)<0 ) black_val(cp)=0;
22413 if ( cyan_val(cp)>unity ) cyan_val(cp)=unity;
22414 if ( magenta_val(cp)>unity ) magenta_val(cp)=unity;
22415 if ( yellow_val(cp)>unity ) yellow_val(cp)=unity;
22416 if ( black_val(cp)>unity ) black_val(cp)=unity;
22417 }
22418
22419 @ @<Transfer a greyscale from the current expression to object~|cp|@>=
22420 { q=mp->cur_exp;
22421 cyan_val(cp)=0;
22422 magenta_val(cp)=0;
22423 yellow_val(cp)=0;
22424 black_val(cp)=0;
22425 grey_val(cp)=q;
22426 color_model(cp)=grey_model;
22427 if ( grey_val(cp)<0 ) grey_val(cp)=0;
22428 if ( grey_val(cp)>unity ) grey_val(cp)=unity;
22429 }
22430
22431 @ @<Transfer a noncolor from the current expression to object~|cp|@>=
22432 {
22433 cyan_val(cp)=0;
22434 magenta_val(cp)=0;
22435 yellow_val(cp)=0;
22436 black_val(cp)=0;
22437 grey_val(cp)=0;
22438 color_model(cp)=no_model;
22439 }
22440
22441 @ @<Make |cp| a colored object in object list~|p|@>=
22442 { cp=p;
22443   while ( cp!=null ){ 
22444     if ( has_color(cp) ) break;
22445     cp=link(cp);
22446   }
22447 }
22448
22449 @ @<Make |pp| an object in list~|p| that needs a pen@>=
22450 { pp=p;
22451   while ( pp!=null ) {
22452     if ( has_pen(pp) ) break;
22453     pp=link(pp);
22454   }
22455 }
22456
22457 @ @<Make |dp| a stroked node in list~|p|@>=
22458 { dp=p;
22459   while ( dp!=null ) {
22460     if ( type(dp)==stroked_code ) break;
22461     dp=link(dp);
22462   }
22463 }
22464
22465 @ @<Copy the information from objects |cp|, |pp|, and |dp| into...@>=
22466 @<Copy |cp|'s color into the colored objects linked to~|cp|@>;
22467 if ( pp>diov )
22468   @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>;
22469 if ( dp>diov ) @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>
22470
22471 @ @<Copy |cp|'s color into the colored objects linked to~|cp|@>=
22472 { q=link(cp);
22473   while ( q!=null ) { 
22474     if ( has_color(q) ) {
22475       red_val(q)=red_val(cp);
22476       green_val(q)=green_val(cp);
22477       blue_val(q)=blue_val(cp);
22478       black_val(q)=black_val(cp);
22479       color_model(q)=color_model(cp);
22480     }
22481     q=link(q);
22482   }
22483 }
22484
22485 @ @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>=
22486 { q=link(pp);
22487   while ( q!=null ) {
22488     if ( has_pen(q) ) {
22489       if ( pen_p(q)!=null ) mp_toss_knot_list(mp, pen_p(q));
22490       pen_p(q)=copy_pen(pen_p(pp));
22491     }
22492     q=link(q);
22493   }
22494 }
22495
22496 @ @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>=
22497 { q=link(dp);
22498   while ( q!=null ) {
22499     if ( type(q)==stroked_code ) {
22500       if ( dash_p(q)!=null ) delete_edge_ref(dash_p(q));
22501       dash_p(q)=dash_p(dp);
22502       dash_scale(q)=unity;
22503       if ( dash_p(q)!=null ) add_edge_ref(dash_p(q));
22504     }
22505     q=link(q);
22506   }
22507 }
22508
22509 @ One of the things we need to do when we've parsed an \&{addto} or
22510 similar command is find the header of a supposed \&{picture} variable, given
22511 a token list for that variable.  Since the edge structure is about to be
22512 updated, we use |private_edges| to make sure that this is possible.
22513
22514 @<Declare action procedures for use by |do_statement|@>=
22515 pointer mp_find_edges_var (MP mp, pointer t) ;
22516
22517 @ @c pointer mp_find_edges_var (MP mp, pointer t) {
22518   pointer p;
22519   pointer cur_edges; /* the return value */
22520   p=mp_find_variable(mp, t); cur_edges=null;
22521   if ( p==null ) { 
22522     mp_obliterated(mp, t); mp_put_get_error(mp);
22523   } else if ( type(p)!=mp_picture_type )  { 
22524     print_err("Variable "); mp_show_token_list(mp, t,null,1000,0);
22525 @.Variable x is the wrong type@>
22526     mp_print(mp, " is the wrong type ("); 
22527     mp_print_type(mp, type(p)); mp_print_char(mp, ')');
22528     help2("I was looking for a \"known\" picture variable.")
22529          ("So I'll not change anything just now."); 
22530     mp_put_get_error(mp);
22531   } else { 
22532     value(p)=mp_private_edges(mp, value(p));
22533     cur_edges=value(p);
22534   }
22535   mp_flush_node_list(mp, t);
22536   return cur_edges;
22537 };
22538
22539 @ @<Cases of |do_statement|...@>=
22540 case add_to_command: mp_do_add_to(mp); break;
22541 case bounds_command:mp_do_bounds(mp); break;
22542
22543 @ @<Put each...@>=
22544 mp_primitive(mp, "clip",bounds_command,mp_start_clip_code);
22545 @:clip_}{\&{clip} primitive@>
22546 mp_primitive(mp, "setbounds",bounds_command,mp_start_bounds_code);
22547 @:set_bounds_}{\&{setbounds} primitive@>
22548
22549 @ @<Cases of |print_cmd...@>=
22550 case bounds_command: 
22551   if ( m==mp_start_clip_code ) mp_print(mp, "clip");
22552   else mp_print(mp, "setbounds");
22553   break;
22554
22555 @ The following function parses the beginning of an \&{addto} or \&{clip}
22556 command: it expects a variable name followed by a token with |cur_cmd=sep|
22557 and then an expression.  The function returns the token list for the variable
22558 and stores the command modifier for the separator token in the global variable
22559 |last_add_type|.  We must be careful because this variable might get overwritten
22560 any time we call |get_x_next|.
22561
22562 @<Glob...@>=
22563 quarterword last_add_type;
22564   /* command modifier that identifies the last \&{addto} command */
22565
22566 @ @<Declare action procedures for use by |do_statement|@>=
22567 pointer mp_start_draw_cmd (MP mp,quarterword sep) ;
22568
22569 @ @c pointer mp_start_draw_cmd (MP mp,quarterword sep) {
22570   pointer lhv; /* variable to add to left */
22571   quarterword add_type=0; /* value to be returned in |last_add_type| */
22572   lhv=null;
22573   mp_get_x_next(mp); mp->var_flag=sep; mp_scan_primary(mp);
22574   if ( mp->cur_type!=mp_token_list ) {
22575     @<Abandon edges command because there's no variable@>;
22576   } else  { 
22577     lhv=mp->cur_exp; add_type=mp->cur_mod;
22578     mp->cur_type=mp_vacuous; mp_get_x_next(mp); mp_scan_expression(mp);
22579   }
22580   mp->last_add_type=add_type;
22581   return lhv;
22582 }
22583
22584 @ @<Abandon edges command because there's no variable@>=
22585 { exp_err("Not a suitable variable");
22586 @.Not a suitable variable@>
22587   help4("At this point I needed to see the name of a picture variable.")
22588     ("(Or perhaps you have indeed presented me with one; I might")
22589     ("have missed it, if it wasn't followed by the proper token.)")
22590     ("So I'll not change anything just now.");
22591   mp_put_get_flush_error(mp, 0);
22592 }
22593
22594 @ Here is an example of how to use |start_draw_cmd|.
22595
22596 @<Declare action procedures for use by |do_statement|@>=
22597 void mp_do_bounds (MP mp) ;
22598
22599 @ @c void mp_do_bounds (MP mp) {
22600   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22601   pointer p; /* for list manipulation */
22602   integer m; /* initial value of |cur_mod| */
22603   m=mp->cur_mod;
22604   lhv=mp_start_draw_cmd(mp, to_token);
22605   if ( lhv!=null ) {
22606     lhe=mp_find_edges_var(mp, lhv);
22607     if ( lhe==null ) {
22608       mp_flush_cur_exp(mp, 0);
22609     } else if ( mp->cur_type!=mp_path_type ) {
22610       exp_err("Improper `clip'");
22611 @.Improper `addto'@>
22612       help2("This expression should have specified a known path.")
22613         ("So I'll not change anything just now."); 
22614       mp_put_get_flush_error(mp, 0);
22615     } else if ( left_type(mp->cur_exp)==endpoint ) {
22616       @<Complain about a non-cycle@>;
22617     } else {
22618       @<Make |cur_exp| into a \&{setbounds} or clipping path and add it to |lhe|@>;
22619     }
22620   }
22621 }
22622
22623 @ @<Complain about a non-cycle@>=
22624 { print_err("Not a cycle");
22625 @.Not a cycle@>
22626   help2("That contour should have ended with `..cycle' or `&cycle'.")
22627     ("So I'll not change anything just now."); mp_put_get_error(mp);
22628 }
22629
22630 @ @<Make |cur_exp| into a \&{setbounds} or clipping path and add...@>=
22631 { p=mp_new_bounds_node(mp, mp->cur_exp,m);
22632   link(p)=link(dummy_loc(lhe));
22633   link(dummy_loc(lhe))=p;
22634   if ( obj_tail(lhe)==dummy_loc(lhe) ) obj_tail(lhe)=p;
22635   p=mp_get_node(mp, mp->gr_object_size[stop_type(m)]);
22636   type(p)=stop_type(m);
22637   link(obj_tail(lhe))=p;
22638   obj_tail(lhe)=p;
22639   mp_init_bbox(mp, lhe);
22640 }
22641
22642 @ The |do_add_to| procedure is a little like |do_clip| but there are a lot more
22643 cases to deal with.
22644
22645 @<Declare action procedures for use by |do_statement|@>=
22646 void mp_do_add_to (MP mp) ;
22647
22648 @ @c void mp_do_add_to (MP mp) {
22649   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22650   pointer p; /* the graphical object or list for |scan_with_list| to update */
22651   pointer e; /* an edge structure to be merged */
22652   quarterword add_type; /* |also_code|, |contour_code|, or |double_path_code| */
22653   lhv=mp_start_draw_cmd(mp, thing_to_add); add_type=mp->last_add_type;
22654   if ( lhv!=null ) {
22655     if ( add_type==also_code ) {
22656       @<Make sure the current expression is a suitable picture and set |e| and |p|
22657        appropriately@>;
22658     } else {
22659       @<Create a graphical object |p| based on |add_type| and the current
22660         expression@>;
22661     }
22662     mp_scan_with_list(mp, p);
22663     @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>;
22664   }
22665 }
22666
22667 @ Setting |p:=null| causes the $\langle$with list$\rangle$ to be ignored;
22668 setting |e:=null| prevents anything from being added to |lhe|.
22669
22670 @ @<Make sure the current expression is a suitable picture and set |e|...@>=
22671
22672   p=null; e=null;
22673   if ( mp->cur_type!=mp_picture_type ) {
22674     exp_err("Improper `addto'");
22675 @.Improper `addto'@>
22676     help2("This expression should have specified a known picture.")
22677       ("So I'll not change anything just now."); mp_put_get_flush_error(mp, 0);
22678   } else { 
22679     e=mp_private_edges(mp, mp->cur_exp); mp->cur_type=mp_vacuous;
22680     p=link(dummy_loc(e));
22681   }
22682 }
22683
22684 @ In this case |add_type<>also_code| so setting |p:=null| suppresses future
22685 attempts to add to the edge structure.
22686
22687 @<Create a graphical object |p| based on |add_type| and the current...@>=
22688 { e=null; p=null;
22689   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
22690   if ( mp->cur_type!=mp_path_type ) {
22691     exp_err("Improper `addto'");
22692 @.Improper `addto'@>
22693     help2("This expression should have specified a known path.")
22694       ("So I'll not change anything just now."); 
22695     mp_put_get_flush_error(mp, 0);
22696   } else if ( add_type==contour_code ) {
22697     if ( left_type(mp->cur_exp)==endpoint ) {
22698       @<Complain about a non-cycle@>;
22699     } else { 
22700       p=mp_new_fill_node(mp, mp->cur_exp);
22701       mp->cur_type=mp_vacuous;
22702     }
22703   } else { 
22704     p=mp_new_stroked_node(mp, mp->cur_exp);
22705     mp->cur_type=mp_vacuous;
22706   }
22707 }
22708
22709 @ @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>=
22710 lhe=mp_find_edges_var(mp, lhv);
22711 if ( lhe==null ) {
22712   if ( (e==null)&&(p!=null) ) e=mp_toss_gr_object(mp, p);
22713   if ( e!=null ) delete_edge_ref(e);
22714 } else if ( add_type==also_code ) {
22715   if ( e!=null ) {
22716     @<Merge |e| into |lhe| and delete |e|@>;
22717   } else { 
22718     do_nothing;
22719   }
22720 } else if ( p!=null ) {
22721   link(obj_tail(lhe))=p;
22722   obj_tail(lhe)=p;
22723   if ( add_type==double_path_code )
22724     if ( pen_p(p)==null ) 
22725       pen_p(p)=mp_get_pen_circle(mp, 0);
22726 }
22727
22728 @ @<Merge |e| into |lhe| and delete |e|@>=
22729 { if ( link(dummy_loc(e))!=null ) {
22730     link(obj_tail(lhe))=link(dummy_loc(e));
22731     obj_tail(lhe)=obj_tail(e);
22732     obj_tail(e)=dummy_loc(e);
22733     link(dummy_loc(e))=null;
22734     mp_flush_dash_list(mp, lhe);
22735   }
22736   mp_toss_edges(mp, e);
22737 }
22738
22739 @ @<Cases of |do_statement|...@>=
22740 case ship_out_command: mp_do_ship_out(mp); break;
22741
22742 @ @<Declare action procedures for use by |do_statement|@>=
22743 @<Declare the function called |tfm_check|@>;
22744 @<Declare the \ps\ output procedures@>;
22745 void mp_do_ship_out (MP mp) ;
22746
22747 @ @c void mp_do_ship_out (MP mp) {
22748   integer c; /* the character code */
22749   mp_get_x_next(mp); mp_scan_expression(mp);
22750   if ( mp->cur_type!=mp_picture_type ) {
22751     @<Complain that it's not a known picture@>;
22752   } else { 
22753     c=mp_round_unscaled(mp, mp->internal[char_code]) % 256;
22754     if ( c<0 ) c=c+256;
22755     @<Store the width information for character code~|c|@>;
22756     mp_ship_out(mp, mp->cur_exp);
22757     mp_flush_cur_exp(mp, 0);
22758   }
22759 }
22760
22761 @ @<Complain that it's not a known picture@>=
22762
22763   exp_err("Not a known picture");
22764   help1("I can only output known pictures.");
22765   mp_put_get_flush_error(mp, 0);
22766 }
22767
22768 @ The \&{everyjob} command simply assigns a nonzero value to the global variable
22769 |start_sym|.
22770
22771 @<Cases of |do_statement|...@>=
22772 case every_job_command: 
22773   mp_get_symbol(mp); mp->start_sym=mp->cur_sym; mp_get_x_next(mp);
22774   break;
22775
22776 @ @<Glob...@>=
22777 halfword start_sym; /* a symbolic token to insert at beginning of job */
22778
22779 @ @<Set init...@>=
22780 mp->start_sym=0;
22781
22782 @ Finally, we have only the ``message'' commands remaining.
22783
22784 @d message_code 0
22785 @d err_message_code 1
22786 @d err_help_code 2
22787 @d filename_template_code 3
22788 @d print_with_leading_zeroes(A)  g = mp->pool_ptr;
22789               mp_print_int(mp, (A)); g = mp->pool_ptr-g;
22790               if ( f>g ) {
22791                 mp->pool_ptr = mp->pool_ptr - g;
22792                 while ( f>g ) {
22793                   mp_print_char(mp, '0');
22794                   decr(f);
22795                   };
22796                 mp_print_int(mp, (A));
22797               };
22798               f = 0
22799
22800 @<Put each...@>=
22801 mp_primitive(mp, "message",message_command,message_code);
22802 @:message_}{\&{message} primitive@>
22803 mp_primitive(mp, "errmessage",message_command,err_message_code);
22804 @:err_message_}{\&{errmessage} primitive@>
22805 mp_primitive(mp, "errhelp",message_command,err_help_code);
22806 @:err_help_}{\&{errhelp} primitive@>
22807 mp_primitive(mp, "filenametemplate",message_command,filename_template_code);
22808 @:filename_template_}{\&{filenametemplate} primitive@>
22809
22810 @ @<Cases of |print_cmd...@>=
22811 case message_command: 
22812   if ( m<err_message_code ) mp_print(mp, "message");
22813   else if ( m==err_message_code ) mp_print(mp, "errmessage");
22814   else if ( m==filename_template_code ) mp_print(mp, "filenametemplate");
22815   else mp_print(mp, "errhelp");
22816   break;
22817
22818 @ @<Cases of |do_statement|...@>=
22819 case message_command: mp_do_message(mp); break;
22820
22821 @ @<Declare action procedures for use by |do_statement|@>=
22822 @<Declare a procedure called |no_string_err|@>;
22823 void mp_do_message (MP mp) ;
22824
22825
22826 @c void mp_do_message (MP mp) {
22827   int m; /* the type of message */
22828   m=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
22829   if ( mp->cur_type!=mp_string_type )
22830     mp_no_string_err(mp, "A message should be a known string expression.");
22831   else {
22832     switch (m) {
22833     case message_code: 
22834       mp_print_nl(mp, ""); mp_print_str(mp, mp->cur_exp);
22835       break;
22836     case err_message_code:
22837       @<Print string |cur_exp| as an error message@>;
22838       break;
22839     case err_help_code:
22840       @<Save string |cur_exp| as the |err_help|@>;
22841       break;
22842     case filename_template_code:
22843       @<Save the filename template@>;
22844       break;
22845     } /* there are no other cases */
22846   }
22847   mp_flush_cur_exp(mp, 0);
22848 }
22849
22850 @ @<Declare a procedure called |no_string_err|@>=
22851 void mp_no_string_err (MP mp,char *s) { 
22852    exp_err("Not a string");
22853 @.Not a string@>
22854   help1(s);
22855   mp_put_get_error(mp);
22856 }
22857
22858 @ The global variable |err_help| is zero when the user has most recently
22859 given an empty help string, or if none has ever been given.
22860
22861 @<Save string |cur_exp| as the |err_help|@>=
22862
22863   if ( mp->err_help!=0 ) delete_str_ref(mp->err_help);
22864   if ( length(mp->cur_exp)==0 ) mp->err_help=0;
22865   else  { mp->err_help=mp->cur_exp; add_str_ref(mp->err_help); }
22866 }
22867
22868 @ If \&{errmessage} occurs often in |mp_scroll_mode|, without user-defined
22869 \&{errhelp}, we don't want to give a long help message each time. So we
22870 give a verbose explanation only once.
22871
22872 @<Glob...@>=
22873 boolean long_help_seen; /* has the long \.{\\errmessage} help been used? */
22874
22875 @ @<Set init...@>=mp->long_help_seen=false;
22876
22877 @ @<Print string |cur_exp| as an error message@>=
22878
22879   print_err(""); mp_print_str(mp, mp->cur_exp);
22880   if ( mp->err_help!=0 ) {
22881     mp->use_err_help=true;
22882   } else if ( mp->long_help_seen ) { 
22883     help1("(That was another `errmessage'.)") ; 
22884   } else  { 
22885    if ( mp->interaction<mp_error_stop_mode ) mp->long_help_seen=true;
22886     help4("This error message was generated by an `errmessage'")
22887      ("command, so I can\'t give any explicit help.")
22888      ("Pretend that you're Miss Marple: Examine all clues,")
22889 @^Marple, Jane@>
22890      ("and deduce the truth by inspired guesses.");
22891   }
22892   mp_put_get_error(mp); mp->use_err_help=false;
22893 }
22894
22895 @ @<Cases of |do_statement|...@>=
22896 case write_command: mp_do_write(mp); break;
22897
22898 @ @<Declare action procedures for use by |do_statement|@>=
22899 void mp_do_write (MP mp) ;
22900
22901 @ @c void mp_do_write (MP mp) {
22902   str_number t; /* the line of text to be written */
22903   write_index n,n0; /* for searching |wr_fname| and |wr_file| arrays */
22904   int old_setting; /* for saving |selector| during output */
22905   mp_get_x_next(mp);
22906   mp_scan_expression(mp);
22907   if ( mp->cur_type!=mp_string_type ) {
22908     mp_no_string_err(mp, "The text to be written should be a known string expression");
22909   } else if ( mp->cur_cmd!=to_token ) { 
22910     print_err("Missing `to' clause");
22911     help1("A write command should end with `to <filename>'");
22912     mp_put_get_error(mp);
22913   } else { 
22914     t=mp->cur_exp; mp->cur_type=mp_vacuous;
22915     mp_get_x_next(mp);
22916     mp_scan_expression(mp);
22917     if ( mp->cur_type!=mp_string_type )
22918       mp_no_string_err(mp, "I can\'t write to that file name.  It isn't a known string");
22919     else {
22920       @<Write |t| to the file named by |cur_exp|@>;
22921     }
22922     delete_str_ref(t);
22923   }
22924   mp_flush_cur_exp(mp, 0);
22925 }
22926
22927 @ @<Write |t| to the file named by |cur_exp|@>=
22928
22929   @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if
22930     |cur_exp| must be inserted@>;
22931   if ( mp_str_vs_str(mp, t,mp->eof_line)==0 ) {
22932     @<Record the end of file on |wr_file[n]|@>;
22933   } else { 
22934     old_setting=mp->selector;
22935     mp->selector=n+write_file;
22936     mp_print_str(mp, t); mp_print_ln(mp);
22937     mp->selector = old_setting;
22938   }
22939 }
22940
22941 @ @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if...@>=
22942 {
22943   char *fn = str(mp->cur_exp);
22944   n=mp->write_files;
22945   n0=mp->write_files;
22946   while (mp_xstrcmp(fn,mp->wr_fname[n])!=0) { 
22947     if ( n==0 ) { /* bottom reached */
22948           if ( n0==mp->write_files ) {
22949         if ( mp->write_files<mp->max_write_files ) {
22950           incr(mp->write_files);
22951         } else {
22952           FILE **wr_file;
22953           char **wr_fname;
22954               write_index l,k;
22955           l = mp->max_write_files + (mp->max_write_files>>2);
22956           wr_file = xmalloc((l+1),sizeof(FILE *));
22957           wr_fname = xmalloc((l+1),sizeof(char *));
22958               for (k=0;k<=l;k++) {
22959             if (k<=mp->max_write_files) {
22960                   wr_file[k]=mp->wr_file[k]; 
22961               wr_fname[k]=mp->wr_fname[k];
22962             } else {
22963                   wr_file[k]=0; 
22964               wr_fname[k]=NULL;
22965             }
22966           }
22967               xfree(mp->wr_file); xfree(mp->wr_fname);
22968           mp->max_write_files = l;
22969           mp->wr_file = wr_file;
22970           mp->wr_fname = wr_fname;
22971         }
22972       }
22973       n=n0;
22974       mp_open_write_file(mp, fn ,n);
22975     } else { 
22976       decr(n);
22977           if ( mp->wr_fname[n]==NULL )  n0=n; 
22978     }
22979   }
22980 }
22981
22982 @ @<Record the end of file on |wr_file[n]|@>=
22983 { fclose(mp->wr_file[n]);
22984   xfree(mp->wr_fname[n]);
22985   mp->wr_fname[n]=NULL;
22986   if ( n==mp->write_files-1 ) mp->write_files=n;
22987 }
22988
22989
22990 @* \[42] Writing font metric data.
22991 \TeX\ gets its knowledge about fonts from font metric files, also called
22992 \.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
22993 but other programs know about them too. One of \MP's duties is to
22994 write \.{TFM} files so that the user's fonts can readily be
22995 applied to typesetting.
22996 @:TFM files}{\.{TFM} files@>
22997 @^font metric files@>
22998
22999 The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
23000 Since the number of bytes is always a multiple of~4, we could
23001 also regard the file as a sequence of 32-bit words, but \MP\ uses the
23002 byte interpretation. The format of \.{TFM} files was designed by
23003 Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
23004 @^Ramshaw, Lyle Harold@>
23005 of information in a compact but useful form.
23006
23007 @<Glob...@>=
23008 FILE * tfm_file; /* the font metric output goes here */
23009 char * metric_file_name; /* full name of the font metric file */
23010
23011 @ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
23012 integers that give the lengths of the various subsequent portions
23013 of the file. These twelve integers are, in order:
23014 $$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
23015 |lf|&length of the entire file, in words;\cr
23016 |lh|&length of the header data, in words;\cr
23017 |bc|&smallest character code in the font;\cr
23018 |ec|&largest character code in the font;\cr
23019 |nw|&number of words in the width table;\cr
23020 |nh|&number of words in the height table;\cr
23021 |nd|&number of words in the depth table;\cr
23022 |ni|&number of words in the italic correction table;\cr
23023 |nl|&number of words in the lig/kern table;\cr
23024 |nk|&number of words in the kern table;\cr
23025 |ne|&number of words in the extensible character table;\cr
23026 |np|&number of font parameter words.\cr}}$$
23027 They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
23028 |ne<=256|, and
23029 $$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
23030 Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
23031 and as few as 0 characters (if |bc=ec+1|).
23032
23033 Incidentally, when two or more 8-bit bytes are combined to form an integer of
23034 16 or more bits, the most significant bytes appear first in the file.
23035 This is called BigEndian order.
23036 @^BigEndian order@>
23037
23038 @ The rest of the \.{TFM} file may be regarded as a sequence of ten data
23039 arrays.
23040
23041 The most important data type used here is a |fix_word|, which is
23042 a 32-bit representation of a binary fraction. A |fix_word| is a signed
23043 quantity, with the two's complement of the entire word used to represent
23044 negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
23045 binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
23046 the smallest is $-2048$. We will see below, however, that all but two of
23047 the |fix_word| values must lie between $-16$ and $+16$.
23048
23049 @ The first data array is a block of header information, which contains
23050 general facts about the font. The header must contain at least two words,
23051 |header[0]| and |header[1]|, whose meaning is explained below.  Additional
23052 header information of use to other software routines might also be
23053 included, and \MP\ will generate it if the \.{headerbyte} command occurs.
23054 For example, 16 more words of header information are in use at the Xerox
23055 Palo Alto Research Center; the first ten specify the character coding
23056 scheme used (e.g., `\.{XEROX TEXT}' or `\.{TEX MATHSY}'), the next five
23057 give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
23058 last gives the ``face byte.''
23059
23060 \yskip\hang|header[0]| is a 32-bit check sum that \MP\ will copy into
23061 the \.{GF} output file. This helps ensure consistency between files,
23062 since \TeX\ records the check sums from the \.{TFM}'s it reads, and these
23063 should match the check sums on actual fonts that are used.  The actual
23064 relation between this check sum and the rest of the \.{TFM} file is not
23065 important; the check sum is simply an identification number with the
23066 property that incompatible fonts almost always have distinct check sums.
23067 @^check sum@>
23068
23069 \yskip\hang|header[1]| is a |fix_word| containing the design size of the
23070 font, in units of \TeX\ points. This number must be at least 1.0; it is
23071 fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
23072 font, i.e., a font that was designed to look best at a 10-point size,
23073 whatever that really means. When a \TeX\ user asks for a font `\.{at}
23074 $\delta$ \.{pt}', the effect is to override the design size and replace it
23075 by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in
23076 the font image by a factor of $\delta$ divided by the design size.  {\sl
23077 All other dimensions in the\/ \.{TFM} file are |fix_word|\kern-1pt\
23078 numbers in design-size units.} Thus, for example, the value of |param[6]|,
23079 which defines the \.{em} unit, is often the |fix_word| value $2^{20}=1.0$,
23080 since many fonts have a design size equal to one em.  The other dimensions
23081 must be less than 16 design-size units in absolute value; thus,
23082 |header[1]| and |param[1]| are the only |fix_word| entries in the whole
23083 \.{TFM} file whose first byte might be something besides 0 or 255.
23084
23085 @ Next comes the |char_info| array, which contains one |char_info_word|
23086 per character. Each word in this part of the file contains six fields
23087 packed into four bytes as follows.
23088
23089 \yskip\hang first byte: |width_index| (8 bits)\par
23090 \hang second byte: |height_index| (4 bits) times 16, plus |depth_index|
23091   (4~bits)\par
23092 \hang third byte: |italic_index| (6 bits) times 4, plus |tag|
23093   (2~bits)\par
23094 \hang fourth byte: |remainder| (8 bits)\par
23095 \yskip\noindent
23096 The actual width of a character is \\{width}|[width_index]|, in design-size
23097 units; this is a device for compressing information, since many characters
23098 have the same width. Since it is quite common for many characters
23099 to have the same height, depth, or italic correction, the \.{TFM} format
23100 imposes a limit of 16 different heights, 16 different depths, and
23101 64 different italic corrections.
23102
23103 Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
23104 \\{italic}[0]=0$ should always hold, so that an index of zero implies a
23105 value of zero.  The |width_index| should never be zero unless the
23106 character does not exist in the font, since a character is valid if and
23107 only if it lies between |bc| and |ec| and has a nonzero |width_index|.
23108
23109 @ The |tag| field in a |char_info_word| has four values that explain how to
23110 interpret the |remainder| field.
23111
23112 \yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
23113 \hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
23114 program starting at location |remainder| in the |lig_kern| array.\par
23115 \hang|tag=2| (|list_tag|) means that this character is part of a chain of
23116 characters of ascending sizes, and not the largest in the chain.  The
23117 |remainder| field gives the character code of the next larger character.\par
23118 \hang|tag=3| (|ext_tag|) means that this character code represents an
23119 extensible character, i.e., a character that is built up of smaller pieces
23120 so that it can be made arbitrarily large. The pieces are specified in
23121 |exten[remainder]|.\par
23122 \yskip\noindent
23123 Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
23124 unless they are used in special circumstances in math formulas. For example,
23125 \TeX's \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
23126 operation looks for both |list_tag| and |ext_tag|.
23127
23128 @d no_tag 0 /* vanilla character */
23129 @d lig_tag 1 /* character has a ligature/kerning program */
23130 @d list_tag 2 /* character has a successor in a charlist */
23131 @d ext_tag 3 /* character is extensible */
23132
23133 @ The |lig_kern| array contains instructions in a simple programming language
23134 that explains what to do for special letter pairs. Each word in this array is a
23135 |lig_kern_command| of four bytes.
23136
23137 \yskip\hang first byte: |skip_byte|, indicates that this is the final program
23138   step if the byte is 128 or more, otherwise the next step is obtained by
23139   skipping this number of intervening steps.\par
23140 \hang second byte: |next_char|, ``if |next_char| follows the current character,
23141   then perform the operation and stop, otherwise continue.''\par
23142 \hang third byte: |op_byte|, indicates a ligature step if less than~128,
23143   a kern step otherwise.\par
23144 \hang fourth byte: |remainder|.\par
23145 \yskip\noindent
23146 In a kern step, an
23147 additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
23148 between the current character and |next_char|. This amount is
23149 often negative, so that the characters are brought closer together
23150 by kerning; but it might be positive.
23151
23152 There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
23153 $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
23154 |remainder| is inserted between the current character and |next_char|;
23155 then the current character is deleted if $b=0$, and |next_char| is
23156 deleted if $c=0$; then we pass over $a$~characters to reach the next
23157 current character (which may have a ligature/kerning program of its own).
23158
23159 If the very first instruction of the |lig_kern| array has |skip_byte=255|,
23160 the |next_char| byte is the so-called right boundary character of this font;
23161 the value of |next_char| need not lie between |bc| and~|ec|.
23162 If the very last instruction of the |lig_kern| array has |skip_byte=255|,
23163 there is a special ligature/kerning program for a left boundary character,
23164 beginning at location |256*op_byte+remainder|.
23165 The interpretation is that \TeX\ puts implicit boundary characters
23166 before and after each consecutive string of characters from the same font.
23167 These implicit characters do not appear in the output, but they can affect
23168 ligatures and kerning.
23169
23170 If the very first instruction of a character's |lig_kern| program has
23171 |skip_byte>128|, the program actually begins in location
23172 |256*op_byte+remainder|. This feature allows access to large |lig_kern|
23173 arrays, because the first instruction must otherwise
23174 appear in a location |<=255|.
23175
23176 Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
23177 the condition
23178 $$\hbox{|256*op_byte+remainder<nl|.}$$
23179 If such an instruction is encountered during
23180 normal program execution, it denotes an unconditional halt; no ligature
23181 command is performed.
23182
23183 @d stop_flag (128)
23184   /* value indicating `\.{STOP}' in a lig/kern program */
23185 @d kern_flag (128) /* op code for a kern step */
23186 @d skip_byte(A) mp->lig_kern[(A)].b0
23187 @d next_char(A) mp->lig_kern[(A)].b1
23188 @d op_byte(A) mp->lig_kern[(A)].b2
23189 @d rem_byte(A) mp->lig_kern[(A)].b3
23190
23191 @ Extensible characters are specified by an |extensible_recipe|, which
23192 consists of four bytes called |top|, |mid|, |bot|, and |rep| (in this
23193 order). These bytes are the character codes of individual pieces used to
23194 build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
23195 present in the built-up result. For example, an extensible vertical line is
23196 like an extensible bracket, except that the top and bottom pieces are missing.
23197
23198 Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
23199 if the piece isn't present. Then the extensible characters have the form
23200 $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
23201 in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
23202 The width of the extensible character is the width of $R$; and the
23203 height-plus-depth is the sum of the individual height-plus-depths of the
23204 components used, since the pieces are butted together in a vertical list.
23205
23206 @d ext_top(A) mp->exten[(A)].b0 /* |top| piece in a recipe */
23207 @d ext_mid(A) mp->exten[(A)].b1 /* |mid| piece in a recipe */
23208 @d ext_bot(A) mp->exten[(A)].b2 /* |bot| piece in a recipe */
23209 @d ext_rep(A) mp->exten[(A)].b3 /* |rep| piece in a recipe */
23210
23211 @ The final portion of a \.{TFM} file is the |param| array, which is another
23212 sequence of |fix_word| values.
23213
23214 \yskip\hang|param[1]=slant| is the amount of italic slant, which is used
23215 to help position accents. For example, |slant=.25| means that when you go
23216 up one unit, you also go .25 units to the right. The |slant| is a pure
23217 number; it is the only |fix_word| other than the design size itself that is
23218 not scaled by the design size.
23219
23220 \hang|param[2]=space| is the normal spacing between words in text.
23221 Note that character 040 in the font need not have anything to do with
23222 blank spaces.
23223
23224 \hang|param[3]=space_stretch| is the amount of glue stretching between words.
23225
23226 \hang|param[4]=space_shrink| is the amount of glue shrinking between words.
23227
23228 \hang|param[5]=x_height| is the size of one ex in the font; it is also
23229 the height of letters for which accents don't have to be raised or lowered.
23230
23231 \hang|param[6]=quad| is the size of one em in the font.
23232
23233 \hang|param[7]=extra_space| is the amount added to |param[2]| at the
23234 ends of sentences.
23235
23236 \yskip\noindent
23237 If fewer than seven parameters are present, \TeX\ sets the missing parameters
23238 to zero.
23239
23240 @d slant_code 1
23241 @d space_code 2
23242 @d space_stretch_code 3
23243 @d space_shrink_code 4
23244 @d x_height_code 5
23245 @d quad_code 6
23246 @d extra_space_code 7
23247
23248 @ So that is what \.{TFM} files hold. One of \MP's duties is to output such
23249 information, and it does this all at once at the end of a job.
23250 In order to prepare for such frenetic activity, it squirrels away the
23251 necessary facts in various arrays as information becomes available.
23252
23253 Character dimensions (\&{charwd}, \&{charht}, \&{chardp}, and \&{charic})
23254 are stored respectively in |tfm_width|, |tfm_height|, |tfm_depth|, and
23255 |tfm_ital_corr|. Other information about a character (e.g., about
23256 its ligatures or successors) is accessible via the |char_tag| and
23257 |char_remainder| arrays. Other information about the font as a whole
23258 is kept in additional arrays called |header_byte|, |lig_kern|,
23259 |kern|, |exten|, and |param|.
23260
23261 @d max_tfm_int 32510
23262 @d undefined_label max_tfm_int /* an undefined local label */
23263
23264 @<Glob...@>=
23265 #define TFM_ITEMS 257
23266 eight_bits bc;
23267 eight_bits ec; /* smallest and largest character codes shipped out */
23268 scaled tfm_width[TFM_ITEMS]; /* \&{charwd} values */
23269 scaled tfm_height[TFM_ITEMS]; /* \&{charht} values */
23270 scaled tfm_depth[TFM_ITEMS]; /* \&{chardp} values */
23271 scaled tfm_ital_corr[TFM_ITEMS]; /* \&{charic} values */
23272 boolean char_exists[TFM_ITEMS]; /* has this code been shipped out? */
23273 int char_tag[TFM_ITEMS]; /* |remainder| category */
23274 int char_remainder[TFM_ITEMS]; /* the |remainder| byte */
23275 char *header_byte; /* bytes of the \.{TFM} header */
23276 int header_last; /* last initialized \.{TFM} header byte */
23277 int header_size; /* size of the \.{TFM} header */
23278 four_quarters *lig_kern; /* the ligature/kern table */
23279 short nl; /* the number of ligature/kern steps so far */
23280 scaled *kern; /* distinct kerning amounts */
23281 short nk; /* the number of distinct kerns so far */
23282 four_quarters exten[TFM_ITEMS]; /* extensible character recipes */
23283 short ne; /* the number of extensible characters so far */
23284 scaled *param; /* \&{fontinfo} parameters */
23285 short np; /* the largest \&{fontinfo} parameter specified so far */
23286 short nw;short nh;short nd;short ni; /* sizes of \.{TFM} subtables */
23287 short skip_table[TFM_ITEMS]; /* local label status */
23288 boolean lk_started; /* has there been a lig/kern step in this command yet? */
23289 integer bchar; /* right boundary character */
23290 short bch_label; /* left boundary starting location */
23291 short ll;short lll; /* registers used for lig/kern processing */
23292 short label_loc[257]; /* lig/kern starting addresses */
23293 eight_bits label_char[257]; /* characters for |label_loc| */
23294 short label_ptr; /* highest position occupied in |label_loc| */
23295
23296 @ @<Allocate or initialize ...@>=
23297 mp->header_last = 0; mp->header_size = 128; /* just for init */
23298 mp->header_byte = xmalloc(mp->header_size, sizeof(char));
23299 mp->lig_kern = NULL; /* allocated when needed */
23300 mp->kern = NULL; /* allocated when needed */ 
23301 mp->param = NULL; /* allocated when needed */
23302
23303 @ @<Dealloc variables@>=
23304 xfree(mp->header_byte);
23305 xfree(mp->lig_kern);
23306 xfree(mp->kern);
23307 xfree(mp->param);
23308
23309 @ @<Set init...@>=
23310 for (k=0;k<= 255;k++ ) {
23311   mp->tfm_width[k]=0; mp->tfm_height[k]=0; mp->tfm_depth[k]=0; mp->tfm_ital_corr[k]=0;
23312   mp->char_exists[k]=false; mp->char_tag[k]=no_tag; mp->char_remainder[k]=0;
23313   mp->skip_table[k]=undefined_label;
23314 };
23315 memset(mp->header_byte,0,mp->header_size);
23316 mp->bc=255; mp->ec=0; mp->nl=0; mp->nk=0; mp->ne=0; mp->np=0;
23317 mp->internal[boundary_char]=-unity;
23318 mp->bch_label=undefined_label;
23319 mp->label_loc[0]=-1; mp->label_ptr=0;
23320
23321 @ @<Declarations@>=
23322 scaled mp_tfm_check (MP mp,small_number m) ;
23323
23324 @ @<Declare the function called |tfm_check|@>=
23325 scaled mp_tfm_check (MP mp,small_number m) {
23326   if ( abs(mp->internal[m])>=fraction_half ) {
23327     print_err("Enormous "); mp_print(mp, mp->int_name[m]);
23328 @.Enormous charwd...@>
23329 @.Enormous chardp...@>
23330 @.Enormous charht...@>
23331 @.Enormous charic...@>
23332 @.Enormous designsize...@>
23333     mp_print(mp, " has been reduced");
23334     help1("Font metric dimensions must be less than 2048pt.");
23335     mp_put_get_error(mp);
23336     if ( mp->internal[m]>0 ) return (fraction_half-1);
23337     else return (1-fraction_half);
23338   } else {
23339     return mp->internal[m];
23340   }
23341 }
23342
23343 @ @<Store the width information for character code~|c|@>=
23344 if ( c<mp->bc ) mp->bc=c;
23345 if ( c>mp->ec ) mp->ec=c;
23346 mp->char_exists[c]=true;
23347 mp->tfm_width[c]=mp_tfm_check(mp, char_wd);
23348 mp->tfm_height[c]=mp_tfm_check(mp, char_ht);
23349 mp->tfm_depth[c]=mp_tfm_check(mp, char_dp);
23350 mp->tfm_ital_corr[c]=mp_tfm_check(mp, char_ic)
23351
23352 @ Now let's consider \MP's special \.{TFM}-oriented commands.
23353
23354 @<Cases of |do_statement|...@>=
23355 case tfm_command: mp_do_tfm_command(mp); break;
23356
23357 @ @d char_list_code 0
23358 @d lig_table_code 1
23359 @d extensible_code 2
23360 @d header_byte_code 3
23361 @d font_dimen_code 4
23362
23363 @<Put each...@>=
23364 mp_primitive(mp, "charlist",tfm_command,char_list_code);
23365 @:char_list_}{\&{charlist} primitive@>
23366 mp_primitive(mp, "ligtable",tfm_command,lig_table_code);
23367 @:lig_table_}{\&{ligtable} primitive@>
23368 mp_primitive(mp, "extensible",tfm_command,extensible_code);
23369 @:extensible_}{\&{extensible} primitive@>
23370 mp_primitive(mp, "headerbyte",tfm_command,header_byte_code);
23371 @:header_byte_}{\&{headerbyte} primitive@>
23372 mp_primitive(mp, "fontdimen",tfm_command,font_dimen_code);
23373 @:font_dimen_}{\&{fontdimen} primitive@>
23374
23375 @ @<Cases of |print_cmd...@>=
23376 case tfm_command: 
23377   switch (m) {
23378   case char_list_code:mp_print(mp, "charlist"); break;
23379   case lig_table_code:mp_print(mp, "ligtable"); break;
23380   case extensible_code:mp_print(mp, "extensible"); break;
23381   case header_byte_code:mp_print(mp, "headerbyte"); break;
23382   default: mp_print(mp, "fontdimen"); break;
23383   }
23384   break;
23385
23386 @ @<Declare action procedures for use by |do_statement|@>=
23387 eight_bits mp_get_code (MP mp) ;
23388
23389 @ @c eight_bits mp_get_code (MP mp) { /* scans a character code value */
23390   integer c; /* the code value found */
23391   mp_get_x_next(mp); mp_scan_expression(mp);
23392   if ( mp->cur_type==mp_known ) { 
23393     c=mp_round_unscaled(mp, mp->cur_exp);
23394     if ( c>=0 ) if ( c<256 ) return c;
23395   } else if ( mp->cur_type==mp_string_type ) {
23396     if ( length(mp->cur_exp)==1 )  { 
23397       c=mp->str_pool[mp->str_start[mp->cur_exp]];
23398       return c;
23399     }
23400   }
23401   exp_err("Invalid code has been replaced by 0");
23402 @.Invalid code...@>
23403   help2("I was looking for a number between 0 and 255, or for a")
23404        ("string of length 1. Didn't find it; will use 0 instead.");
23405   mp_put_get_flush_error(mp, 0); c=0;
23406   return c;
23407 };
23408
23409 @ @<Declare action procedures for use by |do_statement|@>=
23410 void mp_set_tag (MP mp,halfword c, small_number t, halfword r) ;
23411
23412 @ @c void mp_set_tag (MP mp,halfword c, small_number t, halfword r) { 
23413   if ( mp->char_tag[c]==no_tag ) {
23414     mp->char_tag[c]=t; mp->char_remainder[c]=r;
23415     if ( t==lig_tag ){ 
23416       incr(mp->label_ptr); mp->label_loc[mp->label_ptr]=r; 
23417       mp->label_char[mp->label_ptr]=c;
23418     }
23419   } else {
23420     @<Complain about a character tag conflict@>;
23421   }
23422 }
23423
23424 @ @<Complain about a character tag conflict@>=
23425
23426   print_err("Character ");
23427   if ( (c>' ')&&(c<127) ) mp_print_char(mp,c);
23428   else if ( c==256 ) mp_print(mp, "||");
23429   else  { mp_print(mp, "code "); mp_print_int(mp, c); };
23430   mp_print(mp, " is already ");
23431 @.Character c is already...@>
23432   switch (mp->char_tag[c]) {
23433   case lig_tag: mp_print(mp, "in a ligtable"); break;
23434   case list_tag: mp_print(mp, "in a charlist"); break;
23435   case ext_tag: mp_print(mp, "extensible"); break;
23436   } /* there are no other cases */
23437   help2("It's not legal to label a character more than once.")
23438     ("So I'll not change anything just now.");
23439   mp_put_get_error(mp); 
23440 }
23441
23442 @ @<Declare action procedures for use by |do_statement|@>=
23443 void mp_do_tfm_command (MP mp) ;
23444
23445 @ @c void mp_do_tfm_command (MP mp) {
23446   int c,cc; /* character codes */
23447   int k; /* index into the |kern| array */
23448   int j; /* index into |header_byte| or |param| */
23449   switch (mp->cur_mod) {
23450   case char_list_code: 
23451     c=mp_get_code(mp);
23452      /* we will store a list of character successors */
23453     while ( mp->cur_cmd==colon )   { 
23454       cc=mp_get_code(mp); mp_set_tag(mp, c,list_tag,cc); c=cc;
23455     };
23456     break;
23457   case lig_table_code: 
23458     if (mp->lig_kern==NULL) 
23459        mp->lig_kern = xmalloc((max_tfm_int+1),sizeof(four_quarters));
23460     if (mp->kern==NULL) 
23461        mp->kern = xmalloc((max_tfm_int+1),sizeof(scaled));
23462     @<Store a list of ligature/kern steps@>;
23463     break;
23464   case extensible_code: 
23465     @<Define an extensible recipe@>;
23466     break;
23467   case header_byte_code: 
23468   case font_dimen_code: 
23469     c=mp->cur_mod; mp_get_x_next(mp);
23470     mp_scan_expression(mp);
23471     if ( (mp->cur_type!=mp_known)||(mp->cur_exp<half_unit) ) {
23472       exp_err("Improper location");
23473 @.Improper location@>
23474       help2("I was looking for a known, positive number.")
23475        ("For safety's sake I'll ignore the present command.");
23476       mp_put_get_error(mp);
23477     } else  { 
23478       j=mp_round_unscaled(mp, mp->cur_exp);
23479       if ( mp->cur_cmd!=colon ) {
23480         mp_missing_err(mp, ":");
23481 @.Missing `:'@>
23482         help1("A colon should follow a headerbyte or fontinfo location.");
23483         mp_back_error(mp);
23484       }
23485       if ( c==header_byte_code ) { 
23486         @<Store a list of header bytes@>;
23487       } else {     
23488         if (mp->param==NULL) 
23489           mp->param = xmalloc((max_tfm_int+1),sizeof(scaled));
23490         @<Store a list of font dimensions@>;
23491       }
23492     }
23493     break;
23494   } /* there are no other cases */
23495 };
23496
23497 @ @<Store a list of ligature/kern steps@>=
23498
23499   mp->lk_started=false;
23500 CONTINUE: 
23501   mp_get_x_next(mp);
23502   if ((mp->cur_cmd==skip_to)&& mp->lk_started )
23503     @<Process a |skip_to| command and |goto done|@>;
23504   if ( mp->cur_cmd==bchar_label ) { c=256; mp->cur_cmd=colon; }
23505   else { mp_back_input(mp); c=mp_get_code(mp); };
23506   if ((mp->cur_cmd==colon)||(mp->cur_cmd==double_colon)) {
23507     @<Record a label in a lig/kern subprogram and |goto continue|@>;
23508   }
23509   if ( mp->cur_cmd==lig_kern_token ) { 
23510     @<Compile a ligature/kern command@>; 
23511   } else  { 
23512     print_err("Illegal ligtable step");
23513 @.Illegal ligtable step@>
23514     help1("I was looking for `=:' or `kern' here.");
23515     mp_back_error(mp); next_char(mp->nl)=qi(0); 
23516     op_byte(mp->nl)=qi(0); rem_byte(mp->nl)=qi(0);
23517     skip_byte(mp->nl)=stop_flag+1; /* this specifies an unconditional stop */
23518   }
23519   if ( mp->nl==max_tfm_int) mp_fatal_error(mp, "ligtable too large");
23520   incr(mp->nl);
23521   if ( mp->cur_cmd==comma ) goto CONTINUE;
23522   if ( skip_byte(mp->nl-1)<stop_flag ) skip_byte(mp->nl-1)=stop_flag;
23523 }
23524 DONE:
23525
23526 @ @<Put each...@>=
23527 mp_primitive(mp, "=:",lig_kern_token,0);
23528 @:=:_}{\.{=:} primitive@>
23529 mp_primitive(mp, "=:|",lig_kern_token,1);
23530 @:=:/_}{\.{=:\char'174} primitive@>
23531 mp_primitive(mp, "=:|>",lig_kern_token,5);
23532 @:=:/>_}{\.{=:\char'174>} primitive@>
23533 mp_primitive(mp, "|=:",lig_kern_token,2);
23534 @:=:/_}{\.{\char'174=:} primitive@>
23535 mp_primitive(mp, "|=:>",lig_kern_token,6);
23536 @:=:/>_}{\.{\char'174=:>} primitive@>
23537 mp_primitive(mp, "|=:|",lig_kern_token,3);
23538 @:=:/_}{\.{\char'174=:\char'174} primitive@>
23539 mp_primitive(mp, "|=:|>",lig_kern_token,7);
23540 @:=:/>_}{\.{\char'174=:\char'174>} primitive@>
23541 mp_primitive(mp, "|=:|>>",lig_kern_token,11);
23542 @:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
23543 mp_primitive(mp, "kern",lig_kern_token,128);
23544 @:kern_}{\&{kern} primitive@>
23545
23546 @ @<Cases of |print_cmd...@>=
23547 case lig_kern_token: 
23548   switch (m) {
23549   case 0:mp_print(mp, "=:"); break;
23550   case 1:mp_print(mp, "=:|"); break;
23551   case 2:mp_print(mp, "|=:"); break;
23552   case 3:mp_print(mp, "|=:|"); break;
23553   case 5:mp_print(mp, "=:|>"); break;
23554   case 6:mp_print(mp, "|=:>"); break;
23555   case 7:mp_print(mp, "|=:|>"); break;
23556   case 11:mp_print(mp, "|=:|>>"); break;
23557   default: mp_print(mp, "kern"); break;
23558   }
23559   break;
23560
23561 @ Local labels are implemented by maintaining the |skip_table| array,
23562 where |skip_table[c]| is either |undefined_label| or the address of the
23563 most recent lig/kern instruction that skips to local label~|c|. In the
23564 latter case, the |skip_byte| in that instruction will (temporarily)
23565 be zero if there were no prior skips to this label, or it will be the
23566 distance to the prior skip.
23567
23568 We may need to cancel skips that span more than 127 lig/kern steps.
23569
23570 @d cancel_skips(A) mp->ll=(A);
23571   do {  
23572     mp->lll=qo(skip_byte(mp->ll)); 
23573     skip_byte(mp->ll)=stop_flag; mp->ll=mp->ll-mp->lll;
23574   } while (mp->lll!=0)
23575 @d skip_error(A) { print_err("Too far to skip");
23576 @.Too far to skip@>
23577   help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
23578   mp_error(mp); cancel_skips((A));
23579   }
23580
23581 @<Process a |skip_to| command and |goto done|@>=
23582
23583   c=mp_get_code(mp);
23584   if ( mp->nl-mp->skip_table[c]>128 ) { /* |skip_table[c]<<nl<=undefined_label| */
23585     skip_error(mp->skip_table[c]); mp->skip_table[c]=undefined_label;
23586   }
23587   if ( mp->skip_table[c]==undefined_label ) skip_byte(mp->nl-1)=qi(0);
23588   else skip_byte(mp->nl-1)=qi(mp->nl-mp->skip_table[c]-1);
23589   mp->skip_table[c]=mp->nl-1; goto DONE;
23590 }
23591
23592 @ @<Record a label in a lig/kern subprogram and |goto continue|@>=
23593
23594   if ( mp->cur_cmd==colon ) {
23595     if ( c==256 ) mp->bch_label=mp->nl;
23596     else mp_set_tag(mp, c,lig_tag,mp->nl);
23597   } else if ( mp->skip_table[c]<undefined_label ) {
23598     mp->ll=mp->skip_table[c]; mp->skip_table[c]=undefined_label;
23599     do {  
23600       mp->lll=qo(skip_byte(mp->ll));
23601       if ( mp->nl-mp->ll>128 ) {
23602         skip_error(mp->ll); goto CONTINUE;
23603       }
23604       skip_byte(mp->ll)=qi(mp->nl-mp->ll-1); mp->ll=mp->ll-mp->lll;
23605     } while (mp->lll!=0);
23606   }
23607   goto CONTINUE;
23608 }
23609
23610 @ @<Compile a ligature/kern...@>=
23611
23612   next_char(mp->nl)=qi(c); skip_byte(mp->nl)=qi(0);
23613   if ( mp->cur_mod<128 ) { /* ligature op */
23614     op_byte(mp->nl)=qi(mp->cur_mod); rem_byte(mp->nl)=qi(mp_get_code(mp));
23615   } else { 
23616     mp_get_x_next(mp); mp_scan_expression(mp);
23617     if ( mp->cur_type!=mp_known ) {
23618       exp_err("Improper kern");
23619 @.Improper kern@>
23620       help2("The amount of kern should be a known numeric value.")
23621         ("I'm zeroing this one. Proceed, with fingers crossed.");
23622       mp_put_get_flush_error(mp, 0);
23623     }
23624     mp->kern[mp->nk]=mp->cur_exp;
23625     k=0; 
23626     while ( mp->kern[k]!=mp->cur_exp ) incr(k);
23627     if ( k==mp->nk ) {
23628       if ( mp->nk==max_tfm_int ) mp_fatal_error(mp, "too many TFM kerns");
23629       incr(mp->nk);
23630     }
23631     op_byte(mp->nl)=kern_flag+(k / 256);
23632     rem_byte(mp->nl)=qi((k % 256));
23633   }
23634   mp->lk_started=true;
23635 }
23636
23637 @ @d missing_extensible_punctuation(A) 
23638   { mp_missing_err(mp, (A));
23639 @.Missing `\char`\#'@>
23640   help1("I'm processing `extensible c: t,m,b,r'."); mp_back_error(mp);
23641   }
23642
23643 @<Define an extensible recipe@>=
23644
23645   if ( mp->ne==256 ) mp_fatal_error(mp, "too many extensible recipies");
23646   c=mp_get_code(mp); mp_set_tag(mp, c,ext_tag,mp->ne);
23647   if ( mp->cur_cmd!=colon ) missing_extensible_punctuation(":");
23648   ext_top(mp->ne)=qi(mp_get_code(mp));
23649   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23650   ext_mid(mp->ne)=qi(mp_get_code(mp));
23651   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23652   ext_bot(mp->ne)=qi(mp_get_code(mp));
23653   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23654   ext_rep(mp->ne)=qi(mp_get_code(mp));
23655   incr(mp->ne);
23656 }
23657
23658 @ The header could contain ASCII zeroes, so can't use |strdup|.
23659
23660 @<Store a list of header bytes@>=
23661 do {  
23662   if ( j>=mp->header_size ) {
23663     int l = mp->header_size + (mp->header_size >> 2);
23664     char *t = xmalloc(l,sizeof(char));
23665     memset(t,0,l); 
23666     memcpy(t,mp->header_byte,mp->header_size);
23667     xfree (mp->header_byte);
23668     mp->header_byte = t;
23669     mp->header_size = l;
23670   }
23671   mp->header_byte[j]=mp_get_code(mp); 
23672   incr(j); incr(mp->header_last);
23673 } while (mp->cur_cmd==comma)
23674
23675 @ @<Store a list of font dimensions@>=
23676 do {  
23677   if ( j>max_tfm_int ) mp_fatal_error(mp, "too many fontdimens");
23678   while ( j>mp->np ) { incr(mp->np); mp->param[mp->np]=0; };
23679   mp_get_x_next(mp); mp_scan_expression(mp);
23680   if ( mp->cur_type!=mp_known ){ 
23681     exp_err("Improper font parameter");
23682 @.Improper font parameter@>
23683     help1("I'm zeroing this one. Proceed, with fingers crossed.");
23684     mp_put_get_flush_error(mp, 0);
23685   }
23686   mp->param[j]=mp->cur_exp; incr(j);
23687 } while (mp->cur_cmd==comma)
23688
23689 @ OK: We've stored all the data that is needed for the \.{TFM} file.
23690 All that remains is to output it in the correct format.
23691
23692 An interesting problem needs to be solved in this connection, because
23693 the \.{TFM} format allows at most 256~widths, 16~heights, 16~depths,
23694 and 64~italic corrections. If the data has more distinct values than
23695 this, we want to meet the necessary restrictions by perturbing the
23696 given values as little as possible.
23697
23698 \MP\ solves this problem in two steps. First the values of a given
23699 kind (widths, heights, depths, or italic corrections) are sorted;
23700 then the list of sorted values is perturbed, if necessary.
23701
23702 The sorting operation is facilitated by having a special node of
23703 essentially infinite |value| at the end of the current list.
23704
23705 @<Initialize table entries...@>=
23706 value(inf_val)=fraction_four;
23707
23708 @ Straight linear insertion is good enough for sorting, since the lists
23709 are usually not terribly long. As we work on the data, the current list
23710 will start at |link(temp_head)| and end at |inf_val|; the nodes in this
23711 list will be in increasing order of their |value| fields.
23712
23713 Given such a list, the |sort_in| function takes a value and returns a pointer
23714 to where that value can be found in the list. The value is inserted in
23715 the proper place, if necessary.
23716
23717 At the time we need to do these operations, most of \MP's work has been
23718 completed, so we will have plenty of memory to play with. The value nodes
23719 that are allocated for sorting will never be returned to free storage.
23720
23721 @d clear_the_list link(temp_head)=inf_val
23722
23723 @c pointer mp_sort_in (MP mp,scaled v) {
23724   pointer p,q,r; /* list manipulation registers */
23725   p=temp_head;
23726   while (1) { 
23727     q=link(p);
23728     if ( v<=value(q) ) break;
23729     p=q;
23730   }
23731   if ( v<value(q) ) {
23732     r=mp_get_node(mp, value_node_size); value(r)=v; link(r)=q; link(p)=r;
23733   }
23734   return link(p);
23735 }
23736
23737 @ Now we come to the interesting part, where we reduce the list if necessary
23738 until it has the required size. The |min_cover| routine is basic to this
23739 process; it computes the minimum number~|m| such that the values of the
23740 current sorted list can be covered by |m|~intervals of width~|d|. It
23741 also sets the global value |perturbation| to the smallest value $d'>d$
23742 such that the covering found by this algorithm would be different.
23743
23744 In particular, |min_cover(0)| returns the number of distinct values in the
23745 current list and sets |perturbation| to the minimum distance between
23746 adjacent values.
23747
23748 @c integer mp_min_cover (MP mp,scaled d) {
23749   pointer p; /* runs through the current list */
23750   scaled l; /* the least element covered by the current interval */
23751   integer m; /* lower bound on the size of the minimum cover */
23752   m=0; p=link(temp_head); mp->perturbation=el_gordo;
23753   while ( p!=inf_val ){ 
23754     incr(m); l=value(p);
23755     do {  p=link(p); } while (value(p)<=l+d);
23756     if ( value(p)-l<mp->perturbation ) 
23757       mp->perturbation=value(p)-l;
23758   }
23759   return m;
23760 }
23761
23762 @ @<Glob...@>=
23763 scaled perturbation; /* quantity related to \.{TFM} rounding */
23764 integer excess; /* the list is this much too long */
23765
23766 @ The smallest |d| such that a given list can be covered with |m| intervals
23767 is determined by the |threshold| routine, which is sort of an inverse
23768 to |min_cover|. The idea is to increase the interval size rapidly until
23769 finding the range, then to go sequentially until the exact borderline has
23770 been discovered.
23771
23772 @c scaled mp_threshold (MP mp,integer m) {
23773   scaled d; /* lower bound on the smallest interval size */
23774   mp->excess=mp_min_cover(mp, 0)-m;
23775   if ( mp->excess<=0 ) {
23776     return 0;
23777   } else  { 
23778     do {  
23779       d=mp->perturbation;
23780     } while (mp_min_cover(mp, d+d)>m);
23781     while ( mp_min_cover(mp, d)>m ) 
23782       d=mp->perturbation;
23783     return d;
23784   }
23785 }
23786
23787 @ The |skimp| procedure reduces the current list to at most |m| entries,
23788 by changing values if necessary. It also sets |info(p):=k| if |value(p)|
23789 is the |k|th distinct value on the resulting list, and it sets
23790 |perturbation| to the maximum amount by which a |value| field has
23791 been changed. The size of the resulting list is returned as the
23792 value of |skimp|.
23793
23794 @c integer mp_skimp (MP mp,integer m) {
23795   scaled d; /* the size of intervals being coalesced */
23796   pointer p,q,r; /* list manipulation registers */
23797   scaled l; /* the least value in the current interval */
23798   scaled v; /* a compromise value */
23799   d=mp_threshold(mp, m); mp->perturbation=0;
23800   q=temp_head; m=0; p=link(temp_head);
23801   while ( p!=inf_val ) {
23802     incr(m); l=value(p); info(p)=m;
23803     if ( value(link(p))<=l+d ) {
23804       @<Replace an interval of values by its midpoint@>;
23805     }
23806     q=p; p=link(p);
23807   }
23808   return m;
23809 }
23810
23811 @ @<Replace an interval...@>=
23812
23813   do {  
23814     p=link(p); info(p)=m;
23815     decr(mp->excess); if ( mp->excess==0 ) d=0;
23816   } while (value(link(p))<=l+d);
23817   v=l+halfp(value(p)-l);
23818   if ( value(p)-v>mp->perturbation ) 
23819     mp->perturbation=value(p)-v;
23820   r=q;
23821   do {  
23822     r=link(r); value(r)=v;
23823   } while (r!=p);
23824   link(q)=p; /* remove duplicate values from the current list */
23825 }
23826
23827 @ A warning message is issued whenever something is perturbed by
23828 more than 1/16\thinspace pt.
23829
23830 @c void mp_tfm_warning (MP mp,small_number m) { 
23831   mp_print_nl(mp, "(some "); 
23832   mp_print(mp, mp->int_name[m]);
23833 @.some charwds...@>
23834 @.some chardps...@>
23835 @.some charhts...@>
23836 @.some charics...@>
23837   mp_print(mp, " values had to be adjusted by as much as ");
23838   mp_print_scaled(mp, mp->perturbation); mp_print(mp, "pt)");
23839 }
23840
23841 @ Here's an example of how we use these routines.
23842 The width data needs to be perturbed only if there are 256 distinct
23843 widths, but \MP\ must check for this case even though it is
23844 highly unusual.
23845
23846 An integer variable |k| will be defined when we use this code.
23847 The |dimen_head| array will contain pointers to the sorted
23848 lists of dimensions.
23849
23850 @<Massage the \.{TFM} widths@>=
23851 clear_the_list;
23852 for (k=mp->bc;k<=mp->ec;k++)  {
23853   if ( mp->char_exists[k] )
23854     mp->tfm_width[k]=mp_sort_in(mp, mp->tfm_width[k]);
23855 }
23856 mp->nw=mp_skimp(mp, 255)+1; mp->dimen_head[1]=link(temp_head);
23857 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_wd)
23858
23859 @ @<Glob...@>=
23860 pointer dimen_head[5]; /* lists of \.{TFM} dimensions */
23861
23862 @ Heights, depths, and italic corrections are different from widths
23863 not only because their list length is more severely restricted, but
23864 also because zero values do not need to be put into the lists.
23865
23866 @<Massage the \.{TFM} heights, depths, and italic corrections@>=
23867 clear_the_list;
23868 for (k=mp->bc;k<=mp->ec;k++) {
23869   if ( mp->char_exists[k] ) {
23870     if ( mp->tfm_height[k]==0 ) mp->tfm_height[k]=zero_val;
23871     else mp->tfm_height[k]=mp_sort_in(mp, mp->tfm_height[k]);
23872   }
23873 }
23874 mp->nh=mp_skimp(mp, 15)+1; mp->dimen_head[2]=link(temp_head);
23875 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_ht);
23876 clear_the_list;
23877 for (k=mp->bc;k<=mp->ec;k++) {
23878   if ( mp->char_exists[k] ) {
23879     if ( mp->tfm_depth[k]==0 ) mp->tfm_depth[k]=zero_val;
23880     else mp->tfm_depth[k]=mp_sort_in(mp, mp->tfm_depth[k]);
23881   }
23882 }
23883 mp->nd=mp_skimp(mp, 15)+1; mp->dimen_head[3]=link(temp_head);
23884 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_dp);
23885 clear_the_list;
23886 for (k=mp->bc;k<=mp->ec;k++) {
23887   if ( mp->char_exists[k] ) {
23888     if ( mp->tfm_ital_corr[k]==0 ) mp->tfm_ital_corr[k]=zero_val;
23889     else mp->tfm_ital_corr[k]=mp_sort_in(mp, mp->tfm_ital_corr[k]);
23890   }
23891 }
23892 mp->ni=mp_skimp(mp, 63)+1; mp->dimen_head[4]=link(temp_head);
23893 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_ic)
23894
23895 @ @<Initialize table entries...@>=
23896 value(zero_val)=0; info(zero_val)=0;
23897
23898 @ Bytes 5--8 of the header are set to the design size, unless the user has
23899 some crazy reason for specifying them differently.
23900
23901 Error messages are not allowed at the time this procedure is called,
23902 so a warning is printed instead.
23903
23904 The value of |max_tfm_dimen| is calculated so that
23905 $$\hbox{|make_scaled(16*max_tfm_dimen,internal[design_size])|}
23906  < \\{three\_bytes}.$$
23907
23908 @d three_bytes 0100000000 /* $2^{24}$ */
23909
23910 @c 
23911 void mp_fix_design_size (MP mp) {
23912   scaled d; /* the design size */
23913   d=mp->internal[design_size];
23914   if ( (d<unity)||(d>=fraction_half) ) {
23915     if ( d!=0 )
23916       mp_print_nl(mp, "(illegal design size has been changed to 128pt)");
23917 @.illegal design size...@>
23918     d=040000000; mp->internal[design_size]=d;
23919   }
23920   if ( mp->header_byte[4]<0 ) if ( mp->header_byte[5]<0 )
23921     if ( mp->header_byte[6]<0 ) if ( mp->header_byte[7]<0 ) {
23922      mp->header_byte[4]=d / 04000000;
23923      mp->header_byte[5]=(d / 4096) % 256;
23924      mp->header_byte[6]=(d / 16) % 256;
23925      mp->header_byte[7]=(d % 16)*16;
23926   };
23927   mp->max_tfm_dimen=16*mp->internal[design_size]-mp->internal[design_size] / 010000000;
23928   if ( mp->max_tfm_dimen>=fraction_half ) mp->max_tfm_dimen=fraction_half-1;
23929 }
23930
23931 @ The |dimen_out| procedure computes a |fix_word| relative to the
23932 design size. If the data was out of range, it is corrected and the
23933 global variable |tfm_changed| is increased by~one.
23934
23935 @c integer mp_dimen_out (MP mp,scaled x) { 
23936   if ( abs(x)>mp->max_tfm_dimen ) {
23937     incr(mp->tfm_changed);
23938     if ( x>0 ) x=three_bytes-1; else x=1-three_bytes;
23939   } else {
23940     x=mp_make_scaled(mp, x*16,mp->internal[design_size]);
23941   }
23942   return x;
23943 }
23944
23945 @ @<Glob...@>=
23946 scaled max_tfm_dimen; /* bound on widths, heights, kerns, etc. */
23947 integer tfm_changed; /* the number of data entries that were out of bounds */
23948
23949 @ If the user has not specified any of the first four header bytes,
23950 the |fix_check_sum| procedure replaces them by a ``check sum'' computed
23951 from the |tfm_width| data relative to the design size.
23952 @^check sum@>
23953
23954 @c void mp_fix_check_sum (MP mp) {
23955   eight_bits k; /* runs through character codes */
23956   eight_bits B1,B2,B3,B4; /* bytes of the check sum */
23957   integer x;  /* hash value used in check sum computation */
23958   if ( mp->header_byte[0]==0 && mp->header_byte[1]==0 &&
23959        mp->header_byte[2]==0 && mp->header_byte[3]==0 ) {
23960     @<Compute a check sum in |(b1,b2,b3,b4)|@>;
23961     mp->header_byte[0]=B1; mp->header_byte[1]=B2;
23962     mp->header_byte[2]=B3; mp->header_byte[3]=B4; 
23963     return;
23964   }
23965 }
23966
23967 @ @<Compute a check sum in |(b1,b2,b3,b4)|@>=
23968 B1=mp->bc; B2=mp->ec; B3=mp->bc; B4=mp->ec; mp->tfm_changed=0;
23969 for (k=mp->bc;k<=mp->ec;k++) { 
23970   if ( mp->char_exists[k] ) {
23971     x=mp_dimen_out(mp, value(mp->tfm_width[k]))+(k+4)*020000000; /* this is positive */
23972     B1=(B1+B1+x) % 255;
23973     B2=(B2+B2+x) % 253;
23974     B3=(B3+B3+x) % 251;
23975     B4=(B4+B4+x) % 247;
23976   }
23977 }
23978
23979 @ Finally we're ready to actually write the \.{TFM} information.
23980 Here are some utility routines for this purpose.
23981
23982 @d tfm_out(A) fputc((A),mp->tfm_file) /* output one byte to |tfm_file| */
23983
23984 @c void mp_tfm_two (MP mp,integer x) { /* output two bytes to |tfm_file| */
23985   tfm_out(x / 256); tfm_out(x % 256);
23986 }
23987 void mp_tfm_four (MP mp,integer x) { /* output four bytes to |tfm_file| */
23988   if ( x>=0 ) tfm_out(x / three_bytes);
23989   else { 
23990     x=x+010000000000; /* use two's complement for negative values */
23991     x=x+010000000000;
23992     tfm_out((x / three_bytes) + 128);
23993   };
23994   x=x % three_bytes; tfm_out(x / unity);
23995   x=x % unity; tfm_out(x / 0400);
23996   tfm_out(x % 0400);
23997 }
23998 void mp_tfm_qqqq (MP mp,four_quarters x) { /* output four quarterwords to |tfm_file| */
23999   tfm_out(qo(x.b0)); tfm_out(qo(x.b1)); 
24000   tfm_out(qo(x.b2)); tfm_out(qo(x.b3));
24001 }
24002
24003 @ @<Finish the \.{TFM} file@>=
24004 if ( mp->job_name==NULL ) mp_open_log_file(mp);
24005 mp_pack_job_name(mp, ".tfm");
24006 while ( ! mp_b_open_out(mp, &mp->tfm_file, mp_filetype_metrics) )
24007   mp_prompt_file_name(mp, "file name for font metrics",".tfm");
24008 mp->metric_file_name=xstrdup(mp->name_of_file);
24009 @<Output the subfile sizes and header bytes@>;
24010 @<Output the character information bytes, then
24011   output the dimensions themselves@>;
24012 @<Output the ligature/kern program@>;
24013 @<Output the extensible character recipes and the font metric parameters@>;
24014   if ( mp->internal[tracing_stats]>0 )
24015   @<Log the subfile sizes of the \.{TFM} file@>;
24016 mp_print_nl(mp, "Font metrics written on "); 
24017 mp_print(mp, mp->metric_file_name); mp_print_char(mp, '.');
24018 @.Font metrics written...@>
24019 fclose(mp->tfm_file)
24020
24021 @ Integer variables |lh|, |k|, and |lk_offset| will be defined when we use
24022 this code.
24023
24024 @<Output the subfile sizes and header bytes@>=
24025 k=mp->header_last;
24026 LH=(k+3) / 4; /* this is the number of header words */
24027 if ( mp->bc>mp->ec ) mp->bc=1; /* if there are no characters, |ec=0| and |bc=1| */
24028 @<Compute the ligature/kern program offset and implant the
24029   left boundary label@>;
24030 mp_tfm_two(mp,6+LH+(mp->ec-mp->bc+1)+mp->nw+mp->nh+mp->nd+mp->ni+mp->nl
24031      +lk_offset+mp->nk+mp->ne+mp->np);
24032   /* this is the total number of file words that will be output */
24033 mp_tfm_two(mp, LH); mp_tfm_two(mp, mp->bc); mp_tfm_two(mp, mp->ec); 
24034 mp_tfm_two(mp, mp->nw); mp_tfm_two(mp, mp->nh);
24035 mp_tfm_two(mp, mp->nd); mp_tfm_two(mp, mp->ni); mp_tfm_two(mp, mp->nl+lk_offset); 
24036 mp_tfm_two(mp, mp->nk); mp_tfm_two(mp, mp->ne);
24037 mp_tfm_two(mp, mp->np);
24038 for (k=0;k< 4*LH;k++)   { 
24039   tfm_out(mp->header_byte[k]);
24040 }
24041
24042 @ @<Output the character information bytes...@>=
24043 for (k=mp->bc;k<=mp->ec;k++) {
24044   if ( ! mp->char_exists[k] ) {
24045     mp_tfm_four(mp, 0);
24046   } else { 
24047     tfm_out(info(mp->tfm_width[k])); /* the width index */
24048     tfm_out((info(mp->tfm_height[k]))*16+info(mp->tfm_depth[k]));
24049     tfm_out((info(mp->tfm_ital_corr[k]))*4+mp->char_tag[k]);
24050     tfm_out(mp->char_remainder[k]);
24051   };
24052 }
24053 mp->tfm_changed=0;
24054 for (k=1;k<=4;k++) { 
24055   mp_tfm_four(mp, 0); p=mp->dimen_head[k];
24056   while ( p!=inf_val ) {
24057     mp_tfm_four(mp, mp_dimen_out(mp, value(p))); p=link(p);
24058   }
24059 }
24060
24061
24062 @ We need to output special instructions at the beginning of the
24063 |lig_kern| array in order to specify the right boundary character
24064 and/or to handle starting addresses that exceed 255. The |label_loc|
24065 and |label_char| arrays have been set up to record all the
24066 starting addresses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
24067 \le|label_loc|[|label_ptr]|$.
24068
24069 @<Compute the ligature/kern program offset...@>=
24070 mp->bchar=mp_round_unscaled(mp, mp->internal[boundary_char]);
24071 if ((mp->bchar<0)||(mp->bchar>255))
24072   { mp->bchar=-1; mp->lk_started=false; lk_offset=0; }
24073 else { mp->lk_started=true; lk_offset=1; };
24074 @<Find the minimum |lk_offset| and adjust all remainders@>;
24075 if ( mp->bch_label<undefined_label )
24076   { skip_byte(mp->nl)=qi(255); next_char(mp->nl)=qi(0);
24077   op_byte(mp->nl)=qi(((mp->bch_label+lk_offset)/ 256));
24078   rem_byte(mp->nl)=qi(((mp->bch_label+lk_offset)% 256));
24079   incr(mp->nl); /* possibly |nl=lig_table_size+1| */
24080   }
24081
24082 @ @<Find the minimum |lk_offset|...@>=
24083 k=mp->label_ptr; /* pointer to the largest unallocated label */
24084 if ( mp->label_loc[k]+lk_offset>255 ) {
24085   lk_offset=0; mp->lk_started=false; /* location 0 can do double duty */
24086   do {  
24087     mp->char_remainder[mp->label_char[k]]=lk_offset;
24088     while ( mp->label_loc[k-1]==mp->label_loc[k] ) {
24089        decr(k); mp->char_remainder[mp->label_char[k]]=lk_offset;
24090     }
24091     incr(lk_offset); decr(k);
24092   } while (! (lk_offset+mp->label_loc[k]<256));
24093     /* N.B.: |lk_offset=256| satisfies this when |k=0| */
24094 };
24095 if ( lk_offset>0 ) {
24096   while ( k>0 ) {
24097     mp->char_remainder[mp->label_char[k]]
24098      =mp->char_remainder[mp->label_char[k]]+lk_offset;
24099     decr(k);
24100   }
24101 }
24102
24103 @ @<Output the ligature/kern program@>=
24104 for (k=0;k<= 255;k++ ) {
24105   if ( mp->skip_table[k]<undefined_label ) {
24106      mp_print_nl(mp, "(local label "); mp_print_int(mp, k); mp_print(mp, ":: was missing)");
24107 @.local label l:: was missing@>
24108     cancel_skips(mp->skip_table[k]);
24109   }
24110 }
24111 if ( mp->lk_started ) { /* |lk_offset=1| for the special |bchar| */
24112   tfm_out(255); tfm_out(mp->bchar); mp_tfm_two(mp, 0);
24113 } else {
24114   for (k=1;k<=lk_offset;k++) {/* output the redirection specs */
24115     mp->ll=mp->label_loc[mp->label_ptr];
24116     if ( mp->bchar<0 ) { tfm_out(254); tfm_out(0);   }
24117     else { tfm_out(255); tfm_out(mp->bchar);   };
24118     mp_tfm_two(mp, mp->ll+lk_offset);
24119     do {  
24120       decr(mp->label_ptr);
24121     } while (! (mp->label_loc[mp->label_ptr]<mp->ll));
24122   }
24123 }
24124 for (k=0;k<=mp->nl-1;k++) mp_tfm_qqqq(mp, mp->lig_kern[k]);
24125 for (k=0;k<=mp->nk-1;k++) mp_tfm_four(mp, mp_dimen_out(mp, mp->kern[k]))
24126
24127 @ @<Output the extensible character recipes...@>=
24128 for (k=0;k<=mp->ne-1;k++) 
24129   mp_tfm_qqqq(mp, mp->exten[k]);
24130 for (k=1;k<=mp->np;k++) {
24131   if ( k==1 ) {
24132     if ( abs(mp->param[1])<fraction_half ) {
24133       mp_tfm_four(mp, mp->param[1]*16);
24134     } else  { 
24135       incr(mp->tfm_changed);
24136       if ( mp->param[1]>0 ) mp_tfm_four(mp, el_gordo);
24137       else mp_tfm_four(mp, -el_gordo);
24138     }
24139   } else {
24140     mp_tfm_four(mp, mp_dimen_out(mp, mp->param[k]));
24141   }
24142 }
24143 if ( mp->tfm_changed>0 )  { 
24144   if ( mp->tfm_changed==1 ) mp_print_nl(mp, "(a font metric dimension");
24145 @.a font metric dimension...@>
24146   else  { 
24147     mp_print_nl(mp, "("); mp_print_int(mp, mp->tfm_changed);
24148 @.font metric dimensions...@>
24149     mp_print(mp, " font metric dimensions");
24150   }
24151   mp_print(mp, " had to be decreased)");
24152 }
24153
24154 @ @<Log the subfile sizes of the \.{TFM} file@>=
24155
24156   char s[200];
24157   wlog_ln(" ");
24158   if ( mp->bch_label<undefined_label ) decr(mp->nl);
24159   snprintf(s,128,"(You used %iw,%ih,%id,%ii,%il,%ik,%ie,%ip metric file positions)",
24160                  mp->nw, mp->nh, mp->nd, mp->ni, mp->nl, mp->nk, mp->ne,mp->np);
24161   wlog_ln(s);
24162 }
24163
24164 @* \[43] Reading font metric data.
24165
24166 \MP\ isn't a typesetting program but it does need to find the bounding box
24167 of a sequence of typeset characters.  Thus it needs to read \.{TFM} files as
24168 well as write them.
24169
24170 @<Glob...@>=
24171 FILE * tfm_infile;
24172
24173 @ All the width, height, and depth information is stored in an array called
24174 |font_info|.  This array is allocated sequentially and each font is stored
24175 as a series of |char_info| words followed by the width, height, and depth
24176 tables.  Since |font_name| entries are permanent, their |str_ref| values are
24177 set to |max_str_ref|.
24178
24179 @<Types...@>=
24180 typedef unsigned int font_number; /* |0..font_max| */
24181
24182 @ The |font_info| array is indexed via a group directory arrays.
24183 For example, the |char_info| data for character~|c| in font~|f| will be
24184 in |font_info[char_base[f]+c].qqqq|.
24185
24186 @<Glob...@>=
24187 font_number font_max; /* maximum font number for included text fonts */
24188 size_t      font_mem_size; /* number of words for \.{TFM} information for text fonts */
24189 memory_word *font_info; /* height, width, and depth data */
24190 char        **font_enc_name; /* encoding names, if any */
24191 boolean     *font_ps_name_fixed; /* are the postscript names fixed already?  */
24192 int         next_fmem; /* next unused entry in |font_info| */
24193 font_number last_fnum; /* last font number used so far */
24194 scaled      *font_dsize;  /* 16 times the ``design'' size in \ps\ points */
24195 char        **font_name;  /* name as specified in the \&{infont} command */
24196 char        **font_ps_name;  /* PostScript name for use when |internal[prologues]>0| */
24197 font_number last_ps_fnum; /* last valid |font_ps_name| index */
24198 eight_bits  *font_bc;
24199 eight_bits  *font_ec;  /* first and last character code */
24200 int         *char_base;  /* base address for |char_info| */
24201 int         *width_base; /* index for zeroth character width */
24202 int         *height_base; /* index for zeroth character height */
24203 int         *depth_base; /* index for zeroth character depth */
24204 pointer     *font_sizes;
24205
24206 @ @<Allocate or initialize ...@>=
24207 mp->font_mem_size = 10000; 
24208 mp->font_info = xmalloc ((mp->font_mem_size+1),sizeof(memory_word));
24209 memset (mp->font_info,0,sizeof(memory_word)*(mp->font_mem_size+1));
24210 mp->font_enc_name = NULL;
24211 mp->font_ps_name_fixed = NULL;
24212 mp->font_dsize = NULL;
24213 mp->font_name = NULL;
24214 mp->font_ps_name = NULL;
24215 mp->font_bc = NULL;
24216 mp->font_ec = NULL;
24217 mp->last_fnum = null_font;
24218 mp->char_base = NULL;
24219 mp->width_base = NULL;
24220 mp->height_base = NULL;
24221 mp->depth_base = NULL;
24222 mp->font_sizes = null;
24223
24224 @ @<Dealloc variables@>=
24225 xfree(mp->font_info);
24226 xfree(mp->font_enc_name);
24227 xfree(mp->font_ps_name_fixed);
24228 xfree(mp->font_dsize);
24229 xfree(mp->font_name);
24230 xfree(mp->font_ps_name);
24231 xfree(mp->font_bc);
24232 xfree(mp->font_ec);
24233 xfree(mp->char_base);
24234 xfree(mp->width_base);
24235 xfree(mp->height_base);
24236 xfree(mp->depth_base);
24237 xfree(mp->font_sizes);
24238
24239
24240 @c 
24241 void mp_reallocate_fonts (MP mp, font_number l) {
24242   font_number f;
24243   XREALLOC(mp->font_enc_name,      l, char *);
24244   XREALLOC(mp->font_ps_name_fixed, l, boolean);
24245   XREALLOC(mp->font_dsize,         l, scaled);
24246   XREALLOC(mp->font_name,          l, char *);
24247   XREALLOC(mp->font_ps_name,       l, char *);
24248   XREALLOC(mp->font_bc,            l, eight_bits);
24249   XREALLOC(mp->font_ec,            l, eight_bits);
24250   XREALLOC(mp->char_base,          l, int);
24251   XREALLOC(mp->width_base,         l, int);
24252   XREALLOC(mp->height_base,        l, int);
24253   XREALLOC(mp->depth_base,         l, int);
24254   XREALLOC(mp->font_sizes,         l, pointer);
24255   for (f=(mp->last_fnum+1);f<=l;f++) {
24256     mp->font_enc_name[f]=NULL;
24257     mp->font_ps_name_fixed[f] = false;
24258     mp->font_name[f]=NULL;
24259     mp->font_ps_name[f]=NULL;
24260     mp->font_sizes[f]=null;
24261   }
24262   mp->font_max = l;
24263 }
24264
24265 @ @<Declare |mp_reallocate| functions@>=
24266 void mp_reallocate_fonts (MP mp, font_number l);
24267
24268
24269 @ A |null_font| containing no characters is useful for error recovery.  Its
24270 |font_name| entry starts out empty but is reset each time an erroneous font is
24271 found.  This helps to cut down on the number of duplicate error messages without
24272 wasting a lot of space.
24273
24274 @d null_font 0 /* the |font_number| for an empty font */
24275
24276 @<Set initial...@>=
24277 mp->font_dsize[null_font]=0;
24278 mp->font_bc[null_font]=1;
24279 mp->font_ec[null_font]=0;
24280 mp->char_base[null_font]=0;
24281 mp->width_base[null_font]=0;
24282 mp->height_base[null_font]=0;
24283 mp->depth_base[null_font]=0;
24284 mp->next_fmem=0;
24285 mp->last_fnum=null_font;
24286 mp->last_ps_fnum=null_font;
24287 mp->font_name[null_font]="nullfont";
24288 mp->font_ps_name[null_font]="";
24289
24290 @ Each |char_info| word is of type |four_quarters|.  The |b0| field contains
24291 the |width index|; the |b1| field contains the height
24292 index; the |b2| fields contains the depth index, and the |b3| field used only
24293 for temporary storage. (It is used to keep track of which characters occur in
24294 an edge structure that is being shipped out.)
24295 The corresponding words in the width, height, and depth tables are stored as
24296 |scaled| values in units of \ps\ points.
24297
24298 With the macros below, the |char_info| word for character~|c| in font~|f| is
24299 |char_info(f)(c)| and the width is
24300 $$\hbox{|char_width(f)(char_info(f)(c)).sc|.}$$
24301
24302 @d char_info_end(A) (A)].qqqq
24303 @d char_info(A) mp->font_info[mp->char_base[(A)]+char_info_end
24304 @d char_width_end(A) (A).b0].sc
24305 @d char_width(A) mp->font_info[mp->width_base[(A)]+char_width_end
24306 @d char_height_end(A) (A).b1].sc
24307 @d char_height(A) mp->font_info[mp->height_base[(A)]+char_height_end
24308 @d char_depth_end(A) (A).b2].sc
24309 @d char_depth(A) mp->font_info[mp->depth_base[(A)]+char_depth_end
24310 @d ichar_exists(A) ((A).b0>0)
24311
24312 @ The |font_ps_name| for a built-in font should be what PostScript expects.
24313 A preliminary name is obtained here from the \.{TFM} name as given in the
24314 |fname| argument.  This gets updated later from an external table if necessary.
24315
24316 @<Declare text measuring subroutines@>=
24317 @<Declare subroutines for parsing file names@>;
24318 font_number mp_read_font_info (MP mp, char*fname) {
24319   boolean file_opened; /* has |tfm_infile| been opened? */
24320   font_number n; /* the number to return */
24321   halfword lf,tfm_lh,bc,ec,nw,nh,nd; /* subfile size parameters */
24322   size_t whd_size; /* words needed for heights, widths, and depths */
24323   int i,ii; /* |font_info| indices */
24324   int jj; /* counts bytes to be ignored */
24325   scaled z; /* used to compute the design size */
24326   fraction d;
24327   /* height, width, or depth as a fraction of design size times $2^{-8}$ */
24328   eight_bits h_and_d; /* height and depth indices being unpacked */
24329   int tfbyte; /* a byte read from the file */
24330   n=null_font;
24331   @<Open |tfm_infile| for input@>;
24332   @<Read data from |tfm_infile|; if there is no room, say so and |goto done|;
24333     otherwise |goto bad_tfm| or |goto done| as appropriate@>;
24334 BAD_TFM:
24335   @<Complain that the \.{TFM} file is bad@>;
24336 DONE:
24337   if ( file_opened ) fclose(mp->tfm_infile);
24338   if ( n!=null_font ) { 
24339     mp->font_ps_name[n]=fname;
24340     mp->font_name[n]=fname;
24341   }
24342   return n;
24343 }
24344
24345 @ \MP\ doesn't bother to check the entire \.{TFM} file for errors or explain
24346 precisely what is wrong if it does find a problem.  Programs called \.{TFtoPL}
24347 @.TFtoPL@> @.PLtoTF@>
24348 and \.{PLtoTF} can be used to debug \.{TFM} files.
24349
24350 @<Complain that the \.{TFM} file is bad@>=
24351 print_err("Font ");
24352 mp_print(mp, fname);
24353 if ( file_opened ) mp_print(mp, " not usable: TFM file is bad");
24354 else mp_print(mp, " not usable: TFM file not found");
24355 help3("I wasn't able to read the size data for this font so this")
24356   ("`infont' operation won't produce anything. If the font name")
24357   ("is right, you might ask an expert to make a TFM file");
24358 if ( file_opened )
24359   mp->help_line[0]="is right, try asking an expert to fix the TFM file";
24360 mp_error(mp)
24361
24362 @ @<Read data from |tfm_infile|; if there is no room, say so...@>=
24363 @<Read the \.{TFM} size fields@>;
24364 @<Use the size fields to allocate space in |font_info|@>;
24365 @<Read the \.{TFM} header@>;
24366 @<Read the character data and the width, height, and depth tables and
24367   |goto done|@>
24368
24369 @ A bad \.{TFM} file can be shorter than it claims to be.  The code given here
24370 might try to read past the end of the file if this happens.  Changes will be
24371 needed if it causes a system error to refer to |tfm_infile^| or call
24372 |get_tfm_infile| when |eof(tfm_infile)| is true.  For example, the definition
24373 @^system dependencies@>
24374 of |tfget| could be changed to
24375 ``|begin get(tfm_infile); if eof(tfm_infile) then goto bad_tfm; end|.''
24376
24377 @d tfget {tfbyte = fgetc(mp->tfm_infile); }
24378 @d read_two(A) { (A)=tfbyte;
24379   if ( (A)>127 ) goto BAD_TFM;
24380   tfget; (A)=(A)*0400+tfbyte;
24381   }
24382 @d tf_ignore(A) { for (jj=(A);jj>=1;jj--) tfget; }
24383
24384 @<Read the \.{TFM} size fields@>=
24385 tfget; read_two(lf);
24386 tfget; read_two(tfm_lh);
24387 tfget; read_two(bc);
24388 tfget; read_two(ec);
24389 if ( (bc>1+ec)||(ec>255) ) goto BAD_TFM;
24390 tfget; read_two(nw);
24391 tfget; read_two(nh);
24392 tfget; read_two(nd);
24393 whd_size=(ec+1-bc)+nw+nh+nd;
24394 if ( lf<(int)(6+tfm_lh+whd_size) ) goto BAD_TFM;
24395 tf_ignore(10)
24396
24397 @ Offsets are added to |char_base[n]| and |width_base[n]| so that is not
24398 necessary to apply the |so|  and |qo| macros when looking up the width of a
24399 character in the string pool.  In order to ensure nonnegative |char_base|
24400 values when |bc>0|, it may be necessary to reserve a few unused |font_info|
24401 elements.
24402
24403 @<Use the size fields to allocate space in |font_info|@>=
24404 if ( mp->next_fmem<bc) mp->next_fmem=bc;  /* ensure nonnegative |char_base| */
24405 if (mp->last_fnum==mp->font_max)
24406   mp_reallocate_fonts(mp,(mp->font_max+(mp->font_max>>2)));
24407 while (mp->next_fmem+whd_size>=mp->font_mem_size) {
24408   size_t l = mp->font_mem_size+(mp->font_mem_size>>2);
24409   memory_word *font_info;
24410   font_info = xmalloc ((l+1),sizeof(memory_word));
24411   memset (font_info,0,sizeof(memory_word)*(l+1));
24412   memcpy (font_info,mp->font_info,sizeof(memory_word)*(mp->font_mem_size+1));
24413   xfree(mp->font_info);
24414   mp->font_info = font_info;
24415   mp->font_mem_size = l;
24416 }
24417 incr(mp->last_fnum);
24418 n=mp->last_fnum;
24419 mp->font_bc[n]=bc;
24420 mp->font_ec[n]=ec;
24421 mp->char_base[n]=mp->next_fmem-bc;
24422 mp->width_base[n]=mp->next_fmem+ec-bc+1;
24423 mp->height_base[n]=mp->width_base[n]+nw;
24424 mp->depth_base[n]=mp->height_base[n]+nh;
24425 mp->next_fmem=mp->next_fmem+whd_size;
24426
24427
24428 @ @<Read the \.{TFM} header@>=
24429 if ( tfm_lh<2 ) goto BAD_TFM;
24430 tf_ignore(4);
24431 tfget; read_two(z);
24432 tfget; z=z*0400+tfbyte;
24433 tfget; z=z*0400+tfbyte; /* now |z| is 16 times the design size */
24434 mp->font_dsize[n]=mp_take_fraction(mp, z,267432584);
24435   /* times ${72\over72.27}2^{28}$ to convert from \TeX\ points */
24436 tf_ignore(4*(tfm_lh-2))
24437
24438 @ @<Read the character data and the width, height, and depth tables...@>=
24439 ii=mp->width_base[n];
24440 i=mp->char_base[n]+bc;
24441 while ( i<ii ) { 
24442   tfget; mp->font_info[i].qqqq.b0=qi(tfbyte);
24443   tfget; h_and_d=tfbyte;
24444   mp->font_info[i].qqqq.b1=h_and_d / 16;
24445   mp->font_info[i].qqqq.b2=h_and_d % 16;
24446   tfget; tfget;
24447   incr(i);
24448 }
24449 while ( i<mp->next_fmem ) {
24450   @<Read a four byte dimension, scale it by the design size, store it in
24451     |font_info[i]|, and increment |i|@>;
24452 }
24453 if (feof(mp->tfm_infile) ) goto BAD_TFM;
24454 goto DONE
24455
24456 @ The raw dimension read into |d| should have magnitude at most $2^{24}$ when
24457 interpreted as an integer, and this includes a scale factor of $2^{20}$.  Thus
24458 we can multiply it by sixteen and think of it as a |fraction| that has been
24459 divided by sixteen.  This cancels the extra scale factor contained in
24460 |font_dsize[n|.
24461
24462 @<Read a four byte dimension, scale it by the design size, store it in...@>=
24463
24464 tfget; d=tfbyte;
24465 if ( d>=0200 ) d=d-0400;
24466 tfget; d=d*0400+tfbyte;
24467 tfget; d=d*0400+tfbyte;
24468 tfget; d=d*0400+tfbyte;
24469 mp->font_info[i].sc=mp_take_fraction(mp, d*16,mp->font_dsize[n]);
24470 incr(i);
24471 }
24472
24473 @ This function does no longer use the file name parser, because |fname| is
24474 a C string already.
24475 @<Open |tfm_infile| for input@>=
24476 file_opened=false;
24477 mp_ptr_scan_file(mp, fname);
24478 if ( strlen(mp->cur_area)==0 ) { xfree(mp->cur_area); mp->cur_area=xstrdup(MP_font_area);}
24479 if ( strlen(mp->cur_ext)==0 )  { xfree(mp->cur_ext); mp->cur_ext=xstrdup(".tfm"); }
24480 pack_cur_name;
24481 mp->tfm_infile = mp_open_file(mp, mp->name_of_file, "rb",mp_filetype_metrics);
24482 if ( !mp->tfm_infile  ) goto BAD_TFM;
24483 file_opened=true
24484
24485 @ When we have a font name and we don't know whether it has been loaded yet,
24486 we scan the |font_name| array before calling |read_font_info|.
24487
24488 @<Declare text measuring subroutines@>=
24489 font_number mp_find_font (MP mp, char *f) {
24490   font_number n;
24491   for (n=0;n<=mp->last_fnum;n++) {
24492     if (mp_xstrcmp(f,mp->font_name[n])==0 )
24493       return n;
24494   }
24495   return mp_read_font_info(mp, f);
24496 }
24497
24498 @ One simple application of |find_font| is the implementation of the |font_size|
24499 operator that gets the design size for a given font name.
24500
24501 @<Find the design size of the font whose name is |cur_exp|@>=
24502 mp_flush_cur_exp(mp, (mp->font_dsize[mp_find_font(mp, str(mp->cur_exp))]+8) / 16)
24503
24504 @ If we discover that the font doesn't have a requested character, we omit it
24505 from the bounding box computation and expect the \ps\ interpreter to drop it.
24506 This routine issues a warning message if the user has asked for it.
24507
24508 @<Declare text measuring subroutines@>=
24509 void mp_lost_warning (MP mp,font_number f, pool_pointer k) { 
24510   if ( mp->internal[tracing_lost_chars]>0 ) { 
24511     mp_begin_diagnostic(mp);
24512     if ( mp->selector==log_only ) incr(mp->selector);
24513     mp_print_nl(mp, "Missing character: There is no ");
24514 @.Missing character@>
24515     mp_print_str(mp, mp->str_pool[k]); 
24516     mp_print(mp, " in font ");
24517     mp_print(mp, mp->font_name[f]); mp_print_char(mp, '!'); 
24518     mp_end_diagnostic(mp, false);
24519   }
24520 }
24521
24522 @ The whole purpose of saving the height, width, and depth information is to be
24523 able to find the bounding box of an item of text in an edge structure.  The
24524 |set_text_box| procedure takes a text node and adds this information.
24525
24526 @<Declare text measuring subroutines@>=
24527 void mp_set_text_box (MP mp,pointer p) {
24528   font_number f; /* |font_n(p)| */
24529   ASCII_code bc,ec; /* range of valid characters for font |f| */
24530   pool_pointer k,kk; /* current character and character to stop at */
24531   four_quarters cc; /* the |char_info| for the current character */
24532   scaled h,d; /* dimensions of the current character */
24533   width_val(p)=0;
24534   height_val(p)=-el_gordo;
24535   depth_val(p)=-el_gordo;
24536   f=font_n(p);
24537   bc=mp->font_bc[f];
24538   ec=mp->font_ec[f];
24539   kk=str_stop(text_p(p));
24540   k=mp->str_start[text_p(p)];
24541   while ( k<kk ) {
24542     @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>;
24543   }
24544   @<Set the height and depth to zero if the bounding box is empty@>;
24545 }
24546
24547 @ @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>=
24548
24549   if ( (mp->str_pool[k]<bc)||(mp->str_pool[k]>ec) ) {
24550     mp_lost_warning(mp, f,k);
24551   } else { 
24552     cc=char_info(f)(mp->str_pool[k]);
24553     if ( ! ichar_exists(cc) ) {
24554       mp_lost_warning(mp, f,k);
24555     } else { 
24556       width_val(p)=width_val(p)+char_width(f)(cc);
24557       h=char_height(f)(cc);
24558       d=char_depth(f)(cc);
24559       if ( h>height_val(p) ) height_val(p)=h;
24560       if ( d>depth_val(p) ) depth_val(p)=d;
24561     }
24562   }
24563   incr(k);
24564 }
24565
24566 @ Let's hope modern compilers do comparisons correctly when the difference would
24567 overflow.
24568
24569 @<Set the height and depth to zero if the bounding box is empty@>=
24570 if ( height_val(p)<-depth_val(p) ) { 
24571   height_val(p)=0;
24572   depth_val(p)=0;
24573 }
24574
24575 @ The new primitives fontmapfile and fontmapline.
24576
24577 @<Declare action procedures for use by |do_statement|@>=
24578 void mp_do_mapfile (MP mp) ;
24579 void mp_do_mapline (MP mp) ;
24580
24581 @ @c void mp_do_mapfile (MP mp) { 
24582   mp_get_x_next(mp); mp_scan_expression(mp);
24583   if ( mp->cur_type!=mp_string_type ) {
24584     @<Complain about improper map operation@>;
24585   } else {
24586     mp_map_file(mp,mp->cur_exp);
24587   }
24588 }
24589 void mp_do_mapline (MP mp) { 
24590   mp_get_x_next(mp); mp_scan_expression(mp);
24591   if ( mp->cur_type!=mp_string_type ) {
24592      @<Complain about improper map operation@>;
24593   } else { 
24594      mp_map_line(mp,mp->cur_exp);
24595   }
24596 }
24597
24598 @ @<Complain about improper map operation@>=
24599
24600   exp_err("Unsuitable expression");
24601   help1("Only known strings can be map files or map lines.");
24602   mp_put_get_error(mp);
24603 }
24604
24605 @
24606 @<Declare the \ps\ output procedures@>=
24607 void mp_ps_print_cmd (MP mp, char *l, char *s) {
24608   if ( mp->internal[mpprocset]>0 ) { ps_room(strlen(s)); mp_print(mp,s); }
24609   else { ps_room(strlen(l)); mp_print(mp, l); };
24610 }
24611 void mp_print_cmd (MP mp,char *l, char *s) {
24612   if ( mp->internal[mpprocset]>0 ) mp_print(mp, s); 
24613   else mp_print(mp, l);
24614 }
24615
24616 @ To print |scaled| value to PDF output we need some subroutines to ensure
24617 accurary.
24618
24619 @d max_integer   0x7FFFFFFF /* $2^{31}-1$ */
24620
24621 @<Glob...@>=
24622 scaled one_bp; /* scaled value corresponds to 1bp */
24623 scaled one_hundred_bp; /* scaled value corresponds to 100bp */
24624 scaled one_hundred_inch; /* scaled value corresponds to 100in */
24625 integer ten_pow[10]; /* $10^0..10^9$ */
24626 integer scaled_out; /* amount of |scaled| that was taken out in |divide_scaled| */
24627
24628 @ @<Set init...@>=
24629 mp->one_bp = 65782; /* 65781.76 */
24630 mp->one_hundred_bp = 6578176;
24631 mp->one_hundred_inch = 473628672;
24632 mp->ten_pow[0] = 1;
24633 for (i = 1;i<= 9; i++ ) {
24634   mp->ten_pow[i] = 10*mp->ten_pow[i - 1];
24635 }
24636
24637 @ The following function divides |s| by |m|. |dd| is number of decimal digits.
24638
24639 @c scaled mp_divide_scaled (MP mp,scaled s, scaled m, integer  dd) {
24640   scaled q,r;
24641   integer sign,i;
24642   sign = 1;
24643   if ( s < 0 ) { sign = -sign; s = -s; }
24644   if ( m < 0 ) { sign = -sign; m = -m; }
24645   if ( m == 0 )
24646     mp_confusion(mp, "arithmetic: divided by zero");
24647   else if ( m >= (max_integer / 10) )
24648     mp_confusion(mp, "arithmetic: number too big");
24649   q = s / m;
24650   r = s % m;
24651   for (i = 1;i<=dd;i++) {
24652     q = 10*q + (10*r) / m;
24653     r = (10*r) % m;
24654   }
24655   if ( 2*r >= m ) { incr(q); r = r - m; }
24656   mp->scaled_out = sign*(s - (r / mp->ten_pow[dd]));
24657   return (sign*q);
24658 }
24659
24660 @* \[44] Shipping pictures out.
24661 The |ship_out| procedure, to be described below, is given a pointer to
24662 an edge structure. Its mission is to output a file containing the \ps\
24663 description of an edge structure.
24664
24665 @ Each time an edge structure is shipped out we write a new \ps\ output
24666 file named according to the current \&{charcode}.
24667 @:char_code_}{\&{charcode} primitive@>
24668
24669 @<Declare the \ps\ output procedures@>=
24670 void mp_open_output_file (MP mp) ;
24671
24672 @ @c void mp_open_output_file (MP mp) {
24673   integer c; /* \&{charcode} rounded to the nearest integer */
24674   int old_setting; /* previous |selector| setting */
24675   pool_pointer i; /*  indexes into |filename_template|  */
24676   integer cc; /* a temporary integer for template building  */
24677   integer f,g=0; /* field widths */
24678   if ( mp->job_name==NULL ) mp_open_log_file(mp);
24679   c=mp_round_unscaled(mp, mp->internal[char_code]);
24680   if ( mp->filename_template==0 ) {
24681     char *s; /* a file extension derived from |c| */
24682     if ( c<0 ) 
24683       s=xstrdup(".ps");
24684     else 
24685       @<Use |c| to compute the file extension |s|@>;
24686     mp_pack_job_name(mp, s);
24687     xfree(s);
24688     while ( ! mp_a_open_out(mp, &mp->ps_file, mp_filetype_postscript) )
24689       mp_prompt_file_name(mp, "file name for output",s);
24690   } else { /* initializations */
24691     str_number s, n; /* a file extension derived from |c| */
24692     old_setting=mp->selector; 
24693     mp->selector=new_string;
24694     f = 0;
24695     i = mp->str_start[mp->filename_template];
24696     n = rts(""); /* initialize */
24697     while ( i<str_stop(mp->filename_template) ) {
24698        if ( mp->str_pool[i]=='%' ) {
24699       CONTINUE:
24700         incr(i);
24701         if ( i<str_stop(mp->filename_template) ) {
24702           if ( mp->str_pool[i]=='j' ) {
24703             mp_print(mp, mp->job_name);
24704           } else if ( mp->str_pool[i]=='d' ) {
24705              cc= mp_round_unscaled(mp, mp->internal[day]);
24706              print_with_leading_zeroes(cc);
24707           } else if ( mp->str_pool[i]=='m' ) {
24708              cc= mp_round_unscaled(mp, mp->internal[month]);
24709              print_with_leading_zeroes(cc);
24710           } else if ( mp->str_pool[i]=='y' ) {
24711              cc= mp_round_unscaled(mp, mp->internal[year]);
24712              print_with_leading_zeroes(cc);
24713           } else if ( mp->str_pool[i]=='H' ) {
24714              cc= mp_round_unscaled(mp, mp->internal[mp_time]) / 60;
24715              print_with_leading_zeroes(cc);
24716           }  else if ( mp->str_pool[i]=='M' ) {
24717              cc= mp_round_unscaled(mp, mp->internal[mp_time]) % 60;
24718              print_with_leading_zeroes(cc);
24719           } else if ( mp->str_pool[i]=='c' ) {
24720             if ( c<0 ) mp_print(mp, "ps");
24721             else print_with_leading_zeroes(c);
24722           } else if ( (mp->str_pool[i]>='0') && 
24723                       (mp->str_pool[i]<='9') ) {
24724             if ( (f<10)  )
24725               f = (f*10) + mp->str_pool[i]-'0';
24726             goto CONTINUE;
24727           } else {
24728             mp_print_str(mp, mp->str_pool[i]);
24729           }
24730         }
24731       } else {
24732         if ( mp->str_pool[i]=='.' )
24733           if (length(n)==0)
24734             n = mp_make_string(mp);
24735         mp_print_str(mp, mp->str_pool[i]);
24736       };
24737       incr(i);
24738     };
24739     s = mp_make_string(mp);
24740     mp->selector= old_setting;
24741     if (length(n)==0) {
24742        n=s;
24743        s=rts("");
24744     };
24745     mp_pack_file_name(mp, str(n),"",str(s));
24746     while ( ! mp_a_open_out(mp, &mp->ps_file, mp_filetype_postscript) )
24747       mp_prompt_file_name(mp, "file name for output",str(s));
24748     delete_str_ref(n);
24749     delete_str_ref(s);
24750   }
24751   @<Store the true output file name if appropriate@>;
24752   @<Begin the progress report for the output of picture~|c|@>;
24753 }
24754
24755 @ The file extension created here could be up to five characters long in
24756 extreme cases so it may have to be shortened on some systems.
24757 @^system dependencies@>
24758
24759 @<Use |c| to compute the file extension |s|@>=
24760
24761   s = xmalloc(7,1);
24762   snprintf(s,7,".%i",(int)c);
24763 }
24764
24765 @ The user won't want to see all the output file names so we only save the
24766 first and last ones and a count of how many there were.  For this purpose
24767 files are ordered primarily by \&{charcode} and secondarily by order of
24768 creation.
24769 @:char_code_}{\&{charcode} primitive@>
24770
24771 @<Store the true output file name if appropriate@>=
24772 if ((c<mp->first_output_code)&&(mp->first_output_code>=0)) {
24773   mp->first_output_code=c;
24774   xfree(mp->first_file_name);
24775   mp->first_file_name=xstrdup(mp->name_of_file);
24776 }
24777 if ( c>=mp->last_output_code ) {
24778   mp->last_output_code=c;
24779   xfree(mp->last_file_name);
24780   mp->last_file_name=xstrdup(mp->name_of_file);
24781 }
24782
24783 @ @<Glob...@>=
24784 char * first_file_name;
24785 char * last_file_name; /* full file names */
24786 integer first_output_code;integer last_output_code; /* rounded \&{charcode} values */
24787 @:char_code_}{\&{charcode} primitive@>
24788 integer total_shipped; /* total number of |ship_out| operations completed */
24789
24790 @ @<Set init...@>=
24791 mp->first_file_name=xstrdup("");
24792 mp->last_file_name=xstrdup("");
24793 mp->first_output_code=32768;
24794 mp->last_output_code=-32768;
24795 mp->total_shipped=0;
24796
24797 @ @<Dealloc variables@>=
24798 xfree(mp->first_file_name);
24799 xfree(mp->last_file_name);
24800
24801 @ @<Begin the progress report for the output of picture~|c|@>=
24802 if ( (int)mp->term_offset>mp->max_print_line-6 ) mp_print_ln(mp);
24803 else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
24804 mp_print_char(mp, '[');
24805 if ( c>=0 ) mp_print_int(mp, c)
24806
24807 @ @<End progress report@>=
24808 mp_print_char(mp, ']');
24809 update_terminal;
24810 incr(mp->total_shipped)
24811
24812 @ @<Explain what output files were written@>=
24813 if ( mp->total_shipped>0 ) { 
24814   mp_print_nl(mp, "");
24815   mp_print_int(mp, mp->total_shipped);
24816   mp_print(mp, " output file");
24817   if ( mp->total_shipped>1 ) mp_print_char(mp, 's');
24818   mp_print(mp, " written: ");
24819   mp_print(mp, mp->first_file_name);
24820   if ( mp->total_shipped>1 ) {
24821     if ( 31+strlen(mp->first_file_name)+
24822          strlen(mp->last_file_name)> (unsigned)mp->max_print_line) 
24823       mp_print_ln(mp);
24824     mp_print(mp, " .. ");
24825     mp_print(mp, mp->last_file_name);
24826   }
24827 }
24828
24829 @ We often need to print a pair of coordinates.
24830
24831 @d ps_room(A) if ( (mp->ps_offset+(int)(A))>mp->max_print_line ) 
24832   mp_print_ln(mp) /* optional line break */
24833
24834 @<Declare the \ps\ output procedures@>=
24835 void mp_ps_pair_out (MP mp,scaled x, scaled y) { 
24836   ps_room(26);
24837   mp_print_scaled(mp, x); mp_print_char(mp, ' ');
24838   mp_print_scaled(mp, y); mp_print_char(mp, ' ');
24839 }
24840
24841 @ @<Declare the \ps\ output procedures@>=
24842 void mp_ps_print (MP mp,char *s) { 
24843    ps_room(strlen(s));
24844    mp_print(mp, s);
24845 };
24846
24847 @ @<Exported...@>=
24848 void mp_ps_print (MP mp,char *s) ;
24849
24850
24851 @ The most important output procedure is the one that gives the \ps\ version of
24852 a \MP\ path.
24853
24854 @<Declare the \ps\ output procedures@>=
24855 void mp_ps_path_out (MP mp,pointer h) {
24856   pointer p,q; /* for scanning the path */
24857   scaled d; /* a temporary value */
24858   boolean curved; /* |true| unless the cubic is almost straight */
24859   ps_room(40);
24860   if ( mp->need_newpath ) 
24861     mp_print_cmd(mp, "newpath ","n ");
24862   mp->need_newpath=true;
24863   mp_ps_pair_out(mp, x_coord(h),y_coord(h));
24864   mp_print_cmd(mp, "moveto","m");
24865   p=h;
24866   do {  
24867     if ( right_type(p)==endpoint ) { 
24868       if ( p==h ) mp_ps_print_cmd(mp, " 0 0 rlineto"," 0 0 r");
24869       return;
24870     }
24871     q=link(p);
24872     @<Start a new line and print the \ps\ commands for the curve from
24873       |p| to~|q|@>;
24874     p=q;
24875   } while (p!=h);
24876   mp_ps_print_cmd(mp, " closepath"," p");
24877 }
24878
24879 @ @<Glob...@>=
24880 boolean need_newpath;
24881   /* will |ps_path_out| need to issue a \&{newpath} command next time */
24882 @:newpath_}{\&{newpath} command@>
24883
24884 @ @<Start a new line and print the \ps\ commands for the curve from...@>=
24885 curved=true;
24886 @<Set |curved:=false| if the cubic from |p| to |q| is almost straight@>;
24887 mp_print_ln(mp);
24888 if ( curved ){ 
24889   mp_ps_pair_out(mp, right_x(p),right_y(p));
24890   mp_ps_pair_out(mp, left_x(q),left_y(q));
24891   mp_ps_pair_out(mp, x_coord(q),y_coord(q));
24892   mp_ps_print_cmd(mp, "curveto","c");
24893 } else if ( q!=h ){ 
24894   mp_ps_pair_out(mp, x_coord(q),y_coord(q));
24895   mp_ps_print_cmd(mp, "lineto","l");
24896 }
24897
24898 @ Two types of straight lines come up often in \MP\ paths:
24899 cubics with zero initial and final velocity as created by |make_path| or
24900 |make_envelope|, and cubics with control points uniformly spaced on a line
24901 as created by |make_choices|.
24902
24903 @d bend_tolerance 131 /* allow rounding error of $2\cdot10^{-3}$ */
24904
24905 @<Set |curved:=false| if the cubic from |p| to |q| is almost straight@>=
24906 if ( right_x(p)==x_coord(p) )
24907   if ( right_y(p)==y_coord(p) )
24908     if ( left_x(q)==x_coord(q) )
24909       if ( left_y(q)==y_coord(q) ) curved=false;
24910 d=left_x(q)-right_x(p);
24911 if ( abs(right_x(p)-x_coord(p)-d)<=bend_tolerance )
24912   if ( abs(x_coord(q)-left_x(q)-d)<=bend_tolerance )
24913     { d=left_y(q)-right_y(p);
24914     if ( abs(right_y(p)-y_coord(p)-d)<=bend_tolerance )
24915       if ( abs(y_coord(q)-left_y(q)-d)<=bend_tolerance ) curved=false;
24916     }
24917
24918 @ We need to keep track of several parameters from the \ps\ graphics state.
24919 @^graphics state@>
24920 This allows us to be sure that \ps\ has the correct values when they are
24921 needed without wasting time and space setting them unnecessarily.
24922
24923 @d gs_node_size 10
24924 @d gs_red        mp->mem[mp->gs_state+1].sc
24925 @d gs_green      mp->mem[mp->gs_state+2].sc
24926 @d gs_blue       mp->mem[mp->gs_state+3].sc
24927 @d gs_black      mp->mem[mp->gs_state+4].sc
24928    /* color from the last \&{setcmykcolor} or \&{setrgbcolor} or \&{setgray} command */
24929 @d gs_colormodel mp->mem[mp->gs_state+5].qqqq.b0
24930    /* the current colormodel */
24931 @d gs_ljoin      mp->mem[mp->gs_state+5].qqqq.b1
24932 @d gs_lcap       mp->mem[mp->gs_state+5].qqqq.b2
24933    /* values from the last \&{setlinejoin} and \&{setlinecap} commands */
24934 @d gs_adj_wx     mp->mem[mp->gs_state+5].qqqq.b3
24935    /* what resolution-dependent adjustment applies to the width */
24936 @d gs_miterlim   mp->mem[mp->gs_state+6].sc
24937    /* the value from the last \&{setmiterlimit} command */
24938 @d gs_dash_p     mp->mem[mp->gs_state+7].hh.lh
24939    /* edge structure for last \&{setdash} command */
24940 @d gs_previous   mp->mem[mp->gs_state+7].hh.rh
24941    /* backlink to the previous |gs_state| structure */
24942 @d gs_dash_sc    mp->mem[mp->gs_state+8].sc
24943    /* scale factor used with |gs_dash_p| */
24944 @d gs_width      mp->mem[mp->gs_state+9].sc
24945    /* width setting or $-1$ if no \&{setlinewidth} command so far */
24946
24947 @<Glob...@>=
24948 pointer gs_state;
24949
24950 @ @<Set init...@>=
24951 mp->gs_state=null;
24952
24953 @ To avoid making undue assumptions about the initial graphics state, these
24954 parameters are given special values that are guaranteed not to match anything
24955 in the edge structure being shipped out.  On the other hand, the initial color
24956 should be black so that the translation of an all-black picture will have no
24957 \&{setcolor} commands.  (These would be undesirable in a font application.)
24958 Hence we use |c=0| when initializing the graphics state and we use |c<0|
24959 to recover from a situation where we have lost track of the graphics state.
24960
24961 @<Declare the \ps\ output procedures@>=
24962 void mp_unknown_graphics_state (MP mp,scaled c) ;
24963
24964 @ @c void mp_unknown_graphics_state (MP mp,scaled c) {
24965   pointer p; /* to shift graphic states around */
24966   quarterword k; /* a loop index for copying the |gs_state| */
24967   if ( (c==0)||(c==-1) ) {
24968     if ( mp->gs_state==null ) {
24969       mp->gs_state = mp_get_node(mp, gs_node_size);
24970       gs_previous=null;
24971     } else {
24972       while ( gs_previous!=null ) {
24973         p = gs_previous;
24974         mp_free_node(mp, mp->gs_state,gs_node_size);
24975         mp->gs_state=p;
24976       }
24977     }
24978     gs_red=c; gs_green=c; gs_blue=c; gs_black=c;
24979     gs_colormodel=uninitialized_model;
24980     gs_ljoin=3;
24981     gs_lcap=3;
24982     gs_miterlim=0;
24983     gs_dash_p=diov;
24984     gs_dash_sc=0;
24985     gs_width=-1;
24986   } else if ( c==1 ) {
24987     p= mp->gs_state;
24988     mp->gs_state = mp_get_node(mp, gs_node_size);
24989     for (k=1;k<=gs_node_size-1;k++)
24990       mp->mem[mp->gs_state+k]=mp->mem[p+k];
24991     gs_previous = p;
24992   } else if ( c==2 ) {
24993     p = gs_previous;
24994     mp_free_node(mp, mp->gs_state,gs_node_size);
24995     mp->gs_state=p;
24996   }
24997 }
24998
24999 @ When it is time to output a graphical object, |fix_graphics_state| ensures
25000 that \ps's idea of the graphics state agrees with what is stored in the object.
25001
25002 @<Declare the \ps\ output procedures@>=
25003 @<Declare subroutines needed by |fix_graphics_state|@>;
25004 void mp_fix_graphics_state (MP mp, pointer p) ;
25005
25006 @ @c 
25007 void mp_fix_graphics_state (MP mp, pointer p) {
25008   /* get ready to output graphical object |p| */
25009   pointer hh,pp; /* for list manipulation */
25010   scaled wx,wy,ww; /* dimensions of pen bounding box */
25011   boolean adj_wx; /* whether pixel rounding should be based on |wx| or |wy| */
25012   integer tx,ty; /* temporaries for computing |adj_wx| */
25013   scaled scf; /* a scale factor for the dash pattern */
25014   if ( has_color(p) )
25015     @<Make sure \ps\ will use the right color for object~|p|@>;
25016   if ( (type(p)==fill_code)||(type(p)==stroked_code) )
25017     if ( pen_p(p)!=null )
25018       if ( pen_is_elliptical(pen_p(p)) ) {
25019         @<Generate \ps\ code that sets the stroke width to the
25020           appropriate rounded value@>;
25021         @<Make sure \ps\ will use the right dash pattern for |dash_p(p)|@>;
25022         @<Decide whether the line cap parameter matters and set it if necessary@>;
25023         @<Set the other numeric parameters as needed for object~|p|@>;
25024       }
25025   if ( mp->ps_offset>0 ) mp_print_ln(mp);
25026 }
25027
25028 @ @<Decide whether the line cap parameter matters and set it if necessary@>=
25029 if ( type(p)==stroked_code )
25030   if ( (left_type(path_p(p))==endpoint)||(dash_p(p)!=null) )
25031     if ( gs_lcap!=lcap_val(p) ) {
25032       ps_room(13);
25033       mp_print_char(mp, ' ');
25034       mp_print_char(mp, '0'+lcap_val(p)); 
25035       mp_print_cmd(mp, " setlinecap"," lc");
25036       gs_lcap=lcap_val(p);
25037     }
25038
25039 @ @<Set the other numeric parameters as needed for object~|p|@>=
25040 if ( gs_ljoin!=ljoin_val(p) ) {
25041   ps_room(14);
25042   mp_print_char(mp, ' ');
25043   mp_print_char(mp, '0'+ljoin_val(p)); mp_print_cmd(mp, " setlinejoin"," lj");
25044   gs_ljoin=ljoin_val(p);
25045 }
25046 if ( gs_miterlim!=miterlim_val(p) ) {
25047   ps_room(27);
25048   mp_print_char(mp, ' ');
25049   mp_print_scaled(mp, miterlim_val(p)); mp_print_cmd(mp, " setmiterlimit"," ml");
25050   gs_miterlim=miterlim_val(p);
25051 }
25052
25053 @ @<Make sure \ps\ will use the right color for object~|p|@>=
25054 {
25055   if ( (color_model(p)==rgb_model)||
25056      ((color_model(p)==uninitialized_model)&&
25057      ((mp->internal[default_color_model] / unity)==rgb_model)) ) {
25058   if ( (gs_colormodel!=rgb_model)||(gs_red!=red_val(p))||
25059       (gs_green!=green_val(p))||(gs_blue!=blue_val(p)) ) {
25060       gs_red=red_val(p);
25061       gs_green=green_val(p);
25062       gs_blue=blue_val(p);
25063       gs_black= -1;
25064       gs_colormodel=rgb_model;
25065       { ps_room(36);
25066         mp_print_char(mp, ' ');
25067         mp_print_scaled(mp, gs_red); mp_print_char(mp, ' ');
25068         mp_print_scaled(mp, gs_green); mp_print_char(mp, ' ');
25069         mp_print_scaled(mp, gs_blue);
25070         mp_print_cmd(mp, " setrgbcolor", " R");
25071       }
25072     }
25073   } else if ( (color_model(p)==cmyk_model)||
25074      ((color_model(p)==uninitialized_model)&&
25075      ((mp->internal[default_color_model] / unity)==cmyk_model)) ) {
25076    if ( (gs_red!=cyan_val(p))||(gs_green!=magenta_val(p))||
25077       (gs_blue!=yellow_val(p))||(gs_black!=black_val(p))||
25078       (gs_colormodel!=cmyk_model) ) {
25079       if ( color_model(p)==uninitialized_model ) {
25080         gs_red=0;
25081         gs_green=0;
25082         gs_blue=0;
25083         gs_black=unity;
25084       } else {
25085         gs_red=cyan_val(p);
25086         gs_green=magenta_val(p);
25087         gs_blue=yellow_val(p);
25088         gs_black=black_val(p);
25089       }
25090       gs_colormodel=cmyk_model;
25091       { ps_room(45);
25092         mp_print_char(mp, ' ');
25093         mp_print_scaled(mp, gs_red); mp_print_char(mp, ' ');
25094         mp_print_scaled(mp, gs_green); mp_print_char(mp, ' ');
25095         mp_print_scaled(mp, gs_blue); mp_print_char(mp, ' ');
25096         mp_print_scaled(mp, gs_black);
25097         mp_print_cmd(mp, " setcmykcolor"," C");
25098       }
25099     }
25100   } else if ( (color_model(p)==grey_model)||
25101     ((color_model(p)==uninitialized_model)&&
25102      ((mp->internal[default_color_model] / unity)==grey_model)) ) {
25103    if ( (gs_red!=grey_val(p))||(gs_colormodel!=grey_model) ) {
25104       gs_red = grey_val(p);
25105       gs_green= -1;
25106       gs_blue= -1;
25107       gs_black= -1;
25108       gs_colormodel=grey_model;
25109       { ps_room(16);
25110         mp_print_char(mp, ' ');
25111         mp_print_scaled(mp, gs_red);
25112         mp_print_cmd(mp, " setgray"," G");
25113       }
25114     }
25115   }
25116   if ( color_model(p)==no_model )
25117     gs_colormodel=no_model;
25118 }
25119
25120 @ In order to get consistent widths for horizontal and vertical pen strokes, we
25121 want \ps\ to use an integer number of pixels for the \&{setwidth} parameter.
25122 @:setwidth}{\&{setwidth}command@>
25123 We set |gs_width| to the ideal horizontal or vertical stroke width and then
25124 generate \ps\ code that computes the rounded value.  For non-circular pens, the
25125 pen shape will be rescaled so that horizontal or vertical parts of the stroke
25126 have the computed width.
25127
25128 Rounding the width to whole pixels is not likely to improve the appearance of
25129 diagonal or curved strokes, but we do it anyway for consistency.  The
25130 \&{truncate} command generated here tends to make all the strokes a little
25131 @:truncate}{\&{truncate} command@>
25132 thinner, but this is appropriate for \ps's scan-conversion rules.  Even with
25133 truncation, an ideal with of $w$~pixels gets mapped into $\lfloor w\rfloor+1$.
25134 It would be better to have $\lceil w\rceil$ but that is ridiculously expensive
25135 to compute in \ps.
25136
25137 @<Generate \ps\ code that sets the stroke width...@>=
25138 @<Set |wx| and |wy| to the width and height of the bounding box for
25139   |pen_p(p)|@>;
25140 @<Use |pen_p(p)| and |path_p(p)| to decide whether |wx| or |wy| is more
25141   important and set |adj_wx| and |ww| accordingly@>;
25142 if ( (ww!=gs_width) || (adj_wx!=gs_adj_wx) ) {
25143   if ( adj_wx ) {
25144     ps_room(13);
25145     mp_print_char(mp, ' '); mp_print_scaled(mp, ww);
25146     mp_ps_print_cmd(mp, 
25147       " 0 dtransform exch truncate exch idtransform pop setlinewidth"," hlw");
25148   } else {
25149     if ( mp->internal[mpprocset]>0 ) {
25150       ps_room(13);
25151       mp_print_char(mp, ' ');
25152       mp_print_scaled(mp, ww);
25153       mp_ps_print(mp, " vlw");
25154     } else { 
25155       ps_room(15);
25156       mp_print(mp, " 0 "); mp_print_scaled(mp, ww);
25157       mp_ps_print(mp, " dtransform truncate idtransform setlinewidth pop");
25158     }
25159   }
25160   gs_width = ww;
25161   gs_adj_wx = adj_wx;
25162 }
25163
25164 @ @<Set |wx| and |wy| to the width and height of the bounding box for...@>=
25165 pp=pen_p(p);
25166 if ( (right_x(pp)==x_coord(pp)) && (left_y(pp)==y_coord(pp)) ) {
25167   wx = abs(left_x(pp) - x_coord(pp));
25168   wy = abs(right_y(pp) - y_coord(pp));
25169 } else {
25170   wx = mp_pyth_add(mp, left_x(pp)-x_coord(pp), right_x(pp)-x_coord(pp));
25171   wy = mp_pyth_add(mp, left_y(pp)-y_coord(pp), right_y(pp)-y_coord(pp));
25172 }
25173
25174 @ The path is considered ``essentially horizontal'' if its range of
25175 $y$~coordinates is less than the $y$~range |wy| for the pen.  ``Essentially
25176 vertical'' paths are detected similarly.  This code ensures that no component
25177 of the pen transformation is more that |aspect_bound*(ww+1)|.
25178
25179 @d aspect_bound 10 /* ``less important'' of |wx|, |wy| cannot exceed the other by
25180     more than this factor */
25181
25182 @<Use |pen_p(p)| and |path_p(p)| to decide whether |wx| or |wy| is more...@>=
25183 tx=1; ty=1;
25184 if ( mp_coord_rangeOK(mp, path_p(p), y_loc(0), wy) ) tx=aspect_bound;
25185 else if ( mp_coord_rangeOK(mp, path_p(p), x_loc(0), wx) ) ty=aspect_bound;
25186 if ( wy / ty>=wx / tx ) { ww=wy; adj_wx=false; }
25187 else { ww=wx; adj_wx=true;  }
25188
25189 @ This routine quickly tests if path |h| is ``essentially horizontal'' or
25190 ``essentially vertical,'' where |zoff| is |x_loc(0)| or |y_loc(0)| and |dz| is
25191 allowable range for $x$ or~$y$.  We do not need and cannot afford a full
25192 bounding-box computation.
25193
25194 @<Declare subroutines needed by |fix_graphics_state|@>=
25195 boolean mp_coord_rangeOK (MP mp,pointer h, 
25196                           small_number  zoff, scaled dz) {
25197   pointer p; /* for scanning the path form |h| */
25198   scaled zlo,zhi; /* coordinate range so far */
25199   scaled z; /* coordinate currently being tested */
25200   zlo=knot_coord(h+zoff);
25201   zhi=zlo;
25202   p=h;
25203   while ( right_type(p)!=endpoint ) {
25204     z=right_coord(p+zoff);
25205     @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>;
25206     p=link(p);
25207     z=left_coord(p+zoff);
25208     @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>;
25209     z=knot_coord(p+zoff);
25210     @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>;
25211     if ( p==h ) break;
25212   }
25213   return true;
25214 }
25215
25216 @ @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>=
25217 if ( z<zlo ) zlo=z;
25218 else if ( z>zhi ) zhi=z;
25219 if ( zhi-zlo>dz ) return false
25220
25221 @ Filling with an elliptical pen is implemented via a combination of \&{stroke}
25222 and \&{fill} commands and a nontrivial dash pattern would interfere with this.
25223 @:stroke}{\&{stroke} command@>
25224 @:fill}{\&{fill} command@>
25225 Note that we don't use |delete_edge_ref| because |gs_dash_p| is not counted as
25226 a reference.
25227
25228 @<Make sure \ps\ will use the right dash pattern for |dash_p(p)|@>=
25229 if ( type(p)==fill_code ) {
25230   hh=null;
25231 } else { 
25232   hh=dash_p(p);
25233   scf=mp_get_pen_scale(mp, pen_p(p));
25234   if ( scf==0 ) {
25235     if ( gs_width==0 ) scf=dash_scale(p);  else hh=null;
25236   } else { 
25237     scf=mp_make_scaled(mp, gs_width,scf);
25238     scf=mp_take_scaled(mp, scf,dash_scale(p));
25239   }
25240 }
25241 if ( hh==null ) {
25242   if ( gs_dash_p!=null ) {
25243     mp_ps_print_cmd(mp, " [] 0 setdash"," rd");
25244     gs_dash_p=null;
25245   }
25246 } else if ( (gs_dash_sc!=scf) || ! mp_same_dashes(mp, gs_dash_p,hh) ) {
25247   @<Set the dash pattern from |dash_list(hh)| scaled by |scf|@>;
25248 }
25249
25250 @ Translating a dash list into \ps\ is very similar to printing it symbolically
25251 in |print_edges|.  A dash pattern with |dash_y(hh)=0| has length zero and is
25252 ignored.  The same fate applies in the bizarre case of a dash pattern that
25253 cannot be printed without overflow.
25254
25255 @<Set the dash pattern from |dash_list(hh)| scaled by |scf|@>=
25256 { gs_dash_p=hh;
25257   gs_dash_sc=scf;
25258   if ( (dash_y(hh)==0) || (abs(dash_y(hh)) / unity >= el_gordo / scf)){
25259     mp_ps_print_cmd(mp, " [] 0 setdash"," rd");
25260   } else { 
25261     pp=dash_list(hh);
25262     start_x(null_dash)=start_x(pp)+dash_y(hh);
25263     ps_room(28);
25264     mp_print(mp, " [");
25265     while ( pp!=null_dash ) {
25266       mp_ps_pair_out(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf),
25267                          mp_take_scaled(mp, start_x(link(pp))-stop_x(pp),scf));
25268       pp=link(pp);
25269     }
25270     ps_room(22);
25271     mp_print(mp, "] ");
25272     mp_print_scaled(mp, mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
25273     mp_print_cmd(mp, " setdash"," sd");
25274   }
25275 }
25276
25277 @ @<Declare subroutines needed by |fix_graphics_state|@>=
25278 boolean mp_same_dashes (MP mp,pointer h, pointer hh) ;
25279
25280 @ @c
25281 boolean mp_same_dashes (MP mp,pointer h, pointer hh) {
25282   /* do |h| and |hh| represent the same dash pattern? */
25283   pointer p,pp; /* dash nodes being compared */
25284   if ( h==hh ) return true;
25285   else if ( (h<=diov)||(hh<=diov) ) return false;
25286   else if ( dash_y(h)!=dash_y(hh) ) return false;
25287   else { @<Compare |dash_list(h)| and |dash_list(hh)|@>; }
25288   return false; /* can't happen */
25289 }
25290
25291 @ @<Compare |dash_list(h)| and |dash_list(hh)|@>=
25292 { p=dash_list(h);
25293   pp=dash_list(hh);
25294   while ( (p!=null_dash)&&(pp!=null_dash) ) {
25295     if ( (start_x(p)!=start_x(pp))||(stop_x(p)!=stop_x(pp)) ) {
25296       break;
25297     } else { 
25298       p=link(p);
25299       pp=link(pp);
25300     }
25301   }
25302   return (p==pp);
25303 }
25304
25305 @ When stroking a path with an elliptical pen, it is necessary to transform
25306 the coordinate system so that a unit circular pen will have the desired shape.
25307 To keep this transformation local, we enclose it in a
25308 $$\&{gsave}\ldots\&{grestore}$$
25309 block. Any translation component must be applied to the path being stroked
25310 while the rest of the transformation must apply only to the pen.
25311 If |fill_also=true|, the path is to be filled as well as stroked so we must
25312 insert commands to do this after giving the path.
25313
25314 @<Declare the \ps\ output procedures@>=
25315 void mp_stroke_ellipse (MP mp,pointer h, boolean fill_also) ;
25316
25317
25318 @c void mp_stroke_ellipse (MP mp,pointer h, boolean fill_also) {
25319   /* generate an elliptical pen stroke from object |h| */
25320   scaled txx,txy,tyx,tyy; /* transformation parameters */
25321   pointer p; /* the pen to stroke with */
25322   scaled d1,det; /* for tweaking transformation parameters */
25323   integer s; /* also for tweaking transformation paramters */
25324   boolean transformed; /* keeps track of whether gsave/grestore are needed */
25325   transformed=false;
25326   @<Use |pen_p(h)| to set the transformation parameters and give the initial
25327     translation@>;
25328   @<Tweak the transformation parameters so the transformation is nonsingular@>;
25329   mp_ps_path_out(mp, path_p(h));
25330   if ( mp->internal[mpprocset]==0 ) {
25331     if ( fill_also ) mp_print_nl(mp, "gsave fill grestore");
25332     @<Issue \ps\ commands to transform the coordinate system@>;
25333     mp_ps_print(mp, " stroke");
25334     if ( transformed ) mp_ps_print(mp, " grestore");
25335   } else {
25336     if ( fill_also ) mp_print_nl(mp, "B"); else mp_print_ln(mp);
25337     if ( (txy!=0)||(tyx!=0) ) {
25338       mp_print(mp, " [");
25339       mp_ps_pair_out(mp, txx,tyx);
25340       mp_ps_pair_out(mp, txy,tyy);
25341       mp_ps_print(mp, "0 0] t");
25342     } else if ((txx!=unity)||(tyy!=unity) )  {
25343       mp_ps_pair_out(mp,txx,tyy);
25344       mp_print(mp, " s");
25345     };
25346     mp_ps_print(mp, " S");
25347     if ( transformed ) mp_ps_print(mp, " Q");
25348   }
25349   mp_print_ln(mp);
25350 }
25351
25352 @ @<Use |pen_p(h)| to set the transformation parameters and give the...@>=
25353 p=pen_p(h);
25354 txx=left_x(p);
25355 tyx=left_y(p);
25356 txy=right_x(p);
25357 tyy=right_y(p);
25358 if ( (x_coord(p)!=0)||(y_coord(p)!=0) ) {
25359   mp_print_nl(mp, ""); mp_print_cmd(mp, "gsave ","q ");
25360   mp_ps_pair_out(mp, x_coord(p),y_coord(p));
25361   mp_ps_print(mp, "translate ");
25362   txx-=x_coord(p);
25363   tyx-=y_coord(p);
25364   txy-=x_coord(p);
25365   tyy-=y_coord(p);
25366   transformed=true;
25367 } else {
25368   mp_print_nl(mp, "");
25369 }
25370 @<Adjust the transformation to account for |gs_width| and output the
25371   initial \&{gsave} if |transformed| should be |true|@>
25372
25373 @ @<Adjust the transformation to account for |gs_width| and output the...@>=
25374 if ( gs_width!=unity ) {
25375   if ( gs_width==0 ) { 
25376     txx=unity; tyy=unity;
25377   } else { 
25378     txx=mp_make_scaled(mp, txx,gs_width);
25379     txy=mp_make_scaled(mp, txy,gs_width);
25380     tyx=mp_make_scaled(mp, tyx,gs_width);
25381     tyy=mp_make_scaled(mp, tyy,gs_width);
25382   };
25383 }
25384 if ( (txy!=0)||(tyx!=0)||(txx!=unity)||(tyy!=unity) ) {
25385   if ( (! transformed) ){ 
25386     mp_ps_print_cmd(mp, "gsave ","q ");
25387     transformed=true;
25388   }
25389 }
25390
25391 @ @<Issue \ps\ commands to transform the coordinate system@>=
25392 if ( (txy!=0)||(tyx!=0) ){ 
25393   mp_print_ln(mp);
25394   mp_print_char(mp, '[');
25395   mp_ps_pair_out(mp, txx,tyx);
25396   mp_ps_pair_out(mp, txy,tyy);
25397   mp_ps_print(mp, "0 0] concat");
25398 } else if ( (txx!=unity)||(tyy!=unity) ){ 
25399   mp_print_ln(mp);
25400   mp_ps_pair_out(mp, txx,tyy);
25401   mp_print(mp, "scale");
25402 }
25403
25404 @ The \ps\ interpreter will probably abort if it encounters a singular
25405 transformation matrix.  The determinant must be large enough to ensure that
25406 the printed representation will be nonsingular.  Since the printed
25407 representation is always within $2^{-17}$ of the internal |scaled| value, the
25408 total error is at most $4T_{\rm max}2^{-17}$, where $T_{\rm max}$ is a bound on
25409 the magnitudes of |txx/65536|, |txy/65536|, etc.
25410
25411 The |aspect_bound*(gs_width+1)| bound on the components of the pen
25412 transformation allows $T_{\rm max}$ to be at most |2*aspect_bound|.
25413
25414 @<Tweak the transformation parameters so the transformation is nonsingular@>=
25415 det=mp_take_scaled(mp, txx,tyy) - mp_take_scaled(mp, txy,tyx);
25416 d1=4*aspect_bound+1;
25417 if ( abs(det)<d1 ) { 
25418   if ( det>=0 ) { d1=d1-det; s=1;  }
25419   else { d1=-d1-det; s=-1;  };
25420   d1=d1*unity;
25421   if ( abs(txx)+abs(tyy)>=abs(txy)+abs(tyy) ) {
25422     if ( abs(txx)>abs(tyy) ) tyy=tyy+(d1+s*abs(txx)) / txx;
25423     else txx=txx+(d1+s*abs(tyy)) / tyy;
25424   } else {
25425     if ( abs(txy)>abs(tyx) ) tyx=tyx+(d1+s*abs(txy)) / txy;
25426     else txy=txy+(d1+s*abs(tyx)) / tyx;
25427   }
25428 }
25429
25430 @ Here is a simple routine that just fills a cycle.
25431
25432 @<Declare the \ps\ output procedures@>=
25433 void mp_ps_fill_out (MP mp,pointer p) ;
25434
25435 @ @c
25436 void mp_ps_fill_out (MP mp,pointer p) { /* fill cyclic path~|p| */
25437   mp_ps_path_out(mp, p);
25438   mp_ps_print_cmd(mp, " fill"," F");
25439   mp_print_ln(mp);
25440 }
25441
25442 @ Given a cyclic path~|p| and a graphical object~|h|, the |do_outer_envelope|
25443 procedure fills the cycle generated by |make_envelope|.  It need not do
25444 anything unless some region has positive winding number with respect to~|p|,
25445 but it does not seem worthwhile to for test this.
25446
25447 @<Declare the \ps\ output procedures@>=
25448 void mp_do_outer_envelope (MP mp,pointer p, pointer h) ;
25449
25450 @ @c
25451 void mp_do_outer_envelope (MP mp,pointer p, pointer h) {
25452   p=mp_make_envelope(mp, p, pen_p(h), ljoin_val(h), 0, miterlim_val(h));
25453   mp_ps_fill_out(mp, p);
25454   mp_toss_knot_list(mp, p);
25455 }
25456
25457 @ A text node may specify an arbitrary transformation but the usual case
25458 involves only shifting, scaling, and occasionally rotation.  The purpose
25459 of |choose_scale| is to select a scale factor so that the remaining
25460 transformation is as ``nice'' as possible.  The definition of ``nice''
25461 is somewhat arbitrary but shifting and $90^\circ$ rotation are especially
25462 nice because they work out well for bitmap fonts.  The code here selects
25463 a scale factor equal to $1/\sqrt2$ times the Frobenius norm of the
25464 non-shifting part of the transformation matrix.  It is careful to avoid
25465 additions that might cause undetected overflow.
25466
25467 @<Declare the \ps\ output procedures@>=
25468 scaled mp_choose_scale (MP mp,pointer p) ;
25469
25470 @ @c scaled mp_choose_scale (MP mp,pointer p) {
25471   /* |p| should point to a text node */
25472   scaled a,b,c,d,ad,bc; /* temporary values */
25473   a=txx_val(p);
25474   b=txy_val(p);
25475   c=tyx_val(p);
25476   d=tyy_val(p);
25477   if ( (a<0) ) negate(a);
25478   if ( (b<0) ) negate(b);
25479   if ( (c<0) ) negate(c);
25480   if ( (d<0) ) negate(d);
25481   ad=half(a-d);
25482   bc=half(b-c);
25483   return mp_pyth_add(mp, mp_pyth_add(mp, d+ad,ad), mp_pyth_add(mp, c+bc,bc));
25484 }
25485
25486 @ @<Declare the \ps\ output procedures@>=
25487 void mp_ps_string_out (MP mp, char *s) {
25488   char *i; /* current character code position */
25489   ASCII_code k; /* bits to be converted to octal */
25490   mp_print(mp, "(");
25491   i=s;
25492   while (*i) {
25493     if ( mp->ps_offset+5>mp->max_print_line ) {
25494       mp_print_char(mp, '\\');
25495       mp_print_ln(mp);
25496     }
25497     k=*i;
25498     if ( (@<Character |k| is not allowed in PostScript output@>) ) {
25499       mp_print_char(mp, '\\');
25500       mp_print_char(mp, '0'+(k / 64));
25501       mp_print_char(mp, '0'+((k / 8) % 8));
25502       mp_print_char(mp, '0'+(k % 8));
25503     } else { 
25504       if ( (k=='(')||(k==')')||(k=='\\') ) mp_print_char(mp, '\\');
25505       mp_print_char(mp, k);
25506     }
25507     incr(i);
25508   }
25509   mp_print_char(mp, ')');
25510 }
25511
25512
25513 @d mp_is_ps_name(M,A) mp_do_is_ps_name(A)
25514
25515 @<Declare the \ps\ output procedures@>=
25516 boolean mp_do_is_ps_name (char *s) {
25517   char *i; /* current character code position */
25518   ASCII_code k; /* the character being checked */
25519   i=s;
25520   while (*i) {
25521     k=*i;
25522     if ( (k<=' ')||(k>'~') ) return false;
25523     if ( (k=='(')||(k==')')||(k=='<')||(k=='>')||
25524        (k=='{')||(k=='}')||(k=='/')||(k=='%') ) return false;
25525     incr(i);
25526   }
25527   return true;
25528 }
25529
25530 @ @<Exported...@>=
25531 void mp_ps_name_out (MP mp, char *s, boolean lit) ;
25532
25533 @ @c
25534 void mp_ps_name_out (MP mp, char *s, boolean lit) {
25535   ps_room(strlen(s)+2);
25536   mp_print_char(mp, ' ');
25537   if ( mp_is_ps_name(mp, s) ) {
25538     if ( lit ) mp_print_char(mp, '/');
25539       mp_print(mp, s);
25540   } else { 
25541     mp_ps_string_out(mp, s);
25542     if ( ! lit ) mp_ps_print(mp, "cvx ");
25543       mp_ps_print(mp, "cvn");
25544   }
25545 }
25546
25547 @ @<Declare the \ps\ output procedures@>= 
25548 void mp_mark_string_chars (MP mp,font_number f, str_number s) ;
25549
25550 @ @c
25551 void mp_mark_string_chars (MP mp,font_number f, str_number s) {
25552   integer b; /* |char_base[f]| */
25553   ASCII_code bc,ec; /* only characters between these bounds are marked */
25554   pool_pointer k; /* an index into string |s| */
25555   b=mp->char_base[f];
25556   bc=mp->font_bc[f];
25557   ec=mp->font_ec[f];
25558   k=str_stop(s);
25559   while ( k>mp->str_start[s] ){ 
25560     decr(k);
25561     if ( (mp->str_pool[k]>=bc)&&(mp->str_pool[k]<=ec) )
25562       mp->font_info[b+mp->str_pool[k]].qqqq.b3=used;
25563   }
25564 }
25565
25566 @ There may be many sizes of one font and we need to keep track of the
25567 characters used for each size.  This is done by keeping a linked list of
25568 sizes for each font with a counter in each text node giving the appropriate
25569 position in the size list for its font.
25570
25571 @d sc_factor(A) mp->mem[(A)+1].sc /* the scale factor stored in a font size node */
25572 @d font_size_size 2 /* size of a font size node */
25573
25574 @ @<Exported...@>=
25575 boolean mp_has_font_size(MP mp, font_number f );
25576
25577 @ @c 
25578 boolean mp_has_font_size(MP mp, font_number f ) {
25579   return (mp->font_sizes[f]!=null);
25580 }
25581
25582
25583 @ The overflow here is caused by the fact the returned value
25584 has to fit in a |name_type|, which is a quarterword. 
25585
25586 @d fscale_tolerance 65 /* that's $.001\times2^{16}$ */
25587
25588 @<Declare the \ps\ output procedures@>=
25589 quarterword mp_size_index (MP mp, font_number f, scaled s) {
25590   pointer p,q; /* the previous and current font size nodes */
25591   quarterword i; /* the size index for |q| */
25592   q=mp->font_sizes[f];
25593   i=0;
25594   while ( q!=null ) {
25595     if ( abs(s-sc_factor(q))<=fscale_tolerance ) 
25596       return i;
25597     else 
25598       { p=q; q=link(q); incr(i); };
25599     if ( i==max_quarterword )
25600       mp_overflow(mp, "sizes per font",max_quarterword);
25601 @:MetaPost capacity exceeded sizes per font}{\quad sizes per font@>
25602   }
25603   q=mp_get_node(mp, font_size_size);
25604   sc_factor(q)=s;
25605   if ( i==0 ) mp->font_sizes[f]=q;  else link(p)=q;
25606   return i;
25607 }
25608
25609 @ @<Declare the \ps\ output procedures@>=
25610 scaled mp_indexed_size (MP mp,font_number f, quarterword j) {
25611   pointer p; /* a font size node */
25612   quarterword i; /* the size index for |p| */
25613   p=mp->font_sizes[f];
25614   i=0;
25615   if ( p==null ) mp_confusion(mp, "size");
25616   while ( (i!=j) ) { 
25617     incr(i); p=link(p);
25618     if ( p==null ) mp_confusion(mp, "size");
25619   }
25620   return sc_factor(p);
25621 }
25622
25623 @ @<Declare the \ps\ output procedures@>=
25624 void mp_clear_sizes (MP mp) ;
25625
25626 @ @c void mp_clear_sizes (MP mp) {
25627   font_number f;  /* the font whose size list is being cleared */
25628   pointer p;  /* current font size nodes */
25629   for (f=null_font+1;f<=mp->last_fnum;f++) {
25630     while ( mp->font_sizes[f]!=null ) {
25631       p=mp->font_sizes[f];
25632       mp->font_sizes[f]=link(p);
25633       mp_free_node(mp, p,font_size_size);
25634     }
25635   }
25636 }
25637
25638 @ The \&{special} command saves up lines of text to be printed during the next
25639 |ship_out| operation.  The saved items are stored as a list of capsule tokens.
25640
25641 @<Glob...@>=
25642 pointer last_pending; /* the last token in a list of pending specials */
25643
25644 @ @<Set init...@>=
25645 mp->last_pending=spec_head;
25646
25647 @ @<Cases of |do_statement|...@>=
25648 case special_command: 
25649   if ( mp->cur_mod==0 ) mp_do_special(mp); else 
25650   if ( mp->cur_mod==1 ) mp_do_mapfile(mp); else 
25651   mp_do_mapline(mp);
25652   break;
25653
25654 @ @<Declare action procedures for use by |do_statement|@>=
25655 void mp_do_special (MP mp) ;
25656
25657 @ @c void mp_do_special (MP mp) { 
25658   mp_get_x_next(mp); mp_scan_expression(mp);
25659   if ( mp->cur_type!=mp_string_type ) {
25660     @<Complain about improper special operation@>;
25661   } else { 
25662     link(mp->last_pending)=mp_stash_cur_exp(mp);
25663     mp->last_pending=link(mp->last_pending);
25664     link(mp->last_pending)=null;
25665   }
25666 }
25667
25668 @ @<Complain about improper special operation@>=
25669
25670   exp_err("Unsuitable expression");
25671   help1("Only known strings are allowed for output as specials.");
25672   mp_put_get_error(mp);
25673 }
25674
25675 @ @<Print any pending specials@>=
25676 t=link(spec_head);
25677 while ( t!=null ) {
25678   mp_print_str(mp, value(t));
25679   mp_print_ln(mp);
25680   t=link(t);
25681 }
25682 mp_flush_token_list(mp, link(spec_head));
25683 link(spec_head)=null;
25684 mp->last_pending=spec_head
25685
25686 @ We are now ready for the main output procedure.  Note that the |selector|
25687 setting is saved in a global variable so that |begin_diagnostic| can access it.
25688
25689 @<Declare the \ps\ output procedures@>=
25690 void mp_ship_out (MP mp, pointer h) ;
25691
25692 @ @c
25693 void mp_ship_out (MP mp, pointer h) { /* output edge structure |h| */
25694   pointer p; /* the current graphical object */
25695   pointer q; /* something that |p| points to */
25696   integer t; /* a temporary value */
25697   font_number f; /* fonts used in a text node or as loop counters */
25698   font_number ldf;
25699   scaled ds,scf; /* design size and scale factor for a text node */
25700   boolean transformed; /* is the coordinate system being transformed? */
25701   mp_open_output_file(mp);
25702   mp->non_ps_setting=mp->selector; mp->selector=ps_file_only;
25703   if ( (mp->internal[prologues]==two)||(mp->internal[prologues]==three) ) {
25704     @<Print improved initial comment and bounding box for edge structure~|h|@>;
25705     @<Scan all the text nodes and mark the used characters@>;
25706     mp_load_encodings(mp,mp->last_fnum);
25707     @<Update encoding names@>;
25708     @<Print the improved prologue and setup@>;
25709     @<Print any pending specials@>;
25710     mp_unknown_graphics_state(mp, 0);
25711     mp->need_newpath=true;
25712     p=link(dummy_loc(h));
25713     while ( p!=null ) { 
25714       if ( has_color(p) ) {
25715         if ( (pre_script(p))!=null ) {
25716           mp_print_nl (mp, str(pre_script(p))); mp_print_ln(mp);
25717         }
25718       }
25719       mp_fix_graphics_state(mp, p);
25720       switch (type(p)) {
25721       @<Cases for translating graphical object~|p| into \ps@>;
25722       case mp_start_bounds_code:
25723       case mp_stop_bounds_code:
25724             break;
25725       } /* all cases are enumerated */
25726       p=link(p);
25727     }
25728     mp_print_cmd(mp, "showpage","P"); mp_print_ln(mp);
25729     mp_print(mp, "%%EOF"); mp_print_ln(mp);
25730     fclose(mp->ps_file);
25731     mp->selector=mp->non_ps_setting;
25732     if ( mp->internal[prologues]<=0 ) mp_clear_sizes(mp);
25733     @<End progress report@>;
25734   } else {
25735     @<Print the initial comment and give the bounding box for edge structure~|h|@>;
25736     if ( (mp->internal[prologues]>0) && (mp->last_ps_fnum<mp->last_fnum) )
25737       mp_read_psname_table(mp);
25738     mp_print_prologue(mp, (mp->internal[prologues]>>16), (mp->internal[mpprocset]>>16), ldf);
25739     mp_print_nl(mp, "%%Page: 1 1"); mp_print_ln(mp);
25740     @<Print any pending specials@>;
25741     mp_unknown_graphics_state(mp, 0);
25742     mp->need_newpath=true;
25743     p=link(dummy_loc(h));
25744     while ( p!=null ) { 
25745       if ( has_color(p) ) {
25746         if ( (pre_script(p))!=null ) {
25747           mp_print_nl (mp, str(pre_script(p))); mp_print_ln(mp);
25748         }
25749       }
25750       mp_fix_graphics_state(mp, p);
25751       switch (type(p)) {
25752       @<Cases for translating graphical object~|p| into \ps@>;
25753       case mp_start_bounds_code:
25754       case mp_stop_bounds_code: 
25755         break;
25756       } /* all cases are enumerated */
25757       p=link(p);
25758     }
25759     mp_print_cmd(mp, "showpage","P"); mp_print_ln(mp);
25760     mp_print(mp, "%%EOF"); mp_print_ln(mp);
25761     fclose(mp->ps_file);
25762     mp->selector=mp->non_ps_setting;
25763     if ( mp->internal[prologues]<=0 ) mp_clear_sizes(mp);
25764     @<End progress report@>;
25765   }
25766   if ( mp->internal[tracing_output]>0 ) 
25767    mp_print_edges(mp, h," (just shipped out)",true);
25768 }
25769
25770 @ @<Exported...@>=
25771 void mp_apply_mark_string_chars(MP mp, pointer h, int next_size);
25772
25773 @ @c
25774 void mp_apply_mark_string_chars(MP mp, pointer h, int next_size) {
25775   pointer p;
25776   p=link(dummy_loc(h));
25777   while ( p!=null ) {
25778     if ( type(p)==text_code )
25779       if ( font_n(p)!=null_font )
25780         if ( name_type(p)==next_size )
25781           mp_mark_string_chars(mp, font_n(p),text_p(p));
25782     p=link(p);
25783   }
25784 }
25785
25786 @
25787 @<Print the improved prologue and setup@>=
25788 {
25789   mp_print_improved_prologue(mp, (mp->internal[prologues]>>16),(mp->internal[mpprocset]>>16),
25790                             (mp->internal[gtroffmode]>>16), null, h);
25791 }
25792
25793 @
25794 @<Print improved initial comment and bounding box for edge...@>=
25795 mp_print(mp, "%!PS-Adobe-3.0 EPSF-3.0");
25796 mp_print_nl(mp, "%%BoundingBox: ");
25797 mp_set_bbox(mp, h,true);
25798 if ( minx_val(h)>maxx_val(h) ) {
25799   mp_print(mp, "0 0 0 0");
25800 } else { 
25801   mp_ps_pair_out(mp, mp_floor_scaled(mp, minx_val(h)),mp_floor_scaled(mp, miny_val(h)));
25802   mp_ps_pair_out(mp, -mp_floor_scaled(mp, -maxx_val(h)),-mp_floor_scaled(mp, -maxy_val(h)));
25803 };
25804 mp_print_nl(mp, "%%HiResBoundingBox: ");
25805 if ( minx_val(h)>maxx_val(h) ) {
25806   mp_print(mp, "0 0 0 0");
25807 } else {
25808   mp_ps_pair_out(mp, minx_val(h),miny_val(h));
25809   mp_ps_pair_out(mp, maxx_val(h),maxy_val(h));
25810 }
25811 mp_print_nl(mp, "%%Creator: MetaPost ");
25812 mp_print(mp, metapost_version);
25813 mp_print_nl(mp, "%%CreationDate: ");
25814 mp_print_int(mp, mp_round_unscaled(mp, mp->internal[year])); mp_print_char(mp, '.');
25815 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[month])); mp_print_char(mp, '.');
25816 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[day])); mp_print_char(mp, ':');
25817 t=mp_round_unscaled(mp, mp->internal[mp_time]);
25818 mp_print_dd(mp, t / 60); mp_print_dd(mp, t % 60);
25819 mp_print_nl(mp, "%%Pages: 1");
25820
25821 @
25822
25823 @ @<Scan all the text nodes and mark the used ...@>=
25824 for (f=null_font+1;f<=mp->last_fnum;f++) {
25825   if ( mp->font_sizes[f]!=null ) {
25826     mp_unmark_font(mp, f);
25827     mp->font_sizes[f]=null;
25828   }
25829   if ( mp->font_enc_name[f]!=NULL )
25830      xfree(mp->font_enc_name[f]);
25831   mp->font_enc_name[f] = NULL;
25832 }
25833 for (f=null_font+1;f<=mp->last_fnum;f++) {
25834   p=link(dummy_loc(h));
25835   while ( p!=null ) {
25836     if ( type(p)==text_code ) {
25837       if ( font_n(p)!=null_font ) {
25838         mp->font_sizes[font_n(p)] = diov;
25839         mp_mark_string_chars(mp, font_n(p),text_p(p));
25840             if ( mp_has_fm_entry(mp,font_n(p),NULL) )
25841           mp->font_ps_name[font_n(p)] = mp_fm_font_name(mp,font_n(p));
25842       }
25843     }
25844     p=link(p);
25845   }
25846 }
25847
25848 @ @<Update encoding names@>=
25849 for (f=null_font+1;f<=mp->last_fnum;f++) {
25850   p=link(dummy_loc(h));
25851   while ( p!=null ) {
25852     if ( type(p)==text_code )
25853       if ( font_n(p)!=null_font )
25854             if ( mp_has_fm_entry(mp,font_n(p),NULL) )
25855           if ( mp->font_enc_name[font_n(p)]==NULL )
25856             mp->font_enc_name[font_n(p)] = mp_fm_encoding_name(mp,font_n(p));
25857     p=link(p);
25858   }
25859 }
25860
25861 @ These special comments described in the {\sl PostScript Language Reference
25862 Manual}, 2nd.~edition are understood by some \ps-reading programs.
25863 We can't normally output ``conforming'' \ps\ because
25864 the structuring conventions don't allow us to say ``Please make sure the
25865 following characters are downloaded and define the \.{fshow} macro to access
25866 them.''
25867
25868 The exact bounding box is written out if |prologues<0|, although this
25869 is not standard \ps, since it allows \TeX\ to calculate the box dimensions
25870 accurately. (Overfull boxes are avoided if an illustration is made to
25871 match a given \.{\char`\\hsize}.)
25872
25873 @<Print the initial comment and give the bounding box for edge...@>=
25874 mp_print(mp, "%!PS");
25875 if ( mp->internal[prologues]>0 ) mp_print(mp, "-Adobe-3.0 EPSF-3.0");
25876 mp_print_nl(mp, "%%BoundingBox: ");
25877 mp_set_bbox(mp, h,true);
25878 if ( minx_val(h)>maxx_val(h) ) mp_print(mp, "0 0 0 0");
25879 else if ( mp->internal[prologues]<0 ) {
25880   mp_ps_pair_out(mp, minx_val(h),miny_val(h));
25881   mp_ps_pair_out(mp, maxx_val(h),maxy_val(h));
25882 } else { 
25883   mp_ps_pair_out(mp, mp_floor_scaled(mp, minx_val(h)),mp_floor_scaled(mp, miny_val(h)));
25884   mp_ps_pair_out(mp, -mp_floor_scaled(mp, -maxx_val(h)),-mp_floor_scaled(mp, -maxy_val(h)));
25885 }
25886 mp_print_nl(mp, "%%HiResBoundingBox: ");
25887 if ( minx_val(h)>maxx_val(h) ) mp_print(mp, "0 0 0 0");
25888 else {
25889   mp_ps_pair_out(mp, minx_val(h),miny_val(h));
25890   mp_ps_pair_out(mp, maxx_val(h),maxy_val(h));
25891 }
25892 mp_print_nl(mp, "%%Creator: MetaPost ");
25893 mp_print(mp, metapost_version);
25894 mp_print_nl(mp, "%%CreationDate: ");
25895 mp_print_int(mp, mp_round_unscaled(mp, mp->internal[year])); mp_print_char(mp, '.');
25896 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[month])); mp_print_char(mp, '.');
25897 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[day])); mp_print_char(mp, ':');
25898 t=mp_round_unscaled(mp, mp->internal[mp_time]);
25899 mp_print_dd(mp, t / 60); mp_print_dd(mp, t % 60);
25900 mp_print_nl(mp, "%%Pages: 1");
25901 @<List all the fonts and magnifications for edge structure~|h|@>;
25902 mp_print_ln(mp)
25903
25904 @ @<List all the fonts and magnifications for edge structure~|h|@>=
25905 @<Scan all the text nodes and set the |font_sizes| lists;
25906   if |internal[prologues]<=0| list the sizes selected by |choose_scale|,
25907   apply |unmark_font| to each font encountered, and call |mark_string|
25908   whenever the size index is zero@>;
25909 ldf = mp_print_font_comments (mp, (mp->internal[prologues]>>16), null, h)
25910
25911 @ @<Scan all the text nodes and set the |font_sizes| lists;...@>=
25912 for (f=null_font+1;f<=mp->last_fnum;f++) 
25913   mp->font_sizes[f]=null;
25914 p=link(dummy_loc(h));
25915 while ( p!=null ) {
25916   if ( type(p)==text_code ) {
25917     if ( font_n(p)!=null_font ) {
25918       f=font_n(p);
25919       if ( mp->internal[prologues]>0 ) {
25920         mp->font_sizes[f]=diov;
25921       } else { 
25922         if ( mp->font_sizes[f]==null ) mp_unmark_font(mp, f);
25923         name_type(p)=mp_size_index(mp, f,mp_choose_scale(mp, p));
25924         if ( name_type(p)==0 )
25925           mp_mark_string_chars(mp, f,text_p(p));
25926       }
25927     }
25928   }
25929   p=link(p);
25930 }
25931
25932 @ @<Cases for translating graphical object~|p| into \ps@>=
25933 case mp_start_clip_code: 
25934   mp_print_nl(mp, ""); mp_print_cmd(mp, "gsave ","q ");
25935   mp_ps_path_out(mp, path_p(p));
25936   mp_ps_print_cmd(mp, " clip"," W");
25937   mp_print_ln(mp);
25938   if ( mp->internal[restore_clip_color]>0 )
25939     mp_unknown_graphics_state(mp, 1);
25940   break;
25941 case mp_stop_clip_code: 
25942   mp_print_nl(mp, ""); mp_print_cmd(mp, "grestore","Q");
25943   mp_print_ln(mp);
25944   if ( mp->internal[restore_clip_color]>0 )
25945     mp_unknown_graphics_state(mp, 2);
25946   else
25947     mp_unknown_graphics_state(mp, -1);
25948   break;
25949
25950 @ @<Cases for translating graphical object~|p| into \ps@>=
25951 case fill_code: 
25952   if ( pen_p(p)==null ) mp_ps_fill_out(mp, path_p(p));
25953   else if ( pen_is_elliptical(pen_p(p)) ) mp_stroke_ellipse(mp, p,true);
25954   else { 
25955     mp_do_outer_envelope(mp, mp_copy_path(mp, path_p(p)), p);
25956     mp_do_outer_envelope(mp, mp_htap_ypoc(mp, path_p(p)), p);
25957   }
25958   if ( (post_script(p))!=null ) {
25959     mp_print_nl (mp, str(post_script(p))); mp_print_ln(mp);
25960   };
25961   break;
25962 case stroked_code:
25963   if ( pen_is_elliptical(pen_p(p)) ) mp_stroke_ellipse(mp, p,false);
25964   else { 
25965     q=mp_copy_path(mp, path_p(p));
25966     t=lcap_val(p);
25967     @<Break the cycle and set |t:=1| if path |q| is cyclic@>;
25968     q=mp_make_envelope(mp, q,pen_p(p),ljoin_val(p),t,miterlim_val(p));
25969     mp_ps_fill_out(mp, q);
25970     mp_toss_knot_list(mp, q);
25971   };
25972   if ( (post_script(p))!=null ) {
25973     mp_print_nl (mp, str(post_script(p))); mp_print_ln(mp);
25974   };
25975   break;
25976
25977 @ The envelope of a cyclic path~|q| could be computed by calling
25978 |make_envelope| once for |q| and once for its reversal.  We don't do this
25979 because it would fail color regions that are covered by the pen regardless
25980 of where it is placed on~|q|.
25981
25982 @<Break the cycle and set |t:=1| if path |q| is cyclic@>=
25983 if ( left_type(q)!=endpoint ) { 
25984   left_type(mp_insert_knot(mp, q,x_coord(q),y_coord(q)))=endpoint;
25985   right_type(q)=endpoint;
25986   q=link(q);
25987   t=1;
25988 }
25989
25990 @ @<Cases for translating graphical object~|p| into \ps@>=
25991 case text_code: 
25992   if ( (font_n(p)!=null_font) && (length(text_p(p))>0) ) {
25993     if ( mp->internal[prologues]>0 )
25994       scf=mp_choose_scale(mp, p);
25995     else 
25996       scf=mp_indexed_size(mp, font_n(p), name_type(p));
25997     @<Shift or transform as necessary before outputting text node~|p| at scale
25998       factor~|scf|; set |transformed:=true| if the original transformation must
25999       be restored@>;
26000     mp_ps_string_out(mp, str(text_p(p)));
26001     mp_ps_name_out(mp, mp->font_name[font_n(p)],false);
26002     @<Print the size information and \ps\ commands for text node~|p|@>;
26003     mp_print_ln(mp);
26004   }
26005   if ( (post_script(p))!=null ) {
26006     mp_print_nl (mp, str(post_script(p))); mp_print_ln(mp);
26007   }
26008   break;
26009
26010 @ @<Print the size information and \ps\ commands for text node~|p|@>=
26011 ps_room(18);
26012 mp_print_char(mp, ' ');
26013 ds=(mp->font_dsize[font_n(p)]+8) / 16;
26014 mp_print_scaled(mp, mp_take_scaled(mp, ds,scf));
26015 mp_print(mp, " fshow");
26016 if ( transformed ) 
26017   mp_ps_print_cmd(mp, " grestore"," Q")
26018
26019 @ @<Shift or transform as necessary before outputting text node~|p| at...@>=
26020 transformed=(txx_val(p)!=scf)||(tyy_val(p)!=scf)||
26021             (txy_val(p)!=0)||(tyx_val(p)!=0);
26022 if ( transformed ) {
26023   mp_print_cmd(mp, "gsave [", "q [");
26024   mp_ps_pair_out(mp, mp_make_scaled(mp, txx_val(p),scf),
26025                      mp_make_scaled(mp, tyx_val(p),scf));
26026   mp_ps_pair_out(mp, mp_make_scaled(mp, txy_val(p),scf),
26027                      mp_make_scaled(mp, tyy_val(p),scf));
26028   mp_ps_pair_out(mp, tx_val(p),ty_val(p));
26029   mp_ps_print_cmd(mp, "] concat 0 0 moveto","] t 0 0 m");
26030 } else { 
26031   mp_ps_pair_out(mp, tx_val(p),ty_val(p));
26032   mp_ps_print_cmd(mp, "moveto","m");
26033 }
26034 mp_print_ln(mp)
26035
26036 @ Now that we've finished |ship_out|, let's look at the other commands
26037 by which a user can send things to the \.{GF} file.
26038
26039 @ @<Determine if a character has been shipped out@>=
26040
26041   mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256;
26042   if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
26043   boolean_reset(mp->char_exists[mp->cur_exp]);
26044   mp->cur_type=mp_boolean_type;
26045 }
26046
26047 @ @<Glob...@>=
26048 psout_data ps;
26049
26050 @ @<Allocate or initialize ...@>=
26051 mp_backend_initialize(mp);
26052
26053 @ @<Dealloc...@>=
26054 mp_backend_free(mp);
26055
26056
26057 @* \[45] Dumping and undumping the tables.
26058 After \.{INIMP} has seen a collection of macros, it
26059 can write all the necessary information on an auxiliary file so
26060 that production versions of \MP\ are able to initialize their
26061 memory at high speed. The present section of the program takes
26062 care of such output and input. We shall consider simultaneously
26063 the processes of storing and restoring,
26064 so that the inverse relation between them is clear.
26065 @.INIMP@>
26066
26067 The global variable |mem_ident| is a string that is printed right
26068 after the |banner| line when \MP\ is ready to start. For \.{INIMP} this
26069 string says simply `\.{(INIMP)}'; for other versions of \MP\ it says,
26070 for example, `\.{(mem=plain 90.4.14)}', showing the year,
26071 month, and day that the mem file was created. We have |mem_ident=0|
26072 before \MP's tables are loaded.
26073
26074 @<Glob...@>=
26075 char * mem_ident;
26076
26077 @ @<Set init...@>=
26078 mp->mem_ident=NULL;
26079
26080 @ @<Initialize table entries...@>=
26081 if (mp->ini_version) 
26082   mp->mem_ident=xstrdup(" (INIMP)");
26083
26084 @ @<Declare act...@>=
26085 void mp_store_mem_file (MP mp) ;
26086
26087 @ @c void mp_store_mem_file (MP mp) {
26088   integer k;  /* all-purpose index */
26089   pointer p,q; /* all-purpose pointers */
26090   integer x; /* something to dump */
26091   four_quarters w; /* four ASCII codes */
26092   memory_word WW;
26093   @<Create the |mem_ident|, open the mem file,
26094     and inform the user that dumping has begun@>;
26095   @<Dump constants for consistency check@>;
26096   @<Dump the string pool@>;
26097   @<Dump the dynamic memory@>;
26098   @<Dump the table of equivalents and the hash table@>;
26099   @<Dump a few more things and the closing check word@>;
26100   @<Close the mem file@>;
26101 }
26102
26103 @ Corresponding to the procedure that dumps a mem file, we also have a function
26104 that reads~one~in. The function returns |false| if the dumped mem is
26105 incompatible with the present \MP\ table sizes, etc.
26106
26107 @d off_base 6666 /* go here if the mem file is unacceptable */
26108 @d too_small(A) { wake_up_terminal;
26109   wterm_ln("---! Must increase the "); wterm((A));
26110 @.Must increase the x@>
26111   goto OFF_BASE;
26112   }
26113
26114 @c 
26115 boolean mp_load_mem_file (MP mp) {
26116   integer k; /* all-purpose index */
26117   pointer p,q; /* all-purpose pointers */
26118   integer x; /* something undumped */
26119   str_number s; /* some temporary string */
26120   four_quarters w; /* four ASCII codes */
26121   memory_word WW;
26122   @<Undump constants for consistency check@>;
26123   @<Undump the string pool@>;
26124   @<Undump the dynamic memory@>;
26125   @<Undump the table of equivalents and the hash table@>;
26126   @<Undump a few more things and the closing check word@>;
26127   return true; /* it worked! */
26128 OFF_BASE: 
26129   wake_up_terminal;
26130   wterm_ln("(Fatal mem file error; I'm stymied)\n");
26131 @.Fatal mem file error@>
26132    return false;
26133 }
26134
26135 @ @<Declarations@>=
26136 boolean mp_load_mem_file (MP mp) ;
26137
26138 @ Mem files consist of |memory_word| items, and we use the following
26139 macros to dump words of different types:
26140
26141 @d dump_wd(A)   { WW=(A);       fwrite(&WW,sizeof(WW),1,mp->mem_file); }
26142 @d dump_int(A)  { int cint=(A); fwrite(&cint,sizeof(cint),1,mp->mem_file); }
26143 @d dump_hh(A)   { WW.hh=(A);    fwrite(&WW,sizeof(WW),1,mp->mem_file); }
26144 @d dump_qqqq(A) { WW.qqqq=(A);  fwrite(&WW,sizeof(WW),1,mp->mem_file); }
26145 @d dump_string(A) { dump_int(strlen(A)+1);
26146                     fwrite(A,strlen(A)+1,1,mp->mem_file); }
26147
26148 @<Glob...@>=
26149 FILE * mem_file; /* for input or output of mem information */
26150
26151 @ The inverse macros are slightly more complicated, since we need to check
26152 the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
26153 read an integer value |x| that is supposed to be in the range |a<=x<=b|.
26154
26155 @d undump_wd(A)   { fread(&WW,sizeof(WW),1,mp->mem_file); (A)=WW; }
26156 @d undump_int(A)  { int cint; fread(&cint,sizeof(cint),1,mp->mem_file); (A)=cint; }
26157 @d undump_hh(A)   { fread(&WW,sizeof(WW),1,mp->mem_file); (A)=WW.hh; }
26158 @d undump_qqqq(A) { fread(&WW,sizeof(WW),1,mp->mem_file); (A)=WW.qqqq; }
26159 @d undump_strings(A,B,C) { 
26160    undump_int(x); if ( (x<(A)) || (x>(B)) ) goto OFF_BASE; else (C)=str(x); }
26161 @d undump(A,B,C) { undump_int(x); if ( (x<(A)) || (x>(int)(B)) ) goto OFF_BASE; else (C)=x; }
26162 @d undump_size(A,B,C,D) { undump_int(x);
26163                if (x<(A)) goto OFF_BASE; 
26164                if (x>(B)) { too_small((C)); } else {(D)=x;} }
26165 @d undump_string(A) { integer XX=0; undump_int(XX);
26166                       A = xmalloc(XX,sizeof(char));
26167                       fread(A,XX,1,mp->mem_file); }
26168
26169 @ The next few sections of the program should make it clear how we use the
26170 dump/undump macros.
26171
26172 @<Dump constants for consistency check@>=
26173 dump_int(mp->mem_top);
26174 dump_int(mp->hash_size);
26175 dump_int(mp->hash_prime)
26176 dump_int(mp->param_size);
26177 dump_int(mp->max_in_open);
26178
26179 @ Sections of a \.{WEB} program that are ``commented out'' still contribute
26180 strings to the string pool; therefore \.{INIMP} and \MP\ will have
26181 the same strings. (And it is, of course, a good thing that they do.)
26182 @.WEB@>
26183 @^string pool@>
26184
26185 @<Undump constants for consistency check@>=
26186 undump_int(x); mp->mem_top = x;
26187 undump_int(x); if (mp->hash_size != x) goto OFF_BASE;
26188 undump_int(x); if (mp->hash_prime != x) goto OFF_BASE;
26189 undump_int(x); if (mp->param_size != x) goto OFF_BASE;
26190 undump_int(x); if (mp->max_in_open != x) goto OFF_BASE
26191
26192 @ We do string pool compaction to avoid dumping unused strings.
26193
26194 @d dump_four_ASCII 
26195   w.b0=qi(mp->str_pool[k]); w.b1=qi(mp->str_pool[k+1]);
26196   w.b2=qi(mp->str_pool[k+2]); w.b3=qi(mp->str_pool[k+3]);
26197   dump_qqqq(w)
26198
26199 @<Dump the string pool@>=
26200 mp_do_compaction(mp, mp->pool_size);
26201 dump_int(mp->pool_ptr);
26202 dump_int(mp->max_str_ptr);
26203 dump_int(mp->str_ptr);
26204 k=0;
26205 while ( (mp->next_str[k]==k+1) && (k<=mp->max_str_ptr) ) 
26206   incr(k);
26207 dump_int(k);
26208 while ( k<=mp->max_str_ptr ) { 
26209   dump_int(mp->next_str[k]); incr(k);
26210 }
26211 k=0;
26212 while (1)  { 
26213   dump_int(mp->str_start[k]); /* TODO: valgrind warning here */
26214   if ( k==mp->str_ptr ) {
26215     break;
26216   } else { 
26217     k=mp->next_str[k]; 
26218   }
26219 };
26220 k=0;
26221 while (k+4<mp->pool_ptr ) { 
26222   dump_four_ASCII; k=k+4; 
26223 }
26224 k=mp->pool_ptr-4; dump_four_ASCII;
26225 mp_print_ln(mp); mp_print(mp, "at most "); mp_print_int(mp, mp->max_str_ptr);
26226 mp_print(mp, " strings of total length ");
26227 mp_print_int(mp, mp->pool_ptr)
26228
26229 @ @d undump_four_ASCII 
26230   undump_qqqq(w);
26231   mp->str_pool[k]=qo(w.b0); mp->str_pool[k+1]=qo(w.b1);
26232   mp->str_pool[k+2]=qo(w.b2); mp->str_pool[k+3]=qo(w.b3)
26233
26234 @<Undump the string pool@>=
26235 undump_int(mp->pool_ptr);
26236 mp_reallocate_pool(mp, mp->pool_ptr) ;
26237 undump_int(mp->max_str_ptr);
26238 mp_reallocate_strings (mp,mp->max_str_ptr) ;
26239 undump(0,mp->max_str_ptr,mp->str_ptr);
26240 undump(0,mp->max_str_ptr+1,s);
26241 for (k=0;k<=s-1;k++) 
26242   mp->next_str[k]=k+1;
26243 for (k=s;k<=mp->max_str_ptr;k++) 
26244   undump(s+1,mp->max_str_ptr+1,mp->next_str[k]);
26245 mp->fixed_str_use=0;
26246 k=0;
26247 while (1) { 
26248   undump(0,mp->pool_ptr,mp->str_start[k]);
26249   if ( k==mp->str_ptr ) break;
26250   mp->str_ref[k]=max_str_ref;
26251   incr(mp->fixed_str_use);
26252   mp->last_fixed_str=k; k=mp->next_str[k];
26253 }
26254 k=0;
26255 while ( k+4<mp->pool_ptr ) { 
26256   undump_four_ASCII; k=k+4;
26257 }
26258 k=mp->pool_ptr-4; undump_four_ASCII;
26259 mp->init_str_use=mp->fixed_str_use; mp->init_pool_ptr=mp->pool_ptr;
26260 mp->max_pool_ptr=mp->pool_ptr;
26261 mp->strs_used_up=mp->fixed_str_use;
26262 mp->pool_in_use=mp->str_start[mp->str_ptr]; mp->strs_in_use=mp->fixed_str_use;
26263 mp->max_pl_used=mp->pool_in_use; mp->max_strs_used=mp->strs_in_use;
26264 mp->pact_count=0; mp->pact_chars=0; mp->pact_strs=0;
26265
26266 @ By sorting the list of available spaces in the variable-size portion of
26267 |mem|, we are usually able to get by without having to dump very much
26268 of the dynamic memory.
26269
26270 We recompute |var_used| and |dyn_used|, so that \.{INIMP} dumps valid
26271 information even when it has not been gathering statistics.
26272
26273 @<Dump the dynamic memory@>=
26274 mp_sort_avail(mp); mp->var_used=0;
26275 dump_int(mp->lo_mem_max); dump_int(mp->rover);
26276 p=0; q=mp->rover; x=0;
26277 do {  
26278   for (k=p;k<= q+1;k++) 
26279     dump_wd(mp->mem[k]);
26280   x=x+q+2-p; mp->var_used=mp->var_used+q-p;
26281   p=q+node_size(q); q=rlink(q);
26282 } while (q!=mp->rover);
26283 mp->var_used=mp->var_used+mp->lo_mem_max-p; 
26284 mp->dyn_used=mp->mem_end+1-mp->hi_mem_min;
26285 for (k=p;k<= mp->lo_mem_max;k++ ) 
26286   dump_wd(mp->mem[k]);
26287 x=x+mp->lo_mem_max+1-p;
26288 dump_int(mp->hi_mem_min); dump_int(mp->avail);
26289 for (k=mp->hi_mem_min;k<=mp->mem_end;k++ ) 
26290   dump_wd(mp->mem[k]);
26291 x=x+mp->mem_end+1-mp->hi_mem_min;
26292 p=mp->avail;
26293 while ( p!=null ) { 
26294   decr(mp->dyn_used); p=link(p);
26295 }
26296 dump_int(mp->var_used); dump_int(mp->dyn_used);
26297 mp_print_ln(mp); mp_print_int(mp, x);
26298 mp_print(mp, " memory locations dumped; current usage is ");
26299 mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used)
26300
26301 @ @<Undump the dynamic memory@>=
26302 undump(lo_mem_stat_max+1000,hi_mem_stat_min-1,mp->lo_mem_max);
26303 undump(lo_mem_stat_max+1,mp->lo_mem_max,mp->rover);
26304 p=0; q=mp->rover;
26305 do {  
26306   for (k=p;k<= q+1; k++) 
26307     undump_wd(mp->mem[k]);
26308   p=q+node_size(q);
26309   if ( (p>mp->lo_mem_max)||((q>=rlink(q))&&(rlink(q)!=mp->rover)) ) 
26310     goto OFF_BASE;
26311   q=rlink(q);
26312 } while (q!=mp->rover);
26313 for (k=p;k<=mp->lo_mem_max;k++ ) 
26314   undump_wd(mp->mem[k]);
26315 undump(mp->lo_mem_max+1,hi_mem_stat_min,mp->hi_mem_min);
26316 undump(null,mp->mem_top,mp->avail); mp->mem_end=mp->mem_top;
26317 for (k=mp->hi_mem_min;k<= mp->mem_end;k++) 
26318   undump_wd(mp->mem[k]);
26319 undump_int(mp->var_used); undump_int(mp->dyn_used)
26320
26321 @ A different scheme is used to compress the hash table, since its lower region
26322 is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output three
26323 words: |p|, |hash[p]|, and |eqtb[p]|. The hash table is, of course, densely
26324 packed for |p>=hash_used|, so the remaining entries are output in~a~block.
26325
26326 @<Dump the table of equivalents and the hash table@>=
26327 dump_int(mp->hash_used); 
26328 mp->st_count=frozen_inaccessible-1-mp->hash_used;
26329 for (p=1;p<=mp->hash_used;p++) {
26330   if ( text(p)!=0 ) {
26331      dump_int(p); dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]); incr(mp->st_count);
26332   }
26333 }
26334 for (p=mp->hash_used+1;p<=(int)hash_end;p++) {
26335   dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]);
26336 }
26337 dump_int(mp->st_count);
26338 mp_print_ln(mp); mp_print_int(mp, mp->st_count); mp_print(mp, " symbolic tokens")
26339
26340 @ @<Undump the table of equivalents and the hash table@>=
26341 undump(1,frozen_inaccessible,mp->hash_used); 
26342 p=0;
26343 do {  
26344   undump(p+1,mp->hash_used,p); 
26345   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
26346 } while (p!=mp->hash_used);
26347 for (p=mp->hash_used+1;p<=(int)hash_end;p++ )  { 
26348   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
26349 }
26350 undump_int(mp->st_count)
26351
26352 @ We have already printed a lot of statistics, so we set |tracing_stats:=0|
26353 to prevent them appearing again.
26354
26355 @<Dump a few more things and the closing check word@>=
26356 dump_int(mp->max_internal);
26357 dump_int(mp->int_ptr);
26358 for (k=1;k<= mp->int_ptr;k++ ) { 
26359   dump_int(mp->internal[k]); 
26360   dump_string(mp->int_name[k]);
26361 }
26362 dump_int(mp->start_sym); 
26363 dump_int(mp->interaction); 
26364 dump_string(mp->mem_ident);
26365 dump_int(mp->bg_loc); dump_int(mp->eg_loc); dump_int(mp->serial_no); dump_int(69073);
26366 mp->internal[tracing_stats]=0
26367
26368 @ @<Undump a few more things and the closing check word@>=
26369 undump_int(x);
26370 if (x>mp->max_internal) mp_grow_internals(mp,x);
26371 undump_int(mp->int_ptr);
26372 for (k=1;k<= mp->int_ptr;k++) { 
26373   undump_int(mp->internal[k]);
26374   undump_string(mp->int_name[k]);
26375 }
26376 undump(0,frozen_inaccessible,mp->start_sym);
26377 if (mp->interaction==mp_unspecified_mode) {
26378   undump(mp_unspecified_mode,mp_error_stop_mode,mp->interaction);
26379 } else {
26380   undump(mp_unspecified_mode,mp_error_stop_mode,x);
26381 }
26382 undump_string(mp->mem_ident);
26383 undump(1,hash_end,mp->bg_loc);
26384 undump(1,hash_end,mp->eg_loc);
26385 undump_int(mp->serial_no);
26386 undump_int(x); 
26387 if ( (x!=69073)|| feof(mp->mem_file) ) goto OFF_BASE
26388
26389 @ @<Create the |mem_ident|...@>=
26390
26391   xfree(mp->mem_ident);
26392   mp->mem_ident = xmalloc(256,1);
26393   snprintf(mp->mem_ident,256," (mem=%s %i.%i.%i)", 
26394            mp->job_name,
26395            (int)(mp_round_unscaled(mp, mp->internal[year]) % 100),
26396            (int)mp_round_unscaled(mp, mp->internal[month]),
26397            (int)mp_round_unscaled(mp, mp->internal[day]));
26398   mp_pack_job_name(mp, mem_extension);
26399   while (! mp_w_open_out(mp, &mp->mem_file) )
26400     mp_prompt_file_name(mp, "mem file name", mem_extension);
26401   mp_print_nl(mp, "Beginning to dump on file ");
26402 @.Beginning to dump...@>
26403   mp_print(mp, mp->name_of_file); 
26404   mp_print_nl(mp, mp->mem_ident);
26405 }
26406
26407 @ @<Dealloc variables@>=
26408 xfree(mp->mem_ident);
26409
26410 @ @<Close the mem file@>=
26411 fclose(mp->mem_file)
26412
26413 @* \[46] The main program.
26414 This is it: the part of \MP\ that executes all those procedures we have
26415 written.
26416
26417 Well---almost. We haven't put the parsing subroutines into the
26418 program yet; and we'd better leave space for a few more routines that may
26419 have been forgotten.
26420
26421 @c @<Declare the basic parsing subroutines@>;
26422 @<Declare miscellaneous procedures that were declared |forward|@>;
26423 @<Last-minute procedures@>
26424
26425 @ We've noted that there are two versions of \MP. One, called \.{INIMP},
26426 @.INIMP@>
26427 has to be run first; it initializes everything from scratch, without
26428 reading a mem file, and it has the capability of dumping a mem file.
26429 The other one is called `\.{VIRMP}'; it is a ``virgin'' program that needs
26430 @.VIRMP@>
26431 to input a mem file in order to get started. \.{VIRMP} typically has
26432 a bit more memory capacity than \.{INIMP}, because it does not need the
26433 space consumed by the dumping/undumping routines and the numerous calls on
26434 |primitive|, etc.
26435
26436 The \.{VIRMP} program cannot read a mem file instantaneously, of course;
26437 the best implementations therefore allow for production versions of \MP\ that
26438 not only avoid the loading routine for \PASCAL\ object code, they also have
26439 a mem file pre-loaded. 
26440
26441 @<Glob...@>=
26442 boolean ini_version; /* are we iniMP? */
26443
26444 @ @<Option variables@>=
26445 boolean ini_version; /* are we iniMP? */
26446
26447 @ @<Set |ini_version|@>=
26448 mp->ini_version = (opt->ini_version ? true : false);
26449
26450 @ Here we do whatever is needed to complete \MP's job gracefully on the
26451 local operating system. The code here might come into play after a fatal
26452 error; it must therefore consist entirely of ``safe'' operations that
26453 cannot produce error messages. For example, it would be a mistake to call
26454 |str_room| or |make_string| at this time, because a call on |overflow|
26455 might lead to an infinite loop.
26456 @^system dependencies@>
26457
26458 This program doesn't bother to close the input files that may still be open.
26459
26460 @<Last-minute...@>=
26461 void mp_close_files_and_terminate (MP mp) {
26462   integer k; /* all-purpose index */
26463   integer LH; /* the length of the \.{TFM} header, in words */
26464   int lk_offset; /* extra words inserted at beginning of |lig_kern| array */
26465   pointer p; /* runs through a list of \.{TFM} dimensions */
26466   @<Close all open files in the |rd_file| and |wr_file| arrays@>;
26467   if ( mp->internal[tracing_stats]>0 )
26468     @<Output statistics about this job@>;
26469   wake_up_terminal; 
26470   @<Do all the finishing work on the \.{TFM} file@>;
26471   @<Explain what output files were written@>;
26472   if ( mp->log_opened ){ 
26473     wlog_cr;
26474     fclose(mp->log_file); mp->selector=mp->selector-2;
26475     if ( mp->selector==term_only ) {
26476       mp_print_nl(mp, "Transcript written on ");
26477 @.Transcript written...@>
26478       mp_print(mp, mp->log_name); mp_print_char(mp, '.');
26479     }
26480   }
26481   mp_print_ln(mp);
26482 }
26483
26484 @ @<Declarations@>=
26485 void mp_close_files_and_terminate (MP mp) ;
26486
26487 @ @<Close all open files in the |rd_file| and |wr_file| arrays@>=
26488 for (k=0;k<=(int)mp->read_files-1;k++ ) {
26489   if ( mp->rd_fname[k]!=NULL ) {
26490     fclose(mp->rd_file[k]);
26491   }
26492 }
26493 for (k=0;k<=(int)mp->write_files-1;k++) {
26494   if ( mp->wr_fname[k]!=NULL ) {
26495     fclose(mp->wr_file[k]);
26496   }
26497 }
26498
26499 @ @<Dealloc ...@>=
26500 for (k=0;k<(int)mp->max_read_files;k++ ) {
26501   if ( mp->rd_fname[k]!=NULL ) {
26502     fclose(mp->rd_file[k]);
26503     mp_xfree(mp->rd_fname[k]); 
26504   }
26505 }
26506 mp_xfree(mp->rd_file);
26507 mp_xfree(mp->rd_fname);
26508 for (k=0;k<(int)mp->max_write_files;k++) {
26509   if ( mp->wr_fname[k]!=NULL ) {
26510     fclose(mp->wr_file[k]);
26511     mp_xfree(mp->wr_fname[k]); 
26512   }
26513 }
26514 mp_xfree(mp->wr_file);
26515 mp_xfree(mp->wr_fname);
26516
26517
26518 @ We want to produce a \.{TFM} file if and only if |fontmaking| is positive.
26519
26520 We reclaim all of the variable-size memory at this point, so that
26521 there is no chance of another memory overflow after the memory capacity
26522 has already been exceeded.
26523
26524 @<Do all the finishing work on the \.{TFM} file@>=
26525 if ( mp->internal[fontmaking]>0 ) {
26526   @<Make the dynamic memory into one big available node@>;
26527   @<Massage the \.{TFM} widths@>;
26528   mp_fix_design_size(mp); mp_fix_check_sum(mp);
26529   @<Massage the \.{TFM} heights, depths, and italic corrections@>;
26530   mp->internal[fontmaking]=0; /* avoid loop in case of fatal error */
26531   @<Finish the \.{TFM} file@>;
26532 }
26533
26534 @ @<Make the dynamic memory into one big available node@>=
26535 mp->rover=lo_mem_stat_max+1; link(mp->rover)=empty_flag; mp->lo_mem_max=mp->hi_mem_min-1;
26536 if ( mp->lo_mem_max-mp->rover>max_halfword ) mp->lo_mem_max=max_halfword+mp->rover;
26537 node_size(mp->rover)=mp->lo_mem_max-mp->rover; 
26538 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
26539 link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null
26540
26541 @ The present section goes directly to the log file instead of using
26542 |print| commands, because there's no need for these strings to take
26543 up |str_pool| memory when a non-{\bf stat} version of \MP\ is being used.
26544
26545 @<Output statistics...@>=
26546 if ( mp->log_opened ) { 
26547   char s[128];
26548   wlog_ln(" ");
26549   wlog_ln("Here is how much of MetaPost's memory you used:");
26550 @.Here is how much...@>
26551   snprintf(s,128," %i string%s out of %i",(int)mp->max_strs_used-mp->init_str_use,
26552           (mp->max_strs_used!=mp->init_str_use+1 ? "s" : ""),
26553           (int)(mp->max_strings-1-mp->init_str_use));
26554   wlog_ln(s);
26555   snprintf(s,128," %i string characters out of %i",
26556            (int)mp->max_pl_used-mp->init_pool_ptr,
26557            (int)mp->pool_size-mp->init_pool_ptr);
26558   wlog_ln(s);
26559   snprintf(s,128," %i words of memory out of %i",
26560            (int)mp->lo_mem_max+mp->mem_end-mp->hi_mem_min+2,
26561            (int)mp->mem_end+1);
26562   wlog_ln(s);
26563   snprintf(s,128," %i symbolic tokens out of %i", (int)mp->st_count, (int)mp->hash_size);
26564   wlog_ln(s);
26565   snprintf(s,128," %ii, %in, %ip, %ib stack positions out of %ii, %in, %ip, %ib",
26566            (int)mp->max_in_stack,(int)mp->int_ptr,
26567            (int)mp->max_param_stack,(int)mp->max_buf_stack+1,
26568            (int)mp->stack_size,(int)mp->max_internal,(int)mp->param_size,(int)mp->buf_size);
26569   wlog_ln(s);
26570   snprintf(s,128," %i string compactions (moved %i characters, %i strings)",
26571           (int)mp->pact_count,(int)mp->pact_chars,(int)mp->pact_strs);
26572   wlog_ln(s);
26573 }
26574
26575 @ We get to the |final_cleanup| routine when \&{end} or \&{dump} has
26576 been scanned.
26577
26578 @<Last-minute...@>=
26579 void mp_final_cleanup (MP mp) {
26580   small_number c; /* 0 for \&{end}, 1 for \&{dump} */
26581   c=mp->cur_mod;
26582   if ( mp->job_name==NULL ) mp_open_log_file(mp);
26583   while ( mp->input_ptr>0 ) {
26584     if ( token_state ) mp_end_token_list(mp);
26585     else  mp_end_file_reading(mp);
26586   }
26587   while ( mp->loop_ptr!=null ) mp_stop_iteration(mp);
26588   while ( mp->open_parens>0 ) { 
26589     mp_print(mp, " )"); decr(mp->open_parens);
26590   };
26591   while ( mp->cond_ptr!=null ) {
26592     mp_print_nl(mp, "(end occurred when ");
26593 @.end occurred...@>
26594     mp_print_cmd_mod(mp, fi_or_else,mp->cur_if);
26595     /* `\.{if}' or `\.{elseif}' or `\.{else}' */
26596     if ( mp->if_line!=0 ) {
26597       mp_print(mp, " on line "); mp_print_int(mp, mp->if_line);
26598     }
26599     mp_print(mp, " was incomplete)");
26600     mp->if_line=if_line_field(mp->cond_ptr);
26601     mp->cur_if=name_type(mp->cond_ptr); mp->cond_ptr=link(mp->cond_ptr);
26602   }
26603   if ( mp->history!=spotless )
26604     if ( ((mp->history==warning_issued)||(mp->interaction<mp_error_stop_mode)) )
26605       if ( mp->selector==term_and_log ) {
26606     mp->selector=term_only;
26607     mp_print_nl(mp, "(see the transcript file for additional information)");
26608 @.see the transcript file...@>
26609     mp->selector=term_and_log;
26610   }
26611   if ( c==1 ) {
26612     if (mp->ini_version) {
26613       mp_store_mem_file(mp); return;
26614     }
26615     mp_print_nl(mp, "(dump is performed only by INIMP)"); return;
26616 @.dump...only by INIMP@>
26617   }
26618 }
26619
26620 @ @<Declarations@>=
26621 void mp_final_cleanup (MP mp) ;
26622 void mp_init_prim (MP mp) ;
26623 void mp_init_tab (MP mp) ;
26624
26625 @ @<Last-minute...@>=
26626 void mp_init_prim (MP mp) { /* initialize all the primitives */
26627   @<Put each...@>;
26628 }
26629 @#
26630 void mp_init_tab (MP mp) { /* initialize other tables */
26631   integer k; /* all-purpose index */
26632   @<Initialize table entries (done by \.{INIMP} only)@>;
26633 }
26634
26635
26636 @ When we begin the following code, \MP's tables may still contain garbage;
26637 the strings might not even be present. Thus we must proceed cautiously to get
26638 bootstrapped in.
26639
26640 But when we finish this part of the program, \MP\ is ready to call on the
26641 |main_control| routine to do its work.
26642
26643 @<Get the first line...@>=
26644
26645   @<Initialize the input routines@>;
26646   if ( (mp->mem_ident==NULL)||(mp->buffer[loc]=='&') ) {
26647     if ( mp->mem_ident!=NULL ) mp_initialize(mp); /* erase preloaded mem */
26648     if ( ! mp_open_mem_file(mp) ) return false;
26649     if ( ! mp_load_mem_file(mp) ) {
26650       fclose( mp->mem_file); return false;
26651     }
26652     fclose( mp->mem_file);
26653     while ( (loc<limit)&&(mp->buffer[loc]==' ') ) incr(loc);
26654   }
26655   mp->buffer[limit]='%';
26656   mp_fix_date_and_time(mp);
26657   mp->sys_random_seed = (mp->get_random_seed)(mp);
26658   mp_init_randoms(mp, mp->sys_random_seed);
26659   @<Initialize the print |selector|...@>;
26660   if ( loc<limit ) if ( mp->buffer[loc]!='\\' ) 
26661     mp_start_input(mp); /* \&{input} assumed */
26662 }
26663
26664 @ @<Run inimpost commands@>=
26665 {
26666   mp_get_strings_started(mp);
26667   mp_init_tab(mp); /* initialize the tables */
26668   mp_init_prim(mp); /* call |primitive| for each primitive */
26669   mp->init_str_use=mp->str_ptr; mp->init_pool_ptr=mp->pool_ptr;
26670   mp->max_str_ptr=mp->str_ptr; mp->max_pool_ptr=mp->pool_ptr;
26671   mp_fix_date_and_time(mp);
26672 }
26673
26674
26675 @* \[47] Debugging.
26676 Once \MP\ is working, you should be able to diagnose most errors with
26677 the \.{show} commands and other diagnostic features. But for the initial
26678 stages of debugging, and for the revelation of really deep mysteries, you
26679 can compile \MP\ with a few more aids, including the \PASCAL\ runtime
26680 checks and its debugger. An additional routine called |debug_help|
26681 will also come into play when you type `\.D' after an error message;
26682 |debug_help| also occurs just before a fatal error causes \MP\ to succumb.
26683 @^debugging@>
26684 @^system dependencies@>
26685
26686 The interface to |debug_help| is primitive, but it is good enough when used
26687 with a \PASCAL\ debugger that allows you to set breakpoints and to read
26688 variables and change their values. After getting the prompt `\.{debug \#}', you
26689 type either a negative number (this exits |debug_help|), or zero (this
26690 goes to a location where you can set a breakpoint, thereby entering into
26691 dialog with the \PASCAL\ debugger), or a positive number |m| followed by
26692 an argument |n|. The meaning of |m| and |n| will be clear from the
26693 program below. (If |m=13|, there is an additional argument, |l|.)
26694 @.debug \#@>
26695
26696 @<Last-minute...@>=
26697 void mp_debug_help (MP mp) { /* routine to display various things */
26698   integer k;
26699   int l,m,n;
26700   while (1) { 
26701     wake_up_terminal;
26702     mp_print_nl(mp, "debug # (-1 to exit):"); update_terminal;
26703 @.debug \#@>
26704     m = 0;
26705     fscanf(mp->term_in,"%i",&m);
26706     if ( m<=0 )
26707       return;
26708     n = 0 ;
26709     fscanf(mp->term_in,"%i",&n);
26710     switch (m) {
26711     @<Numbered cases for |debug_help|@>;
26712     default: mp_print(mp, "?"); break;
26713     }
26714   }
26715 }
26716
26717 @ @<Numbered cases...@>=
26718 case 1: mp_print_word(mp, mp->mem[n]); /* display |mem[n]| in all forms */
26719   break;
26720 case 2: mp_print_int(mp, info(n));
26721   break;
26722 case 3: mp_print_int(mp, link(n));
26723   break;
26724 case 4: mp_print_int(mp, eq_type(n)); mp_print_char(mp, ':'); mp_print_int(mp, equiv(n));
26725   break;
26726 case 5: mp_print_variable_name(mp, n);
26727   break;
26728 case 6: mp_print_int(mp, mp->internal[n]);
26729   break;
26730 case 7: mp_do_show_dependencies(mp);
26731   break;
26732 case 9: mp_show_token_list(mp, n,null,100000,0);
26733   break;
26734 case 10: mp_print_str(mp, n);
26735   break;
26736 case 11: mp_check_mem(mp, n>0); /* check wellformedness; print new busy locations if |n>0| */
26737   break;
26738 case 12: mp_search_mem(mp, n); /* look for pointers to |n| */
26739   break;
26740 case 13: l = 0;  fscanf(mp->term_in,"%i",&l); mp_print_cmd_mod(mp, n,l); 
26741   break;
26742 case 14: for (k=0;k<=n;k++) mp_print_str(mp, mp->buffer[k]);
26743   break;
26744 case 15: mp->panicking=! mp->panicking;
26745   break;
26746
26747
26748 @ \MP\ used to have one single routine to print to both `write' files
26749 and the PostScript output. Web2c redefines ``Character |k| cannot be
26750 printed'', and that resulted in some bugs where 8-bit characters were
26751 written to the PostScript file (reported by Wlodek Bzyl).
26752
26753 Also, Hans Hagen requested spaces to be output as "\\040" instead of
26754 a plain space, since that makes it easier to parse the result file
26755 for postprocessing.
26756
26757 @<Character |k| is not allowed in PostScript output@>=
26758   (k<=' ')||(k>'~')
26759
26760 @ Saving the filename template
26761
26762 @<Save the filename template@>=
26763
26764   if ( mp->filename_template!=0 ) delete_str_ref(mp->filename_template);
26765   if ( length(mp->cur_exp)==0 ) mp->filename_template=0;
26766   else { 
26767     mp->filename_template=mp->cur_exp; add_str_ref(mp->filename_template);
26768   }
26769 }
26770
26771 @* \[48] System-dependent changes.
26772 This section should be replaced, if necessary, by any special
26773 modification of the program
26774 that are necessary to make \MP\ work at a particular installation.
26775 It is usually best to design your change file so that all changes to
26776 previous sections preserve the section numbering; then everybody's version
26777 will be consistent with the published program. More extensive changes,
26778 which introduce new sections, can be inserted here; then only the index
26779 itself will get a new section number.
26780 @^system dependencies@>
26781
26782 @* \[49] Index.
26783 Here is where you can find all uses of each identifier in the program,
26784 with underlined entries pointing to where the identifier was defined.
26785 If the identifier is only one letter long, however, you get to see only
26786 the underlined entries. {\sl All references are to section numbers instead of
26787 page numbers.}
26788
26789 This index also lists error messages and other aspects of the program
26790 that you might want to look up some day. For example, the entry
26791 for ``system dependencies'' lists all sections that should receive
26792 special attention from people who are installing \MP\ in a new
26793 operating environment. A list of various things that can't happen appears
26794 under ``this can't happen''.
26795 Approximately 25 sections are listed under ``inner loop''; these account
26796 for more than 60\pct! of \MP's running time, exclusive of input and output.