cleanup the fixed line length
[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.20"
88 @d version_string " (Cweb version 0.20)"
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 typedef struct MP_instance * MP;
146 @<Exported types@>
147 typedef struct MP_options {
148   @<Option variables@>
149 } MP_options;
150 @<Exported function headers@>
151
152 @ @(mpmp.h@>=
153 #include <setjmp.h>
154 typedef struct psout_data_struct * psout_data;
155 typedef int boolean;
156 typedef signed int integer;
157 @<Declare helpers@>;
158 @<Types in the outer block@>;
159 @<Constants in the outer block@>
160 #  ifndef LIBAVL_ALLOCATOR
161 #    define LIBAVL_ALLOCATOR
162     struct libavl_allocator {
163         void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
164         void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
165     };
166 #  endif
167 typedef struct MP_instance {
168   @<Global variables@>
169 } MP_instance;
170 @<Internal library declarations@>
171
172 @ @c 
173 #include <stdio.h>
174 #include <stdlib.h>
175 #include <string.h>
176 #include <stdarg.h>
177 #include <assert.h>
178 #include <unistd.h> /* for access() */
179 #include <time.h> /* for struct tm \& co */
180 #include "mplib.h"
181 #include "mpmp.h" /* internal header */
182 #include "mppsout.h" /* internal header */
183 @h
184 @<Declarations@>
185 @<Basic printing procedures@>
186 @<Error handling procedures@>
187
188 @ Here are the functions that set up the \MP\ instance.
189
190 @<Declarations@> =
191 @<Declare |mp_reallocate| functions@>;
192 struct MP_options *mp_options (void);
193 MP mp_new (struct MP_options *opt);
194
195 @ @c
196 struct MP_options *mp_options (void) {
197   struct MP_options *opt;
198   opt = malloc(sizeof(MP_options));
199   if (opt!=NULL) {
200     memset (opt,0,sizeof(MP_options));
201   }
202   return opt;
203
204 MP mp_new (struct MP_options *opt) {
205   MP mp;
206   mp = xmalloc(1,sizeof(MP_instance));
207   @<Set |ini_version|@>;
208   @<Setup the non-local jump buffer in |mp_new|@>;
209   @<Allocate or initialize variables@>
210   if (opt->main_memory>mp->mem_max)
211     mp_reallocate_memory(mp,opt->main_memory);
212   mp_reallocate_paths(mp,1000);
213   mp_reallocate_fonts(mp,8);
214   return mp;
215 }
216 void mp_free (MP mp) {
217   int k; /* loop variable */
218   @<Dealloc variables@>
219   xfree(mp);
220 }
221
222 @ @c
223 void mp_do_initialize ( MP mp) {
224   @<Local variables for initialization@>
225   @<Set initial values of key variables@>
226 }
227 int mp_initialize (MP mp) { /* this procedure gets things started properly */
228   mp->history=mp_fatal_error_stop; /* in case we quit during initialization */
229   @<Install and test the non-local jump buffer@>;
230   t_open_out; /* open the terminal for output */
231   @<Check the ``constant'' values...@>;
232   if ( mp->bad>0 ) {
233         char ss[256];
234     snprintf(ss,256,"Ouch---my internal constants have been clobbered!\n"
235                    "---case %i",(int)mp->bad);
236     do_fprintf(mp->err_out,(char *)ss);
237 @.Ouch...clobbered@>
238     return mp->history;
239   }
240   mp_do_initialize(mp); /* erase preloaded mem */
241   if (mp->ini_version) {
242     @<Run inimpost commands@>;
243   }
244   @<Initialize the output routines@>;
245   @<Get the first line of input and prepare to start@>;
246   mp_set_job_id(mp);
247   mp_init_map_file(mp, mp->troff_mode);
248   mp->history=mp_spotless; /* ready to go! */
249   if (mp->troff_mode) {
250     mp->internal[mp_gtroffmode]=unity; 
251     mp->internal[mp_prologues]=unity; 
252   }
253   if ( mp->start_sym>0 ) { /* insert the `\&{everyjob}' symbol */
254     mp->cur_sym=mp->start_sym; mp_back_input(mp);
255   }
256   return mp->history;
257 }
258
259
260 @<Exported function headers@>=
261 extern struct MP_options *mp_options (void);
262 extern MP mp_new (struct MP_options *opt) ;
263 extern void mp_free (MP mp);
264 extern int mp_initialize (MP mp);
265
266 @ @<Declarations@>=
267 void mp_do_initialize (MP mp);
268
269
270 @ The overall \MP\ program begins with the heading just shown, after which
271 comes a bunch of procedure declarations and function declarations.
272 Finally we will get to the main program, which begins with the
273 comment `|start_here|'. If you want to skip down to the
274 main program now, you can look up `|start_here|' in the index.
275 But the author suggests that the best way to understand this program
276 is to follow pretty much the order of \MP's components as they appear in the
277 \.{WEB} description you are now reading, since the present ordering is
278 intended to combine the advantages of the ``bottom up'' and ``top down''
279 approaches to the problem of understanding a somewhat complicated system.
280
281 @ Some of the code below is intended to be used only when diagnosing the
282 strange behavior that sometimes occurs when \MP\ is being installed or
283 when system wizards are fooling around with \MP\ without quite knowing
284 what they are doing. Such code will not normally be compiled; it is
285 delimited by the preprocessor test `|#ifdef DEBUG .. #endif|'.
286
287 @ This program has two important variations: (1) There is a long and slow
288 version called \.{INIMP}, which does the extra calculations needed to
289 @.INIMP@>
290 initialize \MP's internal tables; and (2)~there is a shorter and faster
291 production version, which cuts the initialization to a bare minimum.
292
293 Which is which is decided at runtime.
294
295 @ The following parameters can be changed at compile time to extend or
296 reduce \MP's capacity. They may have different values in \.{INIMP} and
297 in production versions of \MP.
298 @.INIMP@>
299 @^system dependencies@>
300
301 @<Constants...@>=
302 #define file_name_size 255 /* file names shouldn't be longer than this */
303 #define bistack_size 1500 /* size of stack for bisection algorithms;
304   should probably be left at this value */
305
306 @ Like the preceding parameters, the following quantities can be changed
307 at compile time to extend or reduce \MP's capacity. But if they are changed,
308 it is necessary to rerun the initialization program \.{INIMP}
309 @.INIMP@>
310 to generate new tables for the production \MP\ program.
311 One can't simply make helter-skelter changes to the following constants,
312 since certain rather complex initialization
313 numbers are computed from them. 
314
315 @ @<Glob...@>=
316 int max_strings; /* maximum number of strings; must not exceed |max_halfword| */
317 int pool_size; /* maximum number of characters in strings, including all
318   error messages and help texts, and the names of all identifiers */
319 int error_line; /* width of context lines on terminal error messages */
320 int half_error_line; /* width of first lines of contexts in terminal
321   error messages; should be between 30 and |error_line-15| */
322 int max_print_line; /* width of longest text lines output; should be at least 60 */
323 int mem_max; /* greatest index in \MP's internal |mem| array;
324   must be strictly less than |max_halfword|;
325   must be equal to |mem_top| in \.{INIMP}, otherwise |>=mem_top| */
326 int mem_top; /* largest index in the |mem| array dumped by \.{INIMP};
327   must not be greater than |mem_max| */
328 int hash_size; /* maximum number of symbolic tokens,
329   must be less than |max_halfword-3*param_size| */
330 int hash_prime; /* a prime number equal to about 85\pct! of |hash_size| */
331 int param_size; /* maximum number of simultaneous macro parameters */
332 int max_in_open; /* maximum number of input files and error insertions that
333   can be going on simultaneously */
334
335 @ @<Option variables@>=
336 int error_line;
337 int half_error_line;
338 int max_print_line;
339 int main_memory;
340 int hash_size; 
341 int hash_prime; 
342 int param_size; 
343 int max_in_open; 
344
345
346 @d set_value(a,b,c) do { a=c; if (b>c) a=b; } while (0)
347
348 @<Allocate or ...@>=
349 mp->max_strings=500;
350 mp->pool_size=10000;
351 set_value(mp->error_line,opt->error_line,79);
352 set_value(mp->half_error_line,opt->half_error_line,50);
353 set_value(mp->max_print_line,opt->max_print_line,79);
354 mp->mem_max=5000;
355 mp->mem_top=5000;
356 set_value(mp->hash_size,opt->hash_size,9500);
357 set_value(mp->hash_prime,opt->hash_prime,7919);
358 set_value(mp->param_size,opt->param_size,150);
359 set_value(mp->max_in_open,opt->max_in_open,10);
360
361
362 @ In case somebody has inadvertently made bad settings of the ``constants,''
363 \MP\ checks them using a global variable called |bad|.
364
365 This is the first of many sections of \MP\ where global variables are
366 defined.
367
368 @<Glob...@>=
369 integer bad; /* is some ``constant'' wrong? */
370
371 @ Later on we will say `\ignorespaces|if (mem_max>=max_halfword) bad=10;|',
372 or something similar. (We can't do that until |max_halfword| has been defined.)
373
374 @<Check the ``constant'' values for consistency@>=
375 mp->bad=0;
376 if ( (mp->half_error_line<30)||(mp->half_error_line>mp->error_line-15) ) mp->bad=1;
377 if ( mp->max_print_line<60 ) mp->bad=2;
378 if ( mp->mem_top<=1100 ) mp->bad=4;
379 if (mp->hash_prime>mp->hash_size ) mp->bad=5;
380
381 @ Labels are given symbolic names by the following definitions, so that
382 occasional |goto| statements will be meaningful. We insert the label
383 `|exit|:' just before the `\ignorespaces|end|\unskip' of a procedure in
384 which we have used the `|return|' statement defined below; the label
385 `|restart|' is occasionally used at the very beginning of a procedure; and
386 the label `|reswitch|' is occasionally used just prior to a |case|
387 statement in which some cases change the conditions and we wish to branch
388 to the newly applicable case.  Loops that are set up with the |loop|
389 construction defined below are commonly exited by going to `|done|' or to
390 `|found|' or to `|not_found|', and they are sometimes repeated by going to
391 `|continue|'.  If two or more parts of a subroutine start differently but
392 end up the same, the shared code may be gathered together at
393 `|common_ending|'.
394
395 Incidentally, this program never declares a label that isn't actually used,
396 because some fussy \PASCAL\ compilers will complain about redundant labels.
397
398 @d label_exit 10 /* go here to leave a procedure */
399 @d restart 20 /* go here to start a procedure again */
400 @d reswitch 21 /* go here to start a case statement again */
401 @d continue 22 /* go here to resume a loop */
402 @d done 30 /* go here to exit a loop */
403 @d done1 31 /* like |done|, when there is more than one loop */
404 @d done2 32 /* for exiting the second loop in a long block */
405 @d done3 33 /* for exiting the third loop in a very long block */
406 @d done4 34 /* for exiting the fourth loop in an extremely long block */
407 @d done5 35 /* for exiting the fifth loop in an immense block */
408 @d done6 36 /* for exiting the sixth loop in a block */
409 @d found 40 /* go here when you've found it */
410 @d found1 41 /* like |found|, when there's more than one per routine */
411 @d found2 42 /* like |found|, when there's more than two per routine */
412 @d found3 43 /* like |found|, when there's more than three per routine */
413 @d not_found 45 /* go here when you've found nothing */
414 @d common_ending 50 /* go here when you want to merge with another branch */
415
416 @ Here are some macros for common programming idioms.
417
418 @d incr(A)   (A)=(A)+1 /* increase a variable by unity */
419 @d decr(A)   (A)=(A)-1 /* decrease a variable by unity */
420 @d negate(A) (A)=-(A) /* change the sign of a variable */
421 @d double(A) (A)=(A)+(A)
422 @d odd(A)   ((A)%2==1)
423 @d chr(A)   (A)
424 @d do_nothing   /* empty statement */
425 @d Return   goto exit /* terminate a procedure call */
426 @f return   nil /* \.{WEB} will henceforth say |return| instead of \\{return} */
427
428 @* \[2] The character set.
429 In order to make \MP\ readily portable to a wide variety of
430 computers, all of its input text is converted to an internal eight-bit
431 code that includes standard ASCII, the ``American Standard Code for
432 Information Interchange.''  This conversion is done immediately when each
433 character is read in. Conversely, characters are converted from ASCII to
434 the user's external representation just before they are output to a
435 text file.
436 @^ASCII code@>
437
438 Such an internal code is relevant to users of \MP\ only with respect to
439 the \&{char} and \&{ASCII} operations, and the comparison of strings.
440
441 @ Characters of text that have been converted to \MP's internal form
442 are said to be of type |ASCII_code|, which is a subrange of the integers.
443
444 @<Types...@>=
445 typedef unsigned char ASCII_code; /* eight-bit numbers */
446
447 @ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
448 character sets were common, so it did not make provision for lowercase
449 letters. Nowadays, of course, we need to deal with both capital and small
450 letters in a convenient way, especially in a program for font design;
451 so the present specification of \MP\ has been written under the assumption
452 that the \PASCAL\ compiler and run-time system permit the use of text files
453 with more than 64 distinguishable characters. More precisely, we assume that
454 the character set contains at least the letters and symbols associated
455 with ASCII codes 040 through 0176; all of these characters are now
456 available on most computer terminals.
457
458 Since we are dealing with more characters than were present in the first
459 \PASCAL\ compilers, we have to decide what to call the associated data
460 type. Some \PASCAL s use the original name |char| for the
461 characters in text files, even though there now are more than 64 such
462 characters, while other \PASCAL s consider |char| to be a 64-element
463 subrange of a larger data type that has some other name.
464
465 In order to accommodate this difference, we shall use the name |text_char|
466 to stand for the data type of the characters that are converted to and
467 from |ASCII_code| when they are input and output. We shall also assume
468 that |text_char| consists of the elements |chr(first_text_char)| through
469 |chr(last_text_char)|, inclusive. The following definitions should be
470 adjusted if necessary.
471 @^system dependencies@>
472
473 @d first_text_char 0 /* ordinal number of the smallest element of |text_char| */
474 @d last_text_char 255 /* ordinal number of the largest element of |text_char| */
475
476 @<Types...@>=
477 typedef unsigned char text_char; /* the data type of characters in text files */
478
479 @ @<Local variables for init...@>=
480 integer i;
481
482 @ The \MP\ processor converts between ASCII code and
483 the user's external character set by means of arrays |xord| and |xchr|
484 that are analogous to \PASCAL's |ord| and |chr| functions.
485
486 @d xchr(A) mp->xchr[(A)]
487 @d xord(A) mp->xord[(A)]
488
489 @<Glob...@>=
490 ASCII_code xord[256];  /* specifies conversion of input characters */
491 text_char xchr[256];  /* specifies conversion of output characters */
492
493 @ The core system assumes all 8-bit is acceptable.  If it is not,
494 a change file has to alter the below section.
495 @^system dependencies@>
496
497 Additionally, people with extended character sets can
498 assign codes arbitrarily, giving an |xchr| equivalent to whatever
499 characters the users of \MP\ are allowed to have in their input files.
500 Appropriate changes to \MP's |char_class| table should then be made.
501 (Unlike \TeX, each installation of \MP\ has a fixed assignment of category
502 codes, called the |char_class|.) Such changes make portability of programs
503 more difficult, so they should be introduced cautiously if at all.
504 @^character set dependencies@>
505 @^system dependencies@>
506
507 @<Set initial ...@>=
508 for (i=0;i<=0377;i++) { xchr(i)=i; }
509
510 @ The following system-independent code makes the |xord| array contain a
511 suitable inverse to the information in |xchr|. Note that if |xchr[i]=xchr[j]|
512 where |i<j<0177|, the value of |xord[xchr[i]]| will turn out to be
513 |j| or more; hence, standard ASCII code numbers will be used instead of
514 codes below 040 in case there is a coincidence.
515
516 @<Set initial ...@>=
517 for (i=first_text_char;i<=last_text_char;i++) { 
518    xord(chr(i))=0177;
519 }
520 for (i=0200;i<=0377;i++) { xord(xchr(i))=i;}
521 for (i=0;i<=0176;i++) { xord(xchr(i))=i;}
522
523 @* \[3] Input and output.
524 The bane of portability is the fact that different operating systems treat
525 input and output quite differently, perhaps because computer scientists
526 have not given sufficient attention to this problem. People have felt somehow
527 that input and output are not part of ``real'' programming. Well, it is true
528 that some kinds of programming are more fun than others. With existing
529 input/output conventions being so diverse and so messy, the only sources of
530 joy in such parts of the code are the rare occasions when one can find a
531 way to make the program a little less bad than it might have been. We have
532 two choices, either to attack I/O now and get it over with, or to postpone
533 I/O until near the end. Neither prospect is very attractive, so let's
534 get it over with.
535
536 The basic operations we need to do are (1)~inputting and outputting of
537 text, to or from a file or the user's terminal; (2)~inputting and
538 outputting of eight-bit bytes, to or from a file; (3)~instructing the
539 operating system to initiate (``open'') or to terminate (``close'') input or
540 output from a specified file; (4)~testing whether the end of an input
541 file has been reached; (5)~display of bits on the user's screen.
542 The bit-display operation will be discussed in a later section; we shall
543 deal here only with more traditional kinds of I/O.
544
545 @ Finding files happens in a slightly roundabout fashion: the \MP\
546 instance object contains a field that holds a function pointer that finds a
547 file, and returns its name, or NULL. For this, it receives three
548 parameters: the non-qualified name |fname|, the intended |fopen|
549 operation type |fmode|, and the type of the file |ftype|.
550
551 The file types that are passed on in |ftype| can be  used to 
552 differentiate file searches if a library like kpathsea is used,
553 the fopen mode is passed along for the same reason.
554
555 @<Types...@>=
556 typedef unsigned char eight_bits ; /* unsigned one-byte quantity */
557
558 @ @<Exported types@>=
559 enum mp_filetype {
560   mp_filetype_terminal = 0, /* the terminal */
561   mp_filetype_error, /* the terminal */
562   mp_filetype_program , /* \MP\ language input */
563   mp_filetype_log,  /* the log file */
564   mp_filetype_postscript, /* the postscript output */
565   mp_filetype_memfile, /* memory dumps */
566   mp_filetype_metrics, /* TeX font metric files */
567   mp_filetype_fontmap, /* PostScript font mapping files */
568   mp_filetype_font, /*  PostScript type1 font programs */
569   mp_filetype_encoding, /*  PostScript font encoding files */
570   mp_filetype_text,  /* first text file for readfrom and writeto primitives */
571 };
572 typedef char *(*mp_file_finder)(char *, char *, int);
573 typedef void *(*mp_file_opener)(char *, char *, int);
574 typedef char *(*mp_file_reader)(void *, size_t *);
575 typedef void (*mp_binfile_reader)(void *, void **, size_t *);
576 typedef void (*mp_file_closer)(void *);
577 typedef int (*mp_file_eoftest)(void *);
578 typedef void (*mp_file_flush)(void *);
579 typedef void (*mp_file_writer)(void *, char *);
580 typedef void (*mp_binfile_writer)(void *, void *, size_t);
581 #define NOTTESTING 1
582
583 @ @<Glob...@>=
584 mp_file_finder find_file;
585 mp_file_opener open_file;
586 mp_file_reader read_ascii_file;
587 mp_binfile_reader read_binary_file;
588 mp_file_closer close_file;
589 mp_file_eoftest eof_file;
590 mp_file_flush flush_file;
591 mp_file_writer write_ascii_file;
592 mp_binfile_writer write_binary_file;
593
594 @ @<Option variables@>=
595 mp_file_finder find_file;
596 mp_file_opener open_file;
597 mp_file_reader read_ascii_file;
598 mp_binfile_reader read_binary_file;
599 mp_file_closer close_file;
600 mp_file_eoftest eof_file;
601 mp_file_flush flush_file;
602 mp_file_writer write_ascii_file;
603 mp_binfile_writer write_binary_file;
604
605 @ The default function for finding files is |mp_find_file|. It is 
606 pretty stupid: it will only find files in the current directory.
607
608 This function may disappear altogether, it is currently only
609 used for the default font map file.
610
611 @c
612 char *mp_find_file (char *fname, char *fmode, int ftype)  {
613   if (fmode[0] != 'r' || access (fname,R_OK) || ftype) {  
614      return strdup(fname);
615   }
616   return NULL;
617 }
618
619 @ This has to be done very early on, so it is best to put it in with
620 the |mp_new| allocations
621
622 @d set_callback_option(A) do { mp->A = mp_##A;
623   if (opt->A!=NULL) mp->A = opt->A;
624 } while (0)
625
626 @<Allocate or initialize ...@>=
627 set_callback_option(find_file);
628 set_callback_option(open_file);
629 set_callback_option(read_ascii_file);
630 set_callback_option(read_binary_file);
631 set_callback_option(close_file);
632 set_callback_option(eof_file);
633 set_callback_option(flush_file);
634 set_callback_option(write_ascii_file);
635 set_callback_option(write_binary_file);
636
637 @ Because |mp_find_file| is used so early, it has to be in the helpers
638 section.
639
640 @<Internal ...@>=
641 char *mp_find_file (char *fname, char *fmode, int ftype) ;
642 void *mp_open_file (char *fname, char *fmode, int ftype) ;
643 char *mp_read_ascii_file (void *f, size_t *size) ;
644 void mp_read_binary_file (void *f, void **d, size_t *size) ;
645 void mp_close_file (void *f) ;
646 int mp_eof_file (void *f) ;
647 void mp_flush_file (void *f) ;
648 void mp_write_ascii_file (void *f, char *s) ;
649 void mp_write_binary_file (void *f, void *s, size_t t) ;
650
651 @ The function to open files can now be very short.
652
653 @c
654 void *mp_open_file(char *fname, char *fmode, int ftype)  {
655 #if NOTTESTING
656   if (ftype==mp_filetype_terminal) {
657     return (fmode[0] == 'r' ? stdin : stdout);
658   } else if (ftype==mp_filetype_error) {
659     return stderr;
660   } else if (fname != NULL && (fmode[0] != 'r' || access (fname,R_OK))) {
661     return (void *)fopen(fname, fmode);
662   }
663 #endif
664   return NULL;
665 }
666
667 @ This is a legacy interface: (almost) all file names pass through |name_of_file|.
668
669 @<Glob...@>=
670 char name_of_file[file_name_size+1]; /* the name of a system file */
671 int name_length;/* this many characters are actually
672   relevant in |name_of_file| (the rest are blank) */
673 boolean print_found_names; /* configuration parameter */
674
675 @ @<Option variables@>=
676 int print_found_names; /* configuration parameter */
677
678 @ If this parameter is true, the terminal and log will report the found
679 file names for input files instead of the requested ones. 
680 It is off by default because it creates an extra filename lookup.
681
682 @<Allocate or initialize ...@>=
683 mp->print_found_names = (opt->print_found_names>0 ? true : false);
684
685 @ \MP's file-opening procedures return |false| if no file identified by
686 |name_of_file| could be opened.
687
688 The |OPEN_FILE| macro takes care of the |print_found_names| parameter.
689 It is not used for opening a mem file for read, because that file name 
690 is never printed.
691
692 @d OPEN_FILE(A) do {
693   if (mp->print_found_names) {
694     char *s = (mp->find_file)(mp->name_of_file,A,ftype);
695     if (s!=NULL) {
696       *f = (mp->open_file)(mp->name_of_file,A, ftype); 
697       strncpy(mp->name_of_file,s,file_name_size);
698       xfree(s);
699     } else {
700       *f = NULL;
701     }
702   } else {
703     *f = (mp->open_file)(mp->name_of_file,A, ftype); 
704   }
705 } while (0);
706 return (*f ? true : false)
707
708 @c 
709 boolean mp_a_open_in (MP mp, void **f, int ftype) {
710   /* open a text file for input */
711   OPEN_FILE("r");
712 }
713 @#
714 boolean mp_w_open_in (MP mp, void **f) {
715   /* open a word file for input */
716   *f = (mp->open_file)(mp->name_of_file,"rb",mp_filetype_memfile); 
717   return (*f ? true : false);
718 }
719 @#
720 boolean mp_a_open_out (MP mp, void **f, int ftype) {
721   /* open a text file for output */
722   OPEN_FILE("w");
723 }
724 @#
725 boolean mp_b_open_out (MP mp, void **f, int ftype) {
726   /* open a binary file for output */
727   OPEN_FILE("wb");
728 }
729 @#
730 boolean mp_w_open_out (MP mp, void **f) {
731   /* open a word file for output */
732   int ftype = mp_filetype_memfile;
733   OPEN_FILE("wb");
734 }
735
736 @ @c
737 char *mp_read_ascii_file (void *f, size_t *size) {
738   int c;
739   size_t len = 0, lim = 128;
740   char *s = NULL;
741   *size = 0;
742 #if NOTTESTING
743   c = fgetc(f);
744   if (c==EOF)
745     return NULL;
746   s = malloc(lim); 
747   if (s==NULL) return NULL;
748   while (c!=EOF && c!='\n' && c!='\r') { 
749     if (len==lim) {
750       s =realloc(s, (lim+(lim>>2)));
751       if (s==NULL) return NULL;
752       lim+=(lim>>2);
753     }
754         s[len++] = c;
755     c =fgetc(f);
756   }
757   if (c=='\r') {
758     c = fgetc(f);
759     if (c!=EOF && c!='\n')
760        ungetc(c,f);
761   }
762   s[len] = 0;
763   *size = len;
764 #endif
765   return s;
766 }
767
768 @ @c
769 void mp_write_ascii_file (void *f, char *s) {
770 #if NOTTESTING
771   if (f!=null) {
772     fputs(s,f);
773   }
774 #endif
775 }
776
777 @ @c
778 void mp_read_binary_file (void *f, void **data, size_t *size) {
779   size_t len = 0;
780 #if NOTTESTING
781   len = fread(*data,1,*size,f);
782 #endif
783   *size = len;
784 }
785
786 @ @c
787 void mp_write_binary_file (void *f, void *s, size_t size) {
788 #if NOTTESTING
789   if (f!=null)
790     fwrite(s,size,1,f);
791 #endif
792 }
793
794
795 @ @c
796 void mp_close_file (void *f) {
797 #if NOTTESTING
798   fclose(f);
799 #endif
800 }
801
802 @ @c
803 int mp_eof_file (void *f) {
804 #if NOTTESTING
805   return feof(f);
806 #else
807   return 0;
808 #endif
809 }
810
811 @ @c
812 void mp_flush_file (void *f) {
813 #if NOTTESTING
814   fflush(f);
815 #endif
816 }
817
818 @ Binary input and output are done with \PASCAL's ordinary |get| and |put|
819 procedures, so we don't have to make any other special arrangements for
820 binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
821 The treatment of text input is more difficult, however, because
822 of the necessary translation to |ASCII_code| values.
823 \MP's conventions should be efficient, and they should
824 blend nicely with the user's operating environment.
825
826 @ Input from text files is read one line at a time, using a routine called
827 |input_ln|. This function is defined in terms of global variables called
828 |buffer|, |first|, and |last| that will be described in detail later; for
829 now, it suffices for us to know that |buffer| is an array of |ASCII_code|
830 values, and that |first| and |last| are indices into this array
831 representing the beginning and ending of a line of text.
832
833 @<Glob...@>=
834 size_t buf_size; /* maximum number of characters simultaneously present in
835                     current lines of open files */
836 ASCII_code *buffer; /* lines of characters being read */
837 size_t first; /* the first unused position in |buffer| */
838 size_t last; /* end of the line just input to |buffer| */
839 size_t max_buf_stack; /* largest index used in |buffer| */
840
841 @ @<Allocate or initialize ...@>=
842 mp->buf_size = 200;
843 mp->buffer = xmalloc((mp->buf_size+1),sizeof(ASCII_code));
844
845 @ @<Dealloc variables@>=
846 xfree(mp->buffer);
847
848 @ @c
849 void mp_reallocate_buffer(MP mp, size_t l) {
850   ASCII_code *buffer;
851   if (l>max_halfword) {
852     mp_confusion(mp,"buffer size"); /* can't happen (I hope) */
853   }
854   buffer = xmalloc((l+1),sizeof(ASCII_code));
855   memcpy(buffer,mp->buffer,(mp->buf_size+1));
856   xfree(mp->buffer);
857   mp->buffer = buffer ;
858   mp->buf_size = l;
859 }
860
861 @ The |input_ln| function brings the next line of input from the specified
862 field into available positions of the buffer array and returns the value
863 |true|, unless the file has already been entirely read, in which case it
864 returns |false| and sets |last:=first|.  In general, the |ASCII_code|
865 numbers that represent the next line of the file are input into
866 |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
867 global variable |last| is set equal to |first| plus the length of the
868 line. Trailing blanks are removed from the line; thus, either |last=first|
869 (in which case the line was entirely blank) or |buffer[last-1]<>" "|.
870 @^inner loop@>
871
872 The variable |max_buf_stack|, which is used to keep track of how large
873 the |buf_size| parameter must be to accommodate the present job, is
874 also kept up to date by |input_ln|.
875
876 @c 
877 boolean mp_input_ln (MP mp, void *f ) {
878   /* inputs the next line or returns |false| */
879   char *s;
880   size_t size = 0; 
881   mp->last=mp->first; /* cf.\ Matthew 19\thinspace:\thinspace30 */
882   s = (mp->read_ascii_file)(f, &size);
883   if (s==NULL)
884         return false;
885   if (size>0) {
886     mp->last = mp->first+size;
887     if ( mp->last>=mp->max_buf_stack ) { 
888       mp->max_buf_stack=mp->last+1;
889       while ( mp->max_buf_stack>=mp->buf_size ) {
890         mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
891       }
892     }
893     memcpy((mp->buffer+mp->first),s,size);
894     free(s);
895     /* while ( mp->buffer[mp->last]==' ' ) mp->last--; */
896   } 
897   return true;
898 }
899
900 @ The user's terminal acts essentially like other files of text, except
901 that it is used both for input and for output. When the terminal is
902 considered an input file, the file variable is called |term_in|, and when it
903 is considered an output file the file variable is |term_out|.
904 @^system dependencies@>
905
906 @<Glob...@>=
907 void * term_in; /* the terminal as an input file */
908 void * term_out; /* the terminal as an output file */
909 void * err_out; /* the terminal as an output file */
910
911 @ Here is how to open the terminal files. In the default configuration,
912 nothing happens except that the command line (if there is one) is copied
913 to the input buffer.  The variable |command_line| will be filled by the 
914 |main| procedure. The copying can not be done earlier in the program 
915 logic because in the |INI| version, the |buffer| is also used for primitive 
916 initialization.
917
918 @^system dependencies@>
919
920 @d t_open_out  do {/* open the terminal for text output */
921     mp->term_out = (mp->open_file)("terminal", "w", mp_filetype_terminal);
922     mp->err_out = (mp->open_file)("error", "w", mp_filetype_error);
923 } while (0)
924 @d t_open_in  do { /* open the terminal for text input */
925     mp->term_in = (mp->open_file)("terminal", "r", mp_filetype_terminal);
926     if (mp->command_line!=NULL) {
927       mp->last = strlen(mp->command_line);
928       strncpy((char *)mp->buffer,mp->command_line,mp->last);
929       xfree(mp->command_line);
930     }
931 } while (0)
932
933 @<Glob...@>=
934 char *command_line;
935
936 @ @<Option variables@>=
937 char *command_line;
938
939 @ @<Allocate or initialize ...@>=
940 mp->command_line = opt->command_line;
941
942 @ Sometimes it is necessary to synchronize the input/output mixture that
943 happens on the user's terminal, and three system-dependent
944 procedures are used for this
945 purpose. The first of these, |update_terminal|, is called when we want
946 to make sure that everything we have output to the terminal so far has
947 actually left the computer's internal buffers and been sent.
948 The second, |clear_terminal|, is called when we wish to cancel any
949 input that the user may have typed ahead (since we are about to
950 issue an unexpected error message). The third, |wake_up_terminal|,
951 is supposed to revive the terminal if the user has disabled it by
952 some instruction to the operating system.  The following macros show how
953 these operations can be specified in \ph:
954 @^system dependencies@>
955
956 @d update_terminal   (mp->flush_file)(mp->term_out) /* empty the terminal output buffer */
957 @d clear_terminal   do_nothing /* clear the terminal input buffer */
958 @d wake_up_terminal  (mp->flush_file)(mp->term_out) /* cancel the user's cancellation of output */
959
960 @ We need a special routine to read the first line of \MP\ input from
961 the user's terminal. This line is different because it is read before we
962 have opened the transcript file; there is sort of a ``chicken and
963 egg'' problem here. If the user types `\.{input cmr10}' on the first
964 line, or if some macro invoked by that line does such an \.{input},
965 the transcript file will be named `\.{cmr10.log}'; but if no \.{input}
966 commands are performed during the first line of terminal input, the transcript
967 file will acquire its default name `\.{mpout.log}'. (The transcript file
968 will not contain error messages generated by the first line before the
969 first \.{input} command.)
970
971 The first line is even more special if we are lucky enough to have an operating
972 system that treats \MP\ differently from a run-of-the-mill \PASCAL\ object
973 program. It's nice to let the user start running a \MP\ job by typing
974 a command line like `\.{MP cmr10}'; in such a case, \MP\ will operate
975 as if the first line of input were `\.{cmr10}', i.e., the first line will
976 consist of the remainder of the command line, after the part that invoked \MP.
977
978 @ Different systems have different ways to get started. But regardless of
979 what conventions are adopted, the routine that initializes the terminal
980 should satisfy the following specifications:
981
982 \yskip\textindent{1)}It should open file |term_in| for input from the
983   terminal. (The file |term_out| will already be open for output to the
984   terminal.)
985
986 \textindent{2)}If the user has given a command line, this line should be
987   considered the first line of terminal input. Otherwise the
988   user should be prompted with `\.{**}', and the first line of input
989   should be whatever is typed in response.
990
991 \textindent{3)}The first line of input, which might or might not be a
992   command line, should appear in locations |first| to |last-1| of the
993   |buffer| array.
994
995 \textindent{4)}The global variable |loc| should be set so that the
996   character to be read next by \MP\ is in |buffer[loc]|. This
997   character should not be blank, and we should have |loc<last|.
998
999 \yskip\noindent(It may be necessary to prompt the user several times
1000 before a non-blank line comes in. The prompt is `\.{**}' instead of the
1001 later `\.*' because the meaning is slightly different: `\.{input}' need
1002 not be typed immediately after~`\.{**}'.)
1003
1004 @d loc mp->cur_input.loc_field /* location of first unread character in |buffer| */
1005
1006 @ The following program does the required initialization
1007 without retrieving a possible command line.
1008 It should be clear how to modify this routine to deal with command lines,
1009 if the system permits them.
1010 @^system dependencies@>
1011
1012 @c 
1013 boolean mp_init_terminal (MP mp) { /* gets the terminal input started */
1014   t_open_in; 
1015   if (mp->last!=0) {
1016     loc = mp->first = 0;
1017         return true;
1018   }
1019   while (1) { 
1020     wake_up_terminal; do_fprintf(mp->term_out,"**"); update_terminal;
1021 @.**@>
1022     if ( ! mp_input_ln(mp, mp->term_in ) ) { /* this shouldn't happen */
1023       do_fprintf(mp->term_out,"\n! End of file on the terminal... why?");
1024 @.End of file on the terminal@>
1025       return false;
1026     }
1027     loc=mp->first;
1028     while ( (loc<(int)mp->last)&&(mp->buffer[loc]==' ') ) 
1029       incr(loc);
1030     if ( loc<(int)mp->last ) { 
1031       return true; /* return unless the line was all blank */
1032     };
1033     do_fprintf(mp->term_out,"Please type the name of your input file.\n");
1034   }
1035 }
1036
1037 @ @<Declarations@>=
1038 boolean mp_init_terminal (MP mp) ;
1039
1040
1041 @* \[4] String handling.
1042 Symbolic token names and diagnostic messages are variable-length strings
1043 of eight-bit characters. Since \PASCAL\ does not have a well-developed string
1044 mechanism, \MP\ does all of its string processing by homegrown methods.
1045
1046 \MP\ uses strings more extensively than \MF\ does, but the necessary
1047 operations can still be handled with a fairly simple data structure.
1048 The array |str_pool| contains all of the (eight-bit) ASCII codes in all
1049 of the strings, and the array |str_start| contains indices of the starting
1050 points of each string. Strings are referred to by integer numbers, so that
1051 string number |s| comprises the characters |str_pool[j]| for
1052 |str_start[s]<=j<str_start[ss]| where |ss=next_str[s]|.  The string pool
1053 is allocated sequentially and |str_pool[pool_ptr]| is the next unused
1054 location.  The first string number not currently in use is |str_ptr|
1055 and |next_str[str_ptr]| begins a list of free string numbers.  String
1056 pool entries |str_start[str_ptr]| up to |pool_ptr| are reserved for a
1057 string currently being constructed.
1058
1059 String numbers 0 to 255 are reserved for strings that correspond to single
1060 ASCII characters. This is in accordance with the conventions of \.{WEB},
1061 @.WEB@>
1062 which converts single-character strings into the ASCII code number of the
1063 single character involved, while it converts other strings into integers
1064 and builds a string pool file. Thus, when the string constant \.{"."} appears
1065 in the program below, \.{WEB} converts it into the integer 46, which is the
1066 ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
1067 into some integer greater than~255. String number 46 will presumably be the
1068 single character `\..'\thinspace; but some ASCII codes have no standard visible
1069 representation, and \MP\ may need to be able to print an arbitrary
1070 ASCII character, so the first 256 strings are used to specify exactly what
1071 should be printed for each of the 256 possibilities.
1072
1073 @<Types...@>=
1074 typedef int pool_pointer; /* for variables that point into |str_pool| */
1075 typedef int str_number; /* for variables that point into |str_start| */
1076
1077 @ @<Glob...@>=
1078 ASCII_code *str_pool; /* the characters */
1079 pool_pointer *str_start; /* the starting pointers */
1080 str_number *next_str; /* for linking strings in order */
1081 pool_pointer pool_ptr; /* first unused position in |str_pool| */
1082 str_number str_ptr; /* number of the current string being created */
1083 pool_pointer init_pool_ptr; /* the starting value of |pool_ptr| */
1084 str_number init_str_use; /* the initial number of strings in use */
1085 pool_pointer max_pool_ptr; /* the maximum so far of |pool_ptr| */
1086 str_number max_str_ptr; /* the maximum so far of |str_ptr| */
1087
1088 @ @<Allocate or initialize ...@>=
1089 mp->str_pool  = xmalloc ((mp->pool_size +1),sizeof(ASCII_code));
1090 mp->str_start = xmalloc ((mp->max_strings+1),sizeof(pool_pointer));
1091 mp->next_str  = xmalloc ((mp->max_strings+1),sizeof(str_number));
1092
1093 @ @<Dealloc variables@>=
1094 xfree(mp->str_pool);
1095 xfree(mp->str_start);
1096 xfree(mp->next_str);
1097
1098 @ Most printing is done from |char *|s, but sometimes not. Here are
1099 functions that convert an internal string into a |char *| for use
1100 by the printing routines, and vice versa.
1101
1102 @d str(A) mp_str(mp,A)
1103 @d rts(A) mp_rts(mp,A)
1104
1105 @<Internal ...@>=
1106 int mp_xstrcmp (const char *a, const char *b);
1107 char * mp_str (MP mp, str_number s);
1108
1109 @ @<Declarations@>=
1110 str_number mp_rts (MP mp, char *s);
1111 str_number mp_make_string (MP mp);
1112
1113 @ The attempt to catch interrupted strings that is in |mp_rts|, is not 
1114 very good: it does not handle nesting over more than one level.
1115
1116 @c 
1117 int mp_xstrcmp (const char *a, const char *b) {
1118         if (a==NULL && b==NULL) 
1119           return 0;
1120     if (a==NULL)
1121       return -1;
1122     if (b==NULL)
1123       return 1;
1124     return strcmp(a,b);
1125 }
1126
1127 @ @c
1128 char * mp_str (MP mp, str_number ss) {
1129   char *s;
1130   int len;
1131   if (ss==mp->str_ptr) {
1132     return NULL;
1133   } else {
1134     len = length(ss);
1135     s = xmalloc(len+1,sizeof(char));
1136     strncpy(s,(char *)(mp->str_pool+(mp->str_start[ss])),len);
1137     s[len] = 0;
1138     return (char *)s;
1139   }
1140 }
1141 str_number mp_rts (MP mp, char *s) {
1142   int r; /* the new string */ 
1143   int old; /* a possible string in progress */
1144   int i=0;
1145   if (strlen(s)==0) {
1146     return 256;
1147   } else if (strlen(s)==1) {
1148     return s[0];
1149   } else {
1150    old=0;
1151    str_room((integer)strlen(s));
1152    if (mp->str_start[mp->str_ptr]<mp->pool_ptr)
1153      old = mp_make_string(mp);
1154    while (*s) {
1155      append_char(*s);
1156      s++;
1157    }
1158    r = mp_make_string(mp);
1159    if (old!=0) {
1160       str_room(length(old));
1161       while (i<length(old)) {
1162         append_char((mp->str_start[old]+i));
1163       } 
1164       mp_flush_string(mp,old);
1165     }
1166     return r;
1167   }
1168 }
1169
1170 @ Except for |strs_used_up|, the following string statistics are only
1171 maintained when code between |stat| $\ldots$ |tats| delimiters is not
1172 commented out:
1173
1174 @<Glob...@>=
1175 integer strs_used_up; /* strings in use or unused but not reclaimed */
1176 integer pool_in_use; /* total number of cells of |str_pool| actually in use */
1177 integer strs_in_use; /* total number of strings actually in use */
1178 integer max_pl_used; /* maximum |pool_in_use| so far */
1179 integer max_strs_used; /* maximum |strs_in_use| so far */
1180
1181 @ Several of the elementary string operations are performed using \.{WEB}
1182 macros instead of \PASCAL\ procedures, because many of the
1183 operations are done quite frequently and we want to avoid the
1184 overhead of procedure calls. For example, here is
1185 a simple macro that computes the length of a string.
1186 @.WEB@>
1187
1188 @d str_stop(A) mp->str_start[mp->next_str[(A)]] /* one cell past the end of string
1189   number \# */
1190 @d length(A) (str_stop((A))-mp->str_start[(A)]) /* the number of characters in string \# */
1191
1192 @ The length of the current string is called |cur_length|.  If we decide that
1193 the current string is not needed, |flush_cur_string| resets |pool_ptr| so that
1194 |cur_length| becomes zero.
1195
1196 @d cur_length   (mp->pool_ptr - mp->str_start[mp->str_ptr])
1197 @d flush_cur_string   mp->pool_ptr=mp->str_start[mp->str_ptr]
1198
1199 @ Strings are created by appending character codes to |str_pool|.
1200 The |append_char| macro, defined here, does not check to see if the
1201 value of |pool_ptr| has gotten too high; this test is supposed to be
1202 made before |append_char| is used.
1203
1204 To test if there is room to append |l| more characters to |str_pool|,
1205 we shall write |str_room(l)|, which tries to make sure there is enough room
1206 by compacting the string pool if necessary.  If this does not work,
1207 |do_compaction| aborts \MP\ and gives an apologetic error message.
1208
1209 @d append_char(A)   /* put |ASCII_code| \# at the end of |str_pool| */
1210 { mp->str_pool[mp->pool_ptr]=(A); incr(mp->pool_ptr);
1211 }
1212 @d str_room(A)   /* make sure that the pool hasn't overflowed */
1213   { if ( mp->pool_ptr+(A) > mp->max_pool_ptr ) {
1214     if ( mp->pool_ptr+(A) > mp->pool_size ) mp_do_compaction(mp, (A));
1215     else mp->max_pool_ptr=mp->pool_ptr+(A); }
1216   }
1217
1218 @ The following routine is similar to |str_room(1)| but it uses the
1219 argument |mp->pool_size| to prevent |do_compaction| from aborting when
1220 string space is exhausted.
1221
1222 @<Declare the procedure called |unit_str_room|@>=
1223 void mp_unit_str_room (MP mp);
1224
1225 @ @c
1226 void mp_unit_str_room (MP mp) { 
1227   if ( mp->pool_ptr>=mp->pool_size ) mp_do_compaction(mp, mp->pool_size);
1228   if ( mp->pool_ptr>=mp->max_pool_ptr ) mp->max_pool_ptr=mp->pool_ptr+1;
1229 }
1230
1231 @ \MP's string expressions are implemented in a brute-force way: Every
1232 new string or substring that is needed is simply copied into the string pool.
1233 Space is eventually reclaimed by a procedure called |do_compaction| with
1234 the aid of a simple system system of reference counts.
1235 @^reference counts@>
1236
1237 The number of references to string number |s| will be |str_ref[s]|. The
1238 special value |str_ref[s]=max_str_ref=127| is used to denote an unknown
1239 positive number of references; such strings will never be recycled. If
1240 a string is ever referred to more than 126 times, simultaneously, we
1241 put it in this category. Hence a single byte suffices to store each |str_ref|.
1242
1243 @d max_str_ref 127 /* ``infinite'' number of references */
1244 @d add_str_ref(A) { if ( mp->str_ref[(A)]<max_str_ref ) incr(mp->str_ref[(A)]);
1245   }
1246
1247 @<Glob...@>=
1248 int *str_ref;
1249
1250 @ @<Allocate or initialize ...@>=
1251 mp->str_ref = xmalloc ((mp->max_strings+1),sizeof(int));
1252
1253 @ @<Dealloc variables@>=
1254 xfree(mp->str_ref);
1255
1256 @ Here's what we do when a string reference disappears:
1257
1258 @d delete_str_ref(A)  { 
1259     if ( mp->str_ref[(A)]<max_str_ref ) {
1260        if ( mp->str_ref[(A)]>1 ) decr(mp->str_ref[(A)]); 
1261        else mp_flush_string(mp, (A));
1262     }
1263   }
1264
1265 @<Declare the procedure called |flush_string|@>=
1266 void mp_flush_string (MP mp,str_number s) ;
1267
1268
1269 @ We can't flush the first set of static strings at all, so there 
1270 is no point in trying
1271
1272 @c
1273 void mp_flush_string (MP mp,str_number s) { 
1274   if (length(s)>1) {
1275     mp->pool_in_use=mp->pool_in_use-length(s);
1276     decr(mp->strs_in_use);
1277     if ( mp->next_str[s]!=mp->str_ptr ) {
1278       mp->str_ref[s]=0;
1279     } else { 
1280       mp->str_ptr=s;
1281       decr(mp->strs_used_up);
1282     }
1283     mp->pool_ptr=mp->str_start[mp->str_ptr];
1284   }
1285 }
1286
1287 @ C literals cannot be simply added, they need to be set so they can't
1288 be flushed.
1289
1290 @d intern(A) mp_intern(mp,(A))
1291
1292 @c
1293 str_number mp_intern (MP mp, char *s) {
1294   str_number r ;
1295   r = rts(s);
1296   mp->str_ref[r] = max_str_ref;
1297   return r;
1298 }
1299
1300 @ @<Declarations@>=
1301 str_number mp_intern (MP mp, char *s);
1302
1303
1304 @ Once a sequence of characters has been appended to |str_pool|, it
1305 officially becomes a string when the function |make_string| is called.
1306 This function returns the identification number of the new string as its
1307 value.
1308
1309 When getting the next unused string number from the linked list, we pretend
1310 that
1311 $$ \hbox{|max_str_ptr+1|, |max_str_ptr+2|, $\ldots$, |mp->max_strings|} $$
1312 are linked sequentially even though the |next_str| entries have not been
1313 initialized yet.  We never allow |str_ptr| to reach |mp->max_strings|;
1314 |do_compaction| is responsible for making sure of this.
1315
1316 @<Declarations@>=
1317 @<Declare the procedure called |do_compaction|@>;
1318 @<Declare the procedure called |unit_str_room|@>;
1319 str_number mp_make_string (MP mp);
1320
1321 @ @c 
1322 str_number mp_make_string (MP mp) { /* current string enters the pool */
1323   str_number s; /* the new string */
1324 RESTART: 
1325   s=mp->str_ptr;
1326   mp->str_ptr=mp->next_str[s];
1327   if ( mp->str_ptr>mp->max_str_ptr ) {
1328     if ( mp->str_ptr==mp->max_strings ) { 
1329       mp->str_ptr=s;
1330       mp_do_compaction(mp, 0);
1331       goto RESTART;
1332     } else {
1333 #ifdef DEBUG 
1334       if ( mp->strs_used_up!=mp->max_str_ptr ) mp_confusion(mp, "s");
1335 @:this can't happen s}{\quad \.s@>
1336 #endif
1337       mp->max_str_ptr=mp->str_ptr;
1338       mp->next_str[mp->str_ptr]=mp->max_str_ptr+1;
1339     }
1340   }
1341   mp->str_ref[s]=1;
1342   mp->str_start[mp->str_ptr]=mp->pool_ptr;
1343   incr(mp->strs_used_up);
1344   incr(mp->strs_in_use);
1345   mp->pool_in_use=mp->pool_in_use+length(s);
1346   if ( mp->pool_in_use>mp->max_pl_used ) 
1347     mp->max_pl_used=mp->pool_in_use;
1348   if ( mp->strs_in_use>mp->max_strs_used ) 
1349     mp->max_strs_used=mp->strs_in_use;
1350   return s;
1351 }
1352
1353 @ The most interesting string operation is string pool compaction.  The idea
1354 is to recover unused space in the |str_pool| array by recopying the strings
1355 to close the gaps created when some strings become unused.  All string
1356 numbers~$k$ where |str_ref[k]=0| are to be linked into the list of free string
1357 numbers after |str_ptr|.  If this fails to free enough pool space we issue an
1358 |overflow| error unless |needed=mp->pool_size|.  Calling |do_compaction|
1359 with |needed=mp->pool_size| supresses all overflow tests.
1360
1361 The compaction process starts with |last_fixed_str| because all lower numbered
1362 strings are permanently allocated with |max_str_ref| in their |str_ref| entries.
1363
1364 @<Glob...@>=
1365 str_number last_fixed_str; /* last permanently allocated string */
1366 str_number fixed_str_use; /* number of permanently allocated strings */
1367
1368 @ @<Declare the procedure called |do_compaction|@>=
1369 void mp_do_compaction (MP mp, pool_pointer needed) ;
1370
1371 @ @c
1372 void mp_do_compaction (MP mp, pool_pointer needed) {
1373   str_number str_use; /* a count of strings in use */
1374   str_number r,s,t; /* strings being manipulated */
1375   pool_pointer p,q; /* destination and source for copying string characters */
1376   @<Advance |last_fixed_str| as far as possible and set |str_use|@>;
1377   r=mp->last_fixed_str;
1378   s=mp->next_str[r];
1379   p=mp->str_start[s];
1380   while ( s!=mp->str_ptr ) { 
1381     while ( mp->str_ref[s]==0 ) {
1382       @<Advance |s| and add the old |s| to the list of free string numbers;
1383         then |break| if |s=str_ptr|@>;
1384     }
1385     r=s; s=mp->next_str[s];
1386     incr(str_use);
1387     @<Move string |r| back so that |str_start[r]=p|; make |p| the location
1388      after the end of the string@>;
1389   }
1390   @<Move the current string back so that it starts at |p|@>;
1391   if ( needed<mp->pool_size ) {
1392     @<Make sure that there is room for another string with |needed| characters@>;
1393   }
1394   @<Account for the compaction and make sure the statistics agree with the
1395      global versions@>;
1396   mp->strs_used_up=str_use;
1397 }
1398
1399 @ @<Advance |last_fixed_str| as far as possible and set |str_use|@>=
1400 t=mp->next_str[mp->last_fixed_str];
1401 while (t!=mp->str_ptr && mp->str_ref[t]==max_str_ref) {
1402   incr(mp->fixed_str_use);
1403   mp->last_fixed_str=t;
1404   t=mp->next_str[t];
1405 }
1406 str_use=mp->fixed_str_use
1407
1408 @ Because of the way |flush_string| has been written, it should never be
1409 necessary to |break| here.  The extra line of code seems worthwhile to
1410 preserve the generality of |do_compaction|.
1411
1412 @<Advance |s| and add the old |s| to the list of free string numbers;...@>=
1413 {
1414 t=s;
1415 s=mp->next_str[s];
1416 mp->next_str[r]=s;
1417 mp->next_str[t]=mp->next_str[mp->str_ptr];
1418 mp->next_str[mp->str_ptr]=t;
1419 if ( s==mp->str_ptr ) break;
1420 }
1421
1422 @ The string currently starts at |str_start[r]| and ends just before
1423 |str_start[s]|.  We don't change |str_start[s]| because it might be needed
1424 to locate the next string.
1425
1426 @<Move string |r| back so that |str_start[r]=p|; make |p| the location...@>=
1427 q=mp->str_start[r];
1428 mp->str_start[r]=p;
1429 while ( q<mp->str_start[s] ) { 
1430   mp->str_pool[p]=mp->str_pool[q];
1431   incr(p); incr(q);
1432 }
1433
1434 @ Pointers |str_start[str_ptr]| and |pool_ptr| have not been updated.  When
1435 we do this, anything between them should be moved.
1436
1437 @ @<Move the current string back so that it starts at |p|@>=
1438 q=mp->str_start[mp->str_ptr];
1439 mp->str_start[mp->str_ptr]=p;
1440 while ( q<mp->pool_ptr ) { 
1441   mp->str_pool[p]=mp->str_pool[q];
1442   incr(p); incr(q);
1443 }
1444 mp->pool_ptr=p
1445
1446 @ We must remember that |str_ptr| is not allowed to reach |mp->max_strings|.
1447
1448 @<Make sure that there is room for another string with |needed| char...@>=
1449 if ( str_use>=mp->max_strings-1 )
1450   mp_reallocate_strings (mp,str_use);
1451 if ( mp->pool_ptr+needed>mp->max_pool_ptr ) {
1452   mp_reallocate_pool(mp, mp->pool_ptr+needed);
1453   mp->max_pool_ptr=mp->pool_ptr+needed;
1454 }
1455
1456 @ @<Declarations@>=
1457 void mp_reallocate_strings (MP mp, str_number str_use) ;
1458 void mp_reallocate_pool(MP mp, pool_pointer needed) ;
1459
1460 @ @c 
1461 void mp_reallocate_strings (MP mp, str_number str_use) { 
1462   while ( str_use>=mp->max_strings-1 ) {
1463     int l = mp->max_strings + (mp->max_strings>>2);
1464     XREALLOC (mp->str_ref,   l, int);
1465     XREALLOC (mp->str_start, l, pool_pointer);
1466     XREALLOC (mp->next_str,  l, str_number);
1467     mp->max_strings = l;
1468   }
1469 }
1470 void mp_reallocate_pool(MP mp, pool_pointer needed) {
1471   while ( needed>mp->pool_size ) {
1472     int l = mp->pool_size + (mp->pool_size>>2);
1473         XREALLOC (mp->str_pool, l, ASCII_code);
1474     mp->pool_size = l;
1475   }
1476 }
1477
1478 @ @<Account for the compaction and make sure the statistics agree with...@>=
1479 if ( (mp->str_start[mp->str_ptr]!=mp->pool_in_use)||(str_use!=mp->strs_in_use) )
1480   mp_confusion(mp, "string");
1481 @:this can't happen string}{\quad string@>
1482 incr(mp->pact_count);
1483 mp->pact_chars=mp->pact_chars+mp->pool_ptr-str_stop(mp->last_fixed_str);
1484 mp->pact_strs=mp->pact_strs+str_use-mp->fixed_str_use;
1485 #ifdef DEBUG
1486 s=mp->str_ptr; t=str_use;
1487 while ( s<=mp->max_str_ptr ){
1488   if ( t>mp->max_str_ptr ) mp_confusion(mp, "\"");
1489   incr(t); s=mp->next_str[s];
1490 };
1491 if ( t<=mp->max_str_ptr ) mp_confusion(mp, "\"");
1492 #endif
1493
1494 @ A few more global variables are needed to keep track of statistics when
1495 |stat| $\ldots$ |tats| blocks are not commented out.
1496
1497 @<Glob...@>=
1498 integer pact_count; /* number of string pool compactions so far */
1499 integer pact_chars; /* total number of characters moved during compactions */
1500 integer pact_strs; /* total number of strings moved during compactions */
1501
1502 @ @<Initialize compaction statistics@>=
1503 mp->pact_count=0;
1504 mp->pact_chars=0;
1505 mp->pact_strs=0;
1506
1507 @ The following subroutine compares string |s| with another string of the
1508 same length that appears in |buffer| starting at position |k|;
1509 the result is |true| if and only if the strings are equal.
1510
1511 @c 
1512 boolean mp_str_eq_buf (MP mp,str_number s, integer k) {
1513   /* test equality of strings */
1514   pool_pointer j; /* running index */
1515   j=mp->str_start[s];
1516   while ( j<str_stop(s) ) { 
1517     if ( mp->str_pool[j++]!=mp->buffer[k++] ) 
1518       return false;
1519   }
1520   return true;
1521 }
1522
1523 @ Here is a similar routine, but it compares two strings in the string pool,
1524 and it does not assume that they have the same length. If the first string
1525 is lexicographically greater than, less than, or equal to the second,
1526 the result is respectively positive, negative, or zero.
1527
1528 @c 
1529 integer mp_str_vs_str (MP mp, str_number s, str_number t) {
1530   /* test equality of strings */
1531   pool_pointer j,k; /* running indices */
1532   integer ls,lt; /* lengths */
1533   integer l; /* length remaining to test */
1534   ls=length(s); lt=length(t);
1535   if ( ls<=lt ) l=ls; else l=lt;
1536   j=mp->str_start[s]; k=mp->str_start[t];
1537   while ( l-->0 ) { 
1538     if ( mp->str_pool[j]!=mp->str_pool[k] ) {
1539        return (mp->str_pool[j]-mp->str_pool[k]); 
1540     }
1541     incr(j); incr(k);
1542   }
1543   return (ls-lt);
1544 }
1545
1546 @ The initial values of |str_pool|, |str_start|, |pool_ptr|,
1547 and |str_ptr| are computed by the \.{INIMP} program, based in part
1548 on the information that \.{WEB} has output while processing \MP.
1549 @.INIMP@>
1550 @^string pool@>
1551
1552 @c 
1553 void mp_get_strings_started (MP mp) { 
1554   /* initializes the string pool,
1555     but returns |false| if something goes wrong */
1556   int k; /* small indices or counters */
1557   str_number g; /* a new string */
1558   mp->pool_ptr=0; mp->str_ptr=0; mp->max_pool_ptr=0; mp->max_str_ptr=0;
1559   mp->str_start[0]=0;
1560   mp->next_str[0]=1;
1561   mp->pool_in_use=0; mp->strs_in_use=0;
1562   mp->max_pl_used=0; mp->max_strs_used=0;
1563   @<Initialize compaction statistics@>;
1564   mp->strs_used_up=0;
1565   @<Make the first 256 strings@>;
1566   g=mp_make_string(mp); /* string 256 == "" */
1567   mp->str_ref[g]=max_str_ref;
1568   mp->last_fixed_str=mp->str_ptr-1;
1569   mp->fixed_str_use=mp->str_ptr;
1570   return;
1571 }
1572
1573 @ @<Declarations@>=
1574 void mp_get_strings_started (MP mp);
1575
1576 @ The first 256 strings will consist of a single character only.
1577
1578 @<Make the first 256...@>=
1579 for (k=0;k<=255;k++) { 
1580   append_char(k);
1581   g=mp_make_string(mp); 
1582   mp->str_ref[g]=max_str_ref;
1583 }
1584
1585 @ The first 128 strings will contain 95 standard ASCII characters, and the
1586 other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
1587 unless a system-dependent change is made here. Installations that have
1588 an extended character set, where for example |xchr[032]=@t\.{'^^Z'}@>|,
1589 would like string 032 to be printed as the single character 032 instead
1590 of the three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand,
1591 even people with an extended character set will want to represent string
1592 015 by \.{\^\^M}, since 015 is ASCII's ``carriage return'' code; the idea is
1593 to produce visible strings instead of tabs or line-feeds or carriage-returns
1594 or bell-rings or characters that are treated anomalously in text files.
1595
1596 Unprintable characters of codes 128--255 are, similarly, rendered
1597 \.{\^\^80}--\.{\^\^ff}.
1598
1599 The boolean expression defined here should be |true| unless \MP\ internal
1600 code number~|k| corresponds to a non-troublesome visible symbol in the
1601 local character set.
1602 If character |k| cannot be printed, and |k<0200|, then character |k+0100| or
1603 |k-0100| must be printable; moreover, ASCII codes |[060..071, 0141..0146]|
1604 must be printable.
1605 @^character set dependencies@>
1606 @^system dependencies@>
1607
1608 @<Character |k| cannot be printed@>=
1609   (k<' ')||(k>'~')
1610
1611 @* \[5] On-line and off-line printing.
1612 Messages that are sent to a user's terminal and to the transcript-log file
1613 are produced by several `|print|' procedures. These procedures will
1614 direct their output to a variety of places, based on the setting of
1615 the global variable |selector|, which has the following possible
1616 values:
1617
1618 \yskip
1619 \hang |term_and_log|, the normal setting, prints on the terminal and on the
1620   transcript file.
1621
1622 \hang |log_only|, prints only on the transcript file.
1623
1624 \hang |term_only|, prints only on the terminal.
1625
1626 \hang |no_print|, doesn't print at all. This is used only in rare cases
1627   before the transcript file is open.
1628
1629 \hang |pseudo|, puts output into a cyclic buffer that is used
1630   by the |show_context| routine; when we get to that routine we shall discuss
1631   the reasoning behind this curious mode.
1632
1633 \hang |new_string|, appends the output to the current string in the
1634   string pool.
1635
1636 \hang |>=write_file| prints on one of the files used for the \&{write}
1637 @:write_}{\&{write} primitive@>
1638   command.
1639
1640 \yskip
1641 \noindent The symbolic names `|term_and_log|', etc., have been assigned
1642 numeric codes that satisfy the convenient relations |no_print+1=term_only|,
1643 |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.  These
1644 relations are not used when |selector| could be |pseudo|, or |new_string|.
1645 We need not check for unprintable characters when |selector<pseudo|.
1646
1647 Three additional global variables, |tally|, |term_offset| and |file_offset|
1648 record the number of characters that have been printed
1649 since they were most recently cleared to zero. We use |tally| to record
1650 the length of (possibly very long) stretches of printing; |term_offset|,
1651 and |file_offset|, on the other hand, keep track of how many
1652 characters have appeared so far on the current line that has been output
1653 to the terminal, the transcript file, or the \ps\ output file, respectively.
1654
1655 @d new_string 0 /* printing is deflected to the string pool */
1656 @d pseudo 2 /* special |selector| setting for |show_context| */
1657 @d no_print 3 /* |selector| setting that makes data disappear */
1658 @d term_only 4 /* printing is destined for the terminal only */
1659 @d log_only 5 /* printing is destined for the transcript file only */
1660 @d term_and_log 6 /* normal |selector| setting */
1661 @d write_file 7 /* first write file selector */
1662
1663 @<Glob...@>=
1664 void * log_file; /* transcript of \MP\ session */
1665 void * ps_file; /* the generic font output goes here */
1666 unsigned int selector; /* where to print a message */
1667 unsigned char dig[23]; /* digits in a number being output */
1668 integer tally; /* the number of characters recently printed */
1669 unsigned int term_offset;
1670   /* the number of characters on the current terminal line */
1671 unsigned int file_offset;
1672   /* the number of characters on the current file line */
1673 ASCII_code *trick_buf; /* circular buffer for pseudoprinting */
1674 integer trick_count; /* threshold for pseudoprinting, explained later */
1675 integer first_count; /* another variable for pseudoprinting */
1676
1677 @ @<Allocate or initialize ...@>=
1678 memset(mp->dig,0,23);
1679 mp->trick_buf = xmalloc((mp->error_line+1),sizeof(ASCII_code));
1680
1681 @ @<Dealloc variables@>=
1682 xfree(mp->trick_buf);
1683
1684 @ @<Initialize the output routines@>=
1685 mp->selector=term_only; mp->tally=0; mp->term_offset=0; mp->file_offset=0; 
1686
1687 @ Macro abbreviations for output to the terminal and to the log file are
1688 defined here for convenience. Some systems need special conventions
1689 for terminal output, and it is possible to adhere to those conventions
1690 by changing |wterm|, |wterm_ln|, and |wterm_cr| here.
1691 @^system dependencies@>
1692
1693 @d do_fprintf(f,b) (mp->write_ascii_file)(f,b)
1694 @d wterm(A)     do_fprintf(mp->term_out,(A))
1695 @d wterm_chr(A) { unsigned char ss[2]; ss[0]=(A); ss[1]=0; do_fprintf(mp->term_out,(char *)ss); }
1696 @d wterm_cr     do_fprintf(mp->term_out,"\n")
1697 @d wterm_ln(A)  { wterm_cr; do_fprintf(mp->term_out,(A)); }
1698 @d wlog(A)      do_fprintf(mp->log_file,(A))
1699 @d wlog_chr(A)  { unsigned char ss[2]; ss[0]=(A); ss[1]=0; do_fprintf(mp->log_file,(char *)ss); }
1700 @d wlog_cr      do_fprintf(mp->log_file, "\n")
1701 @d wlog_ln(A)   {wlog_cr; do_fprintf(mp->log_file,(A)); }
1702
1703
1704 @ To end a line of text output, we call |print_ln|.  Cases |0..max_write_files|
1705 use an array |wr_file| that will be declared later.
1706
1707 @d mp_print_text(A) mp_print_str(mp,text((A)))
1708
1709 @<Internal ...@>=
1710 void mp_print_ln (MP mp);
1711 void mp_print_visible_char (MP mp, ASCII_code s); 
1712 void mp_print_char (MP mp, ASCII_code k);
1713 void mp_print (MP mp, char *s);
1714 void mp_print_str (MP mp, str_number s);
1715 void mp_print_nl (MP mp, char *s);
1716 void mp_print_two (MP mp,scaled x, scaled y) ;
1717 void mp_print_scaled (MP mp,scaled s);
1718
1719 @ @<Basic print...@>=
1720 void mp_print_ln (MP mp) { /* prints an end-of-line */
1721  switch (mp->selector) {
1722   case term_and_log: 
1723     wterm_cr; wlog_cr;
1724     mp->term_offset=0;  mp->file_offset=0;
1725     break;
1726   case log_only: 
1727     wlog_cr; mp->file_offset=0;
1728     break;
1729   case term_only: 
1730     wterm_cr; mp->term_offset=0;
1731     break;
1732   case no_print:
1733   case pseudo: 
1734   case new_string: 
1735     break;
1736   default: 
1737     do_fprintf(mp->wr_file[(mp->selector-write_file)],"\n");
1738   }
1739 } /* note that |tally| is not affected */
1740
1741 @ The |print_visible_char| procedure sends one character to the desired
1742 destination, using the |xchr| array to map it into an external character
1743 compatible with |input_ln|.  (It assumes that it is always called with
1744 a visible ASCII character.)  All printing comes through |print_ln| or
1745 |print_char|, which ultimately calls |print_visible_char|, hence these
1746 routines are the ones that limit lines to at most |max_print_line| characters.
1747 But we must make an exception for the \ps\ output file since it is not safe
1748 to cut up lines arbitrarily in \ps.
1749
1750 Procedure |unit_str_room| needs to be declared |forward| here because it calls
1751 |do_compaction| and |do_compaction| can call the error routines.  Actually,
1752 |unit_str_room| avoids |overflow| errors but it can call |confusion|.
1753
1754 @<Basic printing...@>=
1755 void mp_print_visible_char (MP mp, ASCII_code s) { /* prints a single character */
1756   switch (mp->selector) {
1757   case term_and_log: 
1758     wterm_chr(xchr(s)); wlog_chr(xchr(s));
1759     incr(mp->term_offset); incr(mp->file_offset);
1760     if ( mp->term_offset==(unsigned)mp->max_print_line ) { 
1761        wterm_cr; mp->term_offset=0;
1762     };
1763     if ( mp->file_offset==(unsigned)mp->max_print_line ) { 
1764        wlog_cr; mp->file_offset=0;
1765     };
1766     break;
1767   case log_only: 
1768     wlog_chr(xchr(s)); incr(mp->file_offset);
1769     if ( mp->file_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1770     break;
1771   case term_only: 
1772     wterm_chr(xchr(s)); incr(mp->term_offset);
1773     if ( mp->term_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1774     break;
1775   case no_print: 
1776     break;
1777   case pseudo: 
1778     if ( mp->tally<mp->trick_count ) 
1779       mp->trick_buf[mp->tally % mp->error_line]=s;
1780     break;
1781   case new_string: 
1782     if ( mp->pool_ptr>=mp->max_pool_ptr ) { 
1783       mp_unit_str_room(mp);
1784       if ( mp->pool_ptr>=mp->pool_size ) 
1785         goto DONE; /* drop characters if string space is full */
1786     };
1787     append_char(s);
1788     break;
1789   default:
1790     { char ss[2]; ss[0] = xchr(s); ss[1]=0;
1791       do_fprintf(mp->wr_file[(mp->selector-write_file)],(char *)ss);
1792     }
1793   }
1794 DONE:
1795   incr(mp->tally);
1796 }
1797
1798 @ The |print_char| procedure sends one character to the desired destination.
1799 File names and string expressions might contain |ASCII_code| values that
1800 can't be printed using |print_visible_char|.  These characters will be
1801 printed in three- or four-symbol form like `\.{\^\^A}' or `\.{\^\^e4}'.
1802 (This procedure assumes that it is safe to bypass all checks for unprintable
1803 characters when |selector| is in the range |0..max_write_files-1|.
1804 The user might want to write unprintable characters.
1805
1806 @d print_lc_hex(A) do { l=(A);
1807     mp_print_visible_char(mp, (l<10 ? l+'0' : l-10+'a'));
1808   } while (0)
1809
1810 @<Basic printing...@>=
1811 void mp_print_char (MP mp, ASCII_code k) { /* prints a single character */
1812   int l; /* small index or counter */
1813   if ( mp->selector<pseudo || mp->selector>=write_file) {
1814     mp_print_visible_char(mp, k);
1815   } else if ( @<Character |k| cannot be printed@> ) { 
1816     mp_print(mp, "^^"); 
1817     if ( k<0100 ) { 
1818       mp_print_visible_char(mp, k+0100); 
1819     } else if ( k<0200 ) { 
1820       mp_print_visible_char(mp, k-0100); 
1821     } else { 
1822       print_lc_hex(k / 16);  
1823       print_lc_hex(k % 16); 
1824     }
1825   } else {
1826     mp_print_visible_char(mp, k);
1827   }
1828 };
1829
1830 @ An entire string is output by calling |print|. Note that if we are outputting
1831 the single standard ASCII character \.c, we could call |print("c")|, since
1832 |"c"=99| is the number of a single-character string, as explained above. But
1833 |print_char("c")| is quicker, so \MP\ goes directly to the |print_char|
1834 routine when it knows that this is safe. (The present implementation
1835 assumes that it is always safe to print a visible ASCII character.)
1836 @^system dependencies@>
1837
1838 @<Basic print...@>=
1839 void mp_do_print (MP mp, char *ss, unsigned int len) { /* prints string |s| */
1840   unsigned int j = 0;
1841   while ( j<len ){ 
1842     mp_print_char(mp, ss[j]); incr(j);
1843   }
1844 }
1845
1846
1847 @<Basic print...@>=
1848 void mp_print (MP mp, char *ss) {
1849   mp_do_print(mp, ss, strlen(ss));
1850 }
1851 void mp_print_str (MP mp, str_number s) {
1852   pool_pointer j; /* current character code position */
1853   if ( (s<0)||(s>mp->max_str_ptr) ) {
1854      mp_do_print(mp,"???",3); /* this can't happen */
1855 @.???@>
1856   }
1857   j=mp->str_start[s];
1858   mp_do_print(mp, (char *)(mp->str_pool+j), (str_stop(s)-j));
1859 }
1860
1861
1862 @ Here is the very first thing that \MP\ prints: a headline that identifies
1863 the version number and base name. The |term_offset| variable is temporarily
1864 incorrect, but the discrepancy is not serious since we assume that the banner
1865 and mem identifier together will occupy at most |max_print_line|
1866 character positions.
1867
1868 @<Initialize the output...@>=
1869 wterm (banner);
1870 wterm (version_string);
1871 if (mp->mem_ident!=NULL) 
1872   mp_print(mp,mp->mem_ident); 
1873 mp_print_ln(mp);
1874 update_terminal;
1875
1876 @ The procedure |print_nl| is like |print|, but it makes sure that the
1877 string appears at the beginning of a new line.
1878
1879 @<Basic print...@>=
1880 void mp_print_nl (MP mp, char *s) { /* prints string |s| at beginning of line */
1881   switch(mp->selector) {
1882   case term_and_log: 
1883     if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_ln(mp);
1884     break;
1885   case log_only: 
1886     if ( mp->file_offset>0 ) mp_print_ln(mp);
1887     break;
1888   case term_only: 
1889     if ( mp->term_offset>0 ) mp_print_ln(mp);
1890     break;
1891   case no_print:
1892   case pseudo:
1893   case new_string: 
1894         break;
1895   } /* there are no other cases */
1896   mp_print(mp, s);
1897 }
1898
1899 @ An array of digits in the range |0..9| is printed by |print_the_digs|.
1900
1901 @<Basic print...@>=
1902 void mp_print_the_digs (MP mp, eight_bits k) {
1903   /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
1904   while ( k>0 ){ 
1905     decr(k); mp_print_char(mp, '0'+mp->dig[k]);
1906   }
1907 };
1908
1909 @ The following procedure, which prints out the decimal representation of a
1910 given integer |n|, has been written carefully so that it works properly
1911 if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div|
1912 to negative arguments, since such operations are not implemented consistently
1913 by all \PASCAL\ compilers.
1914
1915 @<Basic print...@>=
1916 void mp_print_int (MP mp,integer n) { /* prints an integer in decimal form */
1917   integer m; /* used to negate |n| in possibly dangerous cases */
1918   int k = 0; /* index to current digit; we assume that $|n|<10^{23}$ */
1919   if ( n<0 ) { 
1920     mp_print_char(mp, '-');
1921     if ( n>-100000000 ) {
1922           negate(n);
1923     } else  { 
1924           m=-1-n; n=m / 10; m=(m % 10)+1; k=1;
1925       if ( m<10 ) {
1926         mp->dig[0]=m;
1927       } else { 
1928         mp->dig[0]=0; incr(n);
1929       }
1930     }
1931   }
1932   do {  
1933     mp->dig[k]=n % 10; n=n / 10; incr(k);
1934   } while (n!=0);
1935   mp_print_the_digs(mp, k);
1936 };
1937
1938 @ @<Internal ...@>=
1939 void mp_print_int (MP mp,integer n);
1940
1941 @ \MP\ also makes use of a trivial procedure to print two digits. The
1942 following subroutine is usually called with a parameter in the range |0<=n<=99|.
1943
1944 @c 
1945 void mp_print_dd (MP mp,integer n) { /* prints two least significant digits */
1946   n=abs(n) % 100; 
1947   mp_print_char(mp, '0'+(n / 10));
1948   mp_print_char(mp, '0'+(n % 10));
1949 }
1950
1951
1952 @ @<Internal ...@>=
1953 void mp_print_dd (MP mp,integer n);
1954
1955 @ Here is a procedure that asks the user to type a line of input,
1956 assuming that the |selector| setting is either |term_only| or |term_and_log|.
1957 The input is placed into locations |first| through |last-1| of the
1958 |buffer| array, and echoed on the transcript file if appropriate.
1959
1960 This procedure is never called when |interaction<mp_scroll_mode|.
1961
1962 @d prompt_input(A) do { 
1963     wake_up_terminal; mp_print(mp, (A)); mp_term_input(mp);
1964   } while (0) /* prints a string and gets a line of input */
1965
1966 @c 
1967 void mp_term_input (MP mp) { /* gets a line from the terminal */
1968   size_t k; /* index into |buffer| */
1969   update_terminal; /* Now the user sees the prompt for sure */
1970   if (!mp_input_ln(mp, mp->term_in )) 
1971     mp_fatal_error(mp, "End of file on the terminal!");
1972 @.End of file on the terminal@>
1973   mp->term_offset=0; /* the user's line ended with \<\rm return> */
1974   decr(mp->selector); /* prepare to echo the input */
1975   if ( mp->last!=mp->first ) {
1976     for (k=mp->first;k<=mp->last-1;k++) {
1977       mp_print_char(mp, mp->buffer[k]);
1978     }
1979   }
1980   mp_print_ln(mp); 
1981   mp->buffer[mp->last]='%'; 
1982   incr(mp->selector); /* restore previous status */
1983 };
1984
1985 @* \[6] Reporting errors.
1986 When something anomalous is detected, \MP\ typically does something like this:
1987 $$\vbox{\halign{#\hfil\cr
1988 |print_err("Something anomalous has been detected");|\cr
1989 |help3("This is the first line of my offer to help.")|\cr
1990 |("This is the second line. I'm trying to")|\cr
1991 |("explain the best way for you to proceed.");|\cr
1992 |error;|\cr}}$$
1993 A two-line help message would be given using |help2|, etc.; these informal
1994 helps should use simple vocabulary that complements the words used in the
1995 official error message that was printed. (Outside the U.S.A., the help
1996 messages should preferably be translated into the local vernacular. Each
1997 line of help is at most 60 characters long, in the present implementation,
1998 so that |max_print_line| will not be exceeded.)
1999
2000 The |print_err| procedure supplies a `\.!' before the official message,
2001 and makes sure that the terminal is awake if a stop is going to occur.
2002 The |error| procedure supplies a `\..' after the official message, then it
2003 shows the location of the error; and if |interaction=error_stop_mode|,
2004 it also enters into a dialog with the user, during which time the help
2005 message may be printed.
2006 @^system dependencies@>
2007
2008 @ The global variable |interaction| has four settings, representing increasing
2009 amounts of user interaction:
2010
2011 @<Exported types@>=
2012 enum mp_interaction_mode { 
2013  mp_unspecified_mode=0, /* extra value for command-line switch */
2014  mp_batch_mode, /* omits all stops and omits terminal output */
2015  mp_nonstop_mode, /* omits all stops */
2016  mp_scroll_mode, /* omits error stops */
2017  mp_error_stop_mode, /* stops at every opportunity to interact */
2018 };
2019
2020 @ @<Glob...@>=
2021 int interaction; /* current level of interaction */
2022
2023 @ @<Option variables@>=
2024 int interaction; /* current level of interaction */
2025
2026 @ Set it here so it can be overwritten by the commandline
2027
2028 @<Allocate or initialize ...@>=
2029 mp->interaction=opt->interaction;
2030 if (mp->interaction==mp_unspecified_mode || mp->interaction>mp_error_stop_mode) 
2031   mp->interaction=mp_error_stop_mode;
2032 if (mp->interaction<mp_unspecified_mode) 
2033   mp->interaction=mp_batch_mode;
2034
2035
2036
2037 @d print_err(A) mp_print_err(mp,(A))
2038
2039 @<Internal ...@>=
2040 void mp_print_err(MP mp, char * A);
2041
2042 @ @c
2043 void mp_print_err(MP mp, char * A) { 
2044   if ( mp->interaction==mp_error_stop_mode ) 
2045     wake_up_terminal;
2046   mp_print_nl(mp, "! "); 
2047   mp_print(mp, A);
2048 @.!\relax@>
2049 }
2050
2051
2052 @ \MP\ is careful not to call |error| when the print |selector| setting
2053 might be unusual. The only possible values of |selector| at the time of
2054 error messages are
2055
2056 \yskip\hang|no_print| (when |interaction=mp_batch_mode|
2057   and |log_file| not yet open);
2058
2059 \hang|term_only| (when |interaction>mp_batch_mode| and |log_file| not yet open);
2060
2061 \hang|log_only| (when |interaction=mp_batch_mode| and |log_file| is open);
2062
2063 \hang|term_and_log| (when |interaction>mp_batch_mode| and |log_file| is open).
2064
2065 @<Initialize the print |selector| based on |interaction|@>=
2066 if ( mp->interaction==mp_batch_mode ) mp->selector=no_print; else mp->selector=term_only
2067
2068 @ A global variable |deletions_allowed| is set |false| if the |get_next|
2069 routine is active when |error| is called; this ensures that |get_next|
2070 will never be called recursively.
2071 @^recursion@>
2072
2073 The global variable |history| records the worst level of error that
2074 has been detected. It has four possible values: |spotless|, |warning_issued|,
2075 |error_message_issued|, and |fatal_error_stop|.
2076
2077 Another global variable, |error_count|, is increased by one when an
2078 |error| occurs without an interactive dialog, and it is reset to zero at
2079 the end of every statement.  If |error_count| reaches 100, \MP\ decides
2080 that there is no point in continuing further.
2081
2082 @<Types...@>=
2083 enum mp_history_states {
2084   mp_spotless=0, /* |history| value when nothing has been amiss yet */
2085   mp_warning_issued, /* |history| value when |begin_diagnostic| has been called */
2086   mp_error_message_issued, /* |history| value when |error| has been called */
2087   mp_fatal_error_stop, /* |history| value when termination was premature */
2088 };
2089
2090 @ @<Glob...@>=
2091 boolean deletions_allowed; /* is it safe for |error| to call |get_next|? */
2092 int history; /* has the source input been clean so far? */
2093 int error_count; /* the number of scrolled errors since the last statement ended */
2094
2095 @ The value of |history| is initially |fatal_error_stop|, but it will
2096 be changed to |spotless| if \MP\ survives the initialization process.
2097
2098 @<Allocate or ...@>=
2099 mp->deletions_allowed=true; mp->error_count=0; /* |history| is initialized elsewhere */
2100
2101 @ Since errors can be detected almost anywhere in \MP, we want to declare the
2102 error procedures near the beginning of the program. But the error procedures
2103 in turn use some other procedures, which need to be declared |forward|
2104 before we get to |error| itself.
2105
2106 It is possible for |error| to be called recursively if some error arises
2107 when |get_next| is being used to delete a token, and/or if some fatal error
2108 occurs while \MP\ is trying to fix a non-fatal one. But such recursion
2109 @^recursion@>
2110 is never more than two levels deep.
2111
2112 @<Declarations@>=
2113 void mp_get_next (MP mp);
2114 void mp_term_input (MP mp);
2115 void mp_show_context (MP mp);
2116 void mp_begin_file_reading (MP mp);
2117 void mp_open_log_file (MP mp);
2118 void mp_clear_for_error_prompt (MP mp);
2119 void mp_debug_help (MP mp);
2120 @<Declare the procedure called |flush_string|@>
2121
2122 @ @<Internal ...@>=
2123 void mp_normalize_selector (MP mp);
2124
2125 @ Individual lines of help are recorded in the array |help_line|, which
2126 contains entries in positions |0..(help_ptr-1)|. They should be printed
2127 in reverse order, i.e., with |help_line[0]| appearing last.
2128
2129 @d hlp1(A) mp->help_line[0]=(A); }
2130 @d hlp2(A) mp->help_line[1]=(A); hlp1
2131 @d hlp3(A) mp->help_line[2]=(A); hlp2
2132 @d hlp4(A) mp->help_line[3]=(A); hlp3
2133 @d hlp5(A) mp->help_line[4]=(A); hlp4
2134 @d hlp6(A) mp->help_line[5]=(A); hlp5
2135 @d help0 mp->help_ptr=0 /* sometimes there might be no help */
2136 @d help1  { mp->help_ptr=1; hlp1 /* use this with one help line */
2137 @d help2  { mp->help_ptr=2; hlp2 /* use this with two help lines */
2138 @d help3  { mp->help_ptr=3; hlp3 /* use this with three help lines */
2139 @d help4  { mp->help_ptr=4; hlp4 /* use this with four help lines */
2140 @d help5  { mp->help_ptr=5; hlp5 /* use this with five help lines */
2141 @d help6  { mp->help_ptr=6; hlp6 /* use this with six help lines */
2142
2143 @<Glob...@>=
2144 char * help_line[6]; /* helps for the next |error| */
2145 unsigned int help_ptr; /* the number of help lines present */
2146 boolean use_err_help; /* should the |err_help| string be shown? */
2147 str_number err_help; /* a string set up by \&{errhelp} */
2148 str_number filename_template; /* a string set up by \&{filenametemplate} */
2149
2150 @ @<Allocate or ...@>=
2151 mp->help_ptr=0; mp->use_err_help=false; mp->err_help=0; mp->filename_template=0;
2152
2153 @ The |jump_out| procedure just cuts across all active procedure levels and
2154 goes to |end_of_MP|. This is the only nonlocal |goto| statement in the
2155 whole program. It is used when there is no recovery from a particular error.
2156
2157 The program uses a |jump_buf| to handle this, this is initialized at three
2158 spots: the start of |mp_new|, the start of |mp_initialize|, and the start 
2159 of |mp_run|. Those are the only library enty points.
2160
2161 @^system dependencies@>
2162
2163 @<Glob...@>=
2164 jmp_buf jump_buf;
2165
2166 @ @<Install and test the non-local jump buffer@>=
2167 if (setjmp(mp->jump_buf) != 0) return mp->history;
2168
2169 @ @<Setup the non-local jump buffer in |mp_new|@>=
2170 if (setjmp(mp->jump_buf) != 0) return NULL;
2171
2172 @ If |mp->internal| is zero, then a crash occured during initialization,
2173 and it is not safe to run |mp_close_files_and_terminate|.
2174
2175 @<Error hand...@>=
2176 void mp_jump_out (MP mp) { 
2177   if(mp->internal!=NULL)
2178     mp_close_files_and_terminate(mp);
2179   longjmp(mp->jump_buf,1);
2180 }
2181
2182 @ Here now is the general |error| routine.
2183
2184 @<Error hand...@>=
2185 void mp_error (MP mp) { /* completes the job of error reporting */
2186   ASCII_code c; /* what the user types */
2187   integer s1,s2,s3; /* used to save global variables when deleting tokens */
2188   pool_pointer j; /* character position being printed */
2189   if ( mp->history<mp_error_message_issued ) mp->history=mp_error_message_issued;
2190   mp_print_char(mp, '.'); mp_show_context(mp);
2191   if ( mp->interaction==mp_error_stop_mode ) {
2192     @<Get user's advice and |return|@>;
2193   }
2194   incr(mp->error_count);
2195   if ( mp->error_count==100 ) { 
2196     mp_print_nl(mp,"(That makes 100 errors; please try again.)");
2197 @.That makes 100 errors...@>
2198     mp->history=mp_fatal_error_stop; mp_jump_out(mp);
2199   }
2200   @<Put help message on the transcript file@>;
2201 }
2202 void mp_warn (MP mp, char *msg) {
2203   int saved_selector = mp->selector;
2204   mp_normalize_selector(mp);
2205   mp_print_nl(mp,"Warning: ");
2206   mp_print(mp,msg);
2207   mp->selector = saved_selector;
2208 }
2209
2210 @ @<Exported function ...@>=
2211 void mp_error (MP mp);
2212 void mp_warn (MP mp, char *msg);
2213
2214
2215 @ @<Get user's advice...@>=
2216 while (1) { 
2217 CONTINUE:
2218   mp_clear_for_error_prompt(mp); prompt_input("? ");
2219 @.?\relax@>
2220   if ( mp->last==mp->first ) return;
2221   c=mp->buffer[mp->first];
2222   if ( c>='a' ) c=c+'A'-'a'; /* convert to uppercase */
2223   @<Interpret code |c| and |return| if done@>;
2224 }
2225
2226 @ It is desirable to provide an `\.E' option here that gives the user
2227 an easy way to return from \MP\ to the system editor, with the offending
2228 line ready to be edited. But such an extension requires some system
2229 wizardry, so the present implementation simply types out the name of the
2230 file that should be
2231 edited and the relevant line number.
2232 @^system dependencies@>
2233
2234 @<Exported types@>=
2235 typedef void (*mp_run_editor_command)(MP, char *, int);
2236
2237 @ @<Glob...@>=
2238 mp_run_editor_command run_editor;
2239
2240 @ @<Option variables@>=
2241 mp_run_editor_command run_editor;
2242
2243 @ @<Allocate or initialize ...@>=
2244 set_callback_option(run_editor);
2245
2246 @ @<Declarations@>=
2247 void mp_run_editor (MP mp, char *fname, int fline);
2248
2249 @ @c void mp_run_editor (MP mp, char *fname, int fline) {
2250     mp_print_nl(mp, "You want to edit file ");
2251 @.You want to edit file x@>
2252     mp_print(mp, fname);
2253     mp_print(mp, " at line "); 
2254     mp_print_int(mp, fline);
2255     mp->interaction=mp_scroll_mode; 
2256     mp_jump_out(mp);
2257 }
2258
2259
2260 There is a secret `\.D' option available when the debugging routines haven't
2261 been commented~out.
2262 @^debugging@>
2263
2264 @<Interpret code |c| and |return| if done@>=
2265 switch (c) {
2266 case '0': case '1': case '2': case '3': case '4':
2267 case '5': case '6': case '7': case '8': case '9': 
2268   if ( mp->deletions_allowed ) {
2269     @<Delete |c-"0"| tokens and |continue|@>;
2270   }
2271   break;
2272 #ifdef DEBUG
2273 case 'D': 
2274   mp_debug_help(mp); continue; 
2275   break;
2276 #endif
2277 case 'E': 
2278   if ( mp->file_ptr>0 ){ 
2279     (mp->run_editor)(mp, 
2280                      str(mp->input_stack[mp->file_ptr].name_field), 
2281                      mp_true_line(mp));
2282   }
2283   break;
2284 case 'H': 
2285   @<Print the help information and |continue|@>;
2286   break;
2287 case 'I':
2288   @<Introduce new material from the terminal and |return|@>;
2289   break;
2290 case 'Q': case 'R': case 'S':
2291   @<Change the interaction level and |return|@>;
2292   break;
2293 case 'X':
2294   mp->interaction=mp_scroll_mode; mp_jump_out(mp);
2295   break;
2296 default:
2297   break;
2298 }
2299 @<Print the menu of available options@>
2300
2301 @ @<Print the menu...@>=
2302
2303   mp_print(mp, "Type <return> to proceed, S to scroll future error messages,");
2304 @.Type <return> to proceed...@>
2305   mp_print_nl(mp, "R to run without stopping, Q to run quietly,");
2306   mp_print_nl(mp, "I to insert something, ");
2307   if ( mp->file_ptr>0 ) 
2308     mp_print(mp, "E to edit your file,");
2309   if ( mp->deletions_allowed )
2310     mp_print_nl(mp, "1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
2311   mp_print_nl(mp, "H for help, X to quit.");
2312 }
2313
2314 @ Here the author of \MP\ apologizes for making use of the numerical
2315 relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
2316 |mp_batch_mode|, |mp_nonstop_mode|, |mp_scroll_mode|.
2317 @^Knuth, Donald Ervin@>
2318
2319 @<Change the interaction...@>=
2320
2321   mp->error_count=0; mp->interaction=mp_batch_mode+c-'Q';
2322   mp_print(mp, "OK, entering ");
2323   switch (c) {
2324   case 'Q': mp_print(mp, "batchmode"); decr(mp->selector); break;
2325   case 'R': mp_print(mp, "nonstopmode"); break;
2326   case 'S': mp_print(mp, "scrollmode"); break;
2327   } /* there are no other cases */
2328   mp_print(mp, "..."); mp_print_ln(mp); update_terminal; return;
2329 }
2330
2331 @ When the following code is executed, |buffer[(first+1)..(last-1)]| may
2332 contain the material inserted by the user; otherwise another prompt will
2333 be given. In order to understand this part of the program fully, you need
2334 to be familiar with \MP's input stacks.
2335
2336 @<Introduce new material...@>=
2337
2338   mp_begin_file_reading(mp); /* enter a new syntactic level for terminal input */
2339   if ( mp->last>mp->first+1 ) { 
2340     loc=mp->first+1; mp->buffer[mp->first]=' ';
2341   } else { 
2342    prompt_input("insert>"); loc=mp->first;
2343 @.insert>@>
2344   };
2345   mp->first=mp->last+1; mp->cur_input.limit_field=mp->last; return;
2346 }
2347
2348 @ We allow deletion of up to 99 tokens at a time.
2349
2350 @<Delete |c-"0"| tokens...@>=
2351
2352   s1=mp->cur_cmd; s2=mp->cur_mod; s3=mp->cur_sym; mp->OK_to_interrupt=false;
2353   if ( (mp->last>mp->first+1) && (mp->buffer[mp->first+1]>='0')&&(mp->buffer[mp->first+1]<='9') )
2354     c=c*10+mp->buffer[mp->first+1]-'0'*11;
2355   else 
2356     c=c-'0';
2357   while ( c>0 ) { 
2358     mp_get_next(mp); /* one-level recursive call of |error| is possible */
2359     @<Decrease the string reference count, if the current token is a string@>;
2360     decr(c);
2361   };
2362   mp->cur_cmd=s1; mp->cur_mod=s2; mp->cur_sym=s3; mp->OK_to_interrupt=true;
2363   help2("I have just deleted some text, as you asked.")
2364        ("You can now delete more, or insert, or whatever.");
2365   mp_show_context(mp); 
2366   goto CONTINUE;
2367 }
2368
2369 @ @<Print the help info...@>=
2370
2371   if ( mp->use_err_help ) { 
2372     @<Print the string |err_help|, possibly on several lines@>;
2373     mp->use_err_help=false;
2374   } else { 
2375     if ( mp->help_ptr==0 ) {
2376       help2("Sorry, I don't know how to help in this situation.")
2377            ("Maybe you should try asking a human?");
2378      }
2379     do { 
2380       decr(mp->help_ptr); mp_print(mp, mp->help_line[mp->help_ptr]); mp_print_ln(mp);
2381     } while (mp->help_ptr!=0);
2382   };
2383   help4("Sorry, I already gave what help I could...")
2384        ("Maybe you should try asking a human?")
2385        ("An error might have occurred before I noticed any problems.")
2386        ("``If all else fails, read the instructions.''");
2387   goto CONTINUE;
2388 }
2389
2390 @ @<Print the string |err_help|, possibly on several lines@>=
2391 j=mp->str_start[mp->err_help];
2392 while ( j<str_stop(mp->err_help) ) { 
2393   if ( mp->str_pool[j]!='%' ) mp_print_str(mp, mp->str_pool[j]);
2394   else if ( j+1==str_stop(mp->err_help) ) mp_print_ln(mp);
2395   else if ( mp->str_pool[j+1]!='%' ) mp_print_ln(mp);
2396   else  { incr(j); mp_print_char(mp, '%'); };
2397   incr(j);
2398 }
2399
2400 @ @<Put help message on the transcript file@>=
2401 if ( mp->interaction>mp_batch_mode ) decr(mp->selector); /* avoid terminal output */
2402 if ( mp->use_err_help ) { 
2403   mp_print_nl(mp, "");
2404   @<Print the string |err_help|, possibly on several lines@>;
2405 } else { 
2406   while ( mp->help_ptr>0 ){ 
2407     decr(mp->help_ptr); mp_print_nl(mp, mp->help_line[mp->help_ptr]);
2408   };
2409 }
2410 mp_print_ln(mp);
2411 if ( mp->interaction>mp_batch_mode ) incr(mp->selector); /* re-enable terminal output */
2412 mp_print_ln(mp)
2413
2414 @ In anomalous cases, the print selector might be in an unknown state;
2415 the following subroutine is called to fix things just enough to keep
2416 running a bit longer.
2417
2418 @c 
2419 void mp_normalize_selector (MP mp) { 
2420   if ( mp->log_opened ) mp->selector=term_and_log;
2421   else mp->selector=term_only;
2422   if ( mp->job_name==NULL ) mp_open_log_file(mp);
2423   if ( mp->interaction==mp_batch_mode ) decr(mp->selector);
2424 }
2425
2426 @ The following procedure prints \MP's last words before dying.
2427
2428 @d succumb { if ( mp->interaction==mp_error_stop_mode )
2429     mp->interaction=mp_scroll_mode; /* no more interaction */
2430   if ( mp->log_opened ) mp_error(mp);
2431   /* if ( mp->interaction>mp_batch_mode ) mp_debug_help(mp); */
2432   mp->history=mp_fatal_error_stop; mp_jump_out(mp); /* irrecoverable error */
2433   }
2434
2435 @<Error hand...@>=
2436 void mp_fatal_error (MP mp, char *s) { /* prints |s|, and that's it */
2437   mp_normalize_selector(mp);
2438   print_err("Emergency stop"); help1(s); succumb;
2439 @.Emergency stop@>
2440 }
2441
2442 @ @<Exported function ...@>=
2443 void mp_fatal_error (MP mp, char *s);
2444
2445
2446 @ Here is the most dreaded error message.
2447
2448 @<Error hand...@>=
2449 void mp_overflow (MP mp, char *s, integer n) { /* stop due to finiteness */
2450   mp_normalize_selector(mp);
2451   print_err("MetaPost capacity exceeded, sorry [");
2452 @.MetaPost capacity exceeded ...@>
2453   mp_print(mp, s); mp_print_char(mp, '='); mp_print_int(mp, n); mp_print_char(mp, ']');
2454   help2("If you really absolutely need more capacity,")
2455        ("you can ask a wizard to enlarge me.");
2456   succumb;
2457 }
2458
2459 @ @<Internal library declarations@>=
2460 void mp_overflow (MP mp, char *s, integer n);
2461
2462 @ The program might sometime run completely amok, at which point there is
2463 no choice but to stop. If no previous error has been detected, that's bad
2464 news; a message is printed that is really intended for the \MP\
2465 maintenance person instead of the user (unless the user has been
2466 particularly diabolical).  The index entries for `this can't happen' may
2467 help to pinpoint the problem.
2468 @^dry rot@>
2469
2470 @<Internal library ...@>=
2471 void mp_confusion (MP mp,char *s);
2472
2473 @ @<Error hand...@>=
2474 void mp_confusion (MP mp,char *s) {
2475   /* consistency check violated; |s| tells where */
2476   mp_normalize_selector(mp);
2477   if ( mp->history<mp_error_message_issued ) { 
2478     print_err("This can't happen ("); mp_print(mp, s); mp_print_char(mp, ')');
2479 @.This can't happen@>
2480     help1("I'm broken. Please show this to someone who can fix can fix");
2481   } else { 
2482     print_err("I can\'t go on meeting you like this");
2483 @.I can't go on...@>
2484     help2("One of your faux pas seems to have wounded me deeply...")
2485          ("in fact, I'm barely conscious. Please fix it and try again.");
2486   }
2487   succumb;
2488 }
2489
2490 @ Users occasionally want to interrupt \MP\ while it's running.
2491 If the \PASCAL\ runtime system allows this, one can implement
2492 a routine that sets the global variable |interrupt| to some nonzero value
2493 when such an interrupt is signaled. Otherwise there is probably at least
2494 a way to make |interrupt| nonzero using the \PASCAL\ debugger.
2495 @^system dependencies@>
2496 @^debugging@>
2497
2498 @d check_interrupt { if ( mp->interrupt!=0 )
2499    mp_pause_for_instructions(mp); }
2500
2501 @<Global...@>=
2502 integer interrupt; /* should \MP\ pause for instructions? */
2503 boolean OK_to_interrupt; /* should interrupts be observed? */
2504
2505 @ @<Allocate or ...@>=
2506 mp->interrupt=0; mp->OK_to_interrupt=true;
2507
2508 @ When an interrupt has been detected, the program goes into its
2509 highest interaction level and lets the user have the full flexibility of
2510 the |error| routine.  \MP\ checks for interrupts only at times when it is
2511 safe to do this.
2512
2513 @c 
2514 void mp_pause_for_instructions (MP mp) { 
2515   if ( mp->OK_to_interrupt ) { 
2516     mp->interaction=mp_error_stop_mode;
2517     if ( (mp->selector==log_only)||(mp->selector==no_print) )
2518       incr(mp->selector);
2519     print_err("Interruption");
2520 @.Interruption@>
2521     help3("You rang?")
2522          ("Try to insert some instructions for me (e.g.,`I show x'),")
2523          ("unless you just want to quit by typing `X'.");
2524     mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
2525     mp->interrupt=0;
2526   }
2527 }
2528
2529 @ Many of \MP's error messages state that a missing token has been
2530 inserted behind the scenes. We can save string space and program space
2531 by putting this common code into a subroutine.
2532
2533 @c 
2534 void mp_missing_err (MP mp, char *s) { 
2535   print_err("Missing `"); mp_print(mp, s); mp_print(mp, "' has been inserted");
2536 @.Missing...inserted@>
2537 }
2538
2539 @* \[7] Arithmetic with scaled numbers.
2540 The principal computations performed by \MP\ are done entirely in terms of
2541 integers less than $2^{31}$ in magnitude; thus, the arithmetic specified in this
2542 program can be carried out in exactly the same way on a wide variety of
2543 computers, including some small ones.
2544 @^small computers@>
2545
2546 But \PASCAL\ does not define the |div|
2547 operation in the case of negative dividends; for example, the result of
2548 |(-2*n-1) div 2| is |-(n+1)| on some computers and |-n| on others.
2549 There are two principal types of arithmetic: ``translation-preserving,''
2550 in which the identity |(a+q*b)div b=(a div b)+q| is valid; and
2551 ``negation-preserving,'' in which |(-a)div b=-(a div b)|. This leads to
2552 two \MP s, which can produce different results, although the differences
2553 should be negligible when the language is being used properly.
2554 The \TeX\ processor has been defined carefully so that both varieties
2555 of arithmetic will produce identical output, but it would be too
2556 inefficient to constrain \MP\ in a similar way.
2557
2558 @d el_gordo   017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */
2559
2560 @ One of \MP's most common operations is the calculation of
2561 $\lfloor{a+b\over2}\rfloor$,
2562 the midpoint of two given integers |a| and~|b|. The only decent way to do
2563 this in \PASCAL\ is to write `|(a+b) div 2|'; but on most machines it is
2564 far more efficient to calculate `|(a+b)| right shifted one bit'.
2565
2566 Therefore the midpoint operation will always be denoted by `|half(a+b)|'
2567 in this program. If \MP\ is being implemented with languages that permit
2568 binary shifting, the |half| macro should be changed to make this operation
2569 as efficient as possible.  Since some languages have shift operators that can
2570 only be trusted to work on positive numbers, there is also a macro |halfp|
2571 that is used only when the quantity being halved is known to be positive
2572 or zero.
2573
2574 @d half(A) ((A) / 2)
2575 @d halfp(A) ((A) / 2)
2576
2577 @ A single computation might use several subroutine calls, and it is
2578 desirable to avoid producing multiple error messages in case of arithmetic
2579 overflow. So the routines below set the global variable |arith_error| to |true|
2580 instead of reporting errors directly to the user.
2581
2582 @<Glob...@>=
2583 boolean arith_error; /* has arithmetic overflow occurred recently? */
2584
2585 @ @<Allocate or ...@>=
2586 mp->arith_error=false;
2587
2588 @ At crucial points the program will say |check_arith|, to test if
2589 an arithmetic error has been detected.
2590
2591 @d check_arith { if ( mp->arith_error ) mp_clear_arith(mp); }
2592
2593 @c 
2594 void mp_clear_arith (MP mp) { 
2595   print_err("Arithmetic overflow");
2596 @.Arithmetic overflow@>
2597   help4("Uh, oh. A little while ago one of the quantities that I was")
2598        ("computing got too large, so I'm afraid your answers will be")
2599        ("somewhat askew. You'll probably have to adopt different")
2600        ("tactics next time. But I shall try to carry on anyway.");
2601   mp_error(mp); 
2602   mp->arith_error=false;
2603 }
2604
2605 @ Addition is not always checked to make sure that it doesn't overflow,
2606 but in places where overflow isn't too unlikely the |slow_add| routine
2607 is used.
2608
2609 @c integer mp_slow_add (MP mp,integer x, integer y) { 
2610   if ( x>=0 )  {
2611     if ( y<=el_gordo-x ) { 
2612       return x+y;
2613     } else  { 
2614       mp->arith_error=true; 
2615           return el_gordo;
2616     }
2617   } else  if ( -y<=el_gordo+x ) {
2618     return x+y;
2619   } else { 
2620     mp->arith_error=true; 
2621         return -el_gordo;
2622   }
2623 }
2624
2625 @ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
2626 of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
2627 positions from the right end of a binary computer word.
2628
2629 @d quarter_unit   040000 /* $2^{14}$, represents 0.250000 */
2630 @d half_unit   0100000 /* $2^{15}$, represents 0.50000 */
2631 @d three_quarter_unit   0140000 /* $3\cdot2^{14}$, represents 0.75000 */
2632 @d unity   0200000 /* $2^{16}$, represents 1.00000 */
2633 @d two   0400000 /* $2^{17}$, represents 2.00000 */
2634 @d three   0600000 /* $2^{17}+2^{16}$, represents 3.00000 */
2635
2636 @<Types...@>=
2637 typedef integer scaled; /* this type is used for scaled integers */
2638 typedef unsigned char small_number; /* this type is self-explanatory */
2639
2640 @ The following function is used to create a scaled integer from a given decimal
2641 fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
2642 given in |dig[i]|, and the calculation produces a correctly rounded result.
2643
2644 @c 
2645 scaled mp_round_decimals (MP mp,small_number k) {
2646   /* converts a decimal fraction */
2647  integer a = 0; /* the accumulator */
2648  while ( k-->0 ) { 
2649     a=(a+mp->dig[k]*two) / 10;
2650   }
2651   return halfp(a+1);
2652 }
2653
2654 @ Conversely, here is a procedure analogous to |print_int|. If the output
2655 of this procedure is subsequently read by \MP\ and converted by the
2656 |round_decimals| routine above, it turns out that the original value will
2657 be reproduced exactly. A decimal point is printed only if the value is
2658 not an integer. If there is more than one way to print the result with
2659 the optimum number of digits following the decimal point, the closest
2660 possible value is given.
2661
2662 The invariant relation in the \&{repeat} loop is that a sequence of
2663 decimal digits yet to be printed will yield the original number if and only if
2664 they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
2665 We can stop if and only if $f=0$ satisfies this condition; the loop will
2666 terminate before $s$ can possibly become zero.
2667
2668 @<Basic printing...@>=
2669 void mp_print_scaled (MP mp,scaled s) { /* prints scaled real, rounded to five  digits */
2670   scaled delta; /* amount of allowable inaccuracy */
2671   if ( s<0 ) { 
2672         mp_print_char(mp, '-'); 
2673     negate(s); /* print the sign, if negative */
2674   }
2675   mp_print_int(mp, s / unity); /* print the integer part */
2676   s=10*(s % unity)+5;
2677   if ( s!=5 ) { 
2678     delta=10; 
2679     mp_print_char(mp, '.');
2680     do {  
2681       if ( delta>unity )
2682         s=s+0100000-(delta / 2); /* round the final digit */
2683       mp_print_char(mp, '0'+(s / unity)); 
2684       s=10*(s % unity); 
2685       delta=delta*10;
2686     } while (s>delta);
2687   }
2688 }
2689
2690 @ We often want to print two scaled quantities in parentheses,
2691 separated by a comma.
2692
2693 @<Basic printing...@>=
2694 void mp_print_two (MP mp,scaled x, scaled y) { /* prints `|(x,y)|' */
2695   mp_print_char(mp, '('); 
2696   mp_print_scaled(mp, x); 
2697   mp_print_char(mp, ','); 
2698   mp_print_scaled(mp, y);
2699   mp_print_char(mp, ')');
2700 }
2701
2702 @ The |scaled| quantities in \MP\ programs are generally supposed to be
2703 less than $2^{12}$ in absolute value, so \MP\ does much of its internal
2704 arithmetic with 28~significant bits of precision. A |fraction| denotes
2705 a scaled integer whose binary point is assumed to be 28 bit positions
2706 from the right.
2707
2708 @d fraction_half 01000000000 /* $2^{27}$, represents 0.50000000 */
2709 @d fraction_one 02000000000 /* $2^{28}$, represents 1.00000000 */
2710 @d fraction_two 04000000000 /* $2^{29}$, represents 2.00000000 */
2711 @d fraction_three 06000000000 /* $3\cdot2^{28}$, represents 3.00000000 */
2712 @d fraction_four 010000000000 /* $2^{30}$, represents 4.00000000 */
2713
2714 @<Types...@>=
2715 typedef integer fraction; /* this type is used for scaled fractions */
2716
2717 @ In fact, the two sorts of scaling discussed above aren't quite
2718 sufficient; \MP\ has yet another, used internally to keep track of angles
2719 in units of $2^{-20}$ degrees.
2720
2721 @d forty_five_deg 0264000000 /* $45\cdot2^{20}$, represents $45^\circ$ */
2722 @d ninety_deg 0550000000 /* $90\cdot2^{20}$, represents $90^\circ$ */
2723 @d one_eighty_deg 01320000000 /* $180\cdot2^{20}$, represents $180^\circ$ */
2724 @d three_sixty_deg 02640000000 /* $360\cdot2^{20}$, represents $360^\circ$ */
2725
2726 @<Types...@>=
2727 typedef integer angle; /* this type is used for scaled angles */
2728
2729 @ The |make_fraction| routine produces the |fraction| equivalent of
2730 |p/q|, given integers |p| and~|q|; it computes the integer
2731 $f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
2732 positive. If |p| and |q| are both of the same scaled type |t|,
2733 the ``type relation'' |make_fraction(t,t)=fraction| is valid;
2734 and it's also possible to use the subroutine ``backwards,'' using
2735 the relation |make_fraction(t,fraction)=t| between scaled types.
2736
2737 If the result would have magnitude $2^{31}$ or more, |make_fraction|
2738 sets |arith_error:=true|. Most of \MP's internal computations have
2739 been designed to avoid this sort of error.
2740
2741 If this subroutine were programmed in assembly language on a typical
2742 machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
2743 double-precision product can often be input to a fixed-point division
2744 instruction. But when we are restricted to \PASCAL\ arithmetic it
2745 is necessary either to resort to multiple-precision maneuvering
2746 or to use a simple but slow iteration. The multiple-precision technique
2747 would be about three times faster than the code adopted here, but it
2748 would be comparatively long and tricky, involving about sixteen
2749 additional multiplications and divisions.
2750
2751 This operation is part of \MP's ``inner loop''; indeed, it will
2752 consume nearly 10\pct! of the running time (exclusive of input and output)
2753 if the code below is left unchanged. A machine-dependent recoding
2754 will therefore make \MP\ run faster. The present implementation
2755 is highly portable, but slow; it avoids multiplication and division
2756 except in the initial stage. System wizards should be careful to
2757 replace it with a routine that is guaranteed to produce identical
2758 results in all cases.
2759 @^system dependencies@>
2760
2761 As noted below, a few more routines should also be replaced by machine-dependent
2762 code, for efficiency. But when a procedure is not part of the ``inner loop,''
2763 such changes aren't advisable; simplicity and robustness are
2764 preferable to trickery, unless the cost is too high.
2765 @^inner loop@>
2766
2767 @<Internal ...@>=
2768 fraction mp_make_fraction (MP mp,integer p, integer q);
2769 integer mp_take_scaled (MP mp,integer q, scaled f) ;
2770
2771 @ If FIXPT is not defined, we need these preprocessor values
2772
2773 @d ELGORDO  0x7fffffff
2774 @d TWEXP31  2147483648.0
2775 @d TWEXP28  268435456.0
2776 @d TWEXP16 65536.0
2777 @d TWEXP_16 (1.0/65536.0)
2778 @d TWEXP_28 (1.0/268435456.0)
2779
2780
2781 @c 
2782 fraction mp_make_fraction (MP mp,integer p, integer q) {
2783 #ifdef FIXPT
2784   integer f; /* the fraction bits, with a leading 1 bit */
2785   integer n; /* the integer part of $\vert p/q\vert$ */
2786   integer be_careful; /* disables certain compiler optimizations */
2787   boolean negative = false; /* should the result be negated? */
2788   if ( p<0 ) {
2789     negate(p); negative=true;
2790   }
2791   if ( q<=0 ) { 
2792 #ifdef DEBUG
2793     if ( q==0 ) mp_confusion(mp, '/');
2794 #endif
2795 @:this can't happen /}{\quad \./@>
2796     negate(q); negative = ! negative;
2797   };
2798   n=p / q; p=p % q;
2799   if ( n>=8 ){ 
2800     mp->arith_error=true;
2801     return ( negative ? -el_gordo : el_gordo);
2802   } else { 
2803     n=(n-1)*fraction_one;
2804     @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>;
2805     return (negative ? (-(f+n)) : (f+n));
2806   }
2807 #else /* FIXPT */
2808     register double d;
2809         register integer i;
2810 #ifdef DEBUG
2811         if (q==0) mp_confusion(mp,'/'); 
2812 #endif /* DEBUG */
2813         d = TWEXP28 * (double)p /(double)q;
2814         if ((p^q) >= 0) {
2815                 d += 0.5;
2816                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
2817                 i = (integer) d;
2818                 if (d==i && ( ((q>0 ? -q : q)&077777)
2819                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2820         } else {
2821                 d -= 0.5;
2822                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
2823                 i = (integer) d;
2824                 if (d==i && ( ((q>0 ? q : -q)&077777)
2825                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2826         }
2827         return i;
2828 #endif /* FIXPT */
2829 }
2830
2831 @ The |repeat| loop here preserves the following invariant relations
2832 between |f|, |p|, and~|q|:
2833 (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
2834 $p_0$ is the original value of~$p$.
2835
2836 Notice that the computation specifies
2837 |(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
2838 Let us hope that optimizing compilers do not miss this point; a
2839 special variable |be_careful| is used to emphasize the necessary
2840 order of computation. Optimizing compilers should keep |be_careful|
2841 in a register, not store it in memory.
2842 @^inner loop@>
2843
2844 @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>=
2845 {
2846   f=1;
2847   do {  
2848     be_careful=p-q; p=be_careful+p;
2849     if ( p>=0 ) { 
2850       f=f+f+1;
2851     } else  { 
2852       f+=f; p=p+q;
2853     }
2854   } while (f<fraction_one);
2855   be_careful=p-q;
2856   if ( be_careful+p>=0 ) incr(f);
2857 }
2858
2859 @ The dual of |make_fraction| is |take_fraction|, which multiplies a
2860 given integer~|q| by a fraction~|f|. When the operands are positive, it
2861 computes $p=\lfloor qf/2^{28}+{1\over2}\rfloor$, a symmetric function
2862 of |q| and~|f|.
2863
2864 This routine is even more ``inner loopy'' than |make_fraction|;
2865 the present implementation consumes almost 20\pct! of \MP's computation
2866 time during typical jobs, so a machine-language substitute is advisable.
2867 @^inner loop@> @^system dependencies@>
2868
2869 @<Declarations@>=
2870 integer mp_take_fraction (MP mp,integer q, fraction f) ;
2871
2872 @ @c 
2873 #ifdef FIXPT
2874 integer mp_take_fraction (MP mp,integer q, fraction f) {
2875   integer p; /* the fraction so far */
2876   boolean negative; /* should the result be negated? */
2877   integer n; /* additional multiple of $q$ */
2878   integer be_careful; /* disables certain compiler optimizations */
2879   @<Reduce to the case that |f>=0| and |q>0|@>;
2880   if ( f<fraction_one ) { 
2881     n=0;
2882   } else { 
2883     n=f / fraction_one; f=f % fraction_one;
2884     if ( q<=el_gordo / n ) { 
2885       n=n*q ; 
2886     } else { 
2887       mp->arith_error=true; n=el_gordo;
2888     }
2889   }
2890   f=f+fraction_one;
2891   @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>;
2892   be_careful=n-el_gordo;
2893   if ( be_careful+p>0 ){ 
2894     mp->arith_error=true; n=el_gordo-p;
2895   }
2896   if ( negative ) 
2897         return (-(n+p));
2898   else 
2899     return (n+p);
2900 #else /* FIXPT */
2901 integer mp_take_fraction (MP mp,integer p, fraction q) {
2902     register double d;
2903         register integer i;
2904         d = (double)p * (double)q * TWEXP_28;
2905         if ((p^q) >= 0) {
2906                 d += 0.5;
2907                 if (d>=TWEXP31) {
2908                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2909                                 mp->arith_error = true;
2910                         return ELGORDO;
2911                 }
2912                 i = (integer) d;
2913                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2914         } else {
2915                 d -= 0.5;
2916                 if (d<= -TWEXP31) {
2917                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2918                                 mp->arith_error = true;
2919                         return -ELGORDO;
2920                 }
2921                 i = (integer) d;
2922                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2923         }
2924         return i;
2925 #endif /* FIXPT */
2926 }
2927
2928 @ @<Reduce to the case that |f>=0| and |q>0|@>=
2929 if ( f>=0 ) {
2930   negative=false;
2931 } else { 
2932   negate( f); negative=true;
2933 }
2934 if ( q<0 ) { 
2935   negate(q); negative=! negative;
2936 }
2937
2938 @ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
2939 =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
2940 $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
2941 @^inner loop@>
2942
2943 @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>=
2944 p=fraction_half; /* that's $2^{27}$; the invariants hold now with $k=28$ */
2945 if ( q<fraction_four ) {
2946   do {  
2947     if ( odd(f) ) p=halfp(p+q); else p=halfp(p);
2948     f=halfp(f);
2949   } while (f!=1);
2950 } else  {
2951   do {  
2952     if ( odd(f) ) p=p+halfp(q-p); else p=halfp(p);
2953     f=halfp(f);
2954   } while (f!=1);
2955 }
2956
2957
2958 @ When we want to multiply something by a |scaled| quantity, we use a scheme
2959 analogous to |take_fraction| but with a different scaling.
2960 Given positive operands, |take_scaled|
2961 computes the quantity $p=\lfloor qf/2^{16}+{1\over2}\rfloor$.
2962
2963 Once again it is a good idea to use a machine-language replacement if
2964 possible; otherwise |take_scaled| will use more than 2\pct! of the running time
2965 when the Computer Modern fonts are being generated.
2966 @^inner loop@>
2967
2968 @c 
2969 #ifdef FIXPT
2970 integer mp_take_scaled (MP mp,integer q, scaled f) {
2971   integer p; /* the fraction so far */
2972   boolean negative; /* should the result be negated? */
2973   integer n; /* additional multiple of $q$ */
2974   integer be_careful; /* disables certain compiler optimizations */
2975   @<Reduce to the case that |f>=0| and |q>0|@>;
2976   if ( f<unity ) { 
2977     n=0;
2978   } else  { 
2979     n=f / unity; f=f % unity;
2980     if ( q<=el_gordo / n ) {
2981       n=n*q;
2982     } else  { 
2983       mp->arith_error=true; n=el_gordo;
2984     }
2985   }
2986   f=f+unity;
2987   @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>;
2988   be_careful=n-el_gordo;
2989   if ( be_careful+p>0 ) { 
2990     mp->arith_error=true; n=el_gordo-p;
2991   }
2992   return ( negative ?(-(n+p)) :(n+p));
2993 #else /* FIXPT */
2994 integer mp_take_scaled (MP mp,integer p, scaled q) {
2995     register double d;
2996         register integer i;
2997         d = (double)p * (double)q * TWEXP_16;
2998         if ((p^q) >= 0) {
2999                 d += 0.5;
3000                 if (d>=TWEXP31) {
3001                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
3002                                 mp->arith_error = true;
3003                         return ELGORDO;
3004                 }
3005                 i = (integer) d;
3006                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
3007         } else {
3008                 d -= 0.5;
3009                 if (d<= -TWEXP31) {
3010                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
3011                                 mp->arith_error = true;
3012                         return -ELGORDO;
3013                 }
3014                 i = (integer) d;
3015                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
3016         }
3017         return i;
3018 #endif /* FIXPT */
3019 }
3020
3021 @ @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>=
3022 p=half_unit; /* that's $2^{15}$; the invariants hold now with $k=16$ */
3023 @^inner loop@>
3024 if ( q<fraction_four ) {
3025   do {  
3026     p = (odd(f) ? halfp(p+q) : halfp(p));
3027     f=halfp(f);
3028   } while (f!=1);
3029 } else {
3030   do {  
3031     p = (odd(f) ? p+halfp(q-p) : halfp(p));
3032     f=halfp(f);
3033   } while (f!=1);
3034 }
3035
3036 @ For completeness, there's also |make_scaled|, which computes a
3037 quotient as a |scaled| number instead of as a |fraction|.
3038 In other words, the result is $\lfloor2^{16}p/q+{1\over2}\rfloor$, if the
3039 operands are positive. \ (This procedure is not used especially often,
3040 so it is not part of \MP's inner loop.)
3041
3042 @<Internal library ...@>=
3043 scaled mp_make_scaled (MP mp,integer p, integer q) ;
3044
3045 @ @c 
3046 scaled mp_make_scaled (MP mp,integer p, integer q) {
3047 #ifdef FIXPT 
3048   integer f; /* the fraction bits, with a leading 1 bit */
3049   integer n; /* the integer part of $\vert p/q\vert$ */
3050   boolean negative; /* should the result be negated? */
3051   integer be_careful; /* disables certain compiler optimizations */
3052   if ( p>=0 ) negative=false;
3053   else  { negate(p); negative=true; };
3054   if ( q<=0 ) { 
3055 #ifdef DEBUG 
3056     if ( q==0 ) mp_confusion(mp, "/");
3057 @:this can't happen /}{\quad \./@>
3058 #endif
3059     negate(q); negative=! negative;
3060   }
3061   n=p / q; p=p % q;
3062   if ( n>=0100000 ) { 
3063     mp->arith_error=true;
3064     return (negative ? (-el_gordo) : el_gordo);
3065   } else  { 
3066     n=(n-1)*unity;
3067     @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>;
3068     return ( negative ? (-(f+n)) :(f+n));
3069   }
3070 #else /* FIXPT */
3071     register double d;
3072         register integer i;
3073 #ifdef DEBUG
3074         if (q==0) mp_confusion(mp,"/"); 
3075 #endif /* DEBUG */
3076         d = TWEXP16 * (double)p /(double)q;
3077         if ((p^q) >= 0) {
3078                 d += 0.5;
3079                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
3080                 i = (integer) d;
3081                 if (d==i && ( ((q>0 ? -q : q)&077777)
3082                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
3083         } else {
3084                 d -= 0.5;
3085                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
3086                 i = (integer) d;
3087                 if (d==i && ( ((q>0 ? q : -q)&077777)
3088                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
3089         }
3090         return i;
3091 #endif /* FIXPT */
3092 }
3093
3094 @ @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>=
3095 f=1;
3096 do {  
3097   be_careful=p-q; p=be_careful+p;
3098   if ( p>=0 ) f=f+f+1;
3099   else  { f+=f; p=p+q; };
3100 } while (f<unity);
3101 be_careful=p-q;
3102 if ( be_careful+p>=0 ) incr(f)
3103
3104 @ Here is a typical example of how the routines above can be used.
3105 It computes the function
3106 $${1\over3\tau}f(\theta,\phi)=
3107 {\tau^{-1}\bigl(2+\sqrt2\,(\sin\theta-{1\over16}\sin\phi)
3108  (\sin\phi-{1\over16}\sin\theta)(\cos\theta-\cos\phi)\bigr)\over
3109 3\,\bigl(1+{1\over2}(\sqrt5-1)\cos\theta+{1\over2}(3-\sqrt5\,)\cos\phi\bigr)},$$
3110 where $\tau$ is a |scaled| ``tension'' parameter. This is \MP's magic
3111 fudge factor for placing the first control point of a curve that starts
3112 at an angle $\theta$ and ends at an angle $\phi$ from the straight path.
3113 (Actually, if the stated quantity exceeds 4, \MP\ reduces it to~4.)
3114
3115 The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$.
3116 (It's a sum of eight terms whose absolute values can be bounded using
3117 relations such as $\sin\theta\cos\theta\L{1\over2}$.) Thus the numerator
3118 is positive; and since the tension $\tau$ is constrained to be at least
3119 $3\over4$, the numerator is less than $16\over3$. The denominator is
3120 nonnegative and at most~6.  Hence the fixed-point calculations below
3121 are guaranteed to stay within the bounds of a 32-bit computer word.
3122
3123 The angles $\theta$ and $\phi$ are given implicitly in terms of |fraction|
3124 arguments |st|, |ct|, |sf|, and |cf|, representing $\sin\theta$, $\cos\theta$,
3125 $\sin\phi$, and $\cos\phi$, respectively.
3126
3127 @c 
3128 fraction mp_velocity (MP mp,fraction st, fraction ct, fraction sf,
3129                       fraction cf, scaled t) {
3130   integer acc,num,denom; /* registers for intermediate calculations */
3131   acc=mp_take_fraction(mp, st-(sf / 16), sf-(st / 16));
3132   acc=mp_take_fraction(mp, acc,ct-cf);
3133   num=fraction_two+mp_take_fraction(mp, acc,379625062);
3134                    /* $2^{28}\sqrt2\approx379625062.497$ */
3135   denom=fraction_three+mp_take_fraction(mp, ct,497706707)+mp_take_fraction(mp, cf,307599661);
3136                       /* $3\cdot2^{27}\cdot(\sqrt5-1)\approx497706706.78$ and
3137                          $3\cdot2^{27}\cdot(3-\sqrt5\,)\approx307599661.22$ */
3138   if ( t!=unity ) num=mp_make_scaled(mp, num,t);
3139   /* |make_scaled(fraction,scaled)=fraction| */
3140   if ( num / 4>=denom ) 
3141     return fraction_four;
3142   else 
3143     return mp_make_fraction(mp, num, denom);
3144 }
3145
3146 @ The following somewhat different subroutine tests rigorously if $ab$ is
3147 greater than, equal to, or less than~$cd$,
3148 given integers $(a,b,c,d)$. In most cases a quick decision is reached.
3149 The result is $+1$, 0, or~$-1$ in the three respective cases.
3150
3151 @d mp_ab_vs_cd(M,A,B,C,D) mp_do_ab_vs_cd(A,B,C,D)
3152
3153 @c 
3154 integer mp_do_ab_vs_cd (integer a,integer b, integer c, integer d) {
3155   integer q,r; /* temporary registers */
3156   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
3157   while (1) { 
3158     q = a / d; r = c / b;
3159     if ( q!=r )
3160       return ( q>r ? 1 : -1);
3161     q = a % d; r = c % b;
3162     if ( r==0 )
3163       return (q ? 1 : 0);
3164     if ( q==0 ) return -1;
3165     a=b; b=q; c=d; d=r;
3166   } /* now |a>d>0| and |c>b>0| */
3167 }
3168
3169 @ @<Reduce to the case that |a...@>=
3170 if ( a<0 ) { negate(a); negate(b);  };
3171 if ( c<0 ) { negate(c); negate(d);  };
3172 if ( d<=0 ) { 
3173   if ( b>=0 ) {
3174     if ( (a==0||b==0)&&(c==0||d==0) ) return 0;
3175     else return 1;
3176   }
3177   if ( d==0 )
3178     return ( a==0 ? 0 : -1);
3179   q=a; a=c; c=q; q=-b; b=-d; d=q;
3180 } else if ( b<=0 ) { 
3181   if ( b<0 ) if ( a>0 ) return -1;
3182   return (c==0 ? 0 : -1);
3183 }
3184
3185 @ We conclude this set of elementary routines with some simple rounding
3186 and truncation operations.
3187
3188 @<Internal library declarations@>=
3189 #define mp_floor_scaled(M,i) ((i)&(-65536))
3190 #define mp_round_unscaled(M,i) (((i>>15)+1)>>1)
3191 #define mp_round_fraction(M,i) (((i>>11)+1)>>1)
3192
3193
3194 @* \[8] Algebraic and transcendental functions.
3195 \MP\ computes all of the necessary special functions from scratch, without
3196 relying on |real| arithmetic or system subroutines for sines, cosines, etc.
3197
3198 @ To get the square root of a |scaled| number |x|, we want to calculate
3199 $s=\lfloor 2^8\!\sqrt x +{1\over2}\rfloor$. If $x>0$, this is the unique
3200 integer such that $2^{16}x-s\L s^2<2^{16}x+s$. The following subroutine
3201 determines $s$ by an iterative method that maintains the invariant
3202 relations $x=2^{46-2k}x_0\bmod 2^{30}$, $0<y=\lfloor 2^{16-2k}x_0\rfloor
3203 -s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$
3204 might, however, be zero at the start of the first iteration.
3205
3206 @<Declarations@>=
3207 scaled mp_square_rt (MP mp,scaled x) ;
3208
3209 @ @c 
3210 scaled mp_square_rt (MP mp,scaled x) {
3211   small_number k; /* iteration control counter */
3212   integer y,q; /* registers for intermediate calculations */
3213   if ( x<=0 ) { 
3214     @<Handle square root of zero or negative argument@>;
3215   } else { 
3216     k=23; q=2;
3217     while ( x<fraction_two ) { /* i.e., |while x<@t$2^{29}$@>|\unskip */
3218       decr(k); x=x+x+x+x;
3219     }
3220     if ( x<fraction_four ) y=0;
3221     else  { x=x-fraction_four; y=1; };
3222     do {  
3223       @<Decrease |k| by 1, maintaining the invariant
3224       relations between |x|, |y|, and~|q|@>;
3225     } while (k!=0);
3226     return (halfp(q));
3227   }
3228 }
3229
3230 @ @<Handle square root of zero...@>=
3231
3232   if ( x<0 ) { 
3233     print_err("Square root of ");
3234 @.Square root...replaced by 0@>
3235     mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3236     help2("Since I don't take square roots of negative numbers,")
3237          ("I'm zeroing this one. Proceed, with fingers crossed.");
3238     mp_error(mp);
3239   };
3240   return 0;
3241 }
3242
3243 @ @<Decrease |k| by 1, maintaining...@>=
3244 x+=x; y+=y;
3245 if ( x>=fraction_four ) { /* note that |fraction_four=@t$2^{30}$@>| */
3246   x=x-fraction_four; incr(y);
3247 };
3248 x+=x; y=y+y-q; q+=q;
3249 if ( x>=fraction_four ) { x=x-fraction_four; incr(y); };
3250 if ( y>q ){ y=y-q; q=q+2; }
3251 else if ( y<=0 )  { q=q-2; y=y+q;  };
3252 decr(k)
3253
3254 @ Pythagorean addition $\psqrt{a^2+b^2}$ is implemented by an elegant
3255 iterative scheme due to Cleve Moler and Donald Morrison [{\sl IBM Journal
3256 @^Moler, Cleve Barry@>
3257 @^Morrison, Donald Ross@>
3258 of Research and Development\/ \bf27} (1983), 577--581]. It modifies |a| and~|b|
3259 in such a way that their Pythagorean sum remains invariant, while the
3260 smaller argument decreases.
3261
3262 @<Internal library ...@>=
3263 integer mp_pyth_add (MP mp,integer a, integer b);
3264
3265
3266 @ @c 
3267 integer mp_pyth_add (MP mp,integer a, integer b) {
3268   fraction r; /* register used to transform |a| and |b| */
3269   boolean big; /* is the result dangerously near $2^{31}$? */
3270   a=abs(a); b=abs(b);
3271   if ( a<b ) { r=b; b=a; a=r; }; /* now |0<=b<=a| */
3272   if ( b>0 ) {
3273     if ( a<fraction_two ) {
3274       big=false;
3275     } else { 
3276       a=a / 4; b=b / 4; big=true;
3277     }; /* we reduced the precision to avoid arithmetic overflow */
3278     @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>;
3279     if ( big ) {
3280       if ( a<fraction_two ) {
3281         a=a+a+a+a;
3282       } else  { 
3283         mp->arith_error=true; a=el_gordo;
3284       };
3285     }
3286   }
3287   return a;
3288 }
3289
3290 @ The key idea here is to reflect the vector $(a,b)$ about the
3291 line through $(a,b/2)$.
3292
3293 @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>=
3294 while (1) {  
3295   r=mp_make_fraction(mp, b,a);
3296   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3297   if ( r==0 ) break;
3298   r=mp_make_fraction(mp, r,fraction_four+r);
3299   a=a+mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3300 }
3301
3302
3303 @ Here is a similar algorithm for $\psqrt{a^2-b^2}$.
3304 It converges slowly when $b$ is near $a$, but otherwise it works fine.
3305
3306 @c 
3307 integer mp_pyth_sub (MP mp,integer a, integer b) {
3308   fraction r; /* register used to transform |a| and |b| */
3309   boolean big; /* is the input dangerously near $2^{31}$? */
3310   a=abs(a); b=abs(b);
3311   if ( a<=b ) {
3312     @<Handle erroneous |pyth_sub| and set |a:=0|@>;
3313   } else { 
3314     if ( a<fraction_four ) {
3315       big=false;
3316     } else  { 
3317       a=halfp(a); b=halfp(b); big=true;
3318     }
3319     @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>;
3320     if ( big ) double(a);
3321   }
3322   return a;
3323 }
3324
3325 @ @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>=
3326 while (1) { 
3327   r=mp_make_fraction(mp, b,a);
3328   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3329   if ( r==0 ) break;
3330   r=mp_make_fraction(mp, r,fraction_four-r);
3331   a=a-mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3332 }
3333
3334 @ @<Handle erroneous |pyth_sub| and set |a:=0|@>=
3335
3336   if ( a<b ){ 
3337     print_err("Pythagorean subtraction "); mp_print_scaled(mp, a);
3338     mp_print(mp, "+-+"); mp_print_scaled(mp, b); 
3339     mp_print(mp, " has been replaced by 0");
3340 @.Pythagorean...@>
3341     help2("Since I don't take square roots of negative numbers,")
3342          ("I'm zeroing this one. Proceed, with fingers crossed.");
3343     mp_error(mp);
3344   }
3345   a=0;
3346 }
3347
3348 @ The subroutines for logarithm and exponential involve two tables.
3349 The first is simple: |two_to_the[k]| equals $2^k$. The second involves
3350 a bit more calculation, which the author claims to have done correctly:
3351 |spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
3352 2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
3353 nearest integer.
3354
3355 @d two_to_the(A) (1<<(A))
3356
3357 @<Constants ...@>=
3358 static const integer spec_log[29] = { 0, /* special logarithms */
3359 93032640, 38612034, 17922280, 8662214, 4261238, 2113709,
3360 1052693, 525315, 262400, 131136, 65552, 32772, 16385,
3361 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 1 };
3362
3363 @ @<Local variables for initialization@>=
3364 integer k; /* all-purpose loop index */
3365
3366
3367 @ Here is the routine that calculates $2^8$ times the natural logarithm
3368 of a |scaled| quantity; it is an integer approximation to $2^{24}\ln(x/2^{16})$,
3369 when |x| is a given positive integer.
3370
3371 The method is based on exercise 1.2.2--25 in {\sl The Art of Computer
3372 Programming\/}: During the main iteration we have $1\L 2^{-30}x<1/(1-2^{1-k})$,
3373 and the logarithm of $2^{30}x$ remains to be added to an accumulator
3374 register called~$y$. Three auxiliary bits of accuracy are retained in~$y$
3375 during the calculation, and sixteen auxiliary bits to extend |y| are
3376 kept in~|z| during the initial argument reduction. (We add
3377 $100\cdot2^{16}=6553600$ to~|z| and subtract 100 from~|y| so that |z| will
3378 not become negative; also, the actual amount subtracted from~|y| is~96,
3379 not~100, because we want to add~4 for rounding before the final division by~8.)
3380
3381 @c 
3382 scaled mp_m_log (MP mp,scaled x) {
3383   integer y,z; /* auxiliary registers */
3384   integer k; /* iteration counter */
3385   if ( x<=0 ) {
3386      @<Handle non-positive logarithm@>;
3387   } else  { 
3388     y=1302456956+4-100; /* $14\times2^{27}\ln2\approx1302456956.421063$ */
3389     z=27595+6553600; /* and $2^{16}\times .421063\approx 27595$ */
3390     while ( x<fraction_four ) {
3391        double(x); y-=93032639; z-=48782;
3392     } /* $2^{27}\ln2\approx 93032639.74436163$ and $2^{16}\times.74436163\approx 48782$ */
3393     y=y+(z / unity); k=2;
3394     while ( x>fraction_four+4 ) {
3395       @<Increase |k| until |x| can be multiplied by a
3396         factor of $2^{-k}$, and adjust $y$ accordingly@>;
3397     }
3398     return (y / 8);
3399   }
3400 }
3401
3402 @ @<Increase |k| until |x| can...@>=
3403
3404   z=((x-1) / two_to_the(k))+1; /* $z=\lceil x/2^k\rceil$ */
3405   while ( x<fraction_four+z ) { z=halfp(z+1); incr(k); };
3406   y+=spec_log[k]; x-=z;
3407 }
3408
3409 @ @<Handle non-positive logarithm@>=
3410
3411   print_err("Logarithm of ");
3412 @.Logarithm...replaced by 0@>
3413   mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3414   help2("Since I don't take logs of non-positive numbers,")
3415        ("I'm zeroing this one. Proceed, with fingers crossed.");
3416   mp_error(mp); 
3417   return 0;
3418 }
3419
3420 @ Conversely, the exponential routine calculates $\exp(x/2^8)$,
3421 when |x| is |scaled|. The result is an integer approximation to
3422 $2^{16}\exp(x/2^{24})$, when |x| is regarded as an integer.
3423
3424 @c 
3425 scaled mp_m_exp (MP mp,scaled x) {
3426   small_number k; /* loop control index */
3427   integer y,z; /* auxiliary registers */
3428   if ( x>174436200 ) {
3429     /* $2^{24}\ln((2^{31}-1)/2^{16})\approx 174436199.51$ */
3430     mp->arith_error=true; 
3431     return el_gordo;
3432   } else if ( x<-197694359 ) {
3433         /* $2^{24}\ln(2^{-1}/2^{16})\approx-197694359.45$ */
3434     return 0;
3435   } else { 
3436     if ( x<=0 ) { 
3437        z=-8*x; y=04000000; /* $y=2^{20}$ */
3438     } else { 
3439       if ( x<=127919879 ) { 
3440         z=1023359037-8*x;
3441         /* $2^{27}\ln((2^{31}-1)/2^{20})\approx 1023359037.125$ */
3442       } else {
3443        z=8*(174436200-x); /* |z| is always nonnegative */
3444       }
3445       y=el_gordo;
3446     };
3447     @<Multiply |y| by $\exp(-z/2^{27})$@>;
3448     if ( x<=127919879 ) 
3449        return ((y+8) / 16);
3450      else 
3451        return y;
3452   }
3453 }
3454
3455 @ The idea here is that subtracting |spec_log[k]| from |z| corresponds
3456 to multiplying |y| by $1-2^{-k}$.
3457
3458 A subtle point (which had to be checked) was that if $x=127919879$, the
3459 value of~|y| will decrease so that |y+8| doesn't overflow. In fact,
3460 $z$ will be 5 in this case, and |y| will decrease by~64 when |k=25|
3461 and by~16 when |k=27|.
3462
3463 @<Multiply |y| by...@>=
3464 k=1;
3465 while ( z>0 ) { 
3466   while ( z>=spec_log[k] ) { 
3467     z-=spec_log[k];
3468     y=y-1-((y-two_to_the(k-1)) / two_to_the(k));
3469   }
3470   incr(k);
3471 }
3472
3473 @ The trigonometric subroutines use an auxiliary table such that
3474 |spec_atan[k]| contains an approximation to the |angle| whose tangent
3475 is~$1/2^k$. $\arctan2^{-k}$ times $2^{20}\cdot180/\pi$ 
3476
3477 @<Constants ...@>=
3478 static const angle spec_atan[27] = { 0, 27855475, 14718068, 7471121, 3750058, 
3479 1876857, 938658, 469357, 234682, 117342, 58671, 29335, 14668, 7334, 3667, 
3480 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1 };
3481
3482 @ Given integers |x| and |y|, not both zero, the |n_arg| function
3483 returns the |angle| whose tangent points in the direction $(x,y)$.
3484 This subroutine first determines the correct octant, then solves the
3485 problem for |0<=y<=x|, then converts the result appropriately to
3486 return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|.
3487 (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of
3488 |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.)
3489
3490 The octants are represented in a ``Gray code,'' since that turns out
3491 to be computationally simplest.
3492
3493 @d negate_x 1
3494 @d negate_y 2
3495 @d switch_x_and_y 4
3496 @d first_octant 1
3497 @d second_octant (first_octant+switch_x_and_y)
3498 @d third_octant (first_octant+switch_x_and_y+negate_x)
3499 @d fourth_octant (first_octant+negate_x)
3500 @d fifth_octant (first_octant+negate_x+negate_y)
3501 @d sixth_octant (first_octant+switch_x_and_y+negate_x+negate_y)
3502 @d seventh_octant (first_octant+switch_x_and_y+negate_y)
3503 @d eighth_octant (first_octant+negate_y)
3504
3505 @c 
3506 angle mp_n_arg (MP mp,integer x, integer y) {
3507   angle z; /* auxiliary register */
3508   integer t; /* temporary storage */
3509   small_number k; /* loop counter */
3510   int octant; /* octant code */
3511   if ( x>=0 ) {
3512     octant=first_octant;
3513   } else { 
3514     negate(x); octant=first_octant+negate_x;
3515   }
3516   if ( y<0 ) { 
3517     negate(y); octant=octant+negate_y;
3518   }
3519   if ( x<y ) { 
3520     t=y; y=x; x=t; octant=octant+switch_x_and_y;
3521   }
3522   if ( x==0 ) { 
3523     @<Handle undefined arg@>; 
3524   } else { 
3525     @<Set variable |z| to the arg of $(x,y)$@>;
3526     @<Return an appropriate answer based on |z| and |octant|@>;
3527   }
3528 }
3529
3530 @ @<Handle undefined arg@>=
3531
3532   print_err("angle(0,0) is taken as zero");
3533 @.angle(0,0)...zero@>
3534   help2("The `angle' between two identical points is undefined.")
3535        ("I'm zeroing this one. Proceed, with fingers crossed.");
3536   mp_error(mp); 
3537   return 0;
3538 }
3539
3540 @ @<Return an appropriate answer...@>=
3541 switch (octant) {
3542 case first_octant: return z;
3543 case second_octant: return (ninety_deg-z);
3544 case third_octant: return (ninety_deg+z);
3545 case fourth_octant: return (one_eighty_deg-z);
3546 case fifth_octant: return (z-one_eighty_deg);
3547 case sixth_octant: return (-z-ninety_deg);
3548 case seventh_octant: return (z-ninety_deg);
3549 case eighth_octant: return (-z);
3550 }; /* there are no other cases */
3551 return 0
3552
3553 @ At this point we have |x>=y>=0|, and |x>0|. The numbers are scaled up
3554 or down until $2^{28}\L x<2^{29}$, so that accurate fixed-point calculations
3555 will be made.
3556
3557 @<Set variable |z| to the arg...@>=
3558 while ( x>=fraction_two ) { 
3559   x=halfp(x); y=halfp(y);
3560 }
3561 z=0;
3562 if ( y>0 ) { 
3563  while ( x<fraction_one ) { 
3564     x+=x; y+=y; 
3565  };
3566  @<Increase |z| to the arg of $(x,y)$@>;
3567 }
3568
3569 @ During the calculations of this section, variables |x| and~|y|
3570 represent actual coordinates $(x,2^{-k}y)$. We will maintain the
3571 condition |x>=y|, so that the tangent will be at most $2^{-k}$.
3572 If $x<2y$, the tangent is greater than $2^{-k-1}$. The transformation
3573 $(a,b)\mapsto(a+b\tan\phi,b-a\tan\phi)$ replaces $(a,b)$ by
3574 coordinates whose angle has decreased by~$\phi$; in the special case
3575 $a=x$, $b=2^{-k}y$, and $\tan\phi=2^{-k-1}$, this operation reduces
3576 to the particularly simple iteration shown here. [Cf.~John E. Meggitt,
3577 @^Meggitt, John E.@>
3578 {\sl IBM Journal of Research and Development\/ \bf6} (1962), 210--226.]
3579
3580 The initial value of |x| will be multiplied by at most
3581 $(1+{1\over2})(1+{1\over8})(1+{1\over32})\cdots\approx 1.7584$; hence
3582 there is no chance of integer overflow.
3583
3584 @<Increase |z|...@>=
3585 k=0;
3586 do {  
3587   y+=y; incr(k);
3588   if ( y>x ){ 
3589     z=z+spec_atan[k]; t=x; x=x+(y / two_to_the(k+k)); y=y-t;
3590   };
3591 } while (k!=15);
3592 do {  
3593   y+=y; incr(k);
3594   if ( y>x ) { z=z+spec_atan[k]; y=y-x; };
3595 } while (k!=26)
3596
3597 @ Conversely, the |n_sin_cos| routine takes an |angle| and produces the sine
3598 and cosine of that angle. The results of this routine are
3599 stored in global integer variables |n_sin| and |n_cos|.
3600
3601 @<Glob...@>=
3602 fraction n_sin;fraction n_cos; /* results computed by |n_sin_cos| */
3603
3604 @ Given an integer |z| that is $2^{20}$ times an angle $\theta$ in degrees,
3605 the purpose of |n_sin_cos(z)| is to set
3606 |x=@t$r\cos\theta$@>| and |y=@t$r\sin\theta$@>| (approximately),
3607 for some rather large number~|r|. The maximum of |x| and |y|
3608 will be between $2^{28}$ and $2^{30}$, so that there will be hardly
3609 any loss of accuracy. Then |x| and~|y| are divided by~|r|.
3610
3611 @c 
3612 void mp_n_sin_cos (MP mp,angle z) { /* computes a multiple of the sine
3613                                        and cosine */ 
3614   small_number k; /* loop control variable */
3615   int q; /* specifies the quadrant */
3616   fraction r; /* magnitude of |(x,y)| */
3617   integer x,y,t; /* temporary registers */
3618   while ( z<0 ) z=z+three_sixty_deg;
3619   z=z % three_sixty_deg; /* now |0<=z<three_sixty_deg| */
3620   q=z / forty_five_deg; z=z % forty_five_deg;
3621   x=fraction_one; y=x;
3622   if ( ! odd(q) ) z=forty_five_deg-z;
3623   @<Subtract angle |z| from |(x,y)|@>;
3624   @<Convert |(x,y)| to the octant determined by~|q|@>;
3625   r=mp_pyth_add(mp, x,y); 
3626   mp->n_cos=mp_make_fraction(mp, x,r); 
3627   mp->n_sin=mp_make_fraction(mp, y,r);
3628 }
3629
3630 @ In this case the octants are numbered sequentially.
3631
3632 @<Convert |(x,...@>=
3633 switch (q) {
3634 case 0: break;
3635 case 1: t=x; x=y; y=t; break;
3636 case 2: t=x; x=-y; y=t; break;
3637 case 3: negate(x); break;
3638 case 4: negate(x); negate(y); break;
3639 case 5: t=x; x=-y; y=-t; break;
3640 case 6: t=x; x=y; y=-t; break;
3641 case 7: negate(y); break;
3642 } /* there are no other cases */
3643
3644 @ The main iteration of |n_sin_cos| is similar to that of |n_arg| but
3645 applied in reverse. The values of |spec_atan[k]| decrease slowly enough
3646 that this loop is guaranteed to terminate before the (nonexistent) value
3647 |spec_atan[27]| would be required.
3648
3649 @<Subtract angle |z|...@>=
3650 k=1;
3651 while ( z>0 ){ 
3652   if ( z>=spec_atan[k] ) { 
3653     z=z-spec_atan[k]; t=x;
3654     x=t+y / two_to_the(k);
3655     y=y-t / two_to_the(k);
3656   }
3657   incr(k);
3658 }
3659 if ( y<0 ) y=0 /* this precaution may never be needed */
3660
3661 @ And now let's complete our collection of numeric utility routines
3662 by considering random number generation.
3663 \MP\ generates pseudo-random numbers with the additive scheme recommended
3664 in Section 3.6 of {\sl The Art of Computer Programming}; however, the
3665 results are random fractions between 0 and |fraction_one-1|, inclusive.
3666
3667 There's an auxiliary array |randoms| that contains 55 pseudo-random
3668 fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
3669 we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
3670 The global variable |j_random| tells which element has most recently
3671 been consumed.
3672 The global variable |sys_random_seed| was introduced in version 0.9,
3673 for the sole reason of stressing the fact that the initial value of the
3674 random seed is system-dependant. The pascal code below will initialize
3675 this variable to |(internal[mp_time] div unity)+internal[mp_day]|, but this 
3676 is not good enough on modern fast machines that are capable of running
3677 multiple MetaPost processes within the same second.
3678 @^system dependencies@>
3679
3680 @<Glob...@>=
3681 fraction randoms[55]; /* the last 55 random values generated */
3682 int j_random; /* the number of unused |randoms| */
3683 scaled sys_random_seed; /* the default random seed */
3684
3685 @ @<Exported types@>=
3686 typedef int (*mp_get_random_seed_command)(MP mp);
3687
3688 @ @<Glob...@>=
3689 mp_get_random_seed_command get_random_seed;
3690
3691 @ @<Option variables@>=
3692 mp_get_random_seed_command get_random_seed;
3693
3694 @ @<Allocate or initialize ...@>=
3695 set_callback_option(get_random_seed);
3696
3697 @ @<Internal library declarations@>=
3698 int mp_get_random_seed (MP mp);
3699
3700 @ @c 
3701 int mp_get_random_seed (MP mp) {
3702   return (mp->internal[mp_time] / unity)+mp->internal[mp_day];
3703 }
3704
3705 @ To consume a random fraction, the program below will say `|next_random|'
3706 and then it will fetch |randoms[j_random]|.
3707
3708 @d next_random { if ( mp->j_random==0 ) mp_new_randoms(mp);
3709   else decr(mp->j_random); }
3710
3711 @c 
3712 void mp_new_randoms (MP mp) {
3713   int k; /* index into |randoms| */
3714   fraction x; /* accumulator */
3715   for (k=0;k<=23;k++) { 
3716    x=mp->randoms[k]-mp->randoms[k+31];
3717     if ( x<0 ) x=x+fraction_one;
3718     mp->randoms[k]=x;
3719   }
3720   for (k=24;k<= 54;k++){ 
3721     x=mp->randoms[k]-mp->randoms[k-24];
3722     if ( x<0 ) x=x+fraction_one;
3723     mp->randoms[k]=x;
3724   }
3725   mp->j_random=54;
3726 }
3727
3728 @ @<Declarations@>=
3729 void mp_init_randoms (MP mp,scaled seed);
3730
3731 @ To initialize the |randoms| table, we call the following routine.
3732
3733 @c 
3734 void mp_init_randoms (MP mp,scaled seed) {
3735   fraction j,jj,k; /* more or less random integers */
3736   int i; /* index into |randoms| */
3737   j=abs(seed);
3738   while ( j>=fraction_one ) j=halfp(j);
3739   k=1;
3740   for (i=0;i<=54;i++ ){ 
3741     jj=k; k=j-k; j=jj;
3742     if ( k<0 ) k=k+fraction_one;
3743     mp->randoms[(i*21)% 55]=j;
3744   }
3745   mp_new_randoms(mp); 
3746   mp_new_randoms(mp); 
3747   mp_new_randoms(mp); /* ``warm up'' the array */
3748 }
3749
3750 @ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
3751 or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
3752
3753 Note that the call of |take_fraction| will produce the values 0 and~|x|
3754 with about half the probability that it will produce any other particular
3755 values between 0 and~|x|, because it rounds its answers.
3756
3757 @c 
3758 scaled mp_unif_rand (MP mp,scaled x) {
3759   scaled y; /* trial value */
3760   next_random; y=mp_take_fraction(mp, abs(x),mp->randoms[mp->j_random]);
3761   if ( y==abs(x) ) return 0;
3762   else if ( x>0 ) return y;
3763   else return (-y);
3764 }
3765
3766 @ Finally, a normal deviate with mean zero and unit standard deviation
3767 can readily be obtained with the ratio method (Algorithm 3.4.1R in
3768 {\sl The Art of Computer Programming\/}).
3769
3770 @c 
3771 scaled mp_norm_rand (MP mp) {
3772   integer x,u,l; /* what the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$ */
3773   do { 
3774     do {  
3775       next_random;
3776       x=mp_take_fraction(mp, 112429,mp->randoms[mp->j_random]-fraction_half);
3777       /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */
3778       next_random; u=mp->randoms[mp->j_random];
3779     } while (abs(x)>=u);
3780     x=mp_make_fraction(mp, x,u);
3781     l=139548960-mp_m_log(mp, u); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */
3782   } while (mp_ab_vs_cd(mp, 1024,l,x,x)<0);
3783   return x;
3784 }
3785
3786 @* \[9] Packed data.
3787 In order to make efficient use of storage space, \MP\ bases its major data
3788 structures on a |memory_word|, which contains either a (signed) integer,
3789 possibly scaled, or a small number of fields that are one half or one
3790 quarter of the size used for storing integers.
3791
3792 If |x| is a variable of type |memory_word|, it contains up to four
3793 fields that can be referred to as follows:
3794 $$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
3795 |x|&.|int|&(an |integer|)\cr
3796 |x|&.|sc|\qquad&(a |scaled| integer)\cr
3797 |x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
3798 |x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
3799   field)\cr
3800 |x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
3801   &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
3802 This is somewhat cumbersome to write, and not very readable either, but
3803 macros will be used to make the notation shorter and more transparent.
3804 The code below gives a formal definition of |memory_word| and
3805 its subsidiary types, using packed variant records. \MP\ makes no
3806 assumptions about the relative positions of the fields within a word.
3807
3808 @d max_quarterword 0x3FFF /* largest allowable value in a |quarterword| */
3809 @d max_halfword 0xFFFFFFF /* largest allowable value in a |halfword| */
3810
3811 @ Here are the inequalities that the quarterword and halfword values
3812 must satisfy (or rather, the inequalities that they mustn't satisfy):
3813
3814 @<Check the ``constant''...@>=
3815 if (mp->ini_version) {
3816   if ( mp->mem_max!=mp->mem_top ) mp->bad=8;
3817 } else {
3818   if ( mp->mem_max<mp->mem_top ) mp->bad=8;
3819 }
3820 if ( max_quarterword<255 ) mp->bad=9;
3821 if ( max_halfword<65535 ) mp->bad=10;
3822 if ( max_quarterword>max_halfword ) mp->bad=11;
3823 if ( mp->mem_max>=max_halfword ) mp->bad=12;
3824 if ( mp->max_strings>max_halfword ) mp->bad=13;
3825
3826 @ The macros |qi| and |qo| are used for input to and output 
3827 from quarterwords. These are legacy macros.
3828 @^system dependencies@>
3829
3830 @d qo(A) (A) /* to read eight bits from a quarterword */
3831 @d qi(A) (A) /* to store eight bits in a quarterword */
3832
3833 @ The reader should study the following definitions closely:
3834 @^system dependencies@>
3835
3836 @d sc cint /* |scaled| data is equivalent to |integer| */
3837
3838 @<Types...@>=
3839 typedef short quarterword; /* 1/4 of a word */
3840 typedef int halfword; /* 1/2 of a word */
3841 typedef union {
3842   struct {
3843     halfword RH, LH;
3844   } v;
3845   struct { /* Make B0,B1 overlap the most significant bytes of LH.  */
3846     halfword junk;
3847     quarterword B0, B1;
3848   } u;
3849 } two_halves;
3850 typedef struct {
3851   struct {
3852     quarterword B2, B3, B0, B1;
3853   } u;
3854 } four_quarters;
3855 typedef union {
3856   two_halves hh;
3857   integer cint;
3858   four_quarters qqqq;
3859 } memory_word;
3860 #define b0 u.B0
3861 #define b1 u.B1
3862 #define b2 u.B2
3863 #define b3 u.B3
3864 #define rh v.RH
3865 #define lh v.LH
3866
3867 @ When debugging, we may want to print a |memory_word| without knowing
3868 what type it is; so we print it in all modes.
3869 @^dirty \PASCAL@>@^debugging@>
3870
3871 @c 
3872 void mp_print_word (MP mp,memory_word w) {
3873   /* prints |w| in all ways */
3874   mp_print_int(mp, w.cint); mp_print_char(mp, ' ');
3875   mp_print_scaled(mp, w.sc); mp_print_char(mp, ' '); 
3876   mp_print_scaled(mp, w.sc / 010000); mp_print_ln(mp);
3877   mp_print_int(mp, w.hh.lh); mp_print_char(mp, '='); 
3878   mp_print_int(mp, w.hh.b0); mp_print_char(mp, ':');
3879   mp_print_int(mp, w.hh.b1); mp_print_char(mp, ';'); 
3880   mp_print_int(mp, w.hh.rh); mp_print_char(mp, ' ');
3881   mp_print_int(mp, w.qqqq.b0); mp_print_char(mp, ':'); 
3882   mp_print_int(mp, w.qqqq.b1); mp_print_char(mp, ':');
3883   mp_print_int(mp, w.qqqq.b2); mp_print_char(mp, ':'); 
3884   mp_print_int(mp, w.qqqq.b3);
3885 }
3886
3887
3888 @* \[10] Dynamic memory allocation.
3889
3890 The \MP\ system does nearly all of its own memory allocation, so that it
3891 can readily be transported into environments that do not have automatic
3892 facilities for strings, garbage collection, etc., and so that it can be in
3893 control of what error messages the user receives. The dynamic storage
3894 requirements of \MP\ are handled by providing a large array |mem| in
3895 which consecutive blocks of words are used as nodes by the \MP\ routines.
3896
3897 Pointer variables are indices into this array, or into another array
3898 called |eqtb| that will be explained later. A pointer variable might
3899 also be a special flag that lies outside the bounds of |mem|, so we
3900 allow pointers to assume any |halfword| value. The minimum memory
3901 index represents a null pointer.
3902
3903 @d null 0 /* the null pointer */
3904 @d mp_void (null+1) /* a null pointer different from |null| */
3905
3906
3907 @<Types...@>=
3908 typedef halfword pointer; /* a flag or a location in |mem| or |eqtb| */
3909
3910 @ The |mem| array is divided into two regions that are allocated separately,
3911 but the dividing line between these two regions is not fixed; they grow
3912 together until finding their ``natural'' size in a particular job.
3913 Locations less than or equal to |lo_mem_max| are used for storing
3914 variable-length records consisting of two or more words each. This region
3915 is maintained using an algorithm similar to the one described in exercise
3916 2.5--19 of {\sl The Art of Computer Programming}. However, no size field
3917 appears in the allocated nodes; the program is responsible for knowing the
3918 relevant size when a node is freed. Locations greater than or equal to
3919 |hi_mem_min| are used for storing one-word records; a conventional
3920 \.{AVAIL} stack is used for allocation in this region.
3921
3922 Locations of |mem| between |0| and |mem_top| may be dumped as part
3923 of preloaded format files, by the \.{INIMP} preprocessor.
3924 @.INIMP@>
3925 Production versions of \MP\ may extend the memory at the top end in order to
3926 provide more space; these locations, between |mem_top| and |mem_max|,
3927 are always used for single-word nodes.
3928
3929 The key pointers that govern |mem| allocation have a prescribed order:
3930 $$\hbox{|null=0<lo_mem_max<hi_mem_min<mem_top<=mem_end<=mem_max|.}$$
3931
3932 @<Glob...@>=
3933 memory_word *mem; /* the big dynamic storage area */
3934 pointer lo_mem_max; /* the largest location of variable-size memory in use */
3935 pointer hi_mem_min; /* the smallest location of one-word memory in use */
3936
3937
3938
3939 @d xfree(A) do { mp_xfree(A); A=NULL; } while (0)
3940 @d xrealloc(P,A,B) mp_xrealloc(mp,P,A,B)
3941 @d xmalloc(A,B)  mp_xmalloc(mp,A,B)
3942 @d xstrdup(A)  mp_xstrdup(mp,A)
3943 @d XREALLOC(a,b,c) a = xrealloc(a,(b+1),sizeof(c));
3944
3945 @<Declare helpers@>=
3946 void mp_xfree (void *x);
3947 void *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) ;
3948 void *mp_xmalloc (MP mp, size_t nmem, size_t size) ;
3949 char *mp_xstrdup(MP mp, const char *s);
3950
3951 @ The |max_size_test| guards against overflow, on the assumption that
3952 |size_t| is at least 31bits wide.
3953
3954 @d max_size_test 0x7FFFFFFF
3955
3956 @c
3957 void mp_xfree (void *x) {
3958   if (x!=NULL) free(x);
3959 }
3960 void  *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) {
3961   void *w ; 
3962   if ((max_size_test/size)<nmem) {
3963     do_fprintf(mp->err_out,"Memory size overflow!\n");
3964     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3965   }
3966   w = realloc (p,(nmem*size));
3967   if (w==NULL) {
3968     do_fprintf(mp->err_out,"Out of memory!\n");
3969     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3970   }
3971   return w;
3972 }
3973 void  *mp_xmalloc (MP mp, size_t nmem, size_t size) {
3974   void *w;
3975   if ((max_size_test/size)<nmem) {
3976     do_fprintf(mp->err_out,"Memory size overflow!\n");
3977     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3978   }
3979   w = malloc (nmem*size);
3980   if (w==NULL) {
3981     do_fprintf(mp->err_out,"Out of memory!\n");
3982     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3983   }
3984   return w;
3985 }
3986 char *mp_xstrdup(MP mp, const char *s) {
3987   char *w; 
3988   if (s==NULL)
3989     return NULL;
3990   w = strdup(s);
3991   if (w==NULL) {
3992     do_fprintf(mp->err_out,"Out of memory!\n");
3993     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3994   }
3995   return w;
3996 }
3997
3998
3999
4000 @<Allocate or initialize ...@>=
4001 mp->mem = xmalloc ((mp->mem_max+1),sizeof (memory_word));
4002 memset(mp->mem,0,(mp->mem_max+1)*sizeof (memory_word));
4003
4004 @ @<Dealloc variables@>=
4005 xfree(mp->mem);
4006
4007 @ Users who wish to study the memory requirements of particular applications can
4008 can use optional special features that keep track of current and
4009 maximum memory usage. When code between the delimiters |stat| $\ldots$
4010 |tats| is not ``commented out,'' \MP\ will run a bit slower but it will
4011 report these statistics when |mp_tracing_stats| is positive.
4012
4013 @<Glob...@>=
4014 integer var_used; integer dyn_used; /* how much memory is in use */
4015
4016 @ Let's consider the one-word memory region first, since it's the
4017 simplest. The pointer variable |mem_end| holds the highest-numbered location
4018 of |mem| that has ever been used. The free locations of |mem| that
4019 occur between |hi_mem_min| and |mem_end|, inclusive, are of type
4020 |two_halves|, and we write |info(p)| and |link(p)| for the |lh|
4021 and |rh| fields of |mem[p]| when it is of this type. The single-word
4022 free locations form a linked list
4023 $$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
4024 terminated by |null|.
4025
4026 @d link(A)   mp->mem[(A)].hh.rh /* the |link| field of a memory word */
4027 @d info(A)   mp->mem[(A)].hh.lh /* the |info| field of a memory word */
4028
4029 @<Glob...@>=
4030 pointer avail; /* head of the list of available one-word nodes */
4031 pointer mem_end; /* the last one-word node used in |mem| */
4032
4033 @ If one-word memory is exhausted, it might mean that the user has forgotten
4034 a token like `\&{enddef}' or `\&{endfor}'. We will define some procedures
4035 later that try to help pinpoint the trouble.
4036
4037 @c 
4038 @<Declare the procedure called |show_token_list|@>;
4039 @<Declare the procedure called |runaway|@>
4040
4041 @ The function |get_avail| returns a pointer to a new one-word node whose
4042 |link| field is null. However, \MP\ will halt if there is no more room left.
4043 @^inner loop@>
4044
4045 @c 
4046 pointer mp_get_avail (MP mp) { /* single-word node allocation */
4047   pointer p; /* the new node being got */
4048   p=mp->avail; /* get top location in the |avail| stack */
4049   if ( p!=null ) {
4050     mp->avail=link(mp->avail); /* and pop it off */
4051   } else if ( mp->mem_end<mp->mem_max ) { /* or go into virgin territory */
4052     incr(mp->mem_end); p=mp->mem_end;
4053   } else { 
4054     decr(mp->hi_mem_min); p=mp->hi_mem_min;
4055     if ( mp->hi_mem_min<=mp->lo_mem_max ) { 
4056       mp_runaway(mp); /* if memory is exhausted, display possible runaway text */
4057       mp_overflow(mp, "main memory size",mp->mem_max);
4058       /* quit; all one-word nodes are busy */
4059 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4060     }
4061   }
4062   link(p)=null; /* provide an oft-desired initialization of the new node */
4063   incr(mp->dyn_used);/* maintain statistics */
4064   return p;
4065 };
4066
4067 @ Conversely, a one-word node is recycled by calling |free_avail|.
4068
4069 @d free_avail(A)  /* single-word node liberation */
4070   { link((A))=mp->avail; mp->avail=(A); decr(mp->dyn_used);  }
4071
4072 @ There's also a |fast_get_avail| routine, which saves the procedure-call
4073 overhead at the expense of extra programming. This macro is used in
4074 the places that would otherwise account for the most calls of |get_avail|.
4075 @^inner loop@>
4076
4077 @d fast_get_avail(A) { 
4078   (A)=mp->avail; /* avoid |get_avail| if possible, to save time */
4079   if ( (A)==null ) { (A)=mp_get_avail(mp); } 
4080   else { mp->avail=link((A)); link((A))=null;  incr(mp->dyn_used); }
4081   }
4082
4083 @ The available-space list that keeps track of the variable-size portion
4084 of |mem| is a nonempty, doubly-linked circular list of empty nodes,
4085 pointed to by the roving pointer |rover|.
4086
4087 Each empty node has size 2 or more; the first word contains the special
4088 value |max_halfword| in its |link| field and the size in its |info| field;
4089 the second word contains the two pointers for double linking.
4090
4091 Each nonempty node also has size 2 or more. Its first word is of type
4092 |two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
4093 Otherwise there is complete flexibility with respect to the contents
4094 of its other fields and its other words.
4095
4096 (We require |mem_max<max_halfword| because terrible things can happen
4097 when |max_halfword| appears in the |link| field of a nonempty node.)
4098
4099 @d empty_flag   max_halfword /* the |link| of an empty variable-size node */
4100 @d is_empty(A)   (link((A))==empty_flag) /* tests for empty node */
4101 @d node_size   info /* the size field in empty variable-size nodes */
4102 @d llink(A)   info((A)+1) /* left link in doubly-linked list of empty nodes */
4103 @d rlink(A)   link((A)+1) /* right link in doubly-linked list of empty nodes */
4104
4105 @<Glob...@>=
4106 pointer rover; /* points to some node in the list of empties */
4107
4108 @ A call to |get_node| with argument |s| returns a pointer to a new node
4109 of size~|s|, which must be 2~or more. The |link| field of the first word
4110 of this new node is set to null. An overflow stop occurs if no suitable
4111 space exists.
4112
4113 If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
4114 areas and returns the value |max_halfword|.
4115
4116 @<Internal library declarations@>=
4117 pointer mp_get_node (MP mp,integer s) ;
4118
4119 @ @c 
4120 pointer mp_get_node (MP mp,integer s) { /* variable-size node allocation */
4121   pointer p; /* the node currently under inspection */
4122   pointer q;  /* the node physically after node |p| */
4123   integer r; /* the newly allocated node, or a candidate for this honor */
4124   integer t,tt; /* temporary registers */
4125 @^inner loop@>
4126  RESTART: 
4127   p=mp->rover; /* start at some free node in the ring */
4128   do {  
4129     @<Try to allocate within node |p| and its physical successors,
4130      and |goto found| if allocation was possible@>;
4131     if (rlink(p)==null || rlink(p)==p) {
4132       print_err("Free list garbled");
4133       help3("I found an entry in the list of free nodes that links")
4134        ("badly. I will try to ignore the broken link, but something")
4135        ("is seriously amiss. It is wise to warn the maintainers.")
4136           mp_error(mp);
4137       rlink(p)=mp->rover;
4138     }
4139         p=rlink(p); /* move to the next node in the ring */
4140   } while (p!=mp->rover); /* repeat until the whole list has been traversed */
4141   if ( s==010000000000 ) { 
4142     return max_halfword;
4143   };
4144   if ( mp->lo_mem_max+2<mp->hi_mem_min ) {
4145     if ( mp->lo_mem_max+2<=max_halfword ) {
4146       @<Grow more variable-size memory and |goto restart|@>;
4147     }
4148   }
4149   mp_overflow(mp, "main memory size",mp->mem_max);
4150   /* sorry, nothing satisfactory is left */
4151 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4152 FOUND: 
4153   link(r)=null; /* this node is now nonempty */
4154   mp->var_used+=s; /* maintain usage statistics */
4155   return r;
4156 }
4157
4158 @ The lower part of |mem| grows by 1000 words at a time, unless
4159 we are very close to going under. When it grows, we simply link
4160 a new node into the available-space list. This method of controlled
4161 growth helps to keep the |mem| usage consecutive when \MP\ is
4162 implemented on ``virtual memory'' systems.
4163 @^virtual memory@>
4164
4165 @<Grow more variable-size memory and |goto restart|@>=
4166
4167   if ( mp->hi_mem_min-mp->lo_mem_max>=1998 ) {
4168     t=mp->lo_mem_max+1000;
4169   } else {
4170     t=mp->lo_mem_max+1+(mp->hi_mem_min-mp->lo_mem_max) / 2; 
4171     /* |lo_mem_max+2<=t<hi_mem_min| */
4172   }
4173   if ( t>max_halfword ) t=max_halfword;
4174   p=llink(mp->rover); q=mp->lo_mem_max; rlink(p)=q; llink(mp->rover)=q;
4175   rlink(q)=mp->rover; llink(q)=p; link(q)=empty_flag; 
4176   node_size(q)=t-mp->lo_mem_max;
4177   mp->lo_mem_max=t; link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4178   mp->rover=q; 
4179   goto RESTART;
4180 }
4181
4182 @ @<Try to allocate...@>=
4183 q=p+node_size(p); /* find the physical successor */
4184 while ( is_empty(q) ) { /* merge node |p| with node |q| */
4185   t=rlink(q); tt=llink(q);
4186 @^inner loop@>
4187   if ( q==mp->rover ) mp->rover=t;
4188   llink(t)=tt; rlink(tt)=t;
4189   q=q+node_size(q);
4190 }
4191 r=q-s;
4192 if ( r>p+1 ) {
4193   @<Allocate from the top of node |p| and |goto found|@>;
4194 }
4195 if ( r==p ) { 
4196   if ( rlink(p)!=p ) {
4197     @<Allocate entire node |p| and |goto found|@>;
4198   }
4199 }
4200 node_size(p)=q-p /* reset the size in case it grew */
4201
4202 @ @<Allocate from the top...@>=
4203
4204   node_size(p)=r-p; /* store the remaining size */
4205   mp->rover=p; /* start searching here next time */
4206   goto FOUND;
4207 }
4208
4209 @ Here we delete node |p| from the ring, and let |rover| rove around.
4210
4211 @<Allocate entire...@>=
4212
4213   mp->rover=rlink(p); t=llink(p);
4214   llink(mp->rover)=t; rlink(t)=mp->rover;
4215   goto FOUND;
4216 }
4217
4218 @ Conversely, when some variable-size node |p| of size |s| is no longer needed,
4219 the operation |free_node(p,s)| will make its words available, by inserting
4220 |p| as a new empty node just before where |rover| now points.
4221
4222 @<Internal library declarations@>=
4223 void mp_free_node (MP mp, pointer p, halfword s) ;
4224
4225 @ @c 
4226 void mp_free_node (MP mp, pointer p, halfword s) { /* variable-size node
4227   liberation */
4228   pointer q; /* |llink(rover)| */
4229   node_size(p)=s; link(p)=empty_flag;
4230 @^inner loop@>
4231   q=llink(mp->rover); llink(p)=q; rlink(p)=mp->rover; /* set both links */
4232   llink(mp->rover)=p; rlink(q)=p; /* insert |p| into the ring */
4233   mp->var_used-=s; /* maintain statistics */
4234 }
4235
4236 @ Just before \.{INIMP} writes out the memory, it sorts the doubly linked
4237 available space list. The list is probably very short at such times, so a
4238 simple insertion sort is used. The smallest available location will be
4239 pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
4240
4241 @c 
4242 void mp_sort_avail (MP mp) { /* sorts the available variable-size nodes
4243   by location */
4244   pointer p,q,r; /* indices into |mem| */
4245   pointer old_rover; /* initial |rover| setting */
4246   p=mp_get_node(mp, 010000000000); /* merge adjacent free areas */
4247   p=rlink(mp->rover); rlink(mp->rover)=max_halfword; old_rover=mp->rover;
4248   while ( p!=old_rover ) {
4249     @<Sort |p| into the list starting at |rover|
4250      and advance |p| to |rlink(p)|@>;
4251   }
4252   p=mp->rover;
4253   while ( rlink(p)!=max_halfword ) { 
4254     llink(rlink(p))=p; p=rlink(p);
4255   };
4256   rlink(p)=mp->rover; llink(mp->rover)=p;
4257 }
4258
4259 @ The following |while| loop is guaranteed to
4260 terminate, since the list that starts at
4261 |rover| ends with |max_halfword| during the sorting procedure.
4262
4263 @<Sort |p|...@>=
4264 if ( p<mp->rover ) { 
4265   q=p; p=rlink(q); rlink(q)=mp->rover; mp->rover=q;
4266 } else  { 
4267   q=mp->rover;
4268   while ( rlink(q)<p ) q=rlink(q);
4269   r=rlink(p); rlink(p)=rlink(q); rlink(q)=p; p=r;
4270 }
4271
4272 @* \[11] Memory layout.
4273 Some areas of |mem| are dedicated to fixed usage, since static allocation is
4274 more efficient than dynamic allocation when we can get away with it. For
4275 example, locations |0| to |1| are always used to store a
4276 two-word dummy token whose second word is zero.
4277 The following macro definitions accomplish the static allocation by giving
4278 symbolic names to the fixed positions. Static variable-size nodes appear
4279 in locations |0| through |lo_mem_stat_max|, and static single-word nodes
4280 appear in locations |hi_mem_stat_min| through |mem_top|, inclusive.
4281
4282 @d null_dash (2) /* the first two words are reserved for a null value */
4283 @d dep_head (null_dash+3) /* we will define |dash_node_size=3| */
4284 @d zero_val (dep_head+2) /* two words for a permanently zero value */
4285 @d temp_val (zero_val+2) /* two words for a temporary value node */
4286 @d end_attr temp_val /* we use |end_attr+2| only */
4287 @d inf_val (end_attr+2) /* and |inf_val+1| only */
4288 @d test_pen (inf_val+2)
4289   /* nine words for a pen used when testing the turning number */
4290 @d bad_vardef (test_pen+9) /* two words for \&{vardef} error recovery */
4291 @d lo_mem_stat_max (bad_vardef+1)  /* largest statically
4292   allocated word in the variable-size |mem| */
4293 @#
4294 @d sentinel mp->mem_top /* end of sorted lists */
4295 @d temp_head (mp->mem_top-1) /* head of a temporary list of some kind */
4296 @d hold_head (mp->mem_top-2) /* head of a temporary list of another kind */
4297 @d spec_head (mp->mem_top-3) /* head of a list of unprocessed \&{special} items */
4298 @d hi_mem_stat_min (mp->mem_top-3) /* smallest statically allocated word in
4299   the one-word |mem| */
4300
4301 @ The following code gets the dynamic part of |mem| off to a good start,
4302 when \MP\ is initializing itself the slow way.
4303
4304 @<Initialize table entries (done by \.{INIMP} only)@>=
4305 @^data structure assumptions@>
4306 mp->rover=lo_mem_stat_max+1; /* initialize the dynamic memory */
4307 link(mp->rover)=empty_flag;
4308 node_size(mp->rover)=1000; /* which is a 1000-word available node */
4309 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
4310 mp->lo_mem_max=mp->rover+1000; 
4311 link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4312 for (k=hi_mem_stat_min;k<=(int)mp->mem_top;k++) {
4313   mp->mem[k]=mp->mem[mp->lo_mem_max]; /* clear list heads */
4314 }
4315 mp->avail=null; mp->mem_end=mp->mem_top;
4316 mp->hi_mem_min=hi_mem_stat_min; /* initialize the one-word memory */
4317 mp->var_used=lo_mem_stat_max+1; 
4318 mp->dyn_used=mp->mem_top+1-(hi_mem_stat_min);  /* initialize statistics */
4319 @<Initialize a pen at |test_pen| so that it fits in nine words@>;
4320
4321 @ The procedure |flush_list(p)| frees an entire linked list of one-word
4322 nodes that starts at a given position, until coming to |sentinel| or a
4323 pointer that is not in the one-word region. Another procedure,
4324 |flush_node_list|, frees an entire linked list of one-word and two-word
4325 nodes, until coming to a |null| pointer.
4326 @^inner loop@>
4327
4328 @c 
4329 void mp_flush_list (MP mp,pointer p) { /* makes list of single-word nodes  available */
4330   pointer q,r; /* list traversers */
4331   if ( p>=mp->hi_mem_min ) if ( p!=sentinel ) { 
4332     r=p;
4333     do {  
4334       q=r; r=link(r); 
4335       decr(mp->dyn_used);
4336       if ( r<mp->hi_mem_min ) break;
4337     } while (r!=sentinel);
4338   /* now |q| is the last node on the list */
4339     link(q)=mp->avail; mp->avail=p;
4340   }
4341 }
4342 @#
4343 void mp_flush_node_list (MP mp,pointer p) {
4344   pointer q; /* the node being recycled */
4345   while ( p!=null ){ 
4346     q=p; p=link(p);
4347     if ( q<mp->hi_mem_min ) 
4348       mp_free_node(mp, q,2);
4349     else 
4350       free_avail(q);
4351   }
4352 }
4353
4354 @ If \MP\ is extended improperly, the |mem| array might get screwed up.
4355 For example, some pointers might be wrong, or some ``dead'' nodes might not
4356 have been freed when the last reference to them disappeared. Procedures
4357 |check_mem| and |search_mem| are available to help diagnose such
4358 problems. These procedures make use of two arrays called |free| and
4359 |was_free| that are present only if \MP's debugging routines have
4360 been included. (You may want to decrease the size of |mem| while you
4361 @^debugging@>
4362 are debugging.)
4363
4364 Because |boolean|s are typedef-d as ints, it is better to use
4365 unsigned chars here.
4366
4367 @<Glob...@>=
4368 unsigned char *free; /* free cells */
4369 unsigned char *was_free; /* previously free cells */
4370 pointer was_mem_end; pointer was_lo_max; pointer was_hi_min;
4371   /* previous |mem_end|, |lo_mem_max|,and |hi_mem_min| */
4372 boolean panicking; /* do we want to check memory constantly? */
4373
4374 @ @<Allocate or initialize ...@>=
4375 mp->free = xmalloc ((mp->mem_max+1),sizeof (unsigned char));
4376 mp->was_free = xmalloc ((mp->mem_max+1), sizeof (unsigned char));
4377
4378 @ @<Dealloc variables@>=
4379 xfree(mp->free);
4380 xfree(mp->was_free);
4381
4382 @ @<Allocate or ...@>=
4383 mp->was_mem_end=0; /* indicate that everything was previously free */
4384 mp->was_lo_max=0; mp->was_hi_min=mp->mem_max;
4385 mp->panicking=false;
4386
4387 @ @<Declare |mp_reallocate| functions@>=
4388 void mp_reallocate_memory(MP mp, int l) ;
4389
4390 @ @c
4391 void mp_reallocate_memory(MP mp, int l) {
4392    XREALLOC(mp->free,     l, unsigned char);
4393    XREALLOC(mp->was_free, l, unsigned char);
4394    if (mp->mem) {
4395          int newarea = l-mp->mem_max;
4396      XREALLOC(mp->mem,      l, memory_word);
4397      memset (mp->mem+(mp->mem_max+1),0,sizeof(memory_word)*(newarea));
4398    } else {
4399      XREALLOC(mp->mem,      l, memory_word);
4400      memset(mp->mem,0,sizeof(memory_word)*(l+1));
4401    }
4402    mp->mem_max = l;
4403    if (mp->ini_version) 
4404      mp->mem_top = l;
4405 }
4406
4407
4408
4409 @ Procedure |check_mem| makes sure that the available space lists of
4410 |mem| are well formed, and it optionally prints out all locations
4411 that are reserved now but were free the last time this procedure was called.
4412
4413 @c 
4414 void mp_check_mem (MP mp,boolean print_locs ) {
4415   pointer p,q,r; /* current locations of interest in |mem| */
4416   boolean clobbered; /* is something amiss? */
4417   for (p=0;p<=mp->lo_mem_max;p++) {
4418     mp->free[p]=false; /* you can probably do this faster */
4419   }
4420   for (p=mp->hi_mem_min;p<= mp->mem_end;p++) {
4421     mp->free[p]=false; /* ditto */
4422   }
4423   @<Check single-word |avail| list@>;
4424   @<Check variable-size |avail| list@>;
4425   @<Check flags of unavailable nodes@>;
4426   @<Check the list of linear dependencies@>;
4427   if ( print_locs ) {
4428     @<Print newly busy locations@>;
4429   }
4430   memcpy(mp->was_free,mp->free, sizeof(char)*(mp->mem_end+1));
4431   mp->was_mem_end=mp->mem_end; 
4432   mp->was_lo_max=mp->lo_mem_max; 
4433   mp->was_hi_min=mp->hi_mem_min;
4434 }
4435
4436 @ @<Check single-word...@>=
4437 p=mp->avail; q=null; clobbered=false;
4438 while ( p!=null ) { 
4439   if ( (p>mp->mem_end)||(p<mp->hi_mem_min) ) clobbered=true;
4440   else if ( mp->free[p] ) clobbered=true;
4441   if ( clobbered ) { 
4442     mp_print_nl(mp, "AVAIL list clobbered at ");
4443 @.AVAIL list clobbered...@>
4444     mp_print_int(mp, q); break;
4445   }
4446   mp->free[p]=true; q=p; p=link(q);
4447 }
4448
4449 @ @<Check variable-size...@>=
4450 p=mp->rover; q=null; clobbered=false;
4451 do {  
4452   if ( (p>=mp->lo_mem_max)||(p<0) ) clobbered=true;
4453   else if ( (rlink(p)>=mp->lo_mem_max)||(rlink(p)<0) ) clobbered=true;
4454   else if (  !(is_empty(p))||(node_size(p)<2)||
4455    (p+node_size(p)>mp->lo_mem_max)|| (llink(rlink(p))!=p) ) clobbered=true;
4456   if ( clobbered ) { 
4457     mp_print_nl(mp, "Double-AVAIL list clobbered at ");
4458 @.Double-AVAIL list clobbered...@>
4459     mp_print_int(mp, q); break;
4460   }
4461   for (q=p;q<=p+node_size(p)-1;q++) { /* mark all locations free */
4462     if ( mp->free[q] ) { 
4463       mp_print_nl(mp, "Doubly free location at ");
4464 @.Doubly free location...@>
4465       mp_print_int(mp, q); break;
4466     }
4467     mp->free[q]=true;
4468   }
4469   q=p; p=rlink(p);
4470 } while (p!=mp->rover)
4471
4472
4473 @ @<Check flags...@>=
4474 p=0;
4475 while ( p<=mp->lo_mem_max ) { /* node |p| should not be empty */
4476   if ( is_empty(p) ) {
4477     mp_print_nl(mp, "Bad flag at "); mp_print_int(mp, p);
4478 @.Bad flag...@>
4479   }
4480   while ( (p<=mp->lo_mem_max) && ! mp->free[p] ) incr(p);
4481   while ( (p<=mp->lo_mem_max) && mp->free[p] ) incr(p);
4482 }
4483
4484 @ @<Print newly busy...@>=
4485
4486   @<Do intialization required before printing new busy locations@>;
4487   mp_print_nl(mp, "New busy locs:");
4488 @.New busy locs@>
4489   for (p=0;p<= mp->lo_mem_max;p++ ) {
4490     if ( ! mp->free[p] && ((p>mp->was_lo_max) || mp->was_free[p]) ) {
4491       @<Indicate that |p| is a new busy location@>;
4492     }
4493   }
4494   for (p=mp->hi_mem_min;p<=mp->mem_end;p++ ) {
4495     if ( ! mp->free[p] &&
4496         ((p<mp->was_hi_min) || (p>mp->was_mem_end) || mp->was_free[p]) ) {
4497       @<Indicate that |p| is a new busy location@>;
4498     }
4499   }
4500   @<Finish printing new busy locations@>;
4501 }
4502
4503 @ There might be many new busy locations so we are careful to print contiguous
4504 blocks compactly.  During this operation |q| is the last new busy location and
4505 |r| is the start of the block containing |q|.
4506
4507 @<Indicate that |p| is a new busy location@>=
4508
4509   if ( p>q+1 ) { 
4510     if ( q>r ) { 
4511       mp_print(mp, ".."); mp_print_int(mp, q);
4512     }
4513     mp_print_char(mp, ' '); mp_print_int(mp, p);
4514     r=p;
4515   }
4516   q=p;
4517 }
4518
4519 @ @<Do intialization required before printing new busy locations@>=
4520 q=mp->mem_max; r=mp->mem_max
4521
4522 @ @<Finish printing new busy locations@>=
4523 if ( q>r ) { 
4524   mp_print(mp, ".."); mp_print_int(mp, q);
4525 }
4526
4527 @ The |search_mem| procedure attempts to answer the question ``Who points
4528 to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
4529 that might not be of type |two_halves|. Strictly speaking, this is
4530 @^dirty \PASCAL@>
4531 undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
4532 point to |p| purely by coincidence). But for debugging purposes, we want
4533 to rule out the places that do {\sl not\/} point to |p|, so a few false
4534 drops are tolerable.
4535
4536 @c
4537 void mp_search_mem (MP mp, pointer p) { /* look for pointers to |p| */
4538   integer q; /* current position being searched */
4539   for (q=0;q<=mp->lo_mem_max;q++) { 
4540     if ( link(q)==p ){ 
4541       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4542     }
4543     if ( info(q)==p ) { 
4544       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4545     }
4546   }
4547   for (q=mp->hi_mem_min;q<=mp->mem_end;q++) {
4548     if ( link(q)==p ) {
4549       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4550     }
4551     if ( info(q)==p ) {
4552       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4553     }
4554   }
4555   @<Search |eqtb| for equivalents equal to |p|@>;
4556 }
4557
4558 @* \[12] The command codes.
4559 Before we can go much further, we need to define symbolic names for the internal
4560 code numbers that represent the various commands obeyed by \MP. These codes
4561 are somewhat arbitrary, but not completely so. For example,
4562 some codes have been made adjacent so that |case| statements in the
4563 program need not consider cases that are widely spaced, or so that |case|
4564 statements can be replaced by |if| statements. A command can begin an
4565 expression if and only if its code lies between |min_primary_command| and
4566 |max_primary_command|, inclusive. The first token of a statement that doesn't
4567 begin with an expression has a command code between |min_command| and
4568 |max_statement_command|, inclusive. Anything less than |min_command| is
4569 eliminated during macro expansions, and anything no more than |max_pre_command|
4570 is eliminated when expanding \TeX\ material.  Ranges such as
4571 |min_secondary_command..max_secondary_command| are used when parsing
4572 expressions, but the relative ordering within such a range is generally not
4573 critical.
4574
4575 The ordering of the highest-numbered commands
4576 (|comma<semicolon<end_group<stop|) is crucial for the parsing and
4577 error-recovery methods of this program as is the ordering |if_test<fi_or_else|
4578 for the smallest two commands.  The ordering is also important in the ranges
4579 |numeric_token..plus_or_minus| and |left_brace..ampersand|.
4580
4581 At any rate, here is the list, for future reference.
4582
4583 @d start_tex 1 /* begin \TeX\ material (\&{btex}, \&{verbatimtex}) */
4584 @d etex_marker 2 /* end \TeX\ material (\&{etex}) */
4585 @d mpx_break 3 /* stop reading an \.{MPX} file (\&{mpxbreak}) */
4586 @d max_pre_command mpx_break
4587 @d if_test 4 /* conditional text (\&{if}) */
4588 @d fi_or_else 5 /* delimiters for conditionals (\&{elseif}, \&{else}, \&{fi} */
4589 @d input 6 /* input a source file (\&{input}, \&{endinput}) */
4590 @d iteration 7 /* iterate (\&{for}, \&{forsuffixes}, \&{forever}, \&{endfor}) */
4591 @d repeat_loop 8 /* special command substituted for \&{endfor} */
4592 @d exit_test 9 /* premature exit from a loop (\&{exitif}) */
4593 @d relax 10 /* do nothing (\.{\char`\\}) */
4594 @d scan_tokens 11 /* put a string into the input buffer */
4595 @d expand_after 12 /* look ahead one token */
4596 @d defined_macro 13 /* a macro defined by the user */
4597 @d min_command (defined_macro+1)
4598 @d save_command 14 /* save a list of tokens (\&{save}) */
4599 @d interim_command 15 /* save an internal quantity (\&{interim}) */
4600 @d let_command 16 /* redefine a symbolic token (\&{let}) */
4601 @d new_internal 17 /* define a new internal quantity (\&{newinternal}) */
4602 @d macro_def 18 /* define a macro (\&{def}, \&{vardef}, etc.) */
4603 @d ship_out_command 19 /* output a character (\&{shipout}) */
4604 @d add_to_command 20 /* add to edges (\&{addto}) */
4605 @d bounds_command 21  /* add bounding path to edges (\&{setbounds}, \&{clip}) */
4606 @d tfm_command 22 /* command for font metric info (\&{ligtable}, etc.) */
4607 @d protection_command 23 /* set protection flag (\&{outer}, \&{inner}) */
4608 @d show_command 24 /* diagnostic output (\&{show}, \&{showvariable}, etc.) */
4609 @d mode_command 25 /* set interaction level (\&{batchmode}, etc.) */
4610 @d random_seed 26 /* initialize random number generator (\&{randomseed}) */
4611 @d message_command 27 /* communicate to user (\&{message}, \&{errmessage}) */
4612 @d every_job_command 28 /* designate a starting token (\&{everyjob}) */
4613 @d delimiters 29 /* define a pair of delimiters (\&{delimiters}) */
4614 @d special_command 30 /* output special info (\&{special})
4615                        or font map info (\&{fontmapfile}, \&{fontmapline}) */
4616 @d write_command 31 /* write text to a file (\&{write}) */
4617 @d type_name 32 /* declare a type (\&{numeric}, \&{pair}, etc. */
4618 @d max_statement_command type_name
4619 @d min_primary_command type_name
4620 @d left_delimiter 33 /* the left delimiter of a matching pair */
4621 @d begin_group 34 /* beginning of a group (\&{begingroup}) */
4622 @d nullary 35 /* an operator without arguments (e.g., \&{normaldeviate}) */
4623 @d unary 36 /* an operator with one argument (e.g., \&{sqrt}) */
4624 @d str_op 37 /* convert a suffix to a string (\&{str}) */
4625 @d cycle 38 /* close a cyclic path (\&{cycle}) */
4626 @d primary_binary 39 /* binary operation taking `\&{of}' (e.g., \&{point}) */
4627 @d capsule_token 40 /* a value that has been put into a token list */
4628 @d string_token 41 /* a string constant (e.g., |"hello"|) */
4629 @d internal_quantity 42 /* internal numeric parameter (e.g., \&{pausing}) */
4630 @d min_suffix_token internal_quantity
4631 @d tag_token 43 /* a symbolic token without a primitive meaning */
4632 @d numeric_token 44 /* a numeric constant (e.g., \.{3.14159}) */
4633 @d max_suffix_token numeric_token
4634 @d plus_or_minus 45 /* either `\.+' or `\.-' */
4635 @d max_primary_command plus_or_minus /* should also be |numeric_token+1| */
4636 @d min_tertiary_command plus_or_minus
4637 @d tertiary_secondary_macro 46 /* a macro defined by \&{secondarydef} */
4638 @d tertiary_binary 47 /* an operator at the tertiary level (e.g., `\.{++}') */
4639 @d max_tertiary_command tertiary_binary
4640 @d left_brace 48 /* the operator `\.{\char`\{}' */
4641 @d min_expression_command left_brace
4642 @d path_join 49 /* the operator `\.{..}' */
4643 @d ampersand 50 /* the operator `\.\&' */
4644 @d expression_tertiary_macro 51 /* a macro defined by \&{tertiarydef} */
4645 @d expression_binary 52 /* an operator at the expression level (e.g., `\.<') */
4646 @d equals 53 /* the operator `\.=' */
4647 @d max_expression_command equals
4648 @d and_command 54 /* the operator `\&{and}' */
4649 @d min_secondary_command and_command
4650 @d secondary_primary_macro 55 /* a macro defined by \&{primarydef} */
4651 @d slash 56 /* the operator `\./' */
4652 @d secondary_binary 57 /* an operator at the binary level (e.g., \&{shifted}) */
4653 @d max_secondary_command secondary_binary
4654 @d param_type 58 /* type of parameter (\&{primary}, \&{expr}, \&{suffix}, etc.) */
4655 @d controls 59 /* specify control points explicitly (\&{controls}) */
4656 @d tension 60 /* specify tension between knots (\&{tension}) */
4657 @d at_least 61 /* bounded tension value (\&{atleast}) */
4658 @d curl_command 62 /* specify curl at an end knot (\&{curl}) */
4659 @d macro_special 63 /* special macro operators (\&{quote}, \.{\#\AT!}, etc.) */
4660 @d right_delimiter 64 /* the right delimiter of a matching pair */
4661 @d left_bracket 65 /* the operator `\.[' */
4662 @d right_bracket 66 /* the operator `\.]' */
4663 @d right_brace 67 /* the operator `\.{\char`\}}' */
4664 @d with_option 68 /* option for filling (\&{withpen}, \&{withweight}, etc.) */
4665 @d thing_to_add 69
4666   /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */
4667 @d of_token 70 /* the operator `\&{of}' */
4668 @d to_token 71 /* the operator `\&{to}' */
4669 @d step_token 72 /* the operator `\&{step}' */
4670 @d until_token 73 /* the operator `\&{until}' */
4671 @d within_token 74 /* the operator `\&{within}' */
4672 @d lig_kern_token 75
4673   /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}, etc. */
4674 @d assignment 76 /* the operator `\.{:=}' */
4675 @d skip_to 77 /* the operation `\&{skipto}' */
4676 @d bchar_label 78 /* the operator `\.{\char'174\char'174:}' */
4677 @d double_colon 79 /* the operator `\.{::}' */
4678 @d colon 80 /* the operator `\.:' */
4679 @#
4680 @d comma 81 /* the operator `\.,', must be |colon+1| */
4681 @d end_of_statement (mp->cur_cmd>comma)
4682 @d semicolon 82 /* the operator `\.;', must be |comma+1| */
4683 @d end_group 83 /* end a group (\&{endgroup}), must be |semicolon+1| */
4684 @d stop 84 /* end a job (\&{end}, \&{dump}), must be |end_group+1| */
4685 @d max_command_code stop
4686 @d outer_tag (max_command_code+1) /* protection code added to command code */
4687
4688 @<Types...@>=
4689 typedef int command_code;
4690
4691 @ Variables and capsules in \MP\ have a variety of ``types,''
4692 distinguished by the code numbers defined here. These numbers are also
4693 not completely arbitrary.  Things that get expanded must have types
4694 |>mp_independent|; a type remaining after expansion is numeric if and only if
4695 its code number is at least |numeric_type|; objects containing numeric
4696 parts must have types between |transform_type| and |pair_type|;
4697 all other types must be smaller than |transform_type|; and among the types
4698 that are not unknown or vacuous, the smallest two must be |boolean_type|
4699 and |string_type| in that order.
4700  
4701 @d undefined 0 /* no type has been declared */
4702 @d unknown_tag 1 /* this constant is added to certain type codes below */
4703 @d unknown_types mp_unknown_boolean: case mp_unknown_string:
4704   case mp_unknown_pen: case mp_unknown_picture: case mp_unknown_path
4705
4706 @<Types...@>=
4707 enum mp_variable_type {
4708 mp_vacuous=1, /* no expression was present */
4709 mp_boolean_type, /* \&{boolean} with a known value */
4710 mp_unknown_boolean,
4711 mp_string_type, /* \&{string} with a known value */
4712 mp_unknown_string,
4713 mp_pen_type, /* \&{pen} with a known value */
4714 mp_unknown_pen,
4715 mp_path_type, /* \&{path} with a known value */
4716 mp_unknown_path,
4717 mp_picture_type, /* \&{picture} with a known value */
4718 mp_unknown_picture,
4719 mp_transform_type, /* \&{transform} variable or capsule */
4720 mp_color_type, /* \&{color} variable or capsule */
4721 mp_cmykcolor_type, /* \&{cmykcolor} variable or capsule */
4722 mp_pair_type, /* \&{pair} variable or capsule */
4723 mp_numeric_type, /* variable that has been declared \&{numeric} but not used */
4724 mp_known, /* \&{numeric} with a known value */
4725 mp_dependent, /* a linear combination with |fraction| coefficients */
4726 mp_proto_dependent, /* a linear combination with |scaled| coefficients */
4727 mp_independent, /* \&{numeric} with unknown value */
4728 mp_token_list, /* variable name or suffix argument or text argument */
4729 mp_structured, /* variable with subscripts and attributes */
4730 mp_unsuffixed_macro, /* variable defined with \&{vardef} but no \.{\AT!\#} */
4731 mp_suffixed_macro /* variable defined with \&{vardef} and \.{\AT!\#} */
4732 } ;
4733
4734 @ @<Declarations@>=
4735 void mp_print_type (MP mp,small_number t) ;
4736
4737 @ @<Basic printing procedures@>=
4738 void mp_print_type (MP mp,small_number t) { 
4739   switch (t) {
4740   case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
4741   case mp_boolean_type:mp_print(mp, "boolean"); break;
4742   case mp_unknown_boolean:mp_print(mp, "unknown boolean"); break;
4743   case mp_string_type:mp_print(mp, "string"); break;
4744   case mp_unknown_string:mp_print(mp, "unknown string"); break;
4745   case mp_pen_type:mp_print(mp, "pen"); break;
4746   case mp_unknown_pen:mp_print(mp, "unknown pen"); break;
4747   case mp_path_type:mp_print(mp, "path"); break;
4748   case mp_unknown_path:mp_print(mp, "unknown path"); break;
4749   case mp_picture_type:mp_print(mp, "picture"); break;
4750   case mp_unknown_picture:mp_print(mp, "unknown picture"); break;
4751   case mp_transform_type:mp_print(mp, "transform"); break;
4752   case mp_color_type:mp_print(mp, "color"); break;
4753   case mp_cmykcolor_type:mp_print(mp, "cmykcolor"); break;
4754   case mp_pair_type:mp_print(mp, "pair"); break;
4755   case mp_known:mp_print(mp, "known numeric"); break;
4756   case mp_dependent:mp_print(mp, "dependent"); break;
4757   case mp_proto_dependent:mp_print(mp, "proto-dependent"); break;
4758   case mp_numeric_type:mp_print(mp, "numeric"); break;
4759   case mp_independent:mp_print(mp, "independent"); break;
4760   case mp_token_list:mp_print(mp, "token list"); break;
4761   case mp_structured:mp_print(mp, "mp_structured"); break;
4762   case mp_unsuffixed_macro:mp_print(mp, "unsuffixed macro"); break;
4763   case mp_suffixed_macro:mp_print(mp, "suffixed macro"); break;
4764   default: mp_print(mp, "undefined"); break;
4765   }
4766 }
4767
4768 @ Values inside \MP\ are stored in two-word nodes that have a |name_type|
4769 as well as a |type|. The possibilities for |name_type| are defined
4770 here; they will be explained in more detail later.
4771
4772 @<Types...@>=
4773 enum mp_name_type {
4774  mp_root=0, /* |name_type| at the top level of a variable */
4775  mp_saved_root, /* same, when the variable has been saved */
4776  mp_structured_root, /* |name_type| where a |mp_structured| branch occurs */
4777  mp_subscr, /* |name_type| in a subscript node */
4778  mp_attr, /* |name_type| in an attribute node */
4779  mp_x_part_sector, /* |name_type| in the \&{xpart} of a node */
4780  mp_y_part_sector, /* |name_type| in the \&{ypart} of a node */
4781  mp_xx_part_sector, /* |name_type| in the \&{xxpart} of a node */
4782  mp_xy_part_sector, /* |name_type| in the \&{xypart} of a node */
4783  mp_yx_part_sector, /* |name_type| in the \&{yxpart} of a node */
4784  mp_yy_part_sector, /* |name_type| in the \&{yypart} of a node */
4785  mp_red_part_sector, /* |name_type| in the \&{redpart} of a node */
4786  mp_green_part_sector, /* |name_type| in the \&{greenpart} of a node */
4787  mp_blue_part_sector, /* |name_type| in the \&{bluepart} of a node */
4788  mp_cyan_part_sector, /* |name_type| in the \&{redpart} of a node */
4789  mp_magenta_part_sector, /* |name_type| in the \&{greenpart} of a node */
4790  mp_yellow_part_sector, /* |name_type| in the \&{bluepart} of a node */
4791  mp_black_part_sector, /* |name_type| in the \&{greenpart} of a node */
4792  mp_grey_part_sector, /* |name_type| in the \&{bluepart} of a node */
4793  mp_capsule, /* |name_type| in stashed-away subexpressions */
4794  mp_token  /* |name_type| in a numeric token or string token */
4795 };
4796
4797 @ Primitive operations that produce values have a secondary identification
4798 code in addition to their command code; it's something like genera and species.
4799 For example, `\.*' has the command code |primary_binary|, and its
4800 secondary identification is |times|. The secondary codes start at 30 so that
4801 they don't overlap with the type codes; some type codes (e.g., |mp_string_type|)
4802 are used as operators as well as type identifications.  The relative values
4803 are not critical, except for |true_code..false_code|, |or_op..and_op|,
4804 and |filled_op..bounded_op|.  The restrictions are that
4805 |and_op-false_code=or_op-true_code|, that the ordering of
4806 |x_part...blue_part| must match that of |x_part_sector..mp_blue_part_sector|,
4807 and the ordering of |filled_op..bounded_op| must match that of the code
4808 values they test for.
4809
4810 @d true_code 30 /* operation code for \.{true} */
4811 @d false_code 31 /* operation code for \.{false} */
4812 @d null_picture_code 32 /* operation code for \.{nullpicture} */
4813 @d null_pen_code 33 /* operation code for \.{nullpen} */
4814 @d job_name_op 34 /* operation code for \.{jobname} */
4815 @d read_string_op 35 /* operation code for \.{readstring} */
4816 @d pen_circle 36 /* operation code for \.{pencircle} */
4817 @d normal_deviate 37 /* operation code for \.{normaldeviate} */
4818 @d read_from_op 38 /* operation code for \.{readfrom} */
4819 @d close_from_op 39 /* operation code for \.{closefrom} */
4820 @d odd_op 40 /* operation code for \.{odd} */
4821 @d known_op 41 /* operation code for \.{known} */
4822 @d unknown_op 42 /* operation code for \.{unknown} */
4823 @d not_op 43 /* operation code for \.{not} */
4824 @d decimal 44 /* operation code for \.{decimal} */
4825 @d reverse 45 /* operation code for \.{reverse} */
4826 @d make_path_op 46 /* operation code for \.{makepath} */
4827 @d make_pen_op 47 /* operation code for \.{makepen} */
4828 @d oct_op 48 /* operation code for \.{oct} */
4829 @d hex_op 49 /* operation code for \.{hex} */
4830 @d ASCII_op 50 /* operation code for \.{ASCII} */
4831 @d char_op 51 /* operation code for \.{char} */
4832 @d length_op 52 /* operation code for \.{length} */
4833 @d turning_op 53 /* operation code for \.{turningnumber} */
4834 @d color_model_part 54 /* operation code for \.{colormodel} */
4835 @d x_part 55 /* operation code for \.{xpart} */
4836 @d y_part 56 /* operation code for \.{ypart} */
4837 @d xx_part 57 /* operation code for \.{xxpart} */
4838 @d xy_part 58 /* operation code for \.{xypart} */
4839 @d yx_part 59 /* operation code for \.{yxpart} */
4840 @d yy_part 60 /* operation code for \.{yypart} */
4841 @d red_part 61 /* operation code for \.{redpart} */
4842 @d green_part 62 /* operation code for \.{greenpart} */
4843 @d blue_part 63 /* operation code for \.{bluepart} */
4844 @d cyan_part 64 /* operation code for \.{cyanpart} */
4845 @d magenta_part 65 /* operation code for \.{magentapart} */
4846 @d yellow_part 66 /* operation code for \.{yellowpart} */
4847 @d black_part 67 /* operation code for \.{blackpart} */
4848 @d grey_part 68 /* operation code for \.{greypart} */
4849 @d font_part 69 /* operation code for \.{fontpart} */
4850 @d text_part 70 /* operation code for \.{textpart} */
4851 @d path_part 71 /* operation code for \.{pathpart} */
4852 @d pen_part 72 /* operation code for \.{penpart} */
4853 @d dash_part 73 /* operation code for \.{dashpart} */
4854 @d sqrt_op 74 /* operation code for \.{sqrt} */
4855 @d m_exp_op 75 /* operation code for \.{mexp} */
4856 @d m_log_op 76 /* operation code for \.{mlog} */
4857 @d sin_d_op 77 /* operation code for \.{sind} */
4858 @d cos_d_op 78 /* operation code for \.{cosd} */
4859 @d floor_op 79 /* operation code for \.{floor} */
4860 @d uniform_deviate 80 /* operation code for \.{uniformdeviate} */
4861 @d char_exists_op 81 /* operation code for \.{charexists} */
4862 @d font_size 82 /* operation code for \.{fontsize} */
4863 @d ll_corner_op 83 /* operation code for \.{llcorner} */
4864 @d lr_corner_op 84 /* operation code for \.{lrcorner} */
4865 @d ul_corner_op 85 /* operation code for \.{ulcorner} */
4866 @d ur_corner_op 86 /* operation code for \.{urcorner} */
4867 @d arc_length 87 /* operation code for \.{arclength} */
4868 @d angle_op 88 /* operation code for \.{angle} */
4869 @d cycle_op 89 /* operation code for \.{cycle} */
4870 @d filled_op 90 /* operation code for \.{filled} */
4871 @d stroked_op 91 /* operation code for \.{stroked} */
4872 @d textual_op 92 /* operation code for \.{textual} */
4873 @d clipped_op 93 /* operation code for \.{clipped} */
4874 @d bounded_op 94 /* operation code for \.{bounded} */
4875 @d plus 95 /* operation code for \.+ */
4876 @d minus 96 /* operation code for \.- */
4877 @d times 97 /* operation code for \.* */
4878 @d over 98 /* operation code for \./ */
4879 @d pythag_add 99 /* operation code for \.{++} */
4880 @d pythag_sub 100 /* operation code for \.{+-+} */
4881 @d or_op 101 /* operation code for \.{or} */
4882 @d and_op 102 /* operation code for \.{and} */
4883 @d less_than 103 /* operation code for \.< */
4884 @d less_or_equal 104 /* operation code for \.{<=} */
4885 @d greater_than 105 /* operation code for \.> */
4886 @d greater_or_equal 106 /* operation code for \.{>=} */
4887 @d equal_to 107 /* operation code for \.= */
4888 @d unequal_to 108 /* operation code for \.{<>} */
4889 @d concatenate 109 /* operation code for \.\& */
4890 @d rotated_by 110 /* operation code for \.{rotated} */
4891 @d slanted_by 111 /* operation code for \.{slanted} */
4892 @d scaled_by 112 /* operation code for \.{scaled} */
4893 @d shifted_by 113 /* operation code for \.{shifted} */
4894 @d transformed_by 114 /* operation code for \.{transformed} */
4895 @d x_scaled 115 /* operation code for \.{xscaled} */
4896 @d y_scaled 116 /* operation code for \.{yscaled} */
4897 @d z_scaled 117 /* operation code for \.{zscaled} */
4898 @d in_font 118 /* operation code for \.{infont} */
4899 @d intersect 119 /* operation code for \.{intersectiontimes} */
4900 @d double_dot 120 /* operation code for improper \.{..} */
4901 @d substring_of 121 /* operation code for \.{substring} */
4902 @d min_of substring_of
4903 @d subpath_of 122 /* operation code for \.{subpath} */
4904 @d direction_time_of 123 /* operation code for \.{directiontime} */
4905 @d point_of 124 /* operation code for \.{point} */
4906 @d precontrol_of 125 /* operation code for \.{precontrol} */
4907 @d postcontrol_of 126 /* operation code for \.{postcontrol} */
4908 @d pen_offset_of 127 /* operation code for \.{penoffset} */
4909 @d arc_time_of 128 /* operation code for \.{arctime} */
4910 @d mp_version 129 /* operation code for \.{mpversion} */
4911 @d envelope_of 130 /* operation code for \{.envelope} */
4912
4913 @c void mp_print_op (MP mp,quarterword c) { 
4914   if (c<=mp_numeric_type ) {
4915     mp_print_type(mp, c);
4916   } else {
4917     switch (c) {
4918     case true_code:mp_print(mp, "true"); break;
4919     case false_code:mp_print(mp, "false"); break;
4920     case null_picture_code:mp_print(mp, "nullpicture"); break;
4921     case null_pen_code:mp_print(mp, "nullpen"); break;
4922     case job_name_op:mp_print(mp, "jobname"); break;
4923     case read_string_op:mp_print(mp, "readstring"); break;
4924     case pen_circle:mp_print(mp, "pencircle"); break;
4925     case normal_deviate:mp_print(mp, "normaldeviate"); break;
4926     case read_from_op:mp_print(mp, "readfrom"); break;
4927     case close_from_op:mp_print(mp, "closefrom"); break;
4928     case odd_op:mp_print(mp, "odd"); break;
4929     case known_op:mp_print(mp, "known"); break;
4930     case unknown_op:mp_print(mp, "unknown"); break;
4931     case not_op:mp_print(mp, "not"); break;
4932     case decimal:mp_print(mp, "decimal"); break;
4933     case reverse:mp_print(mp, "reverse"); break;
4934     case make_path_op:mp_print(mp, "makepath"); break;
4935     case make_pen_op:mp_print(mp, "makepen"); break;
4936     case oct_op:mp_print(mp, "oct"); break;
4937     case hex_op:mp_print(mp, "hex"); break;
4938     case ASCII_op:mp_print(mp, "ASCII"); break;
4939     case char_op:mp_print(mp, "char"); break;
4940     case length_op:mp_print(mp, "length"); break;
4941     case turning_op:mp_print(mp, "turningnumber"); break;
4942     case x_part:mp_print(mp, "xpart"); break;
4943     case y_part:mp_print(mp, "ypart"); break;
4944     case xx_part:mp_print(mp, "xxpart"); break;
4945     case xy_part:mp_print(mp, "xypart"); break;
4946     case yx_part:mp_print(mp, "yxpart"); break;
4947     case yy_part:mp_print(mp, "yypart"); break;
4948     case red_part:mp_print(mp, "redpart"); break;
4949     case green_part:mp_print(mp, "greenpart"); break;
4950     case blue_part:mp_print(mp, "bluepart"); break;
4951     case cyan_part:mp_print(mp, "cyanpart"); break;
4952     case magenta_part:mp_print(mp, "magentapart"); break;
4953     case yellow_part:mp_print(mp, "yellowpart"); break;
4954     case black_part:mp_print(mp, "blackpart"); break;
4955     case grey_part:mp_print(mp, "greypart"); break;
4956     case color_model_part:mp_print(mp, "colormodel"); break;
4957     case font_part:mp_print(mp, "fontpart"); break;
4958     case text_part:mp_print(mp, "textpart"); break;
4959     case path_part:mp_print(mp, "pathpart"); break;
4960     case pen_part:mp_print(mp, "penpart"); break;
4961     case dash_part:mp_print(mp, "dashpart"); break;
4962     case sqrt_op:mp_print(mp, "sqrt"); break;
4963     case m_exp_op:mp_print(mp, "mexp"); break;
4964     case m_log_op:mp_print(mp, "mlog"); break;
4965     case sin_d_op:mp_print(mp, "sind"); break;
4966     case cos_d_op:mp_print(mp, "cosd"); break;
4967     case floor_op:mp_print(mp, "floor"); break;
4968     case uniform_deviate:mp_print(mp, "uniformdeviate"); break;
4969     case char_exists_op:mp_print(mp, "charexists"); break;
4970     case font_size:mp_print(mp, "fontsize"); break;
4971     case ll_corner_op:mp_print(mp, "llcorner"); break;
4972     case lr_corner_op:mp_print(mp, "lrcorner"); break;
4973     case ul_corner_op:mp_print(mp, "ulcorner"); break;
4974     case ur_corner_op:mp_print(mp, "urcorner"); break;
4975     case arc_length:mp_print(mp, "arclength"); break;
4976     case angle_op:mp_print(mp, "angle"); break;
4977     case cycle_op:mp_print(mp, "cycle"); break;
4978     case filled_op:mp_print(mp, "filled"); break;
4979     case stroked_op:mp_print(mp, "stroked"); break;
4980     case textual_op:mp_print(mp, "textual"); break;
4981     case clipped_op:mp_print(mp, "clipped"); break;
4982     case bounded_op:mp_print(mp, "bounded"); break;
4983     case plus:mp_print_char(mp, '+'); break;
4984     case minus:mp_print_char(mp, '-'); break;
4985     case times:mp_print_char(mp, '*'); break;
4986     case over:mp_print_char(mp, '/'); break;
4987     case pythag_add:mp_print(mp, "++"); break;
4988     case pythag_sub:mp_print(mp, "+-+"); break;
4989     case or_op:mp_print(mp, "or"); break;
4990     case and_op:mp_print(mp, "and"); break;
4991     case less_than:mp_print_char(mp, '<'); break;
4992     case less_or_equal:mp_print(mp, "<="); break;
4993     case greater_than:mp_print_char(mp, '>'); break;
4994     case greater_or_equal:mp_print(mp, ">="); break;
4995     case equal_to:mp_print_char(mp, '='); break;
4996     case unequal_to:mp_print(mp, "<>"); break;
4997     case concatenate:mp_print(mp, "&"); break;
4998     case rotated_by:mp_print(mp, "rotated"); break;
4999     case slanted_by:mp_print(mp, "slanted"); break;
5000     case scaled_by:mp_print(mp, "scaled"); break;
5001     case shifted_by:mp_print(mp, "shifted"); break;
5002     case transformed_by:mp_print(mp, "transformed"); break;
5003     case x_scaled:mp_print(mp, "xscaled"); break;
5004     case y_scaled:mp_print(mp, "yscaled"); break;
5005     case z_scaled:mp_print(mp, "zscaled"); break;
5006     case in_font:mp_print(mp, "infont"); break;
5007     case intersect:mp_print(mp, "intersectiontimes"); break;
5008     case substring_of:mp_print(mp, "substring"); break;
5009     case subpath_of:mp_print(mp, "subpath"); break;
5010     case direction_time_of:mp_print(mp, "directiontime"); break;
5011     case point_of:mp_print(mp, "point"); break;
5012     case precontrol_of:mp_print(mp, "precontrol"); break;
5013     case postcontrol_of:mp_print(mp, "postcontrol"); break;
5014     case pen_offset_of:mp_print(mp, "penoffset"); break;
5015     case arc_time_of:mp_print(mp, "arctime"); break;
5016     case mp_version:mp_print(mp, "mpversion"); break;
5017     case envelope_of:mp_print(mp, "envelope"); break;
5018     default: mp_print(mp, ".."); break;
5019     }
5020   }
5021 }
5022
5023 @ \MP\ also has a bunch of internal parameters that a user might want to
5024 fuss with. Every such parameter has an identifying code number, defined here.
5025
5026 @<Types...@>=
5027 enum mp_given_internal {
5028   mp_tracing_titles=1, /* show titles online when they appear */
5029   mp_tracing_equations, /* show each variable when it becomes known */
5030   mp_tracing_capsules, /* show capsules too */
5031   mp_tracing_choices, /* show the control points chosen for paths */
5032   mp_tracing_specs, /* show path subdivision prior to filling with polygonal a pen */
5033   mp_tracing_commands, /* show commands and operations before they are performed */
5034   mp_tracing_restores, /* show when a variable or internal is restored */
5035   mp_tracing_macros, /* show macros before they are expanded */
5036   mp_tracing_output, /* show digitized edges as they are output */
5037   mp_tracing_stats, /* show memory usage at end of job */
5038   mp_tracing_lost_chars, /* show characters that aren't \&{infont} */
5039   mp_tracing_online, /* show long diagnostics on terminal and in the log file */
5040   mp_year, /* the current year (e.g., 1984) */
5041   mp_month, /* the current month (e.g, 3 $\equiv$ March) */
5042   mp_day, /* the current day of the month */
5043   mp_time, /* the number of minutes past midnight when this job started */
5044   mp_char_code, /* the number of the next character to be output */
5045   mp_char_ext, /* the extension code of the next character to be output */
5046   mp_char_wd, /* the width of the next character to be output */
5047   mp_char_ht, /* the height of the next character to be output */
5048   mp_char_dp, /* the depth of the next character to be output */
5049   mp_char_ic, /* the italic correction of the next character to be output */
5050   mp_design_size, /* the unit of measure used for |mp_char_wd..mp_char_ic|, in points */
5051   mp_pausing, /* positive to display lines on the terminal before they are read */
5052   mp_showstopping, /* positive to stop after each \&{show} command */
5053   mp_fontmaking, /* positive if font metric output is to be produced */
5054   mp_linejoin, /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */
5055   mp_linecap, /* as in \ps: 0 for butt, 1 for round, 2 for square */
5056   mp_miterlimit, /* controls miter length as in \ps */
5057   mp_warning_check, /* controls error message when variable value is large */
5058   mp_boundary_char, /* the right boundary character for ligatures */
5059   mp_prologues, /* positive to output conforming PostScript using built-in fonts */
5060   mp_true_corners, /* positive to make \&{llcorner} etc. ignore \&{setbounds} */
5061   mp_default_color_model, /* the default color model for unspecified items */
5062   mp_restore_clip_color,
5063   mp_procset, /* wether or not create PostScript command shortcuts */
5064   mp_gtroffmode,  /* whether the user specified |-troff| on the command line */
5065 };
5066
5067 @
5068
5069 @d max_given_internal mp_gtroffmode
5070
5071 @<Glob...@>=
5072 scaled *internal;  /* the values of internal quantities */
5073 char **int_name;  /* their names */
5074 int int_ptr;  /* the maximum internal quantity defined so far */
5075 int max_internal; /* current maximum number of internal quantities */
5076 boolean troff_mode; 
5077
5078 @ @<Option variables@>=
5079 int troff_mode; 
5080
5081 @ @<Allocate or initialize ...@>=
5082 mp->max_internal=2*max_given_internal;
5083 mp->internal = xmalloc ((mp->max_internal+1), sizeof(scaled));
5084 mp->int_name = xmalloc ((mp->max_internal+1), sizeof(char *));
5085 mp->troff_mode=(opt->troff_mode>0 ? true : false);
5086
5087 @ @<Exported function ...@>=
5088 int mp_troff_mode(MP mp);
5089
5090 @ @c
5091 int mp_troff_mode(MP mp) { return mp->troff_mode; }
5092
5093 @ @<Set initial ...@>=
5094 for (k=0;k<= mp->max_internal; k++ ) { 
5095    mp->internal[k]=0; 
5096    mp->int_name[k]=NULL; 
5097 }
5098 mp->int_ptr=max_given_internal;
5099
5100 @ The symbolic names for internal quantities are put into \MP's hash table
5101 by using a routine called |primitive|, which will be defined later. Let us
5102 enter them now, so that we don't have to list all those names again
5103 anywhere else.
5104
5105 @<Put each of \MP's primitives into the hash table@>=
5106 mp_primitive(mp, "tracingtitles",internal_quantity,mp_tracing_titles);
5107 @:tracingtitles_}{\&{tracingtitles} primitive@>
5108 mp_primitive(mp, "tracingequations",internal_quantity,mp_tracing_equations);
5109 @:mp_tracing_equations_}{\&{tracingequations} primitive@>
5110 mp_primitive(mp, "tracingcapsules",internal_quantity,mp_tracing_capsules);
5111 @:mp_tracing_capsules_}{\&{tracingcapsules} primitive@>
5112 mp_primitive(mp, "tracingchoices",internal_quantity,mp_tracing_choices);
5113 @:mp_tracing_choices_}{\&{tracingchoices} primitive@>
5114 mp_primitive(mp, "tracingspecs",internal_quantity,mp_tracing_specs);
5115 @:mp_tracing_specs_}{\&{tracingspecs} primitive@>
5116 mp_primitive(mp, "tracingcommands",internal_quantity,mp_tracing_commands);
5117 @:mp_tracing_commands_}{\&{tracingcommands} primitive@>
5118 mp_primitive(mp, "tracingrestores",internal_quantity,mp_tracing_restores);
5119 @:mp_tracing_restores_}{\&{tracingrestores} primitive@>
5120 mp_primitive(mp, "tracingmacros",internal_quantity,mp_tracing_macros);
5121 @:mp_tracing_macros_}{\&{tracingmacros} primitive@>
5122 mp_primitive(mp, "tracingoutput",internal_quantity,mp_tracing_output);
5123 @:mp_tracing_output_}{\&{tracingoutput} primitive@>
5124 mp_primitive(mp, "tracingstats",internal_quantity,mp_tracing_stats);
5125 @:mp_tracing_stats_}{\&{tracingstats} primitive@>
5126 mp_primitive(mp, "tracinglostchars",internal_quantity,mp_tracing_lost_chars);
5127 @:mp_tracing_lost_chars_}{\&{tracinglostchars} primitive@>
5128 mp_primitive(mp, "tracingonline",internal_quantity,mp_tracing_online);
5129 @:mp_tracing_online_}{\&{tracingonline} primitive@>
5130 mp_primitive(mp, "year",internal_quantity,mp_year);
5131 @:mp_year_}{\&{year} primitive@>
5132 mp_primitive(mp, "month",internal_quantity,mp_month);
5133 @:mp_month_}{\&{month} primitive@>
5134 mp_primitive(mp, "day",internal_quantity,mp_day);
5135 @:mp_day_}{\&{day} primitive@>
5136 mp_primitive(mp, "time",internal_quantity,mp_time);
5137 @:time_}{\&{time} primitive@>
5138 mp_primitive(mp, "charcode",internal_quantity,mp_char_code);
5139 @:mp_char_code_}{\&{charcode} primitive@>
5140 mp_primitive(mp, "charext",internal_quantity,mp_char_ext);
5141 @:mp_char_ext_}{\&{charext} primitive@>
5142 mp_primitive(mp, "charwd",internal_quantity,mp_char_wd);
5143 @:mp_char_wd_}{\&{charwd} primitive@>
5144 mp_primitive(mp, "charht",internal_quantity,mp_char_ht);
5145 @:mp_char_ht_}{\&{charht} primitive@>
5146 mp_primitive(mp, "chardp",internal_quantity,mp_char_dp);
5147 @:mp_char_dp_}{\&{chardp} primitive@>
5148 mp_primitive(mp, "charic",internal_quantity,mp_char_ic);
5149 @:mp_char_ic_}{\&{charic} primitive@>
5150 mp_primitive(mp, "designsize",internal_quantity,mp_design_size);
5151 @:mp_design_size_}{\&{designsize} primitive@>
5152 mp_primitive(mp, "pausing",internal_quantity,mp_pausing);
5153 @:mp_pausing_}{\&{pausing} primitive@>
5154 mp_primitive(mp, "showstopping",internal_quantity,mp_showstopping);
5155 @:mp_showstopping_}{\&{showstopping} primitive@>
5156 mp_primitive(mp, "fontmaking",internal_quantity,mp_fontmaking);
5157 @:mp_fontmaking_}{\&{fontmaking} primitive@>
5158 mp_primitive(mp, "linejoin",internal_quantity,mp_linejoin);
5159 @:mp_linejoin_}{\&{linejoin} primitive@>
5160 mp_primitive(mp, "linecap",internal_quantity,mp_linecap);
5161 @:mp_linecap_}{\&{linecap} primitive@>
5162 mp_primitive(mp, "miterlimit",internal_quantity,mp_miterlimit);
5163 @:mp_miterlimit_}{\&{miterlimit} primitive@>
5164 mp_primitive(mp, "warningcheck",internal_quantity,mp_warning_check);
5165 @:mp_warning_check_}{\&{warningcheck} primitive@>
5166 mp_primitive(mp, "boundarychar",internal_quantity,mp_boundary_char);
5167 @:mp_boundary_char_}{\&{boundarychar} primitive@>
5168 mp_primitive(mp, "prologues",internal_quantity,mp_prologues);
5169 @:mp_prologues_}{\&{prologues} primitive@>
5170 mp_primitive(mp, "truecorners",internal_quantity,mp_true_corners);
5171 @:mp_true_corners_}{\&{truecorners} primitive@>
5172 mp_primitive(mp, "mpprocset",internal_quantity,mp_procset);
5173 @:mp_procset_}{\&{mpprocset} primitive@>
5174 mp_primitive(mp, "troffmode",internal_quantity,mp_gtroffmode);
5175 @:troffmode_}{\&{troffmode} primitive@>
5176 mp_primitive(mp, "defaultcolormodel",internal_quantity,mp_default_color_model);
5177 @:mp_default_color_model_}{\&{defaultcolormodel} primitive@>
5178 mp_primitive(mp, "restoreclipcolor",internal_quantity,mp_restore_clip_color);
5179 @:mp_restore_clip_color_}{\&{restoreclipcolor} primitive@>
5180
5181 @ Colors can be specified in four color models. In the special
5182 case of |no_model|, MetaPost does not output any color operator to
5183 the postscript output.
5184
5185 Note: these values are passed directly on to |with_option|. This only
5186 works because the other possible values passed to |with_option| are
5187 8 and 10 respectively (from |with_pen| and |with_picture|).
5188
5189 There is a first state, that is only used for |gs_colormodel|. It flags
5190 the fact that there has not been any kind of color specification by
5191 the user so far in the game.
5192
5193 @<Types...@>=
5194 enum mp_color_model {
5195   mp_no_model=1,
5196   mp_grey_model=3,
5197   mp_rgb_model=5,
5198   mp_cmyk_model=7,
5199   mp_uninitialized_model=9,
5200 };
5201
5202
5203 @ @<Initialize table entries (done by \.{INIMP} only)@>=
5204 mp->internal[mp_default_color_model]=(mp_rgb_model*unity);
5205 mp->internal[mp_restore_clip_color]=unity;
5206
5207 @ Well, we do have to list the names one more time, for use in symbolic
5208 printouts.
5209
5210 @<Initialize table...@>=
5211 mp->int_name[mp_tracing_titles]=xstrdup("tracingtitles");
5212 mp->int_name[mp_tracing_equations]=xstrdup("tracingequations");
5213 mp->int_name[mp_tracing_capsules]=xstrdup("tracingcapsules");
5214 mp->int_name[mp_tracing_choices]=xstrdup("tracingchoices");
5215 mp->int_name[mp_tracing_specs]=xstrdup("tracingspecs");
5216 mp->int_name[mp_tracing_commands]=xstrdup("tracingcommands");
5217 mp->int_name[mp_tracing_restores]=xstrdup("tracingrestores");
5218 mp->int_name[mp_tracing_macros]=xstrdup("tracingmacros");
5219 mp->int_name[mp_tracing_output]=xstrdup("tracingoutput");
5220 mp->int_name[mp_tracing_stats]=xstrdup("tracingstats");
5221 mp->int_name[mp_tracing_lost_chars]=xstrdup("tracinglostchars");
5222 mp->int_name[mp_tracing_online]=xstrdup("tracingonline");
5223 mp->int_name[mp_year]=xstrdup("year");
5224 mp->int_name[mp_month]=xstrdup("month");
5225 mp->int_name[mp_day]=xstrdup("day");
5226 mp->int_name[mp_time]=xstrdup("time");
5227 mp->int_name[mp_char_code]=xstrdup("charcode");
5228 mp->int_name[mp_char_ext]=xstrdup("charext");
5229 mp->int_name[mp_char_wd]=xstrdup("charwd");
5230 mp->int_name[mp_char_ht]=xstrdup("charht");
5231 mp->int_name[mp_char_dp]=xstrdup("chardp");
5232 mp->int_name[mp_char_ic]=xstrdup("charic");
5233 mp->int_name[mp_design_size]=xstrdup("designsize");
5234 mp->int_name[mp_pausing]=xstrdup("pausing");
5235 mp->int_name[mp_showstopping]=xstrdup("showstopping");
5236 mp->int_name[mp_fontmaking]=xstrdup("fontmaking");
5237 mp->int_name[mp_linejoin]=xstrdup("linejoin");
5238 mp->int_name[mp_linecap]=xstrdup("linecap");
5239 mp->int_name[mp_miterlimit]=xstrdup("miterlimit");
5240 mp->int_name[mp_warning_check]=xstrdup("warningcheck");
5241 mp->int_name[mp_boundary_char]=xstrdup("boundarychar");
5242 mp->int_name[mp_prologues]=xstrdup("prologues");
5243 mp->int_name[mp_true_corners]=xstrdup("truecorners");
5244 mp->int_name[mp_default_color_model]=xstrdup("defaultcolormodel");
5245 mp->int_name[mp_procset]=xstrdup("mpprocset");
5246 mp->int_name[mp_gtroffmode]=xstrdup("troffmode");
5247 mp->int_name[mp_restore_clip_color]=xstrdup("restoreclipcolor");
5248
5249 @ The following procedure, which is called just before \MP\ initializes its
5250 input and output, establishes the initial values of the date and time.
5251 @^system dependencies@>
5252
5253 Note that the values are |scaled| integers. Hence \MP\ can no longer
5254 be used after the year 32767.
5255
5256 @c 
5257 void mp_fix_date_and_time (MP mp) { 
5258   time_t clock = time ((time_t *) 0);
5259   struct tm *tmptr = localtime (&clock);
5260   mp->internal[mp_time]=
5261       (tmptr->tm_hour*60+tmptr->tm_min)*unity; /* minutes since midnight */
5262   mp->internal[mp_day]=(tmptr->tm_mday)*unity; /* fourth day of the month */
5263   mp->internal[mp_month]=(tmptr->tm_mon+1)*unity; /* seventh month of the year */
5264   mp->internal[mp_year]=(tmptr->tm_year+1900)*unity; /* Anno Domini */
5265 }
5266
5267 @ @<Declarations@>=
5268 void mp_fix_date_and_time (MP mp) ;
5269
5270 @ \MP\ is occasionally supposed to print diagnostic information that
5271 goes only into the transcript file, unless |mp_tracing_online| is positive.
5272 Now that we have defined |mp_tracing_online| we can define
5273 two routines that adjust the destination of print commands:
5274
5275 @<Declarations@>=
5276 void mp_begin_diagnostic (MP mp) ;
5277 void mp_end_diagnostic (MP mp,boolean blank_line);
5278 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) ;
5279
5280 @ @<Basic printing...@>=
5281 @<Declare a function called |true_line|@>;
5282 void mp_begin_diagnostic (MP mp) { /* prepare to do some tracing */
5283   mp->old_setting=mp->selector;
5284   if ((mp->internal[mp_tracing_online]<=0)&&(mp->selector==term_and_log)){ 
5285     decr(mp->selector);
5286     if ( mp->history==mp_spotless ) mp->history=mp_warning_issued;
5287   }
5288 }
5289 @#
5290 void mp_end_diagnostic (MP mp,boolean blank_line) {
5291   /* restore proper conditions after tracing */
5292   mp_print_nl(mp, "");
5293   if ( blank_line ) mp_print_ln(mp);
5294   mp->selector=mp->old_setting;
5295 }
5296
5297
5298
5299 @<Glob...@>=
5300 unsigned int old_setting;
5301
5302 @ We will occasionally use |begin_diagnostic| in connection with line-number
5303 printing, as follows. (The parameter |s| is typically |"Path"| or
5304 |"Cycle spec"|, etc.)
5305
5306 @<Basic printing...@>=
5307 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) { 
5308   mp_begin_diagnostic(mp);
5309   if ( nuline ) mp_print_nl(mp, s); else mp_print(mp, s);
5310   mp_print(mp, " at line "); 
5311   mp_print_int(mp, mp_true_line(mp));
5312   mp_print(mp, t); mp_print_char(mp, ':');
5313 }
5314
5315 @ The 256 |ASCII_code| characters are grouped into classes by means of
5316 the |char_class| table. Individual class numbers have no semantic
5317 or syntactic significance, except in a few instances defined here.
5318 There's also |max_class|, which can be used as a basis for additional
5319 class numbers in nonstandard extensions of \MP.
5320
5321 @d digit_class 0 /* the class number of \.{0123456789} */
5322 @d period_class 1 /* the class number of `\..' */
5323 @d space_class 2 /* the class number of spaces and nonstandard characters */
5324 @d percent_class 3 /* the class number of `\.\%' */
5325 @d string_class 4 /* the class number of `\."' */
5326 @d right_paren_class 8 /* the class number of `\.)' */
5327 @d isolated_classes 5: case 6: case 7: case 8 /* characters that make length-one tokens only */
5328 @d letter_class 9 /* letters and the underline character */
5329 @d left_bracket_class 17 /* `\.[' */
5330 @d right_bracket_class 18 /* `\.]' */
5331 @d invalid_class 20 /* bad character in the input */
5332 @d max_class 20 /* the largest class number */
5333
5334 @<Glob...@>=
5335 int char_class[256]; /* the class numbers */
5336
5337 @ If changes are made to accommodate non-ASCII character sets, they should
5338 follow the guidelines in Appendix~C of {\sl The {\logos METAFONT\/}book}.
5339 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
5340 @^system dependencies@>
5341
5342 @<Set initial ...@>=
5343 for (k='0';k<='9';k++) 
5344   mp->char_class[k]=digit_class;
5345 mp->char_class['.']=period_class;
5346 mp->char_class[' ']=space_class;
5347 mp->char_class['%']=percent_class;
5348 mp->char_class['"']=string_class;
5349 mp->char_class[',']=5;
5350 mp->char_class[';']=6;
5351 mp->char_class['(']=7;
5352 mp->char_class[')']=right_paren_class;
5353 for (k='A';k<= 'Z';k++ )
5354   mp->char_class[k]=letter_class;
5355 for (k='a';k<='z';k++) 
5356   mp->char_class[k]=letter_class;
5357 mp->char_class['_']=letter_class;
5358 mp->char_class['<']=10;
5359 mp->char_class['=']=10;
5360 mp->char_class['>']=10;
5361 mp->char_class[':']=10;
5362 mp->char_class['|']=10;
5363 mp->char_class['`']=11;
5364 mp->char_class['\'']=11;
5365 mp->char_class['+']=12;
5366 mp->char_class['-']=12;
5367 mp->char_class['/']=13;
5368 mp->char_class['*']=13;
5369 mp->char_class['\\']=13;
5370 mp->char_class['!']=14;
5371 mp->char_class['?']=14;
5372 mp->char_class['#']=15;
5373 mp->char_class['&']=15;
5374 mp->char_class['@@']=15;
5375 mp->char_class['$']=15;
5376 mp->char_class['^']=16;
5377 mp->char_class['~']=16;
5378 mp->char_class['[']=left_bracket_class;
5379 mp->char_class[']']=right_bracket_class;
5380 mp->char_class['{']=19;
5381 mp->char_class['}']=19;
5382 for (k=0;k<' ';k++)
5383   mp->char_class[k]=invalid_class;
5384 mp->char_class['\t']=space_class;
5385 mp->char_class['\f']=space_class;
5386 for (k=127;k<=255;k++)
5387   mp->char_class[k]=invalid_class;
5388
5389 @* \[13] The hash table.
5390 Symbolic tokens are stored and retrieved by means of a fairly standard hash
5391 table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
5392 in {\sl The Art of Computer Programming\/}). Once a symbolic token enters the
5393 table, it is never removed.
5394
5395 The actual sequence of characters forming a symbolic token is
5396 stored in the |str_pool| array together with all the other strings. An
5397 auxiliary array |hash| consists of items with two halfword fields per
5398 word. The first of these, called |next(p)|, points to the next identifier
5399 belonging to the same coalesced list as the identifier corresponding to~|p|;
5400 and the other, called |text(p)|, points to the |str_start| entry for
5401 |p|'s identifier. If position~|p| of the hash table is empty, we have
5402 |text(p)=0|; if position |p| is either empty or the end of a coalesced
5403 hash list, we have |next(p)=0|.
5404
5405 An auxiliary pointer variable called |hash_used| is maintained in such a
5406 way that all locations |p>=hash_used| are nonempty. The global variable
5407 |st_count| tells how many symbolic tokens have been defined, if statistics
5408 are being kept.
5409
5410 The first 256 locations of |hash| are reserved for symbols of length one.
5411
5412 There's a parallel array called |eqtb| that contains the current equivalent
5413 values of each symbolic token. The entries of this array consist of
5414 two halfwords called |eq_type| (a command code) and |equiv| (a secondary
5415 piece of information that qualifies the |eq_type|).
5416
5417 @d next(A)   mp->hash[(A)].lh /* link for coalesced lists */
5418 @d text(A)   mp->hash[(A)].rh /* string number for symbolic token name */
5419 @d eq_type(A)   mp->eqtb[(A)].lh /* the current ``meaning'' of a symbolic token */
5420 @d equiv(A)   mp->eqtb[(A)].rh /* parametric part of a token's meaning */
5421 @d hash_base 257 /* hashing actually starts here */
5422 @d hash_is_full   (mp->hash_used==hash_base) /* are all positions occupied? */
5423
5424 @<Glob...@>=
5425 pointer hash_used; /* allocation pointer for |hash| */
5426 integer st_count; /* total number of known identifiers */
5427
5428 @ Certain entries in the hash table are ``frozen'' and not redefinable,
5429 since they are used in error recovery.
5430
5431 @d hash_top (hash_base+mp->hash_size) /* the first location of the frozen area */
5432 @d frozen_inaccessible hash_top /* |hash| location to protect the frozen area */
5433 @d frozen_repeat_loop (hash_top+1) /* |hash| location of a loop-repeat token */
5434 @d frozen_right_delimiter (hash_top+2) /* |hash| location of a permanent `\.)' */
5435 @d frozen_left_bracket (hash_top+3) /* |hash| location of a permanent `\.[' */
5436 @d frozen_slash (hash_top+4) /* |hash| location of a permanent `\./' */
5437 @d frozen_colon (hash_top+5) /* |hash| location of a permanent `\.:' */
5438 @d frozen_semicolon (hash_top+6) /* |hash| location of a permanent `\.;' */
5439 @d frozen_end_for (hash_top+7) /* |hash| location of a permanent \&{endfor} */
5440 @d frozen_end_def (hash_top+8) /* |hash| location of a permanent \&{enddef} */
5441 @d frozen_fi (hash_top+9) /* |hash| location of a permanent \&{fi} */
5442 @d frozen_end_group (hash_top+10) /* |hash| location of a permanent `\.{endgroup}' */
5443 @d frozen_etex (hash_top+11) /* |hash| location of a permanent \&{etex} */
5444 @d frozen_mpx_break (hash_top+12) /* |hash| location of a permanent \&{mpxbreak} */
5445 @d frozen_bad_vardef (hash_top+13) /* |hash| location of `\.{a bad variable}' */
5446 @d frozen_undefined (hash_top+14) /* |hash| location that never gets defined */
5447 @d hash_end (hash_top+14) /* the actual size of the |hash| and |eqtb| arrays */
5448
5449 @<Glob...@>=
5450 two_halves *hash; /* the hash table */
5451 two_halves *eqtb; /* the equivalents */
5452
5453 @ @<Allocate or initialize ...@>=
5454 mp->hash = xmalloc((hash_end+1),sizeof(two_halves));
5455 mp->eqtb = xmalloc((hash_end+1),sizeof(two_halves));
5456
5457 @ @<Dealloc variables@>=
5458 xfree(mp->hash);
5459 xfree(mp->eqtb);
5460
5461 @ @<Set init...@>=
5462 next(1)=0; text(1)=0; eq_type(1)=tag_token; equiv(1)=null;
5463 for (k=2;k<=hash_end;k++)  { 
5464   mp->hash[k]=mp->hash[1]; mp->eqtb[k]=mp->eqtb[1];
5465 }
5466
5467 @ @<Initialize table entries...@>=
5468 mp->hash_used=frozen_inaccessible; /* nothing is used */
5469 mp->st_count=0;
5470 text(frozen_bad_vardef)=intern("a bad variable");
5471 text(frozen_etex)=intern("etex");
5472 text(frozen_mpx_break)=intern("mpxbreak");
5473 text(frozen_fi)=intern("fi");
5474 text(frozen_end_group)=intern("endgroup");
5475 text(frozen_end_def)=intern("enddef");
5476 text(frozen_end_for)=intern("endfor");
5477 text(frozen_semicolon)=intern(";");
5478 text(frozen_colon)=intern(":");
5479 text(frozen_slash)=intern("/");
5480 text(frozen_left_bracket)=intern("[");
5481 text(frozen_right_delimiter)=intern(")");
5482 text(frozen_inaccessible)=intern(" INACCESSIBLE");
5483 eq_type(frozen_right_delimiter)=right_delimiter;
5484
5485 @ @<Check the ``constant'' values...@>=
5486 if ( hash_end+mp->max_internal>max_halfword ) mp->bad=17;
5487
5488 @ Here is the subroutine that searches the hash table for an identifier
5489 that matches a given string of length~|l| appearing in |buffer[j..
5490 (j+l-1)]|. If the identifier is not found, it is inserted; hence it
5491 will always be found, and the corresponding hash table address
5492 will be returned.
5493
5494 @c 
5495 pointer mp_id_lookup (MP mp,integer j, integer l) { /* search the hash table */
5496   integer h; /* hash code */
5497   pointer p; /* index in |hash| array */
5498   pointer k; /* index in |buffer| array */
5499   if (l==1) {
5500     @<Treat special case of length 1 and |break|@>;
5501   }
5502   @<Compute the hash code |h|@>;
5503   p=h+hash_base; /* we start searching here; note that |0<=h<hash_prime| */
5504   while (true)  { 
5505         if (text(p)>0 && length(text(p))==l && mp_str_eq_buf(mp, text(p),j)) 
5506       break;
5507     if ( next(p)==0 ) {
5508       @<Insert a new symbolic token after |p|, then
5509         make |p| point to it and |break|@>;
5510     }
5511     p=next(p);
5512   }
5513   return p;
5514 };
5515
5516 @ @<Treat special case of length 1...@>=
5517  p=mp->buffer[j]+1; text(p)=p-1; return p;
5518
5519
5520 @ @<Insert a new symbolic...@>=
5521 {
5522 if ( text(p)>0 ) { 
5523   do {  
5524     if ( hash_is_full )
5525       mp_overflow(mp, "hash size",mp->hash_size);
5526 @:MetaPost capacity exceeded hash size}{\quad hash size@>
5527     decr(mp->hash_used);
5528   } while (text(mp->hash_used)!=0); /* search for an empty location in |hash| */
5529   next(p)=mp->hash_used; 
5530   p=mp->hash_used;
5531 }
5532 str_room(l);
5533 for (k=j;k<=j+l-1;k++) {
5534   append_char(mp->buffer[k]);
5535 }
5536 text(p)=mp_make_string(mp); 
5537 mp->str_ref[text(p)]=max_str_ref;
5538 incr(mp->st_count);
5539 break;
5540 }
5541
5542
5543 @ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
5544 should be a prime number.  The theory of hashing tells us to expect fewer
5545 than two table probes, on the average, when the search is successful.
5546 [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
5547 @^Vitter, Jeffrey Scott@>
5548
5549 @<Compute the hash code |h|@>=
5550 h=mp->buffer[j];
5551 for (k=j+1;k<=j+l-1;k++){ 
5552   h=h+h+mp->buffer[k];
5553   while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
5554 }
5555
5556 @ @<Search |eqtb| for equivalents equal to |p|@>=
5557 for (q=1;q<=hash_end;q++) { 
5558   if ( equiv(q)==p ) { 
5559     mp_print_nl(mp, "EQUIV("); 
5560     mp_print_int(mp, q); 
5561     mp_print_char(mp, ')');
5562   }
5563 }
5564
5565 @ We need to put \MP's ``primitive'' symbolic tokens into the hash
5566 table, together with their command code (which will be the |eq_type|)
5567 and an operand (which will be the |equiv|). The |primitive| procedure
5568 does this, in a way that no \MP\ user can. The global value |cur_sym|
5569 contains the new |eqtb| pointer after |primitive| has acted.
5570
5571 @c 
5572 void mp_primitive (MP mp, char *ss, halfword c, halfword o) {
5573   pool_pointer k; /* index into |str_pool| */
5574   small_number j; /* index into |buffer| */
5575   small_number l; /* length of the string */
5576   str_number s;
5577   s = intern(ss);
5578   k=mp->str_start[s]; l=str_stop(s)-k;
5579   /* we will move |s| into the (empty) |buffer| */
5580   for (j=0;j<=l-1;j++) {
5581     mp->buffer[j]=mp->str_pool[k+j];
5582   }
5583   mp->cur_sym=mp_id_lookup(mp, 0,l);
5584   if ( s>=256 ) { /* we don't want to have the string twice */
5585     mp_flush_string(mp, text(mp->cur_sym)); text(mp->cur_sym)=s;
5586   };
5587   eq_type(mp->cur_sym)=c; 
5588   equiv(mp->cur_sym)=o;
5589 }
5590
5591
5592 @ Many of \MP's primitives need no |equiv|, since they are identifiable
5593 by their |eq_type| alone. These primitives are loaded into the hash table
5594 as follows:
5595
5596 @<Put each of \MP's primitives into the hash table@>=
5597 mp_primitive(mp, "..",path_join,0);
5598 @:.._}{\.{..} primitive@>
5599 mp_primitive(mp, "[",left_bracket,0); mp->eqtb[frozen_left_bracket]=mp->eqtb[mp->cur_sym];
5600 @:[ }{\.{[} primitive@>
5601 mp_primitive(mp, "]",right_bracket,0);
5602 @:] }{\.{]} primitive@>
5603 mp_primitive(mp, "}",right_brace,0);
5604 @:]]}{\.{\char`\}} primitive@>
5605 mp_primitive(mp, "{",left_brace,0);
5606 @:][}{\.{\char`\{} primitive@>
5607 mp_primitive(mp, ":",colon,0); mp->eqtb[frozen_colon]=mp->eqtb[mp->cur_sym];
5608 @:: }{\.{:} primitive@>
5609 mp_primitive(mp, "::",double_colon,0);
5610 @::: }{\.{::} primitive@>
5611 mp_primitive(mp, "||:",bchar_label,0);
5612 @:::: }{\.{\char'174\char'174:} primitive@>
5613 mp_primitive(mp, ":=",assignment,0);
5614 @::=_}{\.{:=} primitive@>
5615 mp_primitive(mp, ",",comma,0);
5616 @:, }{\., primitive@>
5617 mp_primitive(mp, ";",semicolon,0); mp->eqtb[frozen_semicolon]=mp->eqtb[mp->cur_sym];
5618 @:; }{\.; primitive@>
5619 mp_primitive(mp, "\\",relax,0);
5620 @:]]\\}{\.{\char`\\} primitive@>
5621 @#
5622 mp_primitive(mp, "addto",add_to_command,0);
5623 @:add_to_}{\&{addto} primitive@>
5624 mp_primitive(mp, "atleast",at_least,0);
5625 @:at_least_}{\&{atleast} primitive@>
5626 mp_primitive(mp, "begingroup",begin_group,0); mp->bg_loc=mp->cur_sym;
5627 @:begin_group_}{\&{begingroup} primitive@>
5628 mp_primitive(mp, "controls",controls,0);
5629 @:controls_}{\&{controls} primitive@>
5630 mp_primitive(mp, "curl",curl_command,0);
5631 @:curl_}{\&{curl} primitive@>
5632 mp_primitive(mp, "delimiters",delimiters,0);
5633 @:delimiters_}{\&{delimiters} primitive@>
5634 mp_primitive(mp, "endgroup",end_group,0);
5635  mp->eqtb[frozen_end_group]=mp->eqtb[mp->cur_sym]; mp->eg_loc=mp->cur_sym;
5636 @:endgroup_}{\&{endgroup} primitive@>
5637 mp_primitive(mp, "everyjob",every_job_command,0);
5638 @:every_job_}{\&{everyjob} primitive@>
5639 mp_primitive(mp, "exitif",exit_test,0);
5640 @:exit_if_}{\&{exitif} primitive@>
5641 mp_primitive(mp, "expandafter",expand_after,0);
5642 @:expand_after_}{\&{expandafter} primitive@>
5643 mp_primitive(mp, "interim",interim_command,0);
5644 @:interim_}{\&{interim} primitive@>
5645 mp_primitive(mp, "let",let_command,0);
5646 @:let_}{\&{let} primitive@>
5647 mp_primitive(mp, "newinternal",new_internal,0);
5648 @:new_internal_}{\&{newinternal} primitive@>
5649 mp_primitive(mp, "of",of_token,0);
5650 @:of_}{\&{of} primitive@>
5651 mp_primitive(mp, "randomseed",random_seed,0);
5652 @:random_seed_}{\&{randomseed} primitive@>
5653 mp_primitive(mp, "save",save_command,0);
5654 @:save_}{\&{save} primitive@>
5655 mp_primitive(mp, "scantokens",scan_tokens,0);
5656 @:scan_tokens_}{\&{scantokens} primitive@>
5657 mp_primitive(mp, "shipout",ship_out_command,0);
5658 @:ship_out_}{\&{shipout} primitive@>
5659 mp_primitive(mp, "skipto",skip_to,0);
5660 @:skip_to_}{\&{skipto} primitive@>
5661 mp_primitive(mp, "special",special_command,0);
5662 @:special}{\&{special} primitive@>
5663 mp_primitive(mp, "fontmapfile",special_command,1);
5664 @:fontmapfile}{\&{fontmapfile} primitive@>
5665 mp_primitive(mp, "fontmapline",special_command,2);
5666 @:fontmapline}{\&{fontmapline} primitive@>
5667 mp_primitive(mp, "step",step_token,0);
5668 @:step_}{\&{step} primitive@>
5669 mp_primitive(mp, "str",str_op,0);
5670 @:str_}{\&{str} primitive@>
5671 mp_primitive(mp, "tension",tension,0);
5672 @:tension_}{\&{tension} primitive@>
5673 mp_primitive(mp, "to",to_token,0);
5674 @:to_}{\&{to} primitive@>
5675 mp_primitive(mp, "until",until_token,0);
5676 @:until_}{\&{until} primitive@>
5677 mp_primitive(mp, "within",within_token,0);
5678 @:within_}{\&{within} primitive@>
5679 mp_primitive(mp, "write",write_command,0);
5680 @:write_}{\&{write} primitive@>
5681
5682 @ Each primitive has a corresponding inverse, so that it is possible to
5683 display the cryptic numeric contents of |eqtb| in symbolic form.
5684 Every call of |primitive| in this program is therefore accompanied by some
5685 straightforward code that forms part of the |print_cmd_mod| routine
5686 explained below.
5687
5688 @<Cases of |print_cmd_mod| for symbolic printing of primitives@>=
5689 case add_to_command:mp_print(mp, "addto"); break;
5690 case assignment:mp_print(mp, ":="); break;
5691 case at_least:mp_print(mp, "atleast"); break;
5692 case bchar_label:mp_print(mp, "||:"); break;
5693 case begin_group:mp_print(mp, "begingroup"); break;
5694 case colon:mp_print(mp, ":"); break;
5695 case comma:mp_print(mp, ","); break;
5696 case controls:mp_print(mp, "controls"); break;
5697 case curl_command:mp_print(mp, "curl"); break;
5698 case delimiters:mp_print(mp, "delimiters"); break;
5699 case double_colon:mp_print(mp, "::"); break;
5700 case end_group:mp_print(mp, "endgroup"); break;
5701 case every_job_command:mp_print(mp, "everyjob"); break;
5702 case exit_test:mp_print(mp, "exitif"); break;
5703 case expand_after:mp_print(mp, "expandafter"); break;
5704 case interim_command:mp_print(mp, "interim"); break;
5705 case left_brace:mp_print(mp, "{"); break;
5706 case left_bracket:mp_print(mp, "["); break;
5707 case let_command:mp_print(mp, "let"); break;
5708 case new_internal:mp_print(mp, "newinternal"); break;
5709 case of_token:mp_print(mp, "of"); break;
5710 case path_join:mp_print(mp, ".."); break;
5711 case random_seed:mp_print(mp, "randomseed"); break;
5712 case relax:mp_print_char(mp, '\\'); break;
5713 case right_brace:mp_print(mp, "}"); break;
5714 case right_bracket:mp_print(mp, "]"); break;
5715 case save_command:mp_print(mp, "save"); break;
5716 case scan_tokens:mp_print(mp, "scantokens"); break;
5717 case semicolon:mp_print(mp, ";"); break;
5718 case ship_out_command:mp_print(mp, "shipout"); break;
5719 case skip_to:mp_print(mp, "skipto"); break;
5720 case special_command: if ( m==2 ) mp_print(mp, "fontmapline"); else
5721                  if ( m==1 ) mp_print(mp, "fontmapfile"); else
5722                  mp_print(mp, "special"); break;
5723 case step_token:mp_print(mp, "step"); break;
5724 case str_op:mp_print(mp, "str"); break;
5725 case tension:mp_print(mp, "tension"); break;
5726 case to_token:mp_print(mp, "to"); break;
5727 case until_token:mp_print(mp, "until"); break;
5728 case within_token:mp_print(mp, "within"); break;
5729 case write_command:mp_print(mp, "write"); break;
5730
5731 @ We will deal with the other primitives later, at some point in the program
5732 where their |eq_type| and |equiv| values are more meaningful.  For example,
5733 the primitives for macro definitions will be loaded when we consider the
5734 routines that define macros.
5735 It is easy to find where each particular
5736 primitive was treated by looking in the index at the end; for example, the
5737 section where |"def"| entered |eqtb| is listed under `\&{def} primitive'.
5738
5739 @* \[14] Token lists.
5740 A \MP\ token is either symbolic or numeric or a string, or it denotes
5741 a macro parameter or capsule; so there are five corresponding ways to encode it
5742 @^token@>
5743 internally: (1)~A symbolic token whose hash code is~|p|
5744 is represented by the number |p|, in the |info| field of a single-word
5745 node in~|mem|. (2)~A numeric token whose |scaled| value is~|v| is
5746 represented in a two-word node of~|mem|; the |type| field is |known|,
5747 the |name_type| field is |token|, and the |value| field holds~|v|.
5748 The fact that this token appears in a two-word node rather than a
5749 one-word node is, of course, clear from the node address.
5750 (3)~A string token is also represented in a two-word node; the |type|
5751 field is |mp_string_type|, the |name_type| field is |token|, and the
5752 |value| field holds the corresponding |str_number|.  (4)~Capsules have
5753 |name_type=capsule|, and their |type| and |value| fields represent
5754 arbitrary values (in ways to be explained later).  (5)~Macro parameters
5755 are like symbolic tokens in that they appear in |info| fields of
5756 one-word nodes. The $k$th parameter is represented by |expr_base+k| if it
5757 is of type \&{expr}, or by |suffix_base+k| if it is of type \&{suffix}, or
5758 by |text_base+k| if it is of type \&{text}.  (Here |0<=k<param_size|.)
5759 Actual values of these parameters are kept in a separate stack, as we will
5760 see later.  The constants |expr_base|, |suffix_base|, and |text_base| are,
5761 of course, chosen so that there will be no confusion between symbolic
5762 tokens and parameters of various types.
5763
5764 Note that
5765 the `\\{type}' field of a node has nothing to do with ``type'' in a
5766 printer's sense. It's curious that the same word is used in such different ways.
5767
5768 @d type(A)   mp->mem[(A)].hh.b0 /* identifies what kind of value this is */
5769 @d name_type(A)   mp->mem[(A)].hh.b1 /* a clue to the name of this value */
5770 @d token_node_size 2 /* the number of words in a large token node */
5771 @d value_loc(A) ((A)+1) /* the word that contains the |value| field */
5772 @d value(A) mp->mem[value_loc((A))].cint /* the value stored in a large token node */
5773 @d expr_base (hash_end+1) /* code for the zeroth \&{expr} parameter */
5774 @d suffix_base (expr_base+mp->param_size) /* code for the zeroth \&{suffix} parameter */
5775 @d text_base (suffix_base+mp->param_size) /* code for the zeroth \&{text} parameter */
5776
5777 @<Check the ``constant''...@>=
5778 if ( text_base+mp->param_size>max_halfword ) mp->bad=18;
5779
5780 @ We have set aside a two word node beginning at |null| so that we can have
5781 |value(null)=0|.  We will make use of this coincidence later.
5782
5783 @<Initialize table entries...@>=
5784 link(null)=null; value(null)=0;
5785
5786 @ A numeric token is created by the following trivial routine.
5787
5788 @c 
5789 pointer mp_new_num_tok (MP mp,scaled v) {
5790   pointer p; /* the new node */
5791   p=mp_get_node(mp, token_node_size); value(p)=v;
5792   type(p)=mp_known; name_type(p)=mp_token; 
5793   return p;
5794 }
5795
5796 @ A token list is a singly linked list of nodes in |mem|, where
5797 each node contains a token and a link.  Here's a subroutine that gets rid
5798 of a token list when it is no longer needed.
5799
5800 @<Declarations@>=
5801 void mp_token_recycle (MP mp);
5802
5803
5804 @c void mp_flush_token_list (MP mp,pointer p) {
5805   pointer q; /* the node being recycled */
5806   while ( p!=null ) { 
5807     q=p; p=link(p);
5808     if ( q>=mp->hi_mem_min ) {
5809      free_avail(q);
5810     } else { 
5811       switch (type(q)) {
5812       case mp_vacuous: case mp_boolean_type: case mp_known:
5813         break;
5814       case mp_string_type:
5815         delete_str_ref(value(q));
5816         break;
5817       case unknown_types: case mp_pen_type: case mp_path_type: 
5818       case mp_picture_type: case mp_pair_type: case mp_color_type:
5819       case mp_cmykcolor_type: case mp_transform_type: case mp_dependent:
5820       case mp_proto_dependent: case mp_independent:
5821         mp->g_pointer=q; mp_token_recycle(mp);
5822         break;
5823       default: mp_confusion(mp, "token");
5824 @:this can't happen token}{\quad token@>
5825       }
5826       mp_free_node(mp, q,token_node_size);
5827     }
5828   }
5829 }
5830
5831 @ The procedure |show_token_list|, which prints a symbolic form of
5832 the token list that starts at a given node |p|, illustrates these
5833 conventions. The token list being displayed should not begin with a reference
5834 count. However, the procedure is intended to be fairly robust, so that if the
5835 memory links are awry or if |p| is not really a pointer to a token list,
5836 almost nothing catastrophic can happen.
5837
5838 An additional parameter |q| is also given; this parameter is either null
5839 or it points to a node in the token list where a certain magic computation
5840 takes place that will be explained later. (Basically, |q| is non-null when
5841 we are printing the two-line context information at the time of an error
5842 message; |q| marks the place corresponding to where the second line
5843 should begin.)
5844
5845 The generation will stop, and `\.{\char`\ ETC.}' will be printed, if the length
5846 of printing exceeds a given limit~|l|; the length of printing upon entry is
5847 assumed to be a given amount called |null_tally|. (Note that
5848 |show_token_list| sometimes uses itself recursively to print
5849 variable names within a capsule.)
5850 @^recursion@>
5851
5852 Unusual entries are printed in the form of all-caps tokens
5853 preceded by a space, e.g., `\.{\char`\ BAD}'.
5854
5855 @<Declarations@>=
5856 void mp_print_capsule (MP mp);
5857
5858 @ @<Declare the procedure called |show_token_list|@>=
5859 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5860                          integer null_tally) ;
5861
5862 @ @c
5863 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5864                          integer null_tally) {
5865   small_number class,c; /* the |char_class| of previous and new tokens */
5866   integer r,v; /* temporary registers */
5867   class=percent_class;
5868   mp->tally=null_tally;
5869   while ( (p!=null) && (mp->tally<l) ) { 
5870     if ( p==q ) 
5871       @<Do magic computation@>;
5872     @<Display token |p| and set |c| to its class;
5873       but |return| if there are problems@>;
5874     class=c; p=link(p);
5875   }
5876   if ( p!=null ) 
5877      mp_print(mp, " ETC.");
5878 @.ETC@>
5879   return;
5880 };
5881
5882 @ @<Display token |p| and set |c| to its class...@>=
5883 c=letter_class; /* the default */
5884 if ( (p<0)||(p>mp->mem_end) ) { 
5885   mp_print(mp, " CLOBBERED"); return;
5886 @.CLOBBERED@>
5887 }
5888 if ( p<mp->hi_mem_min ) { 
5889   @<Display two-word token@>;
5890 } else { 
5891   r=info(p);
5892   if ( r>=expr_base ) {
5893      @<Display a parameter token@>;
5894   } else {
5895     if ( r<1 ) {
5896       if ( r==0 ) { 
5897         @<Display a collective subscript@>
5898       } else {
5899         mp_print(mp, " IMPOSSIBLE");
5900 @.IMPOSSIBLE@>
5901       }
5902     } else { 
5903       r=text(r);
5904       if ( (r<0)||(r>mp->max_str_ptr) ) {
5905         mp_print(mp, " NONEXISTENT");
5906 @.NONEXISTENT@>
5907       } else {
5908        @<Print string |r| as a symbolic token
5909         and set |c| to its class@>;
5910       }
5911     }
5912   }
5913 }
5914
5915 @ @<Display two-word token@>=
5916 if ( name_type(p)==mp_token ) {
5917   if ( type(p)==mp_known ) {
5918     @<Display a numeric token@>;
5919   } else if ( type(p)!=mp_string_type ) {
5920     mp_print(mp, " BAD");
5921 @.BAD@>
5922   } else { 
5923     mp_print_char(mp, '"'); mp_print_str(mp, value(p)); mp_print_char(mp, '"');
5924     c=string_class;
5925   }
5926 } else if ((name_type(p)!=mp_capsule)||(type(p)<mp_vacuous)||(type(p)>mp_independent) ) {
5927   mp_print(mp, " BAD");
5928 } else { 
5929   mp->g_pointer=p; mp_print_capsule(mp); c=right_paren_class;
5930 }
5931
5932 @ @<Display a numeric token@>=
5933 if ( class==digit_class ) 
5934   mp_print_char(mp, ' ');
5935 v=value(p);
5936 if ( v<0 ){ 
5937   if ( class==left_bracket_class ) 
5938     mp_print_char(mp, ' ');
5939   mp_print_char(mp, '['); mp_print_scaled(mp, v); mp_print_char(mp, ']');
5940   c=right_bracket_class;
5941 } else { 
5942   mp_print_scaled(mp, v); c=digit_class;
5943 }
5944
5945
5946 @ Strictly speaking, a genuine token will never have |info(p)=0|.
5947 But we will see later (in the |print_variable_name| routine) that
5948 it is convenient to let |info(p)=0| stand for `\.{[]}'.
5949
5950 @<Display a collective subscript@>=
5951 {
5952 if ( class==left_bracket_class ) 
5953   mp_print_char(mp, ' ');
5954 mp_print(mp, "[]"); c=right_bracket_class;
5955 }
5956
5957 @ @<Display a parameter token@>=
5958 {
5959 if ( r<suffix_base ) { 
5960   mp_print(mp, "(EXPR"); r=r-(expr_base);
5961 @.EXPR@>
5962 } else if ( r<text_base ) { 
5963   mp_print(mp, "(SUFFIX"); r=r-(suffix_base);
5964 @.SUFFIX@>
5965 } else { 
5966   mp_print(mp, "(TEXT"); r=r-(text_base);
5967 @.TEXT@>
5968 }
5969 mp_print_int(mp, r); mp_print_char(mp, ')'); c=right_paren_class;
5970 }
5971
5972
5973 @ @<Print string |r| as a symbolic token...@>=
5974
5975 c=mp->char_class[mp->str_pool[mp->str_start[r]]];
5976 if ( c==class ) {
5977   switch (c) {
5978   case letter_class:mp_print_char(mp, '.'); break;
5979   case isolated_classes: break;
5980   default: mp_print_char(mp, ' '); break;
5981   }
5982 }
5983 mp_print_str(mp, r);
5984 }
5985
5986 @ The following procedures have been declared |forward| with no parameters,
5987 because the author dislikes \PASCAL's convention about |forward| procedures
5988 with parameters. It was necessary to do something, because |show_token_list|
5989 is recursive (although the recursion is limited to one level), and because
5990 |flush_token_list| is syntactically (but not semantically) recursive.
5991 @^recursion@>
5992
5993 @<Declare miscellaneous procedures that were declared |forward|@>=
5994 void mp_print_capsule (MP mp) { 
5995   mp_print_char(mp, '('); mp_print_exp(mp, mp->g_pointer,0); mp_print_char(mp, ')');
5996 };
5997 @#
5998 void mp_token_recycle (MP mp) { 
5999   mp_recycle_value(mp, mp->g_pointer);
6000 };
6001
6002 @ @<Glob...@>=
6003 pointer g_pointer; /* (global) parameter to the |forward| procedures */
6004
6005 @ Macro definitions are kept in \MP's memory in the form of token lists
6006 that have a few extra one-word nodes at the beginning.
6007
6008 The first node contains a reference count that is used to tell when the
6009 list is no longer needed. To emphasize the fact that a reference count is
6010 present, we shall refer to the |info| field of this special node as the
6011 |ref_count| field.
6012 @^reference counts@>
6013
6014 The next node or nodes after the reference count serve to describe the
6015 formal parameters. They either contain a code word that specifies all
6016 of the parameters, or they contain zero or more parameter tokens followed
6017 by the code `|general_macro|'.
6018
6019 @d ref_count info
6020   /* reference count preceding a macro definition or picture header */
6021 @d add_mac_ref(A) incr(ref_count((A))) /* make a new reference to a macro list */
6022 @d general_macro 0 /* preface to a macro defined with a parameter list */
6023 @d primary_macro 1 /* preface to a macro with a \&{primary} parameter */
6024 @d secondary_macro 2 /* preface to a macro with a \&{secondary} parameter */
6025 @d tertiary_macro 3 /* preface to a macro with a \&{tertiary} parameter */
6026 @d expr_macro 4 /* preface to a macro with an undelimited \&{expr} parameter */
6027 @d of_macro 5 /* preface to a macro with
6028   undelimited `\&{expr} |x| \&{of}~|y|' parameters */
6029 @d suffix_macro 6 /* preface to a macro with an undelimited \&{suffix} parameter */
6030 @d text_macro 7 /* preface to a macro with an undelimited \&{text} parameter */
6031
6032 @c 
6033 void mp_delete_mac_ref (MP mp,pointer p) {
6034   /* |p| points to the reference count of a macro list that is
6035     losing one reference */
6036   if ( ref_count(p)==null ) mp_flush_token_list(mp, p);
6037   else decr(ref_count(p));
6038 }
6039
6040 @ The following subroutine displays a macro, given a pointer to its
6041 reference count.
6042
6043 @c 
6044 @<Declare the procedure called |print_cmd_mod|@>;
6045 void mp_show_macro (MP mp, pointer p, integer q, integer l) {
6046   pointer r; /* temporary storage */
6047   p=link(p); /* bypass the reference count */
6048   while ( info(p)>text_macro ){ 
6049     r=link(p); link(p)=null;
6050     mp_show_token_list(mp, p,null,l,0); link(p)=r; p=r;
6051     if ( l>0 ) l=l-mp->tally; else return;
6052   } /* control printing of `\.{ETC.}' */
6053 @.ETC@>
6054   mp->tally=0;
6055   switch(info(p)) {
6056   case general_macro:mp_print(mp, "->"); break;
6057 @.->@>
6058   case primary_macro: case secondary_macro: case tertiary_macro:
6059     mp_print_char(mp, '<');
6060     mp_print_cmd_mod(mp, param_type,info(p)); 
6061     mp_print(mp, ">->");
6062     break;
6063   case expr_macro:mp_print(mp, "<expr>->"); break;
6064   case of_macro:mp_print(mp, "<expr>of<primary>->"); break;
6065   case suffix_macro:mp_print(mp, "<suffix>->"); break;
6066   case text_macro:mp_print(mp, "<text>->"); break;
6067   } /* there are no other cases */
6068   mp_show_token_list(mp, link(p),q,l-mp->tally,0);
6069 }
6070
6071 @* \[15] Data structures for variables.
6072 The variables of \MP\ programs can be simple, like `\.x', or they can
6073 combine the structural properties of arrays and records, like `\.{x20a.b}'.
6074 A \MP\ user assigns a type to a variable like \.{x20a.b} by saying, for
6075 example, `\.{boolean} \.{x20a.b}'. It's time for us to study how such
6076 things are represented inside of the computer.
6077
6078 Each variable value occupies two consecutive words, either in a two-word
6079 node called a value node, or as a two-word subfield of a larger node.  One
6080 of those two words is called the |value| field; it is an integer,
6081 containing either a |scaled| numeric value or the representation of some
6082 other type of quantity. (It might also be subdivided into halfwords, in
6083 which case it is referred to by other names instead of |value|.) The other
6084 word is broken into subfields called |type|, |name_type|, and |link|.  The
6085 |type| field is a quarterword that specifies the variable's type, and
6086 |name_type| is a quarterword from which \MP\ can reconstruct the
6087 variable's name (sometimes by using the |link| field as well).  Thus, only
6088 1.25 words are actually devoted to the value itself; the other
6089 three-quarters of a word are overhead, but they aren't wasted because they
6090 allow \MP\ to deal with sparse arrays and to provide meaningful diagnostics.
6091
6092 In this section we shall be concerned only with the structural aspects of
6093 variables, not their values. Later parts of the program will change the
6094 |type| and |value| fields, but we shall treat those fields as black boxes
6095 whose contents should not be touched.
6096
6097 However, if the |type| field is |mp_structured|, there is no |value| field,
6098 and the second word is broken into two pointer fields called |attr_head|
6099 and |subscr_head|. Those fields point to additional nodes that
6100 contain structural information, as we shall see.
6101
6102 @d subscr_head_loc(A)   (A)+1 /* where |value|, |subscr_head| and |attr_head| are */
6103 @d attr_head(A)   info(subscr_head_loc((A))) /* pointer to attribute info */
6104 @d subscr_head(A)   link(subscr_head_loc((A))) /* pointer to subscript info */
6105 @d value_node_size 2 /* the number of words in a value node */
6106
6107 @ An attribute node is three words long. Two of these words contain |type|
6108 and |value| fields as described above, and the third word contains
6109 additional information:  There is an |attr_loc| field, which contains the
6110 hash address of the token that names this attribute; and there's also a
6111 |parent| field, which points to the value node of |mp_structured| type at the
6112 next higher level (i.e., at the level to which this attribute is
6113 subsidiary).  The |name_type| in an attribute node is `|attr|'.  The
6114 |link| field points to the next attribute with the same parent; these are
6115 arranged in increasing order, so that |attr_loc(link(p))>attr_loc(p)|. The
6116 final attribute node links to the constant |end_attr|, whose |attr_loc|
6117 field is greater than any legal hash address. The |attr_head| in the
6118 parent points to a node whose |name_type| is |mp_structured_root|; this
6119 node represents the null attribute, i.e., the variable that is relevant
6120 when no attributes are attached to the parent. The |attr_head| node is either
6121 a value node, a subscript node, or an attribute node, depending on what
6122 the parent would be if it were not structured; but the subscript and
6123 attribute fields are ignored, so it effectively contains only the data of
6124 a value node. The |link| field in this special node points to an attribute
6125 node whose |attr_loc| field is zero; the latter node represents a collective
6126 subscript `\.{[]}' attached to the parent, and its |link| field points to
6127 the first non-special attribute node (or to |end_attr| if there are none).
6128
6129 A subscript node likewise occupies three words, with |type| and |value| fields
6130 plus extra information; its |name_type| is |subscr|. In this case the
6131 third word is called the |subscript| field, which is a |scaled| integer.
6132 The |link| field points to the subscript node with the next larger
6133 subscript, if any; otherwise the |link| points to the attribute node
6134 for collective subscripts at this level. We have seen that the latter node
6135 contains an upward pointer, so that the parent can be deduced.
6136
6137 The |name_type| in a parent-less value node is |root|, and the |link|
6138 is the hash address of the token that names this value.
6139
6140 In other words, variables have a hierarchical structure that includes
6141 enough threads running around so that the program is able to move easily
6142 between siblings, parents, and children. An example should be helpful:
6143 (The reader is advised to draw a picture while reading the following
6144 description, since that will help to firm up the ideas.)
6145 Suppose that `\.x' and `\.{x.a}' and `\.{x[]b}' and `\.{x5}'
6146 and `\.{x20b}' have been mentioned in a user's program, where
6147 \.{x[]b} has been declared to be of \&{boolean} type. Let |h(x)|, |h(a)|,
6148 and |h(b)| be the hash addresses of \.x, \.a, and~\.b. Then
6149 |eq_type(h(x))=name| and |equiv(h(x))=p|, where |p|~is a two-word value
6150 node with |name_type(p)=root| and |link(p)=h(x)|. We have |type(p)=mp_structured|,
6151 |attr_head(p)=q|, and |subscr_head(p)=r|, where |q| points to a value
6152 node and |r| to a subscript node. (Are you still following this? Use
6153 a pencil to draw a diagram.) The lone variable `\.x' is represented by
6154 |type(q)| and |value(q)|; furthermore
6155 |name_type(q)=mp_structured_root| and |link(q)=q1|, where |q1| points
6156 to an attribute node representing `\.{x[]}'. Thus |name_type(q1)=attr|,
6157 |attr_loc(q1)=collective_subscript=0|, |parent(q1)=p|,
6158 |type(q1)=mp_structured|, |attr_head(q1)=qq|, and |subscr_head(q1)=qq1|;
6159 |qq| is a value node with |type(qq)=mp_numeric_type| (assuming that \.{x5} is
6160 numeric, because |qq| represents `\.{x[]}' with no further attributes),
6161 |name_type(qq)=mp_structured_root|, and
6162 |link(qq)=qq1|. (Now pay attention to the next part.) Node |qq1| is
6163 an attribute node representing `\.{x[][]}', which has never yet
6164 occurred; its |type| field is |undefined|, and its |value| field is
6165 undefined. We have |name_type(qq1)=attr|, |attr_loc(qq1)=collective_subscript|,
6166 |parent(qq1)=q1|, and |link(qq1)=qq2|. Since |qq2| represents
6167 `\.{x[]b}', |type(qq2)=mp_unknown_boolean|; also |attr_loc(qq2)=h(b)|,
6168 |parent(qq2)=q1|, |name_type(qq2)=attr|, |link(qq2)=end_attr|.
6169 (Maybe colored lines will help untangle your picture.)
6170  Node |r| is a subscript node with |type| and |value|
6171 representing `\.{x5}'; |name_type(r)=subscr|, |subscript(r)=5.0|,
6172 and |link(r)=r1| is another subscript node. To complete the picture,
6173 see if you can guess what |link(r1)| is; give up? It's~|q1|.
6174 Furthermore |subscript(r1)=20.0|, |name_type(r1)=subscr|,
6175 |type(r1)=mp_structured|, |attr_head(r1)=qqq|, |subscr_head(r1)=qqq1|,
6176 and we finish things off with three more nodes
6177 |qqq|, |qqq1|, and |qqq2| hung onto~|r1|. (Perhaps you should start again
6178 with a larger sheet of paper.) The value of variable \.{x20b}
6179 appears in node~|qqq2|, as you can well imagine.
6180
6181 If the example in the previous paragraph doesn't make things crystal
6182 clear, a glance at some of the simpler subroutines below will reveal how
6183 things work out in practice.
6184
6185 The only really unusual thing about these conventions is the use of
6186 collective subscript attributes. The idea is to avoid repeating a lot of
6187 type information when many elements of an array are identical macros
6188 (for which distinct values need not be stored) or when they don't have
6189 all of the possible attributes. Branches of the structure below collective
6190 subscript attributes do not carry actual values except for macro identifiers;
6191 branches of the structure below subscript nodes do not carry significant
6192 information in their collective subscript attributes.
6193
6194 @d attr_loc_loc(A) ((A)+2) /* where the |attr_loc| and |parent| fields are */
6195 @d attr_loc(A) info(attr_loc_loc((A))) /* hash address of this attribute */
6196 @d parent(A) link(attr_loc_loc((A))) /* pointer to |mp_structured| variable */
6197 @d subscript_loc(A) ((A)+2) /* where the |subscript| field lives */
6198 @d subscript(A) mp->mem[subscript_loc((A))].sc /* subscript of this variable */
6199 @d attr_node_size 3 /* the number of words in an attribute node */
6200 @d subscr_node_size 3 /* the number of words in a subscript node */
6201 @d collective_subscript 0 /* code for the attribute `\.{[]}' */
6202
6203 @<Initialize table...@>=
6204 attr_loc(end_attr)=hash_end+1; parent(end_attr)=null;
6205
6206 @ Variables of type \&{pair} will have values that point to four-word
6207 nodes containing two numeric values. The first of these values has
6208 |name_type=mp_x_part_sector| and the second has |name_type=mp_y_part_sector|;
6209 the |link| in the first points back to the node whose |value| points
6210 to this four-word node.
6211
6212 Variables of type \&{transform} are similar, but in this case their
6213 |value| points to a 12-word node containing six values, identified by
6214 |x_part_sector|, |y_part_sector|, |mp_xx_part_sector|, |mp_xy_part_sector|,
6215 |mp_yx_part_sector|, and |mp_yy_part_sector|.
6216 Finally, variables of type \&{color} have three values in six words
6217 identified by |mp_red_part_sector|, |mp_green_part_sector|, and |mp_blue_part_sector|.
6218
6219 When an entire structured variable is saved, the |root| indication
6220 is temporarily replaced by |saved_root|.
6221
6222 Some variables have no name; they just are used for temporary storage
6223 while expressions are being evaluated. We call them {\sl capsules}.
6224
6225 @d x_part_loc(A) (A) /* where the \&{xpart} is found in a pair or transform node */
6226 @d y_part_loc(A) ((A)+2) /* where the \&{ypart} is found in a pair or transform node */
6227 @d xx_part_loc(A) ((A)+4) /* where the \&{xxpart} is found in a transform node */
6228 @d xy_part_loc(A) ((A)+6) /* where the \&{xypart} is found in a transform node */
6229 @d yx_part_loc(A) ((A)+8) /* where the \&{yxpart} is found in a transform node */
6230 @d yy_part_loc(A) ((A)+10) /* where the \&{yypart} is found in a transform node */
6231 @d red_part_loc(A) (A) /* where the \&{redpart} is found in a color node */
6232 @d green_part_loc(A) ((A)+2) /* where the \&{greenpart} is found in a color node */
6233 @d blue_part_loc(A) ((A)+4) /* where the \&{bluepart} is found in a color node */
6234 @d cyan_part_loc(A) (A) /* where the \&{cyanpart} is found in a color node */
6235 @d magenta_part_loc(A) ((A)+2) /* where the \&{magentapart} is found in a color node */
6236 @d yellow_part_loc(A) ((A)+4) /* where the \&{yellowpart} is found in a color node */
6237 @d black_part_loc(A) ((A)+6) /* where the \&{blackpart} is found in a color node */
6238 @d grey_part_loc(A) (A) /* where the \&{greypart} is found in a color node */
6239 @#
6240 @d pair_node_size 4 /* the number of words in a pair node */
6241 @d transform_node_size 12 /* the number of words in a transform node */
6242 @d color_node_size 6 /* the number of words in a color node */
6243 @d cmykcolor_node_size 8 /* the number of words in a color node */
6244
6245 @<Glob...@>=
6246 small_number big_node_size[mp_pair_type+1];
6247 small_number sector0[mp_pair_type+1];
6248 small_number sector_offset[mp_black_part_sector+1];
6249
6250 @ The |sector0| array gives for each big node type, |name_type| values
6251 for its first subfield; the |sector_offset| array gives for each
6252 |name_type| value, the offset from the first subfield in words;
6253 and the |big_node_size| array gives the size in words for each type of
6254 big node.
6255
6256 @<Set init...@>=
6257 mp->big_node_size[mp_transform_type]=transform_node_size;
6258 mp->big_node_size[mp_pair_type]=pair_node_size;
6259 mp->big_node_size[mp_color_type]=color_node_size;
6260 mp->big_node_size[mp_cmykcolor_type]=cmykcolor_node_size;
6261 mp->sector0[mp_transform_type]=mp_x_part_sector;
6262 mp->sector0[mp_pair_type]=mp_x_part_sector;
6263 mp->sector0[mp_color_type]=mp_red_part_sector;
6264 mp->sector0[mp_cmykcolor_type]=mp_cyan_part_sector;
6265 for (k=mp_x_part_sector;k<= mp_yy_part_sector;k++ ) {
6266   mp->sector_offset[k]=2*(k-mp_x_part_sector);
6267 }
6268 for (k=mp_red_part_sector;k<= mp_blue_part_sector ; k++) {
6269   mp->sector_offset[k]=2*(k-mp_red_part_sector);
6270 }
6271 for (k=mp_cyan_part_sector;k<= mp_black_part_sector;k++ ) {
6272   mp->sector_offset[k]=2*(k-mp_cyan_part_sector);
6273 }
6274
6275 @ If |type(p)=mp_pair_type| or |mp_transform_type| and if |value(p)=null|, the
6276 procedure call |init_big_node(p)| will allocate a pair or transform node
6277 for~|p|.  The individual parts of such nodes are initially of type
6278 |mp_independent|.
6279
6280 @c 
6281 void mp_init_big_node (MP mp,pointer p) {
6282   pointer q; /* the new node */
6283   small_number s; /* its size */
6284   s=mp->big_node_size[type(p)]; q=mp_get_node(mp, s);
6285   do {  
6286     s=s-2; 
6287     @<Make variable |q+s| newly independent@>;
6288     name_type(q+s)=halfp(s)+mp->sector0[type(p)]; 
6289     link(q+s)=null;
6290   } while (s!=0);
6291   link(q)=p; value(p)=q;
6292 }
6293
6294 @ The |id_transform| function creates a capsule for the
6295 identity transformation.
6296
6297 @c 
6298 pointer mp_id_transform (MP mp) {
6299   pointer p,q,r; /* list manipulation registers */
6300   p=mp_get_node(mp, value_node_size); type(p)=mp_transform_type;
6301   name_type(p)=mp_capsule; value(p)=null; mp_init_big_node(mp, p); q=value(p);
6302   r=q+transform_node_size;
6303   do {  
6304     r=r-2;
6305     type(r)=mp_known; value(r)=0;
6306   } while (r!=q);
6307   value(xx_part_loc(q))=unity; 
6308   value(yy_part_loc(q))=unity;
6309   return p;
6310 }
6311
6312 @ Tokens are of type |tag_token| when they first appear, but they point
6313 to |null| until they are first used as the root of a variable.
6314 The following subroutine establishes the root node on such grand occasions.
6315
6316 @c 
6317 void mp_new_root (MP mp,pointer x) {
6318   pointer p; /* the new node */
6319   p=mp_get_node(mp, value_node_size); type(p)=undefined; name_type(p)=mp_root;
6320   link(p)=x; equiv(x)=p;
6321 }
6322
6323 @ These conventions for variable representation are illustrated by the
6324 |print_variable_name| routine, which displays the full name of a
6325 variable given only a pointer to its two-word value packet.
6326
6327 @<Declarations@>=
6328 void mp_print_variable_name (MP mp, pointer p);
6329
6330 @ @c 
6331 void mp_print_variable_name (MP mp, pointer p) {
6332   pointer q; /* a token list that will name the variable's suffix */
6333   pointer r; /* temporary for token list creation */
6334   while ( name_type(p)>=mp_x_part_sector ) {
6335     @<Preface the output with a part specifier; |return| in the
6336       case of a capsule@>;
6337   }
6338   q=null;
6339   while ( name_type(p)>mp_saved_root ) {
6340     @<Ascend one level, pushing a token onto list |q|
6341      and replacing |p| by its parent@>;
6342   }
6343   r=mp_get_avail(mp); info(r)=link(p); link(r)=q;
6344   if ( name_type(p)==mp_saved_root ) mp_print(mp, "(SAVED)");
6345 @.SAVED@>
6346   mp_show_token_list(mp, r,null,el_gordo,mp->tally); 
6347   mp_flush_token_list(mp, r);
6348 }
6349
6350 @ @<Ascend one level, pushing a token onto list |q|...@>=
6351
6352   if ( name_type(p)==mp_subscr ) { 
6353     r=mp_new_num_tok(mp, subscript(p));
6354     do {  
6355       p=link(p);
6356     } while (name_type(p)!=mp_attr);
6357   } else if ( name_type(p)==mp_structured_root ) {
6358     p=link(p); goto FOUND;
6359   } else { 
6360     if ( name_type(p)!=mp_attr ) mp_confusion(mp, "var");
6361 @:this can't happen var}{\quad var@>
6362     r=mp_get_avail(mp); info(r)=attr_loc(p);
6363   }
6364   link(r)=q; q=r;
6365 FOUND:  
6366   p=parent(p);
6367 }
6368
6369 @ @<Preface the output with a part specifier...@>=
6370 { switch (name_type(p)) {
6371   case mp_x_part_sector: mp_print_char(mp, 'x'); break;
6372   case mp_y_part_sector: mp_print_char(mp, 'y'); break;
6373   case mp_xx_part_sector: mp_print(mp, "xx"); break;
6374   case mp_xy_part_sector: mp_print(mp, "xy"); break;
6375   case mp_yx_part_sector: mp_print(mp, "yx"); break;
6376   case mp_yy_part_sector: mp_print(mp, "yy"); break;
6377   case mp_red_part_sector: mp_print(mp, "red"); break;
6378   case mp_green_part_sector: mp_print(mp, "green"); break;
6379   case mp_blue_part_sector: mp_print(mp, "blue"); break;
6380   case mp_cyan_part_sector: mp_print(mp, "cyan"); break;
6381   case mp_magenta_part_sector: mp_print(mp, "magenta"); break;
6382   case mp_yellow_part_sector: mp_print(mp, "yellow"); break;
6383   case mp_black_part_sector: mp_print(mp, "black"); break;
6384   case mp_grey_part_sector: mp_print(mp, "grey"); break;
6385   case mp_capsule: 
6386     mp_print(mp, "%CAPSULE"); mp_print_int(mp, p-null); return;
6387     break;
6388 @.CAPSULE@>
6389   } /* there are no other cases */
6390   mp_print(mp, "part "); 
6391   p=link(p-mp->sector_offset[name_type(p)]);
6392 }
6393
6394 @ The |interesting| function returns |true| if a given variable is not
6395 in a capsule, or if the user wants to trace capsules.
6396
6397 @c 
6398 boolean mp_interesting (MP mp,pointer p) {
6399   small_number t; /* a |name_type| */
6400   if ( mp->internal[mp_tracing_capsules]>0 ) {
6401     return true;
6402   } else { 
6403     t=name_type(p);
6404     if ( t>=mp_x_part_sector ) if ( t!=mp_capsule )
6405       t=name_type(link(p-mp->sector_offset[t]));
6406     return (t!=mp_capsule);
6407   }
6408 }
6409
6410 @ Now here is a subroutine that converts an unstructured type into an
6411 equivalent structured type, by inserting a |mp_structured| node that is
6412 capable of growing. This operation is done only when |name_type(p)=root|,
6413 |subscr|, or |attr|.
6414
6415 The procedure returns a pointer to the new node that has taken node~|p|'s
6416 place in the structure. Node~|p| itself does not move, nor are its
6417 |value| or |type| fields changed in any way.
6418
6419 @c 
6420 pointer mp_new_structure (MP mp,pointer p) {
6421   pointer q,r=0; /* list manipulation registers */
6422   switch (name_type(p)) {
6423   case mp_root: 
6424     q=link(p); r=mp_get_node(mp, value_node_size); equiv(q)=r;
6425     break;
6426   case mp_subscr: 
6427     @<Link a new subscript node |r| in place of node |p|@>;
6428     break;
6429   case mp_attr: 
6430     @<Link a new attribute node |r| in place of node |p|@>;
6431     break;
6432   default: 
6433     mp_confusion(mp, "struct");
6434 @:this can't happen struct}{\quad struct@>
6435     break;
6436   }
6437   link(r)=link(p); type(r)=mp_structured; name_type(r)=name_type(p);
6438   attr_head(r)=p; name_type(p)=mp_structured_root;
6439   q=mp_get_node(mp, attr_node_size); link(p)=q; subscr_head(r)=q;
6440   parent(q)=r; type(q)=undefined; name_type(q)=mp_attr; link(q)=end_attr;
6441   attr_loc(q)=collective_subscript; 
6442   return r;
6443 };
6444
6445 @ @<Link a new subscript node |r| in place of node |p|@>=
6446
6447   q=p;
6448   do {  
6449     q=link(q);
6450   } while (name_type(q)!=mp_attr);
6451   q=parent(q); r=subscr_head_loc(q); /* |link(r)=subscr_head(q)| */
6452   do {  
6453     q=r; r=link(r);
6454   } while (r!=p);
6455   r=mp_get_node(mp, subscr_node_size);
6456   link(q)=r; subscript(r)=subscript(p);
6457 }
6458
6459 @ If the attribute is |collective_subscript|, there are two pointers to
6460 node~|p|, so we must change both of them.
6461
6462 @<Link a new attribute node |r| in place of node |p|@>=
6463
6464   q=parent(p); r=attr_head(q);
6465   do {  
6466     q=r; r=link(r);
6467   } while (r!=p);
6468   r=mp_get_node(mp, attr_node_size); link(q)=r;
6469   mp->mem[attr_loc_loc(r)]=mp->mem[attr_loc_loc(p)]; /* copy |attr_loc| and |parent| */
6470   if ( attr_loc(p)==collective_subscript ) { 
6471     q=subscr_head_loc(parent(p));
6472     while ( link(q)!=p ) q=link(q);
6473     link(q)=r;
6474   }
6475 }
6476
6477 @ The |find_variable| routine is given a pointer~|t| to a nonempty token
6478 list of suffixes; it returns a pointer to the corresponding two-word
6479 value. For example, if |t| points to token \.x followed by a numeric
6480 token containing the value~7, |find_variable| finds where the value of
6481 \.{x7} is stored in memory. This may seem a simple task, and it
6482 usually is, except when \.{x7} has never been referenced before.
6483 Indeed, \.x may never have even been subscripted before; complexities
6484 arise with respect to updating the collective subscript information.
6485
6486 If a macro type is detected anywhere along path~|t|, or if the first
6487 item on |t| isn't a |tag_token|, the value |null| is returned.
6488 Otherwise |p| will be a non-null pointer to a node such that
6489 |undefined<type(p)<mp_structured|.
6490
6491 @d abort_find { return null; }
6492
6493 @c 
6494 pointer mp_find_variable (MP mp,pointer t) {
6495   pointer p,q,r,s; /* nodes in the ``value'' line */
6496   pointer pp,qq,rr,ss; /* nodes in the ``collective'' line */
6497   integer n; /* subscript or attribute */
6498   memory_word save_word; /* temporary storage for a word of |mem| */
6499 @^inner loop@>
6500   p=info(t); t=link(t);
6501   if ( (eq_type(p) % outer_tag) != tag_token ) abort_find;
6502   if ( equiv(p)==null ) mp_new_root(mp, p);
6503   p=equiv(p); pp=p;
6504   while ( t!=null ) { 
6505     @<Make sure that both nodes |p| and |pp| are of |mp_structured| type@>;
6506     if ( t<mp->hi_mem_min ) {
6507       @<Descend one level for the subscript |value(t)|@>
6508     } else {
6509       @<Descend one level for the attribute |info(t)|@>;
6510     }
6511     t=link(t);
6512   }
6513   if ( type(pp)>=mp_structured ) {
6514     if ( type(pp)==mp_structured ) pp=attr_head(pp); else abort_find;
6515   }
6516   if ( type(p)==mp_structured ) p=attr_head(p);
6517   if ( type(p)==undefined ) { 
6518     if ( type(pp)==undefined ) { type(pp)=mp_numeric_type; value(pp)=null; };
6519     type(p)=type(pp); value(p)=null;
6520   };
6521   return p;
6522 }
6523
6524 @ Although |pp| and |p| begin together, they diverge when a subscript occurs;
6525 |pp|~stays in the collective line while |p|~goes through actual subscript
6526 values.
6527
6528 @<Make sure that both nodes |p| and |pp|...@>=
6529 if ( type(pp)!=mp_structured ) { 
6530   if ( type(pp)>mp_structured ) abort_find;
6531   ss=mp_new_structure(mp, pp);
6532   if ( p==pp ) p=ss;
6533   pp=ss;
6534 }; /* now |type(pp)=mp_structured| */
6535 if ( type(p)!=mp_structured ) /* it cannot be |>mp_structured| */
6536   p=mp_new_structure(mp, p) /* now |type(p)=mp_structured| */
6537
6538 @ We want this part of the program to be reasonably fast, in case there are
6539 @^inner loop@>
6540 lots of subscripts at the same level of the data structure. Therefore
6541 we store an ``infinite'' value in the word that appears at the end of the
6542 subscript list, even though that word isn't part of a subscript node.
6543
6544 @<Descend one level for the subscript |value(t)|@>=
6545
6546   n=value(t);
6547   pp=link(attr_head(pp)); /* now |attr_loc(pp)=collective_subscript| */
6548   q=link(attr_head(p)); save_word=mp->mem[subscript_loc(q)];
6549   subscript(q)=el_gordo; s=subscr_head_loc(p); /* |link(s)=subscr_head(p)| */
6550   do {  
6551     r=s; s=link(s);
6552   } while (n>subscript(s));
6553   if ( n==subscript(s) ) {
6554     p=s;
6555   } else { 
6556     p=mp_get_node(mp, subscr_node_size); link(r)=p; link(p)=s;
6557     subscript(p)=n; name_type(p)=mp_subscr; type(p)=undefined;
6558   }
6559   mp->mem[subscript_loc(q)]=save_word;
6560 }
6561
6562 @ @<Descend one level for the attribute |info(t)|@>=
6563
6564   n=info(t);
6565   ss=attr_head(pp);
6566   do {  
6567     rr=ss; ss=link(ss);
6568   } while (n>attr_loc(ss));
6569   if ( n<attr_loc(ss) ) { 
6570     qq=mp_get_node(mp, attr_node_size); link(rr)=qq; link(qq)=ss;
6571     attr_loc(qq)=n; name_type(qq)=mp_attr; type(qq)=undefined;
6572     parent(qq)=pp; ss=qq;
6573   }
6574   if ( p==pp ) { 
6575     p=ss; pp=ss;
6576   } else { 
6577     pp=ss; s=attr_head(p);
6578     do {  
6579       r=s; s=link(s);
6580     } while (n>attr_loc(s));
6581     if ( n==attr_loc(s) ) {
6582       p=s;
6583     } else { 
6584       q=mp_get_node(mp, attr_node_size); link(r)=q; link(q)=s;
6585       attr_loc(q)=n; name_type(q)=mp_attr; type(q)=undefined;
6586       parent(q)=p; p=q;
6587     }
6588   }
6589 }
6590
6591 @ Variables lose their former values when they appear in a type declaration,
6592 or when they are defined to be macros or \&{let} equal to something else.
6593 A subroutine will be defined later that recycles the storage associated
6594 with any particular |type| or |value|; our goal now is to study a higher
6595 level process called |flush_variable|, which selectively frees parts of a
6596 variable structure.
6597
6598 This routine has some complexity because of examples such as
6599 `\hbox{\tt numeric x[]a[]b}'
6600 which recycles all variables of the form \.{x[i]a[j]b} (and no others), while
6601 `\hbox{\tt vardef x[]a[]=...}'
6602 discards all variables of the form \.{x[i]a[j]} followed by an arbitrary
6603 suffix, except for the collective node \.{x[]a[]} itself. The obvious way
6604 to handle such examples is to use recursion; so that's what we~do.
6605 @^recursion@>
6606
6607 Parameter |p| points to the root information of the variable;
6608 parameter |t| points to a list of one-word nodes that represent
6609 suffixes, with |info=collective_subscript| for subscripts.
6610
6611 @<Declarations@>=
6612 @<Declare subroutines for printing expressions@>
6613 @<Declare basic dependency-list subroutines@>
6614 @<Declare the recycling subroutines@>
6615 void mp_flush_cur_exp (MP mp,scaled v) ;
6616 @<Declare the procedure called |flush_below_variable|@>
6617
6618 @ @c 
6619 void mp_flush_variable (MP mp,pointer p, pointer t, boolean discard_suffixes) {
6620   pointer q,r; /* list manipulation */
6621   halfword n; /* attribute to match */
6622   while ( t!=null ) { 
6623     if ( type(p)!=mp_structured ) return;
6624     n=info(t); t=link(t);
6625     if ( n==collective_subscript ) { 
6626       r=subscr_head_loc(p); q=link(r); /* |q=subscr_head(p)| */
6627       while ( name_type(q)==mp_subscr ){ 
6628         mp_flush_variable(mp, q,t,discard_suffixes);
6629         if ( t==null ) {
6630           if ( type(q)==mp_structured ) r=q;
6631           else  { link(r)=link(q); mp_free_node(mp, q,subscr_node_size);   }
6632         } else {
6633           r=q;
6634         }
6635         q=link(r);
6636       }
6637     }
6638     p=attr_head(p);
6639     do {  
6640       r=p; p=link(p);
6641     } while (attr_loc(p)<n);
6642     if ( attr_loc(p)!=n ) return;
6643   }
6644   if ( discard_suffixes ) {
6645     mp_flush_below_variable(mp, p);
6646   } else { 
6647     if ( type(p)==mp_structured ) p=attr_head(p);
6648     mp_recycle_value(mp, p);
6649   }
6650 }
6651
6652 @ The next procedure is simpler; it wipes out everything but |p| itself,
6653 which becomes undefined.
6654
6655 @<Declare the procedure called |flush_below_variable|@>=
6656 void mp_flush_below_variable (MP mp, pointer p);
6657
6658 @ @c
6659 void mp_flush_below_variable (MP mp,pointer p) {
6660    pointer q,r; /* list manipulation registers */
6661   if ( type(p)!=mp_structured ) {
6662     mp_recycle_value(mp, p); /* this sets |type(p)=undefined| */
6663   } else { 
6664     q=subscr_head(p);
6665     while ( name_type(q)==mp_subscr ) { 
6666       mp_flush_below_variable(mp, q); r=q; q=link(q);
6667       mp_free_node(mp, r,subscr_node_size);
6668     }
6669     r=attr_head(p); q=link(r); mp_recycle_value(mp, r);
6670     if ( name_type(p)<=mp_saved_root ) mp_free_node(mp, r,value_node_size);
6671     else mp_free_node(mp, r,subscr_node_size);
6672     /* we assume that |subscr_node_size=attr_node_size| */
6673     do {  
6674       mp_flush_below_variable(mp, q); r=q; q=link(q); mp_free_node(mp, r,attr_node_size);
6675     } while (q!=end_attr);
6676     type(p)=undefined;
6677   }
6678 }
6679
6680 @ Just before assigning a new value to a variable, we will recycle the
6681 old value and make the old value undefined. The |und_type| routine
6682 determines what type of undefined value should be given, based on
6683 the current type before recycling.
6684
6685 @c 
6686 small_number mp_und_type (MP mp,pointer p) { 
6687   switch (type(p)) {
6688   case undefined: case mp_vacuous:
6689     return undefined;
6690   case mp_boolean_type: case mp_unknown_boolean:
6691     return mp_unknown_boolean;
6692   case mp_string_type: case mp_unknown_string:
6693     return mp_unknown_string;
6694   case mp_pen_type: case mp_unknown_pen:
6695     return mp_unknown_pen;
6696   case mp_path_type: case mp_unknown_path:
6697     return mp_unknown_path;
6698   case mp_picture_type: case mp_unknown_picture:
6699     return mp_unknown_picture;
6700   case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
6701   case mp_pair_type: case mp_numeric_type: 
6702     return type(p);
6703   case mp_known: case mp_dependent: case mp_proto_dependent: case mp_independent:
6704     return mp_numeric_type;
6705   } /* there are no other cases */
6706   return 0;
6707 }
6708
6709 @ The |clear_symbol| routine is used when we want to redefine the equivalent
6710 of a symbolic token. It must remove any variable structure or macro
6711 definition that is currently attached to that symbol. If the |saving|
6712 parameter is true, a subsidiary structure is saved instead of destroyed.
6713
6714 @c 
6715 void mp_clear_symbol (MP mp,pointer p, boolean saving) {
6716   pointer q; /* |equiv(p)| */
6717   q=equiv(p);
6718   switch (eq_type(p) % outer_tag)  {
6719   case defined_macro:
6720   case secondary_primary_macro:
6721   case tertiary_secondary_macro:
6722   case expression_tertiary_macro: 
6723     if ( ! saving ) mp_delete_mac_ref(mp, q);
6724     break;
6725   case tag_token:
6726     if ( q!=null ) {
6727       if ( saving ) {
6728         name_type(q)=mp_saved_root;
6729       } else { 
6730         mp_flush_below_variable(mp, q); mp_free_node(mp,q,value_node_size); 
6731       }
6732     }
6733     break;
6734   default:
6735     break;
6736   }
6737   mp->eqtb[p]=mp->eqtb[frozen_undefined];
6738 };
6739
6740 @* \[16] Saving and restoring equivalents.
6741 The nested structure given by \&{begingroup} and \&{endgroup}
6742 allows |eqtb| entries to be saved and restored, so that temporary changes
6743 can be made without difficulty.  When the user requests a current value to
6744 be saved, \MP\ puts that value into its ``save stack.'' An appearance of
6745 \&{endgroup} ultimately causes the old values to be removed from the save
6746 stack and put back in their former places.
6747
6748 The save stack is a linked list containing three kinds of entries,
6749 distinguished by their |info| fields. If |p| points to a saved item,
6750 then
6751
6752 \smallskip\hang
6753 |info(p)=0| stands for a group boundary; each \&{begingroup} contributes
6754 such an item to the save stack and each \&{endgroup} cuts back the stack
6755 until the most recent such entry has been removed.
6756
6757 \smallskip\hang
6758 |info(p)=q|, where |1<=q<=hash_end|, means that |mem[p+1]| holds the former
6759 contents of |eqtb[q]|. Such save stack entries are generated by \&{save}
6760 commands or suitable \&{interim} commands.
6761
6762 \smallskip\hang
6763 |info(p)=hash_end+q|, where |q>0|, means that |value(p)| is a |scaled|
6764 integer to be restored to internal parameter number~|q|. Such entries
6765 are generated by \&{interim} commands.
6766
6767 \smallskip\noindent
6768 The global variable |save_ptr| points to the top item on the save stack.
6769
6770 @d save_node_size 2 /* number of words per non-boundary save-stack node */
6771 @d saved_equiv(A) mp->mem[(A)+1].hh /* where an |eqtb| entry gets saved */
6772 @d save_boundary_item(A) { (A)=mp_get_avail(mp); info((A))=0;
6773   link((A))=mp->save_ptr; mp->save_ptr=(A);
6774   }
6775
6776 @<Glob...@>=
6777 pointer save_ptr; /* the most recently saved item */
6778
6779 @ @<Set init...@>=mp->save_ptr=null;
6780
6781 @ The |save_variable| routine is given a hash address |q|; it salts this
6782 address in the save stack, together with its current equivalent,
6783 then makes token~|q| behave as though it were brand new.
6784
6785 Nothing is stacked when |save_ptr=null|, however; there's no way to remove
6786 things from the stack when the program is not inside a group, so there's
6787 no point in wasting the space.
6788
6789 @c void mp_save_variable (MP mp,pointer q) {
6790   pointer p; /* temporary register */
6791   if ( mp->save_ptr!=null ){ 
6792     p=mp_get_node(mp, save_node_size); info(p)=q; link(p)=mp->save_ptr;
6793     saved_equiv(p)=mp->eqtb[q]; mp->save_ptr=p;
6794   }
6795   mp_clear_symbol(mp, q,(mp->save_ptr!=null));
6796 }
6797
6798 @ Similarly, |save_internal| is given the location |q| of an internal
6799 quantity like |mp_tracing_pens|. It creates a save stack entry of the
6800 third kind.
6801
6802 @c void mp_save_internal (MP mp,halfword q) {
6803   pointer p; /* new item for the save stack */
6804   if ( mp->save_ptr!=null ){ 
6805      p=mp_get_node(mp, save_node_size); info(p)=hash_end+q;
6806     link(p)=mp->save_ptr; value(p)=mp->internal[q]; mp->save_ptr=p;
6807   }
6808 }
6809
6810 @ At the end of a group, the |unsave| routine restores all of the saved
6811 equivalents in reverse order. This routine will be called only when there
6812 is at least one boundary item on the save stack.
6813
6814 @c 
6815 void mp_unsave (MP mp) {
6816   pointer q; /* index to saved item */
6817   pointer p; /* temporary register */
6818   while ( info(mp->save_ptr)!=0 ) {
6819     q=info(mp->save_ptr);
6820     if ( q>hash_end ) {
6821       if ( mp->internal[mp_tracing_restores]>0 ) {
6822         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6823         mp_print(mp, mp->int_name[q-(hash_end)]); mp_print_char(mp, '=');
6824         mp_print_scaled(mp, value(mp->save_ptr)); mp_print_char(mp, '}');
6825         mp_end_diagnostic(mp, false);
6826       }
6827       mp->internal[q-(hash_end)]=value(mp->save_ptr);
6828     } else { 
6829       if ( mp->internal[mp_tracing_restores]>0 ) {
6830         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6831         mp_print_text(q); mp_print_char(mp, '}');
6832         mp_end_diagnostic(mp, false);
6833       }
6834       mp_clear_symbol(mp, q,false);
6835       mp->eqtb[q]=saved_equiv(mp->save_ptr);
6836       if ( eq_type(q) % outer_tag==tag_token ) {
6837         p=equiv(q);
6838         if ( p!=null ) name_type(p)=mp_root;
6839       }
6840     }
6841     p=link(mp->save_ptr); 
6842     mp_free_node(mp, mp->save_ptr,save_node_size); mp->save_ptr=p;
6843   }
6844   p=link(mp->save_ptr); free_avail(mp->save_ptr); mp->save_ptr=p;
6845 }
6846
6847 @* \[17] Data structures for paths.
6848 When a \MP\ user specifies a path, \MP\ will create a list of knots
6849 and control points for the associated cubic spline curves. If the
6850 knots are $z_0$, $z_1$, \dots, $z_n$, there are control points
6851 $z_k^+$ and $z_{k+1}^-$ such that the cubic splines between knots
6852 $z_k$ and $z_{k+1}$ are defined by B\'ezier's formula
6853 @:Bezier}{B\'ezier, Pierre Etienne@>
6854 $$\eqalign{z(t)&=B(z_k,z_k^+,z_{k+1}^-,z_{k+1};t)\cr
6855 &=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_{k+1}^-+t^3z_{k+1}\cr}$$
6856 for |0<=t<=1|.
6857
6858 There is a 8-word node for each knot $z_k$, containing one word of
6859 control information and six words for the |x| and |y| coordinates of
6860 $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears in the
6861 |left_type| and |right_type| fields, which each occupy a quarter of
6862 the first word in the node; they specify properties of the curve as it
6863 enters and leaves the knot. There's also a halfword |link| field,
6864 which points to the following knot, and a final supplementary word (of
6865 which only a quarter is used).
6866
6867 If the path is a closed contour, knots 0 and |n| are identical;
6868 i.e., the |link| in knot |n-1| points to knot~0. But if the path
6869 is not closed, the |left_type| of knot~0 and the |right_type| of knot~|n|
6870 are equal to |endpoint|. In the latter case the |link| in knot~|n| points
6871 to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used.
6872
6873 @d left_type(A)   mp->mem[(A)].hh.b0 /* characterizes the path entering this knot */
6874 @d right_type(A)   mp->mem[(A)].hh.b1 /* characterizes the path leaving this knot */
6875 @d x_coord(A)   mp->mem[(A)+1].sc /* the |x| coordinate of this knot */
6876 @d y_coord(A)   mp->mem[(A)+2].sc /* the |y| coordinate of this knot */
6877 @d left_x(A)   mp->mem[(A)+3].sc /* the |x| coordinate of previous control point */
6878 @d left_y(A)   mp->mem[(A)+4].sc /* the |y| coordinate of previous control point */
6879 @d right_x(A)   mp->mem[(A)+5].sc /* the |x| coordinate of next control point */
6880 @d right_y(A)   mp->mem[(A)+6].sc /* the |y| coordinate of next control point */
6881 @d x_loc(A)   ((A)+1) /* where the |x| coordinate is stored in a knot */
6882 @d y_loc(A)   ((A)+2) /* where the |y| coordinate is stored in a knot */
6883 @d knot_coord(A)   mp->mem[(A)].sc /* |x| or |y| coordinate given |x_loc| or |y_loc| */
6884 @d left_coord(A)   mp->mem[(A)+2].sc
6885   /* coordinate of previous control point given |x_loc| or |y_loc| */
6886 @d right_coord(A)   mp->mem[(A)+4].sc
6887   /* coordinate of next control point given |x_loc| or |y_loc| */
6888 @d knot_node_size 8 /* number of words in a knot node */
6889
6890 @<Types...@>=
6891 enum mp_knot_type {
6892  mp_endpoint=0, /* |left_type| at path beginning and |right_type| at path end */
6893  mp_explicit, /* |left_type| or |right_type| when control points are known */
6894  mp_given, /* |left_type| or |right_type| when a direction is given */
6895  mp_curl, /* |left_type| or |right_type| when a curl is desired */
6896  mp_open, /* |left_type| or |right_type| when \MP\ should choose the direction */
6897  mp_end_cycle
6898 } ;
6899
6900 @ Before the B\'ezier control points have been calculated, the memory
6901 space they will ultimately occupy is taken up by information that can be
6902 used to compute them. There are four cases:
6903
6904 \yskip
6905 \textindent{$\bullet$} If |right_type=mp_open|, the curve should leave
6906 the knot in the same direction it entered; \MP\ will figure out a
6907 suitable direction.
6908
6909 \yskip
6910 \textindent{$\bullet$} If |right_type=mp_curl|, the curve should leave the
6911 knot in a direction depending on the angle at which it enters the next
6912 knot and on the curl parameter stored in |right_curl|.
6913
6914 \yskip
6915 \textindent{$\bullet$} If |right_type=mp_given|, the curve should leave the
6916 knot in a nonzero direction stored as an |angle| in |right_given|.
6917
6918 \yskip
6919 \textindent{$\bullet$} If |right_type=mp_explicit|, the B\'ezier control
6920 point for leaving this knot has already been computed; it is in the
6921 |right_x| and |right_y| fields.
6922
6923 \yskip\noindent
6924 The rules for |left_type| are similar, but they refer to the curve entering
6925 the knot, and to \\{left} fields instead of \\{right} fields.
6926
6927 Non-|explicit| control points will be chosen based on ``tension'' parameters
6928 in the |left_tension| and |right_tension| fields. The
6929 `\&{atleast}' option is represented by negative tension values.
6930 @:at_least_}{\&{atleast} primitive@>
6931
6932 For example, the \MP\ path specification
6933 $$\.{z0..z1..tension atleast 1..\{curl 2\}z2..z3\{-1,-2\}..tension
6934   3 and 4..p},$$
6935 where \.p is the path `\.{z4..controls z45 and z54..z5}', will be represented
6936 by the six knots
6937 \def\lodash{\hbox to 1.1em{\thinspace\hrulefill\thinspace}}
6938 $$\vbox{\halign{#\hfil&&\qquad#\hfil\cr
6939 |left_type|&\\{left} info&|x_coord,y_coord|&|right_type|&\\{right} info\cr
6940 \noalign{\yskip}
6941 |endpoint|&\lodash$,\,$\lodash&$x_0,y_0$&|curl|&$1.0,1.0$\cr
6942 |open|&\lodash$,1.0$&$x_1,y_1$&|open|&\lodash$,-1.0$\cr
6943 |curl|&$2.0,-1.0$&$x_2,y_2$&|curl|&$2.0,1.0$\cr
6944 |given|&$d,1.0$&$x_3,y_3$&|given|&$d,3.0$\cr
6945 |open|&\lodash$,4.0$&$x_4,y_4$&|explicit|&$x_{45},y_{45}$\cr
6946 |explicit|&$x_{54},y_{54}$&$x_5,y_5$&|endpoint|&\lodash$,\,$\lodash\cr}}$$
6947 Here |d| is the |angle| obtained by calling |n_arg(-unity,-two)|.
6948 Of course, this example is more complicated than anything a normal user
6949 would ever write.
6950
6951 These types must satisfy certain restrictions because of the form of \MP's
6952 path syntax:
6953 (i)~|open| type never appears in the same node together with |endpoint|,
6954 |given|, or |curl|.
6955 (ii)~The |right_type| of a node is |explicit| if and only if the
6956 |left_type| of the following node is |explicit|.
6957 (iii)~|endpoint| types occur only at the ends, as mentioned above.
6958
6959 @d left_curl left_x /* curl information when entering this knot */
6960 @d left_given left_x /* given direction when entering this knot */
6961 @d left_tension left_y /* tension information when entering this knot */
6962 @d right_curl right_x /* curl information when leaving this knot */
6963 @d right_given right_x /* given direction when leaving this knot */
6964 @d right_tension right_y /* tension information when leaving this knot */
6965
6966 @ Knots can be user-supplied, or they can be created by program code,
6967 like the |split_cubic| function, or |copy_path|. The distinction is
6968 needed for the cleanup routine that runs after |split_cubic|, because
6969 it should only delete knots it has previously inserted, and never
6970 anything that was user-supplied. In order to be able to differentiate
6971 one knot from another, we will set |originator(p):=mp_metapost_user| when
6972 it appeared in the actual metapost program, and
6973 |originator(p):=mp_program_code| in all other cases.
6974
6975 @d originator(A)   mp->mem[(A)+7].hh.b0 /* the creator of this knot */
6976
6977 @<Types...@>=
6978 enum {
6979   mp_program_code=0, /* not created by a user */
6980   mp_metapost_user, /* created by a user */
6981 };
6982
6983 @ Here is a routine that prints a given knot list
6984 in symbolic form. It illustrates the conventions discussed above,
6985 and checks for anomalies that might arise while \MP\ is being debugged.
6986
6987 @<Declare subroutines for printing expressions@>=
6988 void mp_pr_path (MP mp,pointer h);
6989
6990 @ @c
6991 void mp_pr_path (MP mp,pointer h) {
6992   pointer p,q; /* for list traversal */
6993   p=h;
6994   do {  
6995     q=link(p);
6996     if ( (p==null)||(q==null) ) { 
6997       mp_print_nl(mp, "???"); return; /* this won't happen */
6998 @.???@>
6999     }
7000     @<Print information for adjacent knots |p| and |q|@>;
7001   DONE1:
7002     p=q;
7003     if ( (p!=h)||(left_type(h)!=mp_endpoint) ) {
7004       @<Print two dots, followed by |given| or |curl| if present@>;
7005     }
7006   } while (p!=h);
7007   if ( left_type(h)!=mp_endpoint ) 
7008     mp_print(mp, "cycle");
7009 }
7010
7011 @ @<Print information for adjacent knots...@>=
7012 mp_print_two(mp, x_coord(p),y_coord(p));
7013 switch (right_type(p)) {
7014 case mp_endpoint: 
7015   if ( left_type(p)==mp_open ) mp_print(mp, "{open?}"); /* can't happen */
7016 @.open?@>
7017   if ( (left_type(q)!=mp_endpoint)||(q!=h) ) q=null; /* force an error */
7018   goto DONE1;
7019   break;
7020 case mp_explicit: 
7021   @<Print control points between |p| and |q|, then |goto done1|@>;
7022   break;
7023 case mp_open: 
7024   @<Print information for a curve that begins |open|@>;
7025   break;
7026 case mp_curl:
7027 case mp_given: 
7028   @<Print information for a curve that begins |curl| or |given|@>;
7029   break;
7030 default:
7031   mp_print(mp, "???"); /* can't happen */
7032 @.???@>
7033   break;
7034 }
7035 if ( left_type(q)<=mp_explicit ) {
7036   mp_print(mp, "..control?"); /* can't happen */
7037 @.control?@>
7038 } else if ( (right_tension(p)!=unity)||(left_tension(q)!=unity) ) {
7039   @<Print tension between |p| and |q|@>;
7040 }
7041
7042 @ Since |n_sin_cos| produces |fraction| results, which we will print as if they
7043 were |scaled|, the magnitude of a |given| direction vector will be~4096.
7044
7045 @<Print two dots...@>=
7046
7047   mp_print_nl(mp, " ..");
7048   if ( left_type(p)==mp_given ) { 
7049     mp_n_sin_cos(mp, left_given(p)); mp_print_char(mp, '{');
7050     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ',');
7051     mp_print_scaled(mp, mp->n_sin); mp_print_char(mp, '}');
7052   } else if ( left_type(p)==mp_curl ){ 
7053     mp_print(mp, "{curl "); 
7054     mp_print_scaled(mp, left_curl(p)); mp_print_char(mp, '}');
7055   }
7056 }
7057
7058 @ @<Print tension between |p| and |q|@>=
7059
7060   mp_print(mp, "..tension ");
7061   if ( right_tension(p)<0 ) mp_print(mp, "atleast");
7062   mp_print_scaled(mp, abs(right_tension(p)));
7063   if ( right_tension(p)!=left_tension(q) ){ 
7064     mp_print(mp, " and ");
7065     if ( left_tension(q)<0 ) mp_print(mp, "atleast");
7066     mp_print_scaled(mp, abs(left_tension(q)));
7067   }
7068 }
7069
7070 @ @<Print control points between |p| and |q|, then |goto done1|@>=
7071
7072   mp_print(mp, "..controls "); 
7073   mp_print_two(mp, right_x(p),right_y(p)); 
7074   mp_print(mp, " and ");
7075   if ( left_type(q)!=mp_explicit ) { 
7076     mp_print(mp, "??"); /* can't happen */
7077 @.??@>
7078   } else {
7079     mp_print_two(mp, left_x(q),left_y(q));
7080   }
7081   goto DONE1;
7082 }
7083
7084 @ @<Print information for a curve that begins |open|@>=
7085 if ( (left_type(p)!=mp_explicit)&&(left_type(p)!=mp_open) ) {
7086   mp_print(mp, "{open?}"); /* can't happen */
7087 @.open?@>
7088 }
7089
7090 @ A curl of 1 is shown explicitly, so that the user sees clearly that
7091 \MP's default curl is present.
7092
7093 The code here uses the fact that |left_curl==left_given| and
7094 |right_curl==right_given|.
7095
7096 @<Print information for a curve that begins |curl|...@>=
7097
7098   if ( left_type(p)==mp_open )  
7099     mp_print(mp, "??"); /* can't happen */
7100 @.??@>
7101   if ( right_type(p)==mp_curl ) { 
7102     mp_print(mp, "{curl "); mp_print_scaled(mp, right_curl(p));
7103   } else { 
7104     mp_n_sin_cos(mp, right_given(p)); mp_print_char(mp, '{');
7105     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ','); 
7106     mp_print_scaled(mp, mp->n_sin);
7107   }
7108   mp_print_char(mp, '}');
7109 }
7110
7111 @ It is convenient to have another version of |pr_path| that prints the path
7112 as a diagnostic message.
7113
7114 @<Declare subroutines for printing expressions@>=
7115 void mp_print_path (MP mp,pointer h, char *s, boolean nuline) { 
7116   mp_print_diagnostic(mp, "Path", s, nuline); mp_print_ln(mp);
7117 @.Path at line...@>
7118   mp_pr_path(mp, h);
7119   mp_end_diagnostic(mp, true);
7120 }
7121
7122 @ If we want to duplicate a knot node, we can say |copy_knot|:
7123
7124 @c 
7125 pointer mp_copy_knot (MP mp,pointer p) {
7126   pointer q; /* the copy */
7127   int k; /* runs through the words of a knot node */
7128   q=mp_get_node(mp, knot_node_size);
7129   for (k=0;k<knot_node_size;k++) {
7130     mp->mem[q+k]=mp->mem[p+k];
7131   }
7132   originator(q)=originator(p);
7133   return q;
7134 }
7135
7136 @ The |copy_path| routine makes a clone of a given path.
7137
7138 @c 
7139 pointer mp_copy_path (MP mp, pointer p) {
7140   pointer q,pp,qq; /* for list manipulation */
7141   q=mp_copy_knot(mp, p);
7142   qq=q; pp=link(p);
7143   while ( pp!=p ) { 
7144     link(qq)=mp_copy_knot(mp, pp);
7145     qq=link(qq);
7146     pp=link(pp);
7147   }
7148   link(qq)=q;
7149   return q;
7150 }
7151
7152
7153 @ Just before |ship_out|, knot lists are exported for printing.
7154
7155 The |gr_XXXX| macros are defined in |mppsout.h|.
7156
7157 @c 
7158 struct mp_knot *mp_export_knot (MP mp,pointer p) {
7159   struct mp_knot *q; /* the copy */
7160   if (p==null)
7161      return NULL;
7162   q = mp_xmalloc(mp, 1, sizeof (struct mp_knot));
7163   memset(q,0,sizeof (struct mp_knot));
7164   gr_left_type(q)  = left_type(p);
7165   gr_right_type(q) = right_type(p);
7166   gr_x_coord(q)    = x_coord(p);
7167   gr_y_coord(q)    = y_coord(p);
7168   gr_left_x(q)     = left_x(p);
7169   gr_left_y(q)     = left_y(p);
7170   gr_right_x(q)    = right_x(p);
7171   gr_right_y(q)    = right_y(p);
7172   gr_originator(q) = originator(p);
7173   return q;
7174 }
7175
7176 @ The |export_knot_list| routine therefore also makes a clone 
7177 of a given path.
7178
7179 @c 
7180 struct mp_knot *mp_export_knot_list (MP mp, pointer p) {
7181   struct mp_knot *q, *qq; /* for list manipulation */
7182   pointer pp; /* for list manipulation */
7183   if (p==null)
7184      return NULL;
7185   q=mp_export_knot(mp, p);
7186   qq=q; pp=link(p);
7187   while ( pp!=p ) { 
7188     gr_next_knot(qq)=mp_export_knot(mp, pp);
7189     qq=gr_next_knot(qq);
7190     pp=link(pp);
7191   }
7192   gr_next_knot(qq)=q;
7193   return q;
7194 }
7195
7196
7197 @ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure
7198 returns a pointer to the first node of the copy, if the path is a cycle,
7199 but to the final node of a non-cyclic copy. The global
7200 variable |path_tail| will point to the final node of the original path;
7201 this trick makes it easier to implement `\&{doublepath}'.
7202
7203 All node types are assumed to be |endpoint| or |explicit| only.
7204
7205 @c 
7206 pointer mp_htap_ypoc (MP mp,pointer p) {
7207   pointer q,pp,qq,rr; /* for list manipulation */
7208   q=mp_get_node(mp, knot_node_size); /* this will correspond to |p| */
7209   qq=q; pp=p;
7210   while (1) { 
7211     right_type(qq)=left_type(pp); left_type(qq)=right_type(pp);
7212     x_coord(qq)=x_coord(pp); y_coord(qq)=y_coord(pp);
7213     right_x(qq)=left_x(pp); right_y(qq)=left_y(pp);
7214     left_x(qq)=right_x(pp); left_y(qq)=right_y(pp);
7215     originator(qq)=originator(pp);
7216     if ( link(pp)==p ) { 
7217       link(q)=qq; mp->path_tail=pp; return q;
7218     }
7219     rr=mp_get_node(mp, knot_node_size); link(rr)=qq; qq=rr; pp=link(pp);
7220   }
7221 }
7222
7223 @ @<Glob...@>=
7224 pointer path_tail; /* the node that links to the beginning of a path */
7225
7226 @ When a cyclic list of knot nodes is no longer needed, it can be recycled by
7227 calling the following subroutine.
7228
7229 @<Declare the recycling subroutines@>=
7230 void mp_toss_knot_list (MP mp,pointer p) ;
7231
7232 @ @c
7233 void mp_toss_knot_list (MP mp,pointer p) {
7234   pointer q; /* the node being freed */
7235   pointer r; /* the next node */
7236   q=p;
7237   do {  
7238     r=link(q); 
7239     mp_free_node(mp, q,knot_node_size); q=r;
7240   } while (q!=p);
7241 }
7242
7243 @* \[18] Choosing control points.
7244 Now we must actually delve into one of \MP's more difficult routines,
7245 the |make_choices| procedure that chooses angles and control points for
7246 the splines of a curve when the user has not specified them explicitly.
7247 The parameter to |make_choices| points to a list of knots and
7248 path information, as described above.
7249
7250 A path decomposes into independent segments at ``breakpoint'' knots,
7251 which are knots whose left and right angles are both prespecified in
7252 some way (i.e., their |left_type| and |right_type| aren't both open).
7253
7254 @c 
7255 @<Declare the procedure called |solve_choices|@>;
7256 void mp_make_choices (MP mp,pointer knots) {
7257   pointer h; /* the first breakpoint */
7258   pointer p,q; /* consecutive breakpoints being processed */
7259   @<Other local variables for |make_choices|@>;
7260   check_arith; /* make sure that |arith_error=false| */
7261   if ( mp->internal[mp_tracing_choices]>0 )
7262     mp_print_path(mp, knots,", before choices",true);
7263   @<If consecutive knots are equal, join them explicitly@>;
7264   @<Find the first breakpoint, |h|, on the path;
7265     insert an artificial breakpoint if the path is an unbroken cycle@>;
7266   p=h;
7267   do {  
7268     @<Fill in the control points between |p| and the next breakpoint,
7269       then advance |p| to that breakpoint@>;
7270   } while (p!=h);
7271   if ( mp->internal[mp_tracing_choices]>0 )
7272     mp_print_path(mp, knots,", after choices",true);
7273   if ( mp->arith_error ) {
7274     @<Report an unexpected problem during the choice-making@>;
7275   }
7276 }
7277
7278 @ @<Report an unexpected problem during the choice...@>=
7279
7280   print_err("Some number got too big");
7281 @.Some number got too big@>
7282   help2("The path that I just computed is out of range.")
7283        ("So it will probably look funny. Proceed, for a laugh.");
7284   mp_put_get_error(mp); mp->arith_error=false;
7285 }
7286
7287 @ Two knots in a row with the same coordinates will always be joined
7288 by an explicit ``curve'' whose control points are identical with the
7289 knots.
7290
7291 @<If consecutive knots are equal, join them explicitly@>=
7292 p=knots;
7293 do {  
7294   q=link(p);
7295   if ( x_coord(p)==x_coord(q) && y_coord(p)==y_coord(q) && right_type(p)>mp_explicit ) { 
7296     right_type(p)=mp_explicit;
7297     if ( left_type(p)==mp_open ) { 
7298       left_type(p)=mp_curl; left_curl(p)=unity;
7299     }
7300     left_type(q)=mp_explicit;
7301     if ( right_type(q)==mp_open ) { 
7302       right_type(q)=mp_curl; right_curl(q)=unity;
7303     }
7304     right_x(p)=x_coord(p); left_x(q)=x_coord(p);
7305     right_y(p)=y_coord(p); left_y(q)=y_coord(p);
7306   }
7307   p=q;
7308 } while (p!=knots)
7309
7310 @ If there are no breakpoints, it is necessary to compute the direction
7311 angles around an entire cycle. In this case the |left_type| of the first
7312 node is temporarily changed to |end_cycle|.
7313
7314 @<Find the first breakpoint, |h|, on the path...@>=
7315 h=knots;
7316 while (1) { 
7317   if ( left_type(h)!=mp_open ) break;
7318   if ( right_type(h)!=mp_open ) break;
7319   h=link(h);
7320   if ( h==knots ) { 
7321     left_type(h)=mp_end_cycle; break;
7322   }
7323 }
7324
7325 @ If |right_type(p)<given| and |q=link(p)|, we must have
7326 |right_type(p)=left_type(q)=mp_explicit| or |endpoint|.
7327
7328 @<Fill in the control points between |p| and the next breakpoint...@>=
7329 q=link(p);
7330 if ( right_type(p)>=mp_given ) { 
7331   while ( (left_type(q)==mp_open)&&(right_type(q)==mp_open) ) q=link(q);
7332   @<Fill in the control information between
7333     consecutive breakpoints |p| and |q|@>;
7334 } else if ( right_type(p)==mp_endpoint ) {
7335   @<Give reasonable values for the unused control points between |p| and~|q|@>;
7336 }
7337 p=q
7338
7339 @ This step makes it possible to transform an explicitly computed path without
7340 checking the |left_type| and |right_type| fields.
7341
7342 @<Give reasonable values for the unused control points between |p| and~|q|@>=
7343
7344   right_x(p)=x_coord(p); right_y(p)=y_coord(p);
7345   left_x(q)=x_coord(q); left_y(q)=y_coord(q);
7346 }
7347
7348 @ Before we can go further into the way choices are made, we need to
7349 consider the underlying theory. The basic ideas implemented in |make_choices|
7350 are due to John Hobby, who introduced the notion of ``mock curvature''
7351 @^Hobby, John Douglas@>
7352 at a knot. Angles are chosen so that they preserve mock curvature when
7353 a knot is passed, and this has been found to produce excellent results.
7354
7355 It is convenient to introduce some notations that simplify the necessary
7356 formulas. Let $d_{k,k+1}=\vert z\k-z_k\vert$ be the (nonzero) distance
7357 between knots |k| and |k+1|; and let
7358 $${z\k-z_k\over z_k-z_{k-1}}={d_{k,k+1}\over d_{k-1,k}}e^{i\psi_k}$$
7359 so that a polygonal line from $z_{k-1}$ to $z_k$ to $z\k$ turns left
7360 through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$.
7361 The control points for the spline from $z_k$ to $z\k$ will be denoted by
7362 $$\eqalign{z_k^+&=z_k+
7363   \textstyle{1\over3}\rho_k e^{i\theta_k}(z\k-z_k),\cr
7364  z\k^-&=z\k-
7365   \textstyle{1\over3}\sigma\k e^{-i\phi\k}(z\k-z_k),\cr}$$
7366 where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the
7367 beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the
7368 corresponding ``offset angles.'' These angles satisfy the condition
7369 $$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$
7370 whenever the curve leaves an intermediate knot~|k| in the direction that
7371 it enters.
7372
7373 @ Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of
7374 the curve at its beginning and ending points. This means that
7375 $\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$,
7376 where $f(\theta,\phi)$ is \MP's standard velocity function defined in
7377 the |velocity| subroutine. The cubic spline $B(z_k^{\phantom+},z_k^+,
7378 z\k^-,z\k^{\phantom+};t)$
7379 has curvature
7380 @^curvature@>
7381 $${2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_{k,k+1}}
7382 \qquad{\rm and}\qquad
7383 {2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_{k,k+1}}$$
7384 at |t=0| and |t=1|, respectively. The mock curvature is the linear
7385 @^mock curvature@>
7386 approximation to this true curvature that arises in the limit for
7387 small $\theta_k$ and~$\phi\k$, if second-order terms are discarded.
7388 The standard velocity function satisfies
7389 $$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$
7390 hence the mock curvatures are respectively
7391 $${2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_{k,k+1}}
7392 \qquad{\rm and}\qquad
7393 {2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_{k,k+1}}.\eqno(**)$$
7394
7395 @ The turning angles $\psi_k$ are given, and equation $(*)$ above
7396 determines $\phi_k$ when $\theta_k$ is known, so the task of
7397 angle selection is essentially to choose appropriate values for each
7398 $\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables
7399 from $(**)$, we obtain a system of linear equations of the form
7400 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7401 where
7402 $$A_k={\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7403 \qquad B_k={3-\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7404 \qquad C_k={3-\beta\k\over\alpha_k^2d_{k,k+1}},
7405 \qquad D_k={\beta\k\over\alpha_k^2d_{k,k+1}}.$$
7406 The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$
7407 will be at most $4\over3$. It follows that $B_k\G{5\over4}A_k$ and
7408 $C_k\G{5\over4}D_k$; hence the equations are diagonally dominant;
7409 hence they have a unique solution. Moreover, in most cases the tensions
7410 are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the
7411 solution numerically stable, and there is an exponential damping
7412 effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by
7413 a factor of~$O(2^{-j})$.
7414
7415 @ However, we still must consider the angles at the starting and ending
7416 knots of a non-cyclic path. These angles might be given explicitly, or
7417 they might be specified implicitly in terms of an amount of ``curl.''
7418
7419 Let's assume that angles need to be determined for a non-cyclic path
7420 starting at $z_0$ and ending at~$z_n$. Then equations of the form
7421 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta_{k+1}=R_k$$
7422 have been given for $0<k<n$, and it will be convenient to introduce
7423 equations of the same form for $k=0$ and $k=n$, where
7424 $$A_0=B_0=C_n=D_n=0.$$
7425 If $\theta_0$ is supposed to have a given value $E_0$, we simply
7426 define $C_0=0$, $D_0=0$, and $R_0=E_0$. Otherwise a curl
7427 parameter, $\gamma_0$, has been specified at~$z_0$; this means
7428 that the mock curvature at $z_0$ should be $\gamma_0$ times the
7429 mock curvature at $z_1$; i.e.,
7430 $${2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_{01}}
7431 =\gamma_0{2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_{01}}.$$
7432 This equation simplifies to
7433 $$(\alpha_0\chi_0+3-\beta_1)\theta_0+
7434  \bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1=
7435  -\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$
7436 where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0=
7437 \chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$.
7438 It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$,
7439 hence the linear equations remain nonsingular.
7440
7441 Similar considerations apply at the right end, when the final angle $\phi_n$
7442 may or may not need to be determined. It is convenient to let $\psi_n=0$,
7443 hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$,
7444 or we have
7445 $$\bigl((3-\beta_n)\chi_n+\alpha_{n-1}\bigr)\theta_{n-1}+
7446 (\beta_n\chi_n+3-\alpha_{n-1})\theta_n=0,\qquad
7447   \chi_n={\beta_n^2\gamma_n\over\alpha_{n-1}^2}.$$
7448
7449 When |make_choices| chooses angles, it must compute the coefficients of
7450 these linear equations, then solve the equations. To compute the coefficients,
7451 it is necessary to compute arctangents of the given turning angles~$\psi_k$.
7452 When the equations are solved, the chosen directions $\theta_k$ are put
7453 back into the form of control points by essentially computing sines and
7454 cosines.
7455
7456 @ OK, we are ready to make the hard choices of |make_choices|.
7457 Most of the work is relegated to an auxiliary procedure
7458 called |solve_choices|, which has been introduced to keep
7459 |make_choices| from being extremely long.
7460
7461 @<Fill in the control information between...@>=
7462 @<Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$;
7463   set $n$ to the length of the path@>;
7464 @<Remove |open| types at the breakpoints@>;
7465 mp_solve_choices(mp, p,q,n)
7466
7467 @ It's convenient to precompute quantities that will be needed several
7468 times later. The values of |delta_x[k]| and |delta_y[k]| will be the
7469 coordinates of $z\k-z_k$, and the magnitude of this vector will be
7470 |delta[k]=@t$d_{k,k+1}$@>|. The path angle $\psi_k$ between $z_k-z_{k-1}$
7471 and $z\k-z_k$ will be stored in |psi[k]|.
7472
7473 @<Glob...@>=
7474 int path_size; /* maximum number of knots between breakpoints of a path */
7475 scaled *delta_x;
7476 scaled *delta_y;
7477 scaled *delta; /* knot differences */
7478 angle  *psi; /* turning angles */
7479
7480 @ @<Allocate or initialize ...@>=
7481 mp->delta_x = NULL;
7482 mp->delta_y = NULL;
7483 mp->delta = NULL;
7484 mp->psi = NULL;
7485
7486 @ @<Dealloc variables@>=
7487 xfree(mp->delta_x);
7488 xfree(mp->delta_y);
7489 xfree(mp->delta);
7490 xfree(mp->psi);
7491
7492 @ @<Other local variables for |make_choices|@>=
7493   int k,n; /* current and final knot numbers */
7494   pointer s,t; /* registers for list traversal */
7495   scaled delx,dely; /* directions where |open| meets |explicit| */
7496   fraction sine,cosine; /* trig functions of various angles */
7497
7498 @ @<Calculate the turning angles...@>=
7499 {
7500 RESTART:
7501   k=0; s=p; n=mp->path_size;
7502   do {  
7503     t=link(s);
7504     mp->delta_x[k]=x_coord(t)-x_coord(s);
7505     mp->delta_y[k]=y_coord(t)-y_coord(s);
7506     mp->delta[k]=mp_pyth_add(mp, mp->delta_x[k],mp->delta_y[k]);
7507     if ( k>0 ) { 
7508       sine=mp_make_fraction(mp, mp->delta_y[k-1],mp->delta[k-1]);
7509       cosine=mp_make_fraction(mp, mp->delta_x[k-1],mp->delta[k-1]);
7510       mp->psi[k]=mp_n_arg(mp, mp_take_fraction(mp, mp->delta_x[k],cosine)+
7511         mp_take_fraction(mp, mp->delta_y[k],sine),
7512         mp_take_fraction(mp, mp->delta_y[k],cosine)-
7513           mp_take_fraction(mp, mp->delta_x[k],sine));
7514     }
7515     incr(k); s=t;
7516     if ( k==mp->path_size ) {
7517       mp_reallocate_paths(mp, mp->path_size+(mp->path_size>>2));
7518       goto RESTART; /* retry, loop size has changed */
7519     }
7520     if ( s==q ) n=k;
7521   } while (!((k>=n)&&(left_type(s)!=mp_end_cycle)));
7522   if ( k==n ) mp->psi[n]=0; else mp->psi[k]=mp->psi[1];
7523 }
7524
7525 @ When we get to this point of the code, |right_type(p)| is either
7526 |given| or |curl| or |open|. If it is |open|, we must have
7527 |left_type(p)=mp_end_cycle| or |left_type(p)=mp_explicit|. In the latter
7528 case, the |open| type is converted to |given|; however, if the
7529 velocity coming into this knot is zero, the |open| type is
7530 converted to a |curl|, since we don't know the incoming direction.
7531
7532 Similarly, |left_type(q)| is either |given| or |curl| or |open| or
7533 |mp_end_cycle|. The |open| possibility is reduced either to |given| or to |curl|.
7534
7535 @<Remove |open| types at the breakpoints@>=
7536 if ( left_type(q)==mp_open ) { 
7537   delx=right_x(q)-x_coord(q); dely=right_y(q)-y_coord(q);
7538   if ( (delx==0)&&(dely==0) ) { 
7539     left_type(q)=mp_curl; left_curl(q)=unity;
7540   } else { 
7541     left_type(q)=mp_given; left_given(q)=mp_n_arg(mp, delx,dely);
7542   }
7543 }
7544 if ( (right_type(p)==mp_open)&&(left_type(p)==mp_explicit) ) { 
7545   delx=x_coord(p)-left_x(p); dely=y_coord(p)-left_y(p);
7546   if ( (delx==0)&&(dely==0) ) { 
7547     right_type(p)=mp_curl; right_curl(p)=unity;
7548   } else { 
7549     right_type(p)=mp_given; right_given(p)=mp_n_arg(mp, delx,dely);
7550   }
7551 }
7552
7553 @ Linear equations need to be solved whenever |n>1|; and also when |n=1|
7554 and exactly one of the breakpoints involves a curl. The simplest case occurs
7555 when |n=1| and there is a curl at both breakpoints; then we simply draw
7556 a straight line.
7557
7558 But before coding up the simple cases, we might as well face the general case,
7559 since we must deal with it sooner or later, and since the general case
7560 is likely to give some insight into the way simple cases can be handled best.
7561
7562 When there is no cycle, the linear equations to be solved form a tridiagonal
7563 system, and we can apply the standard technique of Gaussian elimination
7564 to convert that system to a sequence of equations of the form
7565 $$\theta_0+u_0\theta_1=v_0,\quad
7566 \theta_1+u_1\theta_2=v_1,\quad\ldots,\quad
7567 \theta_{n-1}+u_{n-1}\theta_n=v_{n-1},\quad
7568 \theta_n=v_n.$$
7569 It is possible to do this diagonalization while generating the equations.
7570 Once $\theta_n$ is known, it is easy to determine $\theta_{n-1}$, \dots,
7571 $\theta_1$, $\theta_0$; thus, the equations will be solved.
7572
7573 The procedure is slightly more complex when there is a cycle, but the
7574 basic idea will be nearly the same. In the cyclic case the right-hand
7575 sides will be $v_k+w_k\theta_0$ instead of simply $v_k$, and we will start
7576 the process off with $u_0=v_0=0$, $w_0=1$. The final equation will be not
7577 $\theta_n=v_n$ but $\theta_n+u_n\theta_1=v_n+w_n\theta_0$; an appropriate
7578 ending routine will take account of the fact that $\theta_n=\theta_0$ and
7579 eliminate the $w$'s from the system, after which the solution can be
7580 obtained as before.
7581
7582 When $u_k$, $v_k$, and $w_k$ are being computed, the three pointer
7583 variables |r|, |s|,~|t| will point respectively to knots |k-1|, |k|,
7584 and~|k+1|. The $u$'s and $w$'s are scaled by $2^{28}$, i.e., they are
7585 of type |fraction|; the $\theta$'s and $v$'s are of type |angle|.
7586
7587 @<Glob...@>=
7588 angle *theta; /* values of $\theta_k$ */
7589 fraction *uu; /* values of $u_k$ */
7590 angle *vv; /* values of $v_k$ */
7591 fraction *ww; /* values of $w_k$ */
7592
7593 @ @<Allocate or initialize ...@>=
7594 mp->theta = NULL;
7595 mp->uu = NULL;
7596 mp->vv = NULL;
7597 mp->ww = NULL;
7598
7599 @ @<Dealloc variables@>=
7600 xfree(mp->theta);
7601 xfree(mp->uu);
7602 xfree(mp->vv);
7603 xfree(mp->ww);
7604
7605 @ @<Declare |mp_reallocate| functions@>=
7606 void mp_reallocate_paths (MP mp, int l);
7607
7608 @ @c
7609 void mp_reallocate_paths (MP mp, int l) {
7610   XREALLOC (mp->delta_x, l, scaled);
7611   XREALLOC (mp->delta_y, l, scaled);
7612   XREALLOC (mp->delta,   l, scaled);
7613   XREALLOC (mp->psi,     l, angle);
7614   XREALLOC (mp->theta,   l, angle);
7615   XREALLOC (mp->uu,      l, fraction);
7616   XREALLOC (mp->vv,      l, angle);
7617   XREALLOC (mp->ww,      l, fraction);
7618   mp->path_size = l;
7619 }
7620
7621 @ Our immediate problem is to get the ball rolling by setting up the
7622 first equation or by realizing that no equations are needed, and to fit
7623 this initialization into a framework suitable for the overall computation.
7624
7625 @<Declare the procedure called |solve_choices|@>=
7626 @<Declare subroutines needed by |solve_choices|@>;
7627 void mp_solve_choices (MP mp,pointer p, pointer q, halfword n) {
7628   int k; /* current knot number */
7629   pointer r,s,t; /* registers for list traversal */
7630   @<Other local variables for |solve_choices|@>;
7631   k=0; s=p; r=0;
7632   while (1) { 
7633     t=link(s);
7634     if ( k==0 ) {
7635       @<Get the linear equations started; or |return|
7636         with the control points in place, if linear equations
7637         needn't be solved@>
7638     } else  { 
7639       switch (left_type(s)) {
7640       case mp_end_cycle: case mp_open:
7641         @<Set up equation to match mock curvatures
7642           at $z_k$; then |goto found| with $\theta_n$
7643           adjusted to equal $\theta_0$, if a cycle has ended@>;
7644         break;
7645       case mp_curl:
7646         @<Set up equation for a curl at $\theta_n$
7647           and |goto found|@>;
7648         break;
7649       case mp_given:
7650         @<Calculate the given value of $\theta_n$
7651           and |goto found|@>;
7652         break;
7653       } /* there are no other cases */
7654     }
7655     r=s; s=t; incr(k);
7656   }
7657 FOUND:
7658   @<Finish choosing angles and assigning control points@>;
7659 }
7660
7661 @ On the first time through the loop, we have |k=0| and |r| is not yet
7662 defined. The first linear equation, if any, will have $A_0=B_0=0$.
7663
7664 @<Get the linear equations started...@>=
7665 switch (right_type(s)) {
7666 case mp_given: 
7667   if ( left_type(t)==mp_given ) {
7668     @<Reduce to simple case of two givens  and |return|@>
7669   } else {
7670     @<Set up the equation for a given value of $\theta_0$@>;
7671   }
7672   break;
7673 case mp_curl: 
7674   if ( left_type(t)==mp_curl ) {
7675     @<Reduce to simple case of straight line and |return|@>
7676   } else {
7677     @<Set up the equation for a curl at $\theta_0$@>;
7678   }
7679   break;
7680 case mp_open: 
7681   mp->uu[0]=0; mp->vv[0]=0; mp->ww[0]=fraction_one;
7682   /* this begins a cycle */
7683   break;
7684 } /* there are no other cases */
7685
7686 @ The general equation that specifies equality of mock curvature at $z_k$ is
7687 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7688 as derived above. We want to combine this with the already-derived equation
7689 $\theta_{k-1}+u_{k-1}\theta_k=v_{k-1}+w_{k-1}\theta_0$ in order to obtain
7690 a new equation
7691 $\theta_k+u_k\theta\k=v_k+w_k\theta_0$. This can be done by dividing the
7692 equation
7693 $$(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}
7694     -A_kw_{k-1}\theta_0$$
7695 by $B_k-u_{k-1}A_k+C_k$. The trick is to do this carefully with
7696 fixed-point arithmetic, avoiding the chance of overflow while retaining
7697 suitable precision.
7698
7699 The calculations will be performed in several registers that
7700 provide temporary storage for intermediate quantities.
7701
7702 @<Other local variables for |solve_choices|@>=
7703 fraction aa,bb,cc,ff,acc; /* temporary registers */
7704 scaled dd,ee; /* likewise, but |scaled| */
7705 scaled lt,rt; /* tension values */
7706
7707 @ @<Set up equation to match mock curvatures...@>=
7708 { @<Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$,
7709     $\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$,
7710     and $\\{cc}=(B_k-u_{k-1}A_k)/B_k$@>;
7711   @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>;
7712   mp->uu[k]=mp_take_fraction(mp, ff,bb);
7713   @<Calculate the values of $v_k$ and $w_k$@>;
7714   if ( left_type(s)==mp_end_cycle ) {
7715     @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>;
7716   }
7717 }
7718
7719 @ Since tension values are never less than 3/4, the values |aa| and
7720 |bb| computed here are never more than 4/5.
7721
7722 @<Calculate the values $\\{aa}=...@>=
7723 if ( abs(right_tension(r))==unity) { 
7724   aa=fraction_half; dd=2*mp->delta[k];
7725 } else { 
7726   aa=mp_make_fraction(mp, unity,3*abs(right_tension(r))-unity);
7727   dd=mp_take_fraction(mp, mp->delta[k],
7728     fraction_three-mp_make_fraction(mp, unity,abs(right_tension(r))));
7729 }
7730 if ( abs(left_tension(t))==unity ){ 
7731   bb=fraction_half; ee=2*mp->delta[k-1];
7732 } else { 
7733   bb=mp_make_fraction(mp, unity,3*abs(left_tension(t))-unity);
7734   ee=mp_take_fraction(mp, mp->delta[k-1],
7735     fraction_three-mp_make_fraction(mp, unity,abs(left_tension(t))));
7736 }
7737 cc=fraction_one-mp_take_fraction(mp, mp->uu[k-1],aa)
7738
7739 @ The ratio to be calculated in this step can be written in the form
7740 $$\beta_k^2\cdot\\{ee}\over\beta_k^2\cdot\\{ee}+\alpha_k^2\cdot
7741   \\{cc}\cdot\\{dd},$$
7742 because of the quantities just calculated. The values of |dd| and |ee|
7743 will not be needed after this step has been performed.
7744
7745 @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>=
7746 dd=mp_take_fraction(mp, dd,cc); lt=abs(left_tension(s)); rt=abs(right_tension(s));
7747 if ( lt!=rt ) { /* $\beta_k^{-1}\ne\alpha_k^{-1}$ */
7748   if ( lt<rt ) { 
7749     ff=mp_make_fraction(mp, lt,rt);
7750     ff=mp_take_fraction(mp, ff,ff); /* $\alpha_k^2/\beta_k^2$ */
7751     dd=mp_take_fraction(mp, dd,ff);
7752   } else { 
7753     ff=mp_make_fraction(mp, rt,lt);
7754     ff=mp_take_fraction(mp, ff,ff); /* $\beta_k^2/\alpha_k^2$ */
7755     ee=mp_take_fraction(mp, ee,ff);
7756   }
7757 }
7758 ff=mp_make_fraction(mp, ee,ee+dd)
7759
7760 @ The value of $u_{k-1}$ will be |<=1| except when $k=1$ and the previous
7761 equation was specified by a curl. In that case we must use a special
7762 method of computation to prevent overflow.
7763
7764 Fortunately, the calculations turn out to be even simpler in this ``hard''
7765 case. The curl equation makes $w_0=0$ and $v_0=-u_0\psi_1$, hence
7766 $-B_1\psi_1-A_1v_0=-(B_1-u_0A_1)\psi_1=-\\{cc}\cdot B_1\psi_1$.
7767
7768 @<Calculate the values of $v_k$ and $w_k$@>=
7769 acc=-mp_take_fraction(mp, mp->psi[k+1],mp->uu[k]);
7770 if ( right_type(r)==mp_curl ) { 
7771   mp->ww[k]=0;
7772   mp->vv[k]=acc-mp_take_fraction(mp, mp->psi[1],fraction_one-ff);
7773 } else { 
7774   ff=mp_make_fraction(mp, fraction_one-ff,cc); /* this is
7775     $B_k/(C_k+B_k-u_{k-1}A_k)<5$ */
7776   acc=acc-mp_take_fraction(mp, mp->psi[k],ff);
7777   ff=mp_take_fraction(mp, ff,aa); /* this is $A_k/(C_k+B_k-u_{k-1}A_k)$ */
7778   mp->vv[k]=acc-mp_take_fraction(mp, mp->vv[k-1],ff);
7779   if ( mp->ww[k-1]==0 ) mp->ww[k]=0;
7780   else mp->ww[k]=-mp_take_fraction(mp, mp->ww[k-1],ff);
7781 }
7782
7783 @ When a complete cycle has been traversed, we have $\theta_k+u_k\theta\k=
7784 v_k+w_k\theta_0$, for |1<=k<=n|. We would like to determine the value of
7785 $\theta_n$ and reduce the system to the form $\theta_k+u_k\theta\k=v_k$
7786 for |0<=k<n|, so that the cyclic case can be finished up just as if there
7787 were no cycle.
7788
7789 The idea in the following code is to observe that
7790 $$\eqalign{\theta_n&=v_n+w_n\theta_0-u_n\theta_1=\cdots\cr
7791 &=v_n+w_n\theta_0-u_n\bigl(v_1+w_1\theta_0-u_1(v_2+\cdots
7792   -u_{n-2}(v_{n-1}+w_{n-1}\theta_0-u_{n-1}\theta_0))\bigr),\cr}$$
7793 so we can solve for $\theta_n=\theta_0$.
7794
7795 @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>=
7796
7797 aa=0; bb=fraction_one; /* we have |k=n| */
7798 do {  decr(k);
7799 if ( k==0 ) k=n;
7800   aa=mp->vv[k]-mp_take_fraction(mp, aa,mp->uu[k]);
7801   bb=mp->ww[k]-mp_take_fraction(mp, bb,mp->uu[k]);
7802 } while (k!=n); /* now $\theta_n=\\{aa}+\\{bb}\cdot\theta_n$ */
7803 aa=mp_make_fraction(mp, aa,fraction_one-bb);
7804 mp->theta[n]=aa; mp->vv[0]=aa;
7805 for (k=1;k<=n-1;k++) {
7806   mp->vv[k]=mp->vv[k]+mp_take_fraction(mp, aa,mp->ww[k]);
7807 }
7808 goto FOUND;
7809 }
7810
7811 @ @d reduce_angle(A) if ( abs((A))>one_eighty_deg ) {
7812   if ( (A)>0 ) (A)=(A)-three_sixty_deg; else (A)=(A)+three_sixty_deg; }
7813
7814 @<Calculate the given value of $\theta_n$...@>=
7815
7816   mp->theta[n]=left_given(s)-mp_n_arg(mp, mp->delta_x[n-1],mp->delta_y[n-1]);
7817   reduce_angle(mp->theta[n]);
7818   goto FOUND;
7819 }
7820
7821 @ @<Set up the equation for a given value of $\theta_0$@>=
7822
7823   mp->vv[0]=right_given(s)-mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7824   reduce_angle(mp->vv[0]);
7825   mp->uu[0]=0; mp->ww[0]=0;
7826 }
7827
7828 @ @<Set up the equation for a curl at $\theta_0$@>=
7829 { cc=right_curl(s); lt=abs(left_tension(t)); rt=abs(right_tension(s));
7830   if ( (rt==unity)&&(lt==unity) )
7831     mp->uu[0]=mp_make_fraction(mp, cc+cc+unity,cc+two);
7832   else 
7833     mp->uu[0]=mp_curl_ratio(mp, cc,rt,lt);
7834   mp->vv[0]=-mp_take_fraction(mp, mp->psi[1],mp->uu[0]); mp->ww[0]=0;
7835 }
7836
7837 @ @<Set up equation for a curl at $\theta_n$...@>=
7838 { cc=left_curl(s); lt=abs(left_tension(s)); rt=abs(right_tension(r));
7839   if ( (rt==unity)&&(lt==unity) )
7840     ff=mp_make_fraction(mp, cc+cc+unity,cc+two);
7841   else 
7842     ff=mp_curl_ratio(mp, cc,lt,rt);
7843   mp->theta[n]=-mp_make_fraction(mp, mp_take_fraction(mp, mp->vv[n-1],ff),
7844     fraction_one-mp_take_fraction(mp, ff,mp->uu[n-1]));
7845   goto FOUND;
7846 }
7847
7848 @ The |curl_ratio| subroutine has three arguments, which our previous notation
7849 encourages us to call $\gamma$, $\alpha^{-1}$, and $\beta^{-1}$. It is
7850 a somewhat tedious program to calculate
7851 $${(3-\alpha)\alpha^2\gamma+\beta^3\over
7852   \alpha^3\gamma+(3-\beta)\beta^2},$$
7853 with the result reduced to 4 if it exceeds 4. (This reduction of curl
7854 is necessary only if the curl and tension are both large.)
7855 The values of $\alpha$ and $\beta$ will be at most~4/3.
7856
7857 @<Declare subroutines needed by |solve_choices|@>=
7858 fraction mp_curl_ratio (MP mp,scaled gamma, scaled a_tension, 
7859                         scaled b_tension) {
7860   fraction alpha,beta,num,denom,ff; /* registers */
7861   alpha=mp_make_fraction(mp, unity,a_tension);
7862   beta=mp_make_fraction(mp, unity,b_tension);
7863   if ( alpha<=beta ) {
7864     ff=mp_make_fraction(mp, alpha,beta); ff=mp_take_fraction(mp, ff,ff);
7865     gamma=mp_take_fraction(mp, gamma,ff);
7866     beta=beta / 010000; /* convert |fraction| to |scaled| */
7867     denom=mp_take_fraction(mp, gamma,alpha)+three-beta;
7868     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7869   } else { 
7870     ff=mp_make_fraction(mp, beta,alpha); ff=mp_take_fraction(mp, ff,ff);
7871     beta=mp_take_fraction(mp, beta,ff) / 010000; /* convert |fraction| to |scaled| */
7872     denom=mp_take_fraction(mp, gamma,alpha)+(ff / 1365)-beta;
7873       /* $1365\approx 2^{12}/3$ */
7874     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7875   }
7876   if ( num>=denom+denom+denom+denom ) return fraction_four;
7877   else return mp_make_fraction(mp, num,denom);
7878 }
7879
7880 @ We're in the home stretch now.
7881
7882 @<Finish choosing angles and assigning control points@>=
7883 for (k=n-1;k>=0;k--) {
7884   mp->theta[k]=mp->vv[k]-mp_take_fraction(mp,mp->theta[k+1],mp->uu[k]);
7885 }
7886 s=p; k=0;
7887 do {  
7888   t=link(s);
7889   mp_n_sin_cos(mp, mp->theta[k]); mp->st=mp->n_sin; mp->ct=mp->n_cos;
7890   mp_n_sin_cos(mp, -mp->psi[k+1]-mp->theta[k+1]); mp->sf=mp->n_sin; mp->cf=mp->n_cos;
7891   mp_set_controls(mp, s,t,k);
7892   incr(k); s=t;
7893 } while (k!=n)
7894
7895 @ The |set_controls| routine actually puts the control points into
7896 a pair of consecutive nodes |p| and~|q|. Global variables are used to
7897 record the values of $\sin\theta$, $\cos\theta$, $\sin\phi$, and
7898 $\cos\phi$ needed in this calculation.
7899
7900 @<Glob...@>=
7901 fraction st;
7902 fraction ct;
7903 fraction sf;
7904 fraction cf; /* sines and cosines */
7905
7906 @ @<Declare subroutines needed by |solve_choices|@>=
7907 void mp_set_controls (MP mp,pointer p, pointer q, integer k) {
7908   fraction rr,ss; /* velocities, divided by thrice the tension */
7909   scaled lt,rt; /* tensions */
7910   fraction sine; /* $\sin(\theta+\phi)$ */
7911   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7912   rr=mp_velocity(mp, mp->st,mp->ct,mp->sf,mp->cf,rt);
7913   ss=mp_velocity(mp, mp->sf,mp->cf,mp->st,mp->ct,lt);
7914   if ( (right_tension(p)<0)||(left_tension(q)<0) ) {
7915     @<Decrease the velocities,
7916       if necessary, to stay inside the bounding triangle@>;
7917   }
7918   right_x(p)=x_coord(p)+mp_take_fraction(mp, 
7919                           mp_take_fraction(mp, mp->delta_x[k],mp->ct)-
7920                           mp_take_fraction(mp, mp->delta_y[k],mp->st),rr);
7921   right_y(p)=y_coord(p)+mp_take_fraction(mp, 
7922                           mp_take_fraction(mp, mp->delta_y[k],mp->ct)+
7923                           mp_take_fraction(mp, mp->delta_x[k],mp->st),rr);
7924   left_x(q)=x_coord(q)-mp_take_fraction(mp, 
7925                          mp_take_fraction(mp, mp->delta_x[k],mp->cf)+
7926                          mp_take_fraction(mp, mp->delta_y[k],mp->sf),ss);
7927   left_y(q)=y_coord(q)-mp_take_fraction(mp, 
7928                          mp_take_fraction(mp, mp->delta_y[k],mp->cf)-
7929                          mp_take_fraction(mp, mp->delta_x[k],mp->sf),ss);
7930   right_type(p)=mp_explicit; left_type(q)=mp_explicit;
7931 }
7932
7933 @ The boundedness conditions $\\{rr}\L\sin\phi\,/\sin(\theta+\phi)$ and
7934 $\\{ss}\L\sin\theta\,/\sin(\theta+\phi)$ are to be enforced if $\sin\theta$,
7935 $\sin\phi$, and $\sin(\theta+\phi)$ all have the same sign. Otherwise
7936 there is no ``bounding triangle.''
7937 @:at_least_}{\&{atleast} primitive@>
7938
7939 @<Decrease the velocities, if necessary...@>=
7940 if (((mp->st>=0)&&(mp->sf>=0))||((mp->st<=0)&&(mp->sf<=0)) ) {
7941   sine=mp_take_fraction(mp, abs(mp->st),mp->cf)+
7942                             mp_take_fraction(mp, abs(mp->sf),mp->ct);
7943   if ( sine>0 ) {
7944     sine=mp_take_fraction(mp, sine,fraction_one+unity); /* safety factor */
7945     if ( right_tension(p)<0 )
7946      if ( mp_ab_vs_cd(mp, abs(mp->sf),fraction_one,rr,sine)<0 )
7947       rr=mp_make_fraction(mp, abs(mp->sf),sine);
7948     if ( left_tension(q)<0 )
7949      if ( mp_ab_vs_cd(mp, abs(mp->st),fraction_one,ss,sine)<0 )
7950       ss=mp_make_fraction(mp, abs(mp->st),sine);
7951   }
7952 }
7953
7954 @ Only the simple cases remain to be handled.
7955
7956 @<Reduce to simple case of two givens and |return|@>=
7957
7958   aa=mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7959   mp_n_sin_cos(mp, right_given(p)-aa); mp->ct=mp->n_cos; mp->st=mp->n_sin;
7960   mp_n_sin_cos(mp, left_given(q)-aa); mp->cf=mp->n_cos; mp->sf=-mp->n_sin;
7961   mp_set_controls(mp, p,q,0); return;
7962 }
7963
7964 @ @<Reduce to simple case of straight line and |return|@>=
7965
7966   right_type(p)=mp_explicit; left_type(q)=mp_explicit;
7967   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7968   if ( rt==unity ) {
7969     if ( mp->delta_x[0]>=0 ) right_x(p)=x_coord(p)+((mp->delta_x[0]+1) / 3);
7970     else right_x(p)=x_coord(p)+((mp->delta_x[0]-1) / 3);
7971     if ( mp->delta_y[0]>=0 ) right_y(p)=y_coord(p)+((mp->delta_y[0]+1) / 3);
7972     else right_y(p)=y_coord(p)+((mp->delta_y[0]-1) / 3);
7973   } else { 
7974     ff=mp_make_fraction(mp, unity,3*rt); /* $\alpha/3$ */
7975     right_x(p)=x_coord(p)+mp_take_fraction(mp, mp->delta_x[0],ff);
7976     right_y(p)=y_coord(p)+mp_take_fraction(mp, mp->delta_y[0],ff);
7977   }
7978   if ( lt==unity ) {
7979     if ( mp->delta_x[0]>=0 ) left_x(q)=x_coord(q)-((mp->delta_x[0]+1) / 3);
7980     else left_x(q)=x_coord(q)-((mp->delta_x[0]-1) / 3);
7981     if ( mp->delta_y[0]>=0 ) left_y(q)=y_coord(q)-((mp->delta_y[0]+1) / 3);
7982     else left_y(q)=y_coord(q)-((mp->delta_y[0]-1) / 3);
7983   } else  { 
7984     ff=mp_make_fraction(mp, unity,3*lt); /* $\beta/3$ */
7985     left_x(q)=x_coord(q)-mp_take_fraction(mp, mp->delta_x[0],ff);
7986     left_y(q)=y_coord(q)-mp_take_fraction(mp, mp->delta_y[0],ff);
7987   }
7988   return;
7989 }
7990
7991 @* \[19] Measuring paths.
7992 \MP's \&{llcorner}, \&{lrcorner}, \&{ulcorner}, and \&{urcorner} operators
7993 allow the user to measure the bounding box of anything that can go into a
7994 picture.  It's easy to get rough bounds on the $x$ and $y$ extent of a path
7995 by just finding the bounding box of the knots and the control points. We
7996 need a more accurate version of the bounding box, but we can still use the
7997 easy estimate to save time by focusing on the interesting parts of the path.
7998
7999 @ Computing an accurate bounding box involves a theme that will come up again
8000 and again. Given a Bernshte{\u\i}n polynomial
8001 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
8002 $$B(z_0,z_1,\ldots,z_n;t)=\sum_k{n\choose k}t^k(1-t)^{n-k}z_k,$$
8003 we can conveniently bisect its range as follows:
8004
8005 \smallskip
8006 \textindent{1)} Let $z_k^{(0)}=z_k$, for |0<=k<=n|.
8007
8008 \smallskip
8009 \textindent{2)} Let $z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$, for
8010 |0<=k<n-j|, for |0<=j<n|.
8011
8012 \smallskip\noindent
8013 Then
8014 $$B(z_0,z_1,\ldots,z_n;t)=B(z_0^{(0)},z_0^{(1)},\ldots,z_0^{(n)};2t)
8015  =B(z_0^{(n)},z_1^{(n-1)},\ldots,z_n^{(0)};2t-1).$$
8016 This formula gives us the coefficients of polynomials to use over the ranges
8017 $0\L t\L{1\over2}$ and ${1\over2}\L t\L1$.
8018
8019 @ Now here's a subroutine that's handy for all sorts of path computations:
8020 Given a quadratic polynomial $B(a,b,c;t)$, the |crossing_point| function
8021 returns the unique |fraction| value |t| between 0 and~1 at which
8022 $B(a,b,c;t)$ changes from positive to negative, or returns
8023 |t=fraction_one+1| if no such value exists. If |a<0| (so that $B(a,b,c;t)$
8024 is already negative at |t=0|), |crossing_point| returns the value zero.
8025
8026 @d no_crossing {  return (fraction_one+1); }
8027 @d one_crossing { return fraction_one; }
8028 @d zero_crossing { return 0; }
8029 @d mp_crossing_point(M,A,B,C) mp_do_crossing_point(A,B,C)
8030
8031 @c fraction mp_do_crossing_point (integer a, integer b, integer c) {
8032   integer d; /* recursive counter */
8033   integer x,xx,x0,x1,x2; /* temporary registers for bisection */
8034   if ( a<0 ) zero_crossing;
8035   if ( c>=0 ) { 
8036     if ( b>=0 ) {
8037       if ( c>0 ) { no_crossing; }
8038       else if ( (a==0)&&(b==0) ) { no_crossing;} 
8039       else { one_crossing; } 
8040     }
8041     if ( a==0 ) zero_crossing;
8042   } else if ( a==0 ) {
8043     if ( b<=0 ) zero_crossing;
8044   }
8045   @<Use bisection to find the crossing point, if one exists@>;
8046 }
8047
8048 @ The general bisection method is quite simple when $n=2$, hence
8049 |crossing_point| does not take much time. At each stage in the
8050 recursion we have a subinterval defined by |l| and~|j| such that
8051 $B(a,b,c;2^{-l}(j+t))=B(x_0,x_1,x_2;t)$, and we want to ``zero in'' on
8052 the subinterval where $x_0\G0$ and $\min(x_1,x_2)<0$.
8053
8054 It is convenient for purposes of calculation to combine the values
8055 of |l| and~|j| in a single variable $d=2^l+j$, because the operation
8056 of bisection then corresponds simply to doubling $d$ and possibly
8057 adding~1. Furthermore it proves to be convenient to modify
8058 our previous conventions for bisection slightly, maintaining the
8059 variables $X_0=2^lx_0$, $X_1=2^l(x_0-x_1)$, and $X_2=2^l(x_1-x_2)$.
8060 With these variables the conditions $x_0\ge0$ and $\min(x_1,x_2)<0$ are
8061 equivalent to $\max(X_1,X_1+X_2)>X_0\ge0$.
8062
8063 The following code maintains the invariant relations
8064 $0\L|x0|<\max(|x1|,|x1|+|x2|)$,
8065 $\vert|x1|\vert<2^{30}$, $\vert|x2|\vert<2^{30}$;
8066 it has been constructed in such a way that no arithmetic overflow
8067 will occur if the inputs satisfy
8068 $a<2^{30}$, $\vert a-b\vert<2^{30}$, and $\vert b-c\vert<2^{30}$.
8069
8070 @<Use bisection to find the crossing point...@>=
8071 d=1; x0=a; x1=a-b; x2=b-c;
8072 do {  
8073   x=half(x1+x2);
8074   if ( x1-x0>x0 ) { 
8075     x2=x; x0+=x0; d+=d;  
8076   } else { 
8077     xx=x1+x-x0;
8078     if ( xx>x0 ) { 
8079       x2=x; x0+=x0; d+=d;
8080     }  else { 
8081       x0=x0-xx;
8082       if ( x<=x0 ) { if ( x+x2<=x0 ) no_crossing; }
8083       x1=x; d=d+d+1;
8084     }
8085   }
8086 } while (d<fraction_one);
8087 return (d-fraction_one)
8088
8089 @ Here is a routine that computes the $x$ or $y$ coordinate of the point on
8090 a cubic corresponding to the |fraction| value~|t|.
8091
8092 It is convenient to define a \.{WEB} macro |t_of_the_way| such that
8093 |t_of_the_way(a,b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|.
8094
8095 @d t_of_the_way(A,B) ((A)-mp_take_fraction(mp,((A)-(B)),t))
8096
8097 @c scaled mp_eval_cubic (MP mp,pointer p, pointer q, fraction t) {
8098   scaled x1,x2,x3; /* intermediate values */
8099   x1=t_of_the_way(knot_coord(p),right_coord(p));
8100   x2=t_of_the_way(right_coord(p),left_coord(q));
8101   x3=t_of_the_way(left_coord(q),knot_coord(q));
8102   x1=t_of_the_way(x1,x2);
8103   x2=t_of_the_way(x2,x3);
8104   return t_of_the_way(x1,x2);
8105 }
8106
8107 @ The actual bounding box information is stored in global variables.
8108 Since it is convenient to address the $x$ and $y$ information
8109 separately, we define arrays indexed by |x_code..y_code| and use
8110 macros to give them more convenient names.
8111
8112 @<Types...@>=
8113 enum mp_bb_code  {
8114   mp_x_code=0, /* index for |minx| and |maxx| */
8115   mp_y_code /* index for |miny| and |maxy| */
8116 } ;
8117
8118
8119 @d minx mp->bbmin[mp_x_code]
8120 @d maxx mp->bbmax[mp_x_code]
8121 @d miny mp->bbmin[mp_y_code]
8122 @d maxy mp->bbmax[mp_y_code]
8123
8124 @<Glob...@>=
8125 scaled bbmin[mp_y_code+1];
8126 scaled bbmax[mp_y_code+1]; 
8127 /* the result of procedures that compute bounding box information */
8128
8129 @ Now we're ready for the key part of the bounding box computation.
8130 The |bound_cubic| procedure updates |bbmin[c]| and |bbmax[c]| based on
8131 $$B(\hbox{|knot_coord(p)|}, \hbox{|right_coord(p)|},
8132     \hbox{|left_coord(q)|}, \hbox{|knot_coord(q)|};t)
8133 $$
8134 for $0<t\le1$.  In other words, the procedure adjusts the bounds to
8135 accommodate |knot_coord(q)| and any extremes over the range $0<t<1$.
8136 The |c| parameter is |x_code| or |y_code|.
8137
8138 @c void mp_bound_cubic (MP mp,pointer p, pointer q, small_number c) {
8139   boolean wavy; /* whether we need to look for extremes */
8140   scaled del1,del2,del3,del,dmax; /* proportional to the control
8141      points of a quadratic derived from a cubic */
8142   fraction t,tt; /* where a quadratic crosses zero */
8143   scaled x; /* a value that |bbmin[c]| and |bbmax[c]| must accommodate */
8144   x=knot_coord(q);
8145   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8146   @<Check the control points against the bounding box and set |wavy:=true|
8147     if any of them lie outside@>;
8148   if ( wavy ) {
8149     del1=right_coord(p)-knot_coord(p);
8150     del2=left_coord(q)-right_coord(p);
8151     del3=knot_coord(q)-left_coord(q);
8152     @<Scale up |del1|, |del2|, and |del3| for greater accuracy;
8153       also set |del| to the first nonzero element of |(del1,del2,del3)|@>;
8154     if ( del<0 ) {
8155       negate(del1); negate(del2); negate(del3);
8156     };
8157     t=mp_crossing_point(mp, del1,del2,del3);
8158     if ( t<fraction_one ) {
8159       @<Test the extremes of the cubic against the bounding box@>;
8160     }
8161   }
8162 }
8163
8164 @ @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>=
8165 if ( x<mp->bbmin[c] ) mp->bbmin[c]=x;
8166 if ( x>mp->bbmax[c] ) mp->bbmax[c]=x
8167
8168 @ @<Check the control points against the bounding box and set...@>=
8169 wavy=true;
8170 if ( mp->bbmin[c]<=right_coord(p) )
8171   if ( right_coord(p)<=mp->bbmax[c] )
8172     if ( mp->bbmin[c]<=left_coord(q) )
8173       if ( left_coord(q)<=mp->bbmax[c] )
8174         wavy=false
8175
8176 @ If |del1=del2=del3=0|, it's impossible to obey the title of this
8177 section. We just set |del=0| in that case.
8178
8179 @<Scale up |del1|, |del2|, and |del3| for greater accuracy...@>=
8180 if ( del1!=0 ) del=del1;
8181 else if ( del2!=0 ) del=del2;
8182 else del=del3;
8183 if ( del!=0 ) {
8184   dmax=abs(del1);
8185   if ( abs(del2)>dmax ) dmax=abs(del2);
8186   if ( abs(del3)>dmax ) dmax=abs(del3);
8187   while ( dmax<fraction_half ) {
8188     dmax+=dmax; del1+=del1; del2+=del2; del3+=del3;
8189   }
8190 }
8191
8192 @ Since |crossing_point| has tried to choose |t| so that
8193 $B(|del1|,|del2|,|del3|;\tau)$ crosses zero at $\tau=|t|$ with negative
8194 slope, the value of |del2| computed below should not be positive.
8195 But rounding error could make it slightly positive in which case we
8196 must cut it to zero to avoid confusion.
8197
8198 @<Test the extremes of the cubic against the bounding box@>=
8199
8200   x=mp_eval_cubic(mp, p,q,t);
8201   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8202   del2=t_of_the_way(del2,del3);
8203     /* now |0,del2,del3| represent the derivative on the remaining interval */
8204   if ( del2>0 ) del2=0;
8205   tt=mp_crossing_point(mp, 0,-del2,-del3);
8206   if ( tt<fraction_one ) {
8207     @<Test the second extreme against the bounding box@>;
8208   }
8209 }
8210
8211 @ @<Test the second extreme against the bounding box@>=
8212 {
8213    x=mp_eval_cubic(mp, p,q,t_of_the_way(tt,fraction_one));
8214   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8215 }
8216
8217 @ Finding the bounding box of a path is basically a matter of applying
8218 |bound_cubic| twice for each pair of adjacent knots.
8219
8220 @c void mp_path_bbox (MP mp,pointer h) {
8221   pointer p,q; /* a pair of adjacent knots */
8222    minx=x_coord(h); miny=y_coord(h);
8223   maxx=minx; maxy=miny;
8224   p=h;
8225   do {  
8226     if ( right_type(p)==mp_endpoint ) return;
8227     q=link(p);
8228     mp_bound_cubic(mp, x_loc(p),x_loc(q),mp_x_code);
8229     mp_bound_cubic(mp, y_loc(p),y_loc(q),mp_y_code);
8230     p=q;
8231   } while (p!=h);
8232 }
8233
8234 @ Another important way to measure a path is to find its arc length.  This
8235 is best done by using the general bisection algorithm to subdivide the path
8236 until obtaining ``well behaved'' subpaths whose arc lengths can be approximated
8237 by simple means.
8238
8239 Since the arc length is the integral with respect to time of the magnitude of
8240 the velocity, it is natural to use Simpson's rule for the approximation.
8241 @^Simpson's rule@>
8242 If $\dot B(t)$ is the spline velocity, Simpson's rule gives
8243 $$ \vb\dot B(0)\vb + 4\vb\dot B({1\over2})\vb + \vb\dot B(1)\vb \over 6 $$
8244 for the arc length of a path of length~1.  For a cubic spline
8245 $B(z_0,z_1,z_2,z_3;t)$, the time derivative $\dot B(t)$ is
8246 $3B(dz_0,dz_1,dz_2;t)$, where $dz_i=z_{i+1}-z_i$.  Hence the arc length
8247 approximation is
8248 $$ {\vb dz_0\vb \over 2} + 2\vb dz_{02}\vb + {\vb dz_2\vb \over 2}, $$
8249 where
8250 $$ dz_{02}={1\over2}\left({dz_0+dz_1\over 2}+{dz_1+dz_2\over 2}\right)$$
8251 is the result of the bisection algorithm.
8252
8253 @ The remaining problem is how to decide when a subpath is ``well behaved.''
8254 This could be done via the theoretical error bound for Simpson's rule,
8255 @^Simpson's rule@>
8256 but this is impractical because it requires an estimate of the fourth
8257 derivative of the quantity being integrated.  It is much easier to just perform
8258 a bisection step and see how much the arc length estimate changes.  Since the
8259 error for Simpson's rule is proportional to the fourth power of the sample
8260 spacing, the remaining error is typically about $1\over16$ of the amount of
8261 the change.  We say ``typically'' because the error has a pseudo-random behavior
8262 that could cause the two estimates to agree when each contain large errors.
8263
8264 To protect against disasters such as undetected cusps, the bisection process
8265 should always continue until all the $dz_i$ vectors belong to a single
8266 $90^\circ$ sector.  This ensures that no point on the spline can have velocity
8267 less than 70\% of the minimum of $\vb dz_0\vb$, $\vb dz_1\vb$ and $\vb dz_2\vb$.
8268 If such a spline happens to produce an erroneous arc length estimate that
8269 is little changed by bisection, the amount of the error is likely to be fairly
8270 small.  We will try to arrange things so that freak accidents of this type do
8271 not destroy the inverse relationship between the \&{arclength} and
8272 \&{arctime} operations.
8273 @:arclength_}{\&{arclength} primitive@>
8274 @:arctime_}{\&{arctime} primitive@>
8275
8276 @ The \&{arclength} and \&{arctime} operations are both based on a recursive
8277 @^recursion@>
8278 function that finds the arc length of a cubic spline given $dz_0$, $dz_1$,
8279 $dz_2$. This |arc_test| routine also takes an arc length goal |a_goal| and
8280 returns the time when the arc length reaches |a_goal| if there is such a time.
8281 Thus the return value is either an arc length less than |a_goal| or, if the
8282 arc length would be at least |a_goal|, it returns a time value decreased by
8283 |two|.  This allows the caller to use the sign of the result to distinguish
8284 between arc lengths and time values.  On certain types of overflow, it is
8285 possible for |a_goal| and the result of |arc_test| both to be |el_gordo|.
8286 Otherwise, the result is always less than |a_goal|.
8287
8288 Rather than halving the control point coordinates on each recursive call to
8289 |arc_test|, it is better to keep them proportional to velocity on the original
8290 curve and halve the results instead.  This means that recursive calls can
8291 potentially use larger error tolerances in their arc length estimates.  How
8292 much larger depends on to what extent the errors behave as though they are
8293 independent of each other.  To save computing time, we use optimistic assumptions
8294 and increase the tolerance by a factor of about $\sqrt2$ for each recursive
8295 call.
8296
8297 In addition to the tolerance parameter, |arc_test| should also have parameters
8298 for ${1\over3}\vb\dot B(0)\vb$, ${2\over3}\vb\dot B({1\over2})\vb$, and
8299 ${1\over3}\vb\dot B(1)\vb$.  These quantities are relatively expensive to compute
8300 and they are needed in different instances of |arc_test|.
8301
8302 @c @t\4@>@<Declare subroutines needed by |arc_test|@>;
8303 scaled mp_arc_test (MP mp, scaled dx0, scaled dy0, scaled dx1, scaled dy1, 
8304                     scaled dx2, scaled dy2, scaled  v0, scaled v02, 
8305                     scaled v2, scaled a_goal, scaled tol) {
8306   boolean simple; /* are the control points confined to a $90^\circ$ sector? */
8307   scaled dx01, dy01, dx12, dy12, dx02, dy02;  /* bisection results */
8308   scaled v002, v022;
8309     /* twice the velocity magnitudes at $t={1\over4}$ and $t={3\over4}$ */
8310   scaled arc; /* best arc length estimate before recursion */
8311   @<Other local variables in |arc_test|@>;
8312   @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,
8313     |dx2|, |dy2|@>;
8314   @<Initialize |v002|, |v022|, and the arc length estimate |arc|; if it overflows
8315     set |arc_test| and |return|@>;
8316   @<Test if the control points are confined to one quadrant or rotating them
8317     $45^\circ$ would put them in one quadrant.  Then set |simple| appropriately@>;
8318   if ( simple && (abs(arc-v02-halfp(v0+v2)) <= tol) ) {
8319     if ( arc < a_goal ) {
8320       return arc;
8321     } else {
8322        @<Estimate when the arc length reaches |a_goal| and set |arc_test| to
8323          that time minus |two|@>;
8324     }
8325   } else {
8326     @<Use one or two recursive calls to compute the |arc_test| function@>;
8327   }
8328 }
8329
8330 @ The |tol| value should by multiplied by $\sqrt 2$ before making recursive
8331 calls, but $1.5$ is an adequate approximation.  It is best to avoid using
8332 |make_fraction| in this inner loop.
8333 @^inner loop@>
8334
8335 @<Use one or two recursive calls to compute the |arc_test| function@>=
8336
8337   @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is as
8338     large as possible@>;
8339   tol = tol + halfp(tol);
8340   a = mp_arc_test(mp, dx0,dy0, dx01,dy01, dx02,dy02, v0, v002, 
8341                   halfp(v02), a_new, tol);
8342   if ( a<0 )  {
8343      return (-halfp(two-a));
8344   } else { 
8345     @<Update |a_new| to reduce |a_new+a_aux| by |a|@>;
8346     b = mp_arc_test(mp, dx02,dy02, dx12,dy12, dx2,dy2,
8347                     halfp(v02), v022, v2, a_new, tol);
8348     if ( b<0 )  
8349       return (-halfp(-b) - half_unit);
8350     else  
8351       return (a + half(b-a));
8352   }
8353 }
8354
8355 @ @<Other local variables in |arc_test|@>=
8356 scaled a,b; /* results of recursive calls */
8357 scaled a_new,a_aux; /* the sum of these gives the |a_goal| */
8358
8359 @ @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is...@>=
8360 a_aux = el_gordo - a_goal;
8361 if ( a_goal > a_aux ) {
8362   a_aux = a_goal - a_aux;
8363   a_new = el_gordo;
8364 } else { 
8365   a_new = a_goal + a_goal;
8366   a_aux = 0;
8367 }
8368
8369 @ There is no need to maintain |a_aux| at this point so we use it as a temporary
8370 to force the additions and subtractions to be done in an order that avoids
8371 overflow.
8372
8373 @<Update |a_new| to reduce |a_new+a_aux| by |a|@>=
8374 if ( a > a_aux ) {
8375   a_aux = a_aux - a;
8376   a_new = a_new + a_aux;
8377 }
8378
8379 @ This code assumes all {\it dx} and {\it dy} variables have magnitude less than
8380 |fraction_four|.  To simplify the rest of the |arc_test| routine, we strengthen
8381 this assumption by requiring the norm of each $({\it dx},{\it dy})$ pair to obey
8382 this bound.  Note that recursive calls will maintain this invariant.
8383
8384 @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,...@>=
8385 dx01 = half(dx0 + dx1);
8386 dx12 = half(dx1 + dx2);
8387 dx02 = half(dx01 + dx12);
8388 dy01 = half(dy0 + dy1);
8389 dy12 = half(dy1 + dy2);
8390 dy02 = half(dy01 + dy12)
8391
8392 @ We should be careful to keep |arc<el_gordo| so that calling |arc_test| with
8393 |a_goal=el_gordo| is guaranteed to yield the arc length.
8394
8395 @<Initialize |v002|, |v022|, and the arc length estimate |arc|;...@>=
8396 v002 = mp_pyth_add(mp, dx01+half(dx0+dx02), dy01+half(dy0+dy02));
8397 v022 = mp_pyth_add(mp, dx12+half(dx02+dx2), dy12+half(dy02+dy2));
8398 tmp = halfp(v02+2);
8399 arc1 = v002 + half(halfp(v0+tmp) - v002);
8400 arc = v022 + half(halfp(v2+tmp) - v022);
8401 if ( (arc < el_gordo-arc1) )  {
8402   arc = arc+arc1;
8403 } else { 
8404   mp->arith_error = true;
8405   if ( a_goal==el_gordo )  return (el_gordo);
8406   else return (-two);
8407 }
8408
8409 @ @<Other local variables in |arc_test|@>=
8410 scaled tmp, tmp2; /* all purpose temporary registers */
8411 scaled arc1; /* arc length estimate for the first half */
8412
8413 @ @<Test if the control points are confined to one quadrant or rotating...@>=
8414 simple = ((dx0>=0) && (dx1>=0) && (dx2>=0)) ||
8415          ((dx0<=0) && (dx1<=0) && (dx2<=0));
8416 if ( simple )
8417   simple = ((dy0>=0) && (dy1>=0) && (dy2>=0)) ||
8418            ((dy0<=0) && (dy1<=0) && (dy2<=0));
8419 if ( ! simple ) {
8420   simple = ((dx0>=dy0) && (dx1>=dy1) && (dx2>=dy2)) ||
8421            ((dx0<=dy0) && (dx1<=dy1) && (dx2<=dy2));
8422   if ( simple ) 
8423     simple = ((-dx0>=dy0) && (-dx1>=dy1) && (-dx2>=dy2)) ||
8424              ((-dx0<=dy0) && (-dx1<=dy1) && (-dx2<=dy2));
8425 }
8426
8427 @ Since Simpson's rule is based on approximating the integrand by a parabola,
8428 @^Simpson's rule@>
8429 it is appropriate to use the same approximation to decide when the integral
8430 reaches the intermediate value |a_goal|.  At this point
8431 $$\eqalign{
8432     {\vb\dot B(0)\vb\over 3} &= \hbox{|v0|}, \qquad
8433     {\vb\dot B({1\over4})\vb\over 3} = {\hbox{|v002|}\over 2}, \qquad
8434     {\vb\dot B({1\over2})\vb\over 3} = {\hbox{|v02|}\over 2}, \cr
8435     {\vb\dot B({3\over4})\vb\over 3} &= {\hbox{|v022|}\over 2}, \qquad
8436     {\vb\dot B(1)\vb\over 3} = \hbox{|v2|} \cr
8437 }
8438 $$
8439 and
8440 $$ {\vb\dot B(t)\vb\over 3} \approx
8441   \cases{B\left(\hbox{|v0|},
8442       \hbox{|v002|}-{1\over 2}\hbox{|v0|}-{1\over 4}\hbox{|v02|},
8443       {1\over 2}\hbox{|v02|}; 2t \right)&
8444     if $t\le{1\over 2}$\cr
8445   B\left({1\over 2}\hbox{|v02|},
8446       \hbox{|v022|}-{1\over 4}\hbox{|v02|}-{1\over 2}\hbox{|v2|},
8447       \hbox{|v2|}; 2t-1 \right)&
8448     if $t\ge{1\over 2}$.\cr}
8449  \eqno (*)
8450 $$
8451 We can integrate $\vb\dot B(t)\vb$ by using
8452 $$\int 3B(a,b,c;\tau)\,dt =
8453   {B(0,a,a+b,a+b+c;\tau) + {\rm constant} \over {d\tau\over dt}}.
8454 $$
8455
8456 This construction allows us to find the time when the arc length reaches
8457 |a_goal| by solving a cubic equation of the form
8458 $$ B(0,a,a+b,a+b+c;\tau) = x, $$
8459 where $\tau$ is $2t$ or $2t+1$, $x$ is |a_goal| or |a_goal-arc1|, and $a$, $b$,
8460 and $c$ are the Bernshte{\u\i}n coefficients from $(*)$ divided by
8461 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
8462 $d\tau\over dt$.  We shall define a function |solve_rising_cubic| that finds
8463 $\tau$ given $a$, $b$, $c$, and $x$.
8464
8465 @<Estimate when the arc length reaches |a_goal| and set |arc_test| to...@>=
8466
8467   tmp = (v02 + 2) / 4;
8468   if ( a_goal<=arc1 ) {
8469     tmp2 = halfp(v0);
8470     return 
8471       (halfp(mp_solve_rising_cubic(mp, tmp2, arc1-tmp2-tmp, tmp, a_goal))- two);
8472   } else { 
8473     tmp2 = halfp(v2);
8474     return ((half_unit - two) +
8475       halfp(mp_solve_rising_cubic(mp, tmp, arc-arc1-tmp-tmp2, tmp2, a_goal-arc1)));
8476   }
8477 }
8478
8479 @ Here is the |solve_rising_cubic| routine that finds the time~$t$ when
8480 $$ B(0, a, a+b, a+b+c; t) = x. $$
8481 This routine is based on |crossing_point| but is simplified by the
8482 assumptions that $B(a,b,c;t)\ge0$ for $0\le t\le1$ and that |0<=x<=a+b+c|.
8483 If rounding error causes this condition to be violated slightly, we just ignore
8484 it and proceed with binary search.  This finds a time when the function value
8485 reaches |x| and the slope is positive.
8486
8487 @<Declare subroutines needed by |arc_test|@>=
8488 scaled mp_solve_rising_cubic (MP mp,scaled a, scaled b,  scaled c, scaled x) {
8489   scaled ab, bc, ac; /* bisection results */
8490   integer t; /* $2^k+q$ where unscaled answer is in $[q2^{-k},(q+1)2^{-k})$ */
8491   integer xx; /* temporary for updating |x| */
8492   if ( (a<0) || (c<0) ) mp_confusion(mp, "rising?");
8493 @:this can't happen rising?}{\quad rising?@>
8494   if ( x<=0 ) {
8495         return 0;
8496   } else if ( x >= a+b+c ) {
8497     return unity;
8498   } else { 
8499     t = 1;
8500     @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than
8501       |el_gordo div 3|@>;
8502     do {  
8503       t+=t;
8504       @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>;
8505       xx = x - a - ab - ac;
8506       if ( xx < -x ) { x+=x; b=ab; c=ac;  }
8507       else { x = x + xx;  a=ac; b=mp->bc; t = t+1; };
8508     } while (t < unity);
8509     return (t - unity);
8510   }
8511 }
8512
8513 @ @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>=
8514 ab = half(a+b);
8515 bc = half(b+c);
8516 ac = half(ab+bc)
8517
8518 @ @d one_third_el_gordo 05252525252 /* upper bound on |a|, |b|, and |c| */
8519
8520 @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than...@>=
8521 while ((a>one_third_el_gordo)||(b>one_third_el_gordo)||(c>one_third_el_gordo)) { 
8522   a = halfp(a);
8523   b = half(b);
8524   c = halfp(c);
8525   x = halfp(x);
8526 }
8527
8528 @ It is convenient to have a simpler interface to |arc_test| that requires no
8529 unnecessary arguments and ensures that each $({\it dx},{\it dy})$ pair has
8530 length less than |fraction_four|.
8531
8532 @d arc_tol   16  /* quit when change in arc length estimate reaches this */
8533
8534 @c scaled mp_do_arc_test (MP mp,scaled dx0, scaled dy0, scaled dx1, 
8535                           scaled dy1, scaled dx2, scaled dy2, scaled a_goal) {
8536   scaled v0,v1,v2; /* length of each $({\it dx},{\it dy})$ pair */
8537   scaled v02; /* twice the norm of the quadratic at $t={1\over2}$ */
8538   v0 = mp_pyth_add(mp, dx0,dy0);
8539   v1 = mp_pyth_add(mp, dx1,dy1);
8540   v2 = mp_pyth_add(mp, dx2,dy2);
8541   if ( (v0>=fraction_four) || (v1>=fraction_four) || (v2>=fraction_four) ) { 
8542     mp->arith_error = true;
8543     if ( a_goal==el_gordo )  return el_gordo;
8544     else return (-two);
8545   } else { 
8546     v02 = mp_pyth_add(mp, dx1+half(dx0+dx2), dy1+half(dy0+dy2));
8547     return (mp_arc_test(mp, dx0,dy0, dx1,dy1, dx2,dy2,
8548                                  v0, v02, v2, a_goal, arc_tol));
8549   }
8550 }
8551
8552 @ Now it is easy to find the arc length of an entire path.
8553
8554 @c scaled mp_get_arc_length (MP mp,pointer h) {
8555   pointer p,q; /* for traversing the path */
8556   scaled a,a_tot; /* current and total arc lengths */
8557   a_tot = 0;
8558   p = h;
8559   while ( right_type(p)!=mp_endpoint ){ 
8560     q = link(p);
8561     a = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8562       left_x(q)-right_x(p), left_y(q)-right_y(p),
8563       x_coord(q)-left_x(q), y_coord(q)-left_y(q), el_gordo);
8564     a_tot = mp_slow_add(mp, a, a_tot);
8565     if ( q==h ) break;  else p=q;
8566   }
8567   check_arith;
8568   return a_tot;
8569 }
8570
8571 @ The inverse operation of finding the time on a path~|h| when the arc length
8572 reaches some value |arc0| can also be accomplished via |do_arc_test|.  Some care
8573 is required to handle very large times or negative times on cyclic paths.  For
8574 non-cyclic paths, |arc0| values that are negative or too large cause
8575 |get_arc_time| to return 0 or the length of path~|h|.
8576
8577 If |arc0| is greater than the arc length of a cyclic path~|h|, the result is a
8578 time value greater than the length of the path.  Since it could be much greater,
8579 we must be prepared to compute the arc length of path~|h| and divide this into
8580 |arc0| to find how many multiples of the length of path~|h| to add.
8581
8582 @c scaled mp_get_arc_time (MP mp,pointer h, scaled  arc0) {
8583   pointer p,q; /* for traversing the path */
8584   scaled t_tot; /* accumulator for the result */
8585   scaled t; /* the result of |do_arc_test| */
8586   scaled arc; /* portion of |arc0| not used up so far */
8587   integer n; /* number of extra times to go around the cycle */
8588   if ( arc0<0 ) {
8589     @<Deal with a negative |arc0| value and |return|@>;
8590   }
8591   if ( arc0==el_gordo ) decr(arc0);
8592   t_tot = 0;
8593   arc = arc0;
8594   p = h;
8595   while ( (right_type(p)!=mp_endpoint) && (arc>0) ) {
8596     q = link(p);
8597     t = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8598       left_x(q)-right_x(p), left_y(q)-right_y(p),
8599       x_coord(q)-left_x(q), y_coord(q)-left_y(q), arc);
8600     @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>;
8601     if ( q==h ) {
8602       @<Update |t_tot| and |arc| to avoid going around the cyclic
8603         path too many times but set |arith_error:=true| and |goto done| on
8604         overflow@>;
8605     }
8606     p = q;
8607   }
8608   check_arith;
8609   return t_tot;
8610 }
8611
8612 @ @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>=
8613 if ( t<0 ) { t_tot = t_tot + t + two;  arc = 0;  }
8614 else { t_tot = t_tot + unity;  arc = arc - t;  }
8615
8616 @ @<Deal with a negative |arc0| value and |return|@>=
8617
8618   if ( left_type(h)==mp_endpoint ) {
8619     t_tot=0;
8620   } else { 
8621     p = mp_htap_ypoc(mp, h);
8622     t_tot = -mp_get_arc_time(mp, p, -arc0);
8623     mp_toss_knot_list(mp, p);
8624   }
8625   check_arith;
8626   return t_tot;
8627 }
8628
8629 @ @<Update |t_tot| and |arc| to avoid going around the cyclic...@>=
8630 if ( arc>0 ) { 
8631   n = arc / (arc0 - arc);
8632   arc = arc - n*(arc0 - arc);
8633   if ( t_tot > el_gordo / (n+1) ) { 
8634     mp->arith_error = true;
8635     t_tot = el_gordo;
8636     break;
8637   }
8638   t_tot = (n + 1)*t_tot;
8639 }
8640
8641 @* \[20] Data structures for pens.
8642 A Pen in \MP\ can be either elliptical or polygonal.  Elliptical pens result
8643 in \ps\ \&{stroke} commands, while anything drawn with a polygonal pen is
8644 @:stroke}{\&{stroke} command@>
8645 converted into an area fill as described in the next part of this program.
8646 The mathematics behind this process is based on simple aspects of the theory
8647 of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge Stolfi
8648 [``A kinematic framework for computational geometry,'' Proc.\ IEEE Symp.\
8649 Foundations of Computer Science {\bf 24} (1983), 100--111].
8650
8651 Polygonal pens are created from paths via \MP's \&{makepen} primitive.
8652 @:makepen_}{\&{makepen} primitive@>
8653 This path representation is almost sufficient for our purposes except that
8654 a pen path should always be a convex polygon with the vertices in
8655 counter-clockwise order.
8656 Since we will need to scan pen polygons both forward and backward, a pen
8657 should be represented as a doubly linked ring of knot nodes.  There is
8658 room for the extra back pointer because we do not need the
8659 |left_type| or |right_type| fields.  In fact, we don't need the |left_x|,
8660 |left_y|, |right_x|, or |right_y| fields either but we leave these alone
8661 so that certain procedures can operate on both pens and paths.  In particular,
8662 pens can be copied using |copy_path| and recycled using |toss_knot_list|.
8663
8664 @d knil info
8665   /* this replaces the |left_type| and |right_type| fields in a pen knot */
8666
8667 @ The |make_pen| procedure turns a path into a pen by initializing
8668 the |knil| pointers and making sure the knots form a convex polygon.
8669 Thus each cubic in the given path becomes a straight line and the control
8670 points are ignored.  If the path is not cyclic, the ends are connected by a
8671 straight line.
8672
8673 @d copy_pen(A) mp_make_pen(mp, mp_copy_path(mp, (A)),false)
8674
8675 @c @<Declare a function called |convex_hull|@>;
8676 pointer mp_make_pen (MP mp,pointer h, boolean need_hull) {
8677   pointer p,q; /* two consecutive knots */
8678   q=h;
8679   do {  
8680     p=q; q=link(q);
8681     knil(q)=p;
8682   } while (q!=h);
8683   if ( need_hull ){ 
8684     h=mp_convex_hull(mp, h);
8685     @<Make sure |h| isn't confused with an elliptical pen@>;
8686   }
8687   return h;
8688 }
8689
8690 @ The only information required about an elliptical pen is the overall
8691 transformation that has been applied to the original \&{pencircle}.
8692 @:pencircle_}{\&{pencircle} primitive@>
8693 Since it suffices to keep track of how the three points $(0,0)$, $(1,0)$,
8694 and $(0,1)$ are transformed, an elliptical pen can be stored in a single
8695 knot node and transformed as if it were a path.
8696
8697 @d pen_is_elliptical(A) ((A)==link((A)))
8698
8699 @c pointer mp_get_pen_circle (MP mp,scaled diam) {
8700   pointer h; /* the knot node to return */
8701   h=mp_get_node(mp, knot_node_size);
8702   link(h)=h; knil(h)=h;
8703   originator(h)=mp_program_code;
8704   x_coord(h)=0; y_coord(h)=0;
8705   left_x(h)=diam; left_y(h)=0;
8706   right_x(h)=0; right_y(h)=diam;
8707   return h;
8708 }
8709
8710 @ If the polygon being returned by |make_pen| has only one vertex, it will
8711 be interpreted as an elliptical pen.  This is no problem since a degenerate
8712 polygon can equally well be thought of as a degenerate ellipse.  We need only
8713 initialize the |left_x|, |left_y|, |right_x|, and |right_y| fields.
8714
8715 @<Make sure |h| isn't confused with an elliptical pen@>=
8716 if ( pen_is_elliptical( h) ){ 
8717   left_x(h)=x_coord(h); left_y(h)=y_coord(h);
8718   right_x(h)=x_coord(h); right_y(h)=y_coord(h);
8719 }
8720
8721 @ We have to cheat a little here but most operations on pens only use
8722 the first three words in each knot node.
8723 @^data structure assumptions@>
8724
8725 @<Initialize a pen at |test_pen| so that it fits in nine words@>=
8726 x_coord(test_pen)=-half_unit;
8727 y_coord(test_pen)=0;
8728 x_coord(test_pen+3)=half_unit;
8729 y_coord(test_pen+3)=0;
8730 x_coord(test_pen+6)=0;
8731 y_coord(test_pen+6)=unity;
8732 link(test_pen)=test_pen+3;
8733 link(test_pen+3)=test_pen+6;
8734 link(test_pen+6)=test_pen;
8735 knil(test_pen)=test_pen+6;
8736 knil(test_pen+3)=test_pen;
8737 knil(test_pen+6)=test_pen+3
8738
8739 @ Printing a polygonal pen is very much like printing a path
8740
8741 @<Declare subroutines for printing expressions@>=
8742 void mp_pr_pen (MP mp,pointer h) {
8743   pointer p,q; /* for list traversal */
8744   if ( pen_is_elliptical(h) ) {
8745     @<Print the elliptical pen |h|@>;
8746   } else { 
8747     p=h;
8748     do {  
8749       mp_print_two(mp, x_coord(p),y_coord(p));
8750       mp_print_nl(mp, " .. ");
8751       @<Advance |p| making sure the links are OK and |return| if there is
8752         a problem@>;
8753      } while (p!=h);
8754      mp_print(mp, "cycle");
8755   }
8756 }
8757
8758 @ @<Advance |p| making sure the links are OK and |return| if there is...@>=
8759 q=link(p);
8760 if ( (q==null) || (knil(q)!=p) ) { 
8761   mp_print_nl(mp, "???"); return; /* this won't happen */
8762 @.???@>
8763 }
8764 p=q
8765
8766 @ @<Print the elliptical pen |h|@>=
8767
8768 mp_print(mp, "pencircle transformed (");
8769 mp_print_scaled(mp, x_coord(h));
8770 mp_print_char(mp, ',');
8771 mp_print_scaled(mp, y_coord(h));
8772 mp_print_char(mp, ',');
8773 mp_print_scaled(mp, left_x(h)-x_coord(h));
8774 mp_print_char(mp, ',');
8775 mp_print_scaled(mp, right_x(h)-x_coord(h));
8776 mp_print_char(mp, ',');
8777 mp_print_scaled(mp, left_y(h)-y_coord(h));
8778 mp_print_char(mp, ',');
8779 mp_print_scaled(mp, right_y(h)-y_coord(h));
8780 mp_print_char(mp, ')');
8781 }
8782
8783 @ Here us another version of |pr_pen| that prints the pen as a diagnostic
8784 message.
8785
8786 @<Declare subroutines for printing expressions@>=
8787 void mp_print_pen (MP mp,pointer h, char *s, boolean nuline) { 
8788   mp_print_diagnostic(mp, "Pen",s,nuline); mp_print_ln(mp);
8789 @.Pen at line...@>
8790   mp_pr_pen(mp, h);
8791   mp_end_diagnostic(mp, true);
8792 }
8793
8794 @ Making a polygonal pen into a path involves restoring the |left_type| and
8795 |right_type| fields and setting the control points so as to make a polygonal
8796 path.
8797
8798 @c 
8799 void mp_make_path (MP mp,pointer h) {
8800   pointer p; /* for traversing the knot list */
8801   small_number k; /* a loop counter */
8802   @<Other local variables in |make_path|@>;
8803   if ( pen_is_elliptical(h) ) {
8804     @<Make the elliptical pen |h| into a path@>;
8805   } else { 
8806     p=h;
8807     do {  
8808       left_type(p)=mp_explicit;
8809       right_type(p)=mp_explicit;
8810       @<copy the coordinates of knot |p| into its control points@>;
8811        p=link(p);
8812     } while (p!=h);
8813   }
8814 }
8815
8816 @ @<copy the coordinates of knot |p| into its control points@>=
8817 left_x(p)=x_coord(p);
8818 left_y(p)=y_coord(p);
8819 right_x(p)=x_coord(p);
8820 right_y(p)=y_coord(p)
8821
8822 @ We need an eight knot path to get a good approximation to an ellipse.
8823
8824 @<Make the elliptical pen |h| into a path@>=
8825
8826   @<Extract the transformation parameters from the elliptical pen~|h|@>;
8827   p=h;
8828   for (k=0;k<=7;k++ ) { 
8829     @<Initialize |p| as the |k|th knot of a circle of unit diameter,
8830       transforming it appropriately@>;
8831     if ( k==7 ) link(p)=h;  else link(p)=mp_get_node(mp, knot_node_size);
8832     p=link(p);
8833   }
8834 }
8835
8836 @ @<Extract the transformation parameters from the elliptical pen~|h|@>=
8837 center_x=x_coord(h);
8838 center_y=y_coord(h);
8839 width_x=left_x(h)-center_x;
8840 width_y=left_y(h)-center_y;
8841 height_x=right_x(h)-center_x;
8842 height_y=right_y(h)-center_y
8843
8844 @ @<Other local variables in |make_path|@>=
8845 scaled center_x,center_y; /* translation parameters for an elliptical pen */
8846 scaled width_x,width_y; /* the effect of a unit change in $x$ */
8847 scaled height_x,height_y; /* the effect of a unit change in $y$ */
8848 scaled dx,dy; /* the vector from knot |p| to its right control point */
8849 integer kk;
8850   /* |k| advanced $270^\circ$ around the ring (cf. $\sin\theta=\cos(\theta+270)$) */
8851
8852 @ The only tricky thing here are the tables |half_cos| and |d_cos| used to
8853 find the point $k/8$ of the way around the circle and the direction vector
8854 to use there.
8855
8856 @<Initialize |p| as the |k|th knot of a circle of unit diameter,...@>=
8857 kk=(k+6)% 8;
8858 x_coord(p)=center_x+mp_take_fraction(mp, mp->half_cos[k],width_x)
8859            +mp_take_fraction(mp, mp->half_cos[kk],height_x);
8860 y_coord(p)=center_y+mp_take_fraction(mp, mp->half_cos[k],width_y)
8861            +mp_take_fraction(mp, mp->half_cos[kk],height_y);
8862 dx=-mp_take_fraction(mp, mp->d_cos[kk],width_x)
8863    +mp_take_fraction(mp, mp->d_cos[k],height_x);
8864 dy=-mp_take_fraction(mp, mp->d_cos[kk],width_y)
8865    +mp_take_fraction(mp, mp->d_cos[k],height_y);
8866 right_x(p)=x_coord(p)+dx;
8867 right_y(p)=y_coord(p)+dy;
8868 left_x(p)=x_coord(p)-dx;
8869 left_y(p)=y_coord(p)-dy;
8870 left_type(p)=mp_explicit;
8871 right_type(p)=mp_explicit;
8872 originator(p)=mp_program_code
8873
8874 @ @<Glob...@>=
8875 fraction half_cos[8]; /* ${1\over2}\cos(45k)$ */
8876 fraction d_cos[8]; /* a magic constant times $\cos(45k)$ */
8877
8878 @ The magic constant for |d_cos| is the distance between $({1\over2},0)$ and
8879 $({1\over4}\sqrt2,{1\over4}\sqrt2)$ times the result of the |velocity|
8880 function for $\theta=\phi=22.5^\circ$.  This comes out to be
8881 $$ d = {\sqrt{2-\sqrt2}\over 3+3\cos22.5^\circ}
8882   \approx 0.132608244919772.
8883 $$
8884
8885 @<Set init...@>=
8886 mp->half_cos[0]=fraction_half;
8887 mp->half_cos[1]=94906266; /* $2^{26}\sqrt2\approx94906265.62$ */
8888 mp->half_cos[2]=0;
8889 mp->d_cos[0]=35596755; /* $2^{28}d\approx35596754.69$ */
8890 mp->d_cos[1]=25170707; /* $2^{27}\sqrt2\,d\approx25170706.63$ */
8891 mp->d_cos[2]=0;
8892 for (k=3;k<= 4;k++ ) { 
8893   mp->half_cos[k]=-mp->half_cos[4-k];
8894   mp->d_cos[k]=-mp->d_cos[4-k];
8895 }
8896 for (k=5;k<= 7;k++ ) { 
8897   mp->half_cos[k]=mp->half_cos[8-k];
8898   mp->d_cos[k]=mp->d_cos[8-k];
8899 }
8900
8901 @ The |convex_hull| function forces a pen polygon to be convex when it is
8902 returned by |make_pen| and after any subsequent transformation where rounding
8903 error might allow the convexity to be lost.
8904 The convex hull algorithm used here is described by F.~P. Preparata and
8905 M.~I. Shamos [{\sl Computational Geometry}, Springer-Verlag, 1985].
8906
8907 @<Declare a function called |convex_hull|@>=
8908 @<Declare a procedure called |move_knot|@>;
8909 pointer mp_convex_hull (MP mp,pointer h) { /* Make a polygonal pen convex */
8910   pointer l,r; /* the leftmost and rightmost knots */
8911   pointer p,q; /* knots being scanned */
8912   pointer s; /* the starting point for an upcoming scan */
8913   scaled dx,dy; /* a temporary pointer */
8914   if ( pen_is_elliptical(h) ) {
8915      return h;
8916   } else { 
8917     @<Set |l| to the leftmost knot in polygon~|h|@>;
8918     @<Set |r| to the rightmost knot in polygon~|h|@>;
8919     if ( l!=r ) { 
8920       s=link(r);
8921       @<Find any knots on the path from |l| to |r| above the |l|-|r| line and
8922         move them past~|r|@>;
8923       @<Find any knots on the path from |s| to |l| below the |l|-|r| line and
8924         move them past~|l|@>;
8925       @<Sort the path from |l| to |r| by increasing $x$@>;
8926       @<Sort the path from |r| to |l| by decreasing $x$@>;
8927     }
8928     if ( l!=link(l) ) {
8929       @<Do a Gramm scan and remove vertices where there is no left turn@>;
8930     }
8931     return l;
8932   }
8933 }
8934
8935 @ All comparisons are done primarily on $x$ and secondarily on $y$.
8936
8937 @<Set |l| to the leftmost knot in polygon~|h|@>=
8938 l=h;
8939 p=link(h);
8940 while ( p!=h ) { 
8941   if ( x_coord(p)<=x_coord(l) )
8942     if ( (x_coord(p)<x_coord(l)) || (y_coord(p)<y_coord(l)) )
8943       l=p;
8944   p=link(p);
8945 }
8946
8947 @ @<Set |r| to the rightmost knot in polygon~|h|@>=
8948 r=h;
8949 p=link(h);
8950 while ( p!=h ) { 
8951   if ( x_coord(p)>=x_coord(r) )
8952     if ( (x_coord(p)>x_coord(r)) || (y_coord(p)>y_coord(r)) )
8953       r=p;
8954   p=link(p);
8955 }
8956
8957 @ @<Find any knots on the path from |l| to |r| above the |l|-|r| line...@>=
8958 dx=x_coord(r)-x_coord(l);
8959 dy=y_coord(r)-y_coord(l);
8960 p=link(l);
8961 while ( p!=r ) { 
8962   q=link(p);
8963   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))>0 )
8964     mp_move_knot(mp, p, r);
8965   p=q;
8966 }
8967
8968 @ The |move_knot| procedure removes |p| from a doubly linked list and inserts
8969 it after |q|.
8970
8971 @ @<Declare a procedure called |move_knot|@>=
8972 void mp_move_knot (MP mp,pointer p, pointer q) { 
8973   link(knil(p))=link(p);
8974   knil(link(p))=knil(p);
8975   knil(p)=q;
8976   link(p)=link(q);
8977   link(q)=p;
8978   knil(link(p))=p;
8979 }
8980
8981 @ @<Find any knots on the path from |s| to |l| below the |l|-|r| line...@>=
8982 p=s;
8983 while ( p!=l ) { 
8984   q=link(p);
8985   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))<0 )
8986     mp_move_knot(mp, p,l);
8987   p=q;
8988 }
8989
8990 @ The list is likely to be in order already so we just do linear insertions.
8991 Secondary comparisons on $y$ ensure that the sort is consistent with the
8992 choice of |l| and |r|.
8993
8994 @<Sort the path from |l| to |r| by increasing $x$@>=
8995 p=link(l);
8996 while ( p!=r ) { 
8997   q=knil(p);
8998   while ( x_coord(q)>x_coord(p) ) q=knil(q);
8999   while ( x_coord(q)==x_coord(p) ) {
9000     if ( y_coord(q)>y_coord(p) ) q=knil(q); else break;
9001   }
9002   if ( q==knil(p) ) p=link(p);
9003   else { p=link(p); mp_move_knot(mp, knil(p),q); };
9004 }
9005
9006 @ @<Sort the path from |r| to |l| by decreasing $x$@>=
9007 p=link(r);
9008 while ( p!=l ){ 
9009   q=knil(p);
9010   while ( x_coord(q)<x_coord(p) ) q=knil(q);
9011   while ( x_coord(q)==x_coord(p) ) {
9012     if ( y_coord(q)<y_coord(p) ) q=knil(q); else break;
9013   }
9014   if ( q==knil(p) ) p=link(p);
9015   else { p=link(p); mp_move_knot(mp, knil(p),q); };
9016 }
9017
9018 @ The condition involving |ab_vs_cd| tests if there is not a left turn
9019 at knot |q|.  There usually will be a left turn so we streamline the case
9020 where the |then| clause is not executed.
9021
9022 @<Do a Gramm scan and remove vertices where there...@>=
9023
9024 p=l; q=link(l);
9025 while (1) { 
9026   dx=x_coord(q)-x_coord(p);
9027   dy=y_coord(q)-y_coord(p);
9028   p=q; q=link(q);
9029   if ( p==l ) break;
9030   if ( p!=r )
9031     if ( mp_ab_vs_cd(mp, dx,y_coord(q)-y_coord(p),dy,x_coord(q)-x_coord(p))<=0 ) {
9032       @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>;
9033     }
9034   }
9035 }
9036
9037 @ @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>=
9038
9039 s=knil(p);
9040 mp_free_node(mp, p,knot_node_size);
9041 link(s)=q; knil(q)=s;
9042 if ( s==l ) p=s;
9043 else { p=knil(s); q=s; };
9044 }
9045
9046 @ The |find_offset| procedure sets global variables |(cur_x,cur_y)| to the
9047 offset associated with the given direction |(x,y)|.  If two different offsets
9048 apply, it chooses one of them.
9049
9050 @c 
9051 void mp_find_offset (MP mp,scaled x, scaled y, pointer h) {
9052   pointer p,q; /* consecutive knots */
9053   scaled wx,wy,hx,hy;
9054   /* the transformation matrix for an elliptical pen */
9055   fraction xx,yy; /* untransformed offset for an elliptical pen */
9056   fraction d; /* a temporary register */
9057   if ( pen_is_elliptical(h) ) {
9058     @<Find the offset for |(x,y)| on the elliptical pen~|h|@>
9059   } else { 
9060     q=h;
9061     do {  
9062       p=q; q=link(q);
9063     } while (!(mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)>=0));
9064     do {  
9065       p=q; q=link(q);
9066     } while (!(mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)<=0));
9067     mp->cur_x=x_coord(p);
9068     mp->cur_y=y_coord(p);
9069   }
9070 }
9071
9072 @ @<Glob...@>=
9073 scaled cur_x;
9074 scaled cur_y; /* all-purpose return value registers */
9075
9076 @ @<Find the offset for |(x,y)| on the elliptical pen~|h|@>=
9077 if ( (x==0) && (y==0) ) {
9078   mp->cur_x=x_coord(h); mp->cur_y=y_coord(h);  
9079 } else { 
9080   @<Find the non-constant part of the transformation for |h|@>;
9081   while ( (abs(x)<fraction_half) && (abs(y)<fraction_half) ){ 
9082     x+=x; y+=y;  
9083   };
9084   @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the
9085     untransformed version of |(x,y)|@>;
9086   mp->cur_x=x_coord(h)+mp_take_fraction(mp, xx,wx)+mp_take_fraction(mp, yy,hx);
9087   mp->cur_y=y_coord(h)+mp_take_fraction(mp, xx,wy)+mp_take_fraction(mp, yy,hy);
9088 }
9089
9090 @ @<Find the non-constant part of the transformation for |h|@>=
9091 wx=left_x(h)-x_coord(h);
9092 wy=left_y(h)-y_coord(h);
9093 hx=right_x(h)-x_coord(h);
9094 hy=right_y(h)-y_coord(h)
9095
9096 @ @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the...@>=
9097 yy=-(mp_take_fraction(mp, x,hy)+mp_take_fraction(mp, y,-hx));
9098 xx=mp_take_fraction(mp, x,-wy)+mp_take_fraction(mp, y,wx);
9099 d=mp_pyth_add(mp, xx,yy);
9100 if ( d>0 ) { 
9101   xx=half(mp_make_fraction(mp, xx,d));
9102   yy=half(mp_make_fraction(mp, yy,d));
9103 }
9104
9105 @ Finding the bounding box of a pen is easy except if the pen is elliptical.
9106 But we can handle that case by just calling |find_offset| twice.  The answer
9107 is stored in the global variables |minx|, |maxx|, |miny|, and |maxy|.
9108
9109 @c 
9110 void mp_pen_bbox (MP mp,pointer h) {
9111   pointer p; /* for scanning the knot list */
9112   if ( pen_is_elliptical(h) ) {
9113     @<Find the bounding box of an elliptical pen@>;
9114   } else { 
9115     minx=x_coord(h); maxx=minx;
9116     miny=y_coord(h); maxy=miny;
9117     p=link(h);
9118     while ( p!=h ) {
9119       if ( x_coord(p)<minx ) minx=x_coord(p);
9120       if ( y_coord(p)<miny ) miny=y_coord(p);
9121       if ( x_coord(p)>maxx ) maxx=x_coord(p);
9122       if ( y_coord(p)>maxy ) maxy=y_coord(p);
9123       p=link(p);
9124     }
9125   }
9126 }
9127
9128 @ @<Find the bounding box of an elliptical pen@>=
9129
9130 mp_find_offset(mp, 0,fraction_one,h);
9131 maxx=mp->cur_x;
9132 minx=2*x_coord(h)-mp->cur_x;
9133 mp_find_offset(mp, -fraction_one,0,h);
9134 maxy=mp->cur_y;
9135 miny=2*y_coord(h)-mp->cur_y;
9136 }
9137
9138 @* \[21] Edge structures.
9139 Now we come to \MP's internal scheme for representing pictures.
9140 The representation is very different from \MF's edge structures
9141 because \MP\ pictures contain \ps\ graphics objects instead of pixel
9142 images.  However, the basic idea is somewhat similar in that shapes
9143 are represented via their boundaries.
9144
9145 The main purpose of edge structures is to keep track of graphical objects
9146 until it is time to translate them into \ps.  Since \MP\ does not need to
9147 know anything about an edge structure other than how to translate it into
9148 \ps\ and how to find its bounding box, edge structures can be just linked
9149 lists of graphical objects.  \MP\ has no easy way to determine whether
9150 two such objects overlap, but it suffices to draw the first one first and
9151 let the second one overwrite it if necessary.
9152
9153 @<Types...@>=
9154 enum mp_graphical_object_code {
9155   @<Graphical object codes@>
9156 };
9157
9158 @ Let's consider the types of graphical objects one at a time.
9159 First of all, a filled contour is represented by a eight-word node.  The first
9160 word contains |type| and |link| fields, and the next six words contain a
9161 pointer to a cyclic path and the value to use for \ps' \&{currentrgbcolor}
9162 parameter.  If a pen is used for filling |pen_p|, |ljoin_val| and |miterlim_val|
9163 give the relevant information.
9164
9165 @d path_p(A) link((A)+1)
9166   /* a pointer to the path that needs filling */
9167 @d pen_p(A) info((A)+1)
9168   /* a pointer to the pen to fill or stroke with */
9169 @d color_model(A) type((A)+2) /*  the color model  */
9170 @d obj_red_loc(A) ((A)+3)  /* the first of three locations for the color */
9171 @d obj_cyan_loc obj_red_loc  /* the first of four locations for the color */
9172 @d obj_grey_loc obj_red_loc  /* the location for the color */
9173 @d red_val(A) mp->mem[(A)+3].sc
9174   /* the red component of the color in the range $0\ldots1$ */
9175 @d cyan_val red_val
9176 @d grey_val red_val
9177 @d green_val(A) mp->mem[(A)+4].sc
9178   /* the green component of the color in the range $0\ldots1$ */
9179 @d magenta_val green_val
9180 @d blue_val(A) mp->mem[(A)+5].sc
9181   /* the blue component of the color in the range $0\ldots1$ */
9182 @d yellow_val blue_val
9183 @d black_val(A) mp->mem[(A)+6].sc
9184   /* the blue component of the color in the range $0\ldots1$ */
9185 @d ljoin_val(A) name_type((A))  /* the value of \&{linejoin} */
9186 @:mp_linejoin_}{\&{linejoin} primitive@>
9187 @d miterlim_val(A) mp->mem[(A)+7].sc  /* the value of \&{miterlimit} */
9188 @:mp_miterlimit_}{\&{miterlimit} primitive@>
9189 @d obj_color_part(A) mp->mem[(A)+3-red_part].sc
9190   /* interpret an object pointer that has been offset by |red_part..blue_part| */
9191 @d pre_script(A) mp->mem[(A)+8].hh.lh
9192 @d post_script(A) mp->mem[(A)+8].hh.rh
9193 @d fill_node_size 9
9194
9195 @ @<Graphical object codes@>=
9196 mp_fill_code=1,
9197
9198 @ @c 
9199 pointer mp_new_fill_node (MP mp,pointer p) {
9200   /* make a fill node for cyclic path |p| and color black */
9201   pointer t; /* the new node */
9202   t=mp_get_node(mp, fill_node_size);
9203   type(t)=mp_fill_code;
9204   path_p(t)=p;
9205   pen_p(t)=null; /* |null| means don't use a pen */
9206   red_val(t)=0;
9207   green_val(t)=0;
9208   blue_val(t)=0;
9209   black_val(t)=0;
9210   color_model(t)=mp_uninitialized_model;
9211   pre_script(t)=null;
9212   post_script(t)=null;
9213   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9214   return t;
9215 }
9216
9217 @ @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>=
9218 if ( mp->internal[mp_linejoin]>unity ) ljoin_val(t)=2;
9219 else if ( mp->internal[mp_linejoin]>0 ) ljoin_val(t)=1;
9220 else ljoin_val(t)=0;
9221 if ( mp->internal[mp_miterlimit]<unity )
9222   miterlim_val(t)=unity;
9223 else
9224   miterlim_val(t)=mp->internal[mp_miterlimit]
9225
9226 @ A stroked path is represented by an eight-word node that is like a filled
9227 contour node except that it contains the current \&{linecap} value, a scale
9228 factor for the dash pattern, and a pointer that is non-null if the stroke
9229 is to be dashed.  The purpose of the scale factor is to allow a picture to
9230 be transformed without touching the picture that |dash_p| points to.
9231
9232 @d dash_p(A) link((A)+9)
9233   /* a pointer to the edge structure that gives the dash pattern */
9234 @d lcap_val(A) type((A)+9)
9235   /* the value of \&{linecap} */
9236 @:mp_linecap_}{\&{linecap} primitive@>
9237 @d dash_scale(A) mp->mem[(A)+10].sc /* dash lengths are scaled by this factor */
9238 @d stroked_node_size 11
9239
9240 @ @<Graphical object codes@>=
9241 mp_stroked_code=2,
9242
9243 @ @c 
9244 pointer mp_new_stroked_node (MP mp,pointer p) {
9245   /* make a stroked node for path |p| with |pen_p(p)| temporarily |null| */
9246   pointer t; /* the new node */
9247   t=mp_get_node(mp, stroked_node_size);
9248   type(t)=mp_stroked_code;
9249   path_p(t)=p; pen_p(t)=null;
9250   dash_p(t)=null;
9251   dash_scale(t)=unity;
9252   red_val(t)=0;
9253   green_val(t)=0;
9254   blue_val(t)=0;
9255   black_val(t)=0;
9256   color_model(t)=mp_uninitialized_model;
9257   pre_script(t)=null;
9258   post_script(t)=null;
9259   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9260   if ( mp->internal[mp_linecap]>unity ) lcap_val(t)=2;
9261   else if ( mp->internal[mp_linecap]>0 ) lcap_val(t)=1;
9262   else lcap_val(t)=0;
9263   return t;
9264 }
9265
9266 @ When a dashed line is computed in a transformed coordinate system, the dash
9267 lengths get scaled like the pen shape and we need to compensate for this.  Since
9268 there is no unique scale factor for an arbitrary transformation, we use the
9269 the square root of the determinant.  The properties of the determinant make it
9270 easier to maintain the |dash_scale|.  The computation is fairly straight-forward
9271 except for the initialization of the scale factor |s|.  The factor of 64 is
9272 needed because |square_rt| scales its result by $2^8$ while we need $2^{14}$
9273 to counteract the effect of |take_fraction|.
9274
9275 @<Declare subroutines needed by |print_edges|@>=
9276 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) {
9277   scaled maxabs; /* $max(|a|,|b|,|c|,|d|)$ */
9278   integer s; /* amount by which the result of |square_rt| needs to be scaled */
9279   @<Initialize |maxabs|@>;
9280   s=64;
9281   while ( (maxabs<fraction_one) && (s>1) ){ 
9282     a+=a; b+=b; c+=c; d+=d;
9283     maxabs+=maxabs; s=halfp(s);
9284   }
9285   return s*mp_square_rt(mp, abs(mp_take_fraction(mp, a,d)-mp_take_fraction(mp, b,c)));
9286 }
9287 @#
9288 scaled mp_get_pen_scale (MP mp,pointer p) { 
9289   return mp_sqrt_det(mp, 
9290     left_x(p)-x_coord(p), right_x(p)-x_coord(p),
9291     left_y(p)-y_coord(p), right_y(p)-y_coord(p));
9292 }
9293
9294 @ @<Internal library ...@>=
9295 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) ;
9296
9297
9298 @ @<Initialize |maxabs|@>=
9299 maxabs=abs(a);
9300 if ( abs(b)>maxabs ) maxabs=abs(b);
9301 if ( abs(c)>maxabs ) maxabs=abs(c);
9302 if ( abs(d)>maxabs ) maxabs=abs(d)
9303
9304 @ When a picture contains text, this is represented by a fourteen-word node
9305 where the color information and |type| and |link| fields are augmented by
9306 additional fields that describe the text and  how it is transformed.
9307 The |path_p| and |pen_p| pointers are replaced by a number that identifies
9308 the font and a string number that gives the text to be displayed.
9309 The |width|, |height|, and |depth| fields
9310 give the dimensions of the text at its design size, and the remaining six
9311 words give a transformation to be applied to the text.  The |new_text_node|
9312 function initializes everything to default values so that the text comes out
9313 black with its reference point at the origin.
9314
9315 @d text_p(A) link((A)+1)  /* a string pointer for the text to display */
9316 @d font_n(A) info((A)+1)  /* the font number */
9317 @d width_val(A) mp->mem[(A)+7].sc  /* unscaled width of the text */
9318 @d height_val(A) mp->mem[(A)+9].sc  /* unscaled height of the text */
9319 @d depth_val(A) mp->mem[(A)+10].sc  /* unscaled depth of the text */
9320 @d text_tx_loc(A) ((A)+11)
9321   /* the first of six locations for transformation parameters */
9322 @d tx_val(A) mp->mem[(A)+11].sc  /* $x$ shift amount */
9323 @d ty_val(A) mp->mem[(A)+12].sc  /* $y$ shift amount */
9324 @d txx_val(A) mp->mem[(A)+13].sc  /* |txx| transformation parameter */
9325 @d txy_val(A) mp->mem[(A)+14].sc  /* |txy| transformation parameter */
9326 @d tyx_val(A) mp->mem[(A)+15].sc  /* |tyx| transformation parameter */
9327 @d tyy_val(A) mp->mem[(A)+16].sc  /* |tyy| transformation parameter */
9328 @d text_trans_part(A) mp->mem[(A)+11-x_part].sc
9329     /* interpret a text node pointer that has been offset by |x_part..yy_part| */
9330 @d text_node_size 17
9331
9332 @ @<Graphical object codes@>=
9333 mp_text_code=3,
9334
9335 @ @c @<Declare text measuring subroutines@>;
9336 pointer mp_new_text_node (MP mp,char *f,str_number s) {
9337   /* make a text node for font |f| and text string |s| */
9338   pointer t; /* the new node */
9339   t=mp_get_node(mp, text_node_size);
9340   type(t)=mp_text_code;
9341   text_p(t)=s;
9342   font_n(t)=mp_find_font(mp, f); /* this identifies the font */
9343   red_val(t)=0;
9344   green_val(t)=0;
9345   blue_val(t)=0;
9346   black_val(t)=0;
9347   color_model(t)=mp_uninitialized_model;
9348   pre_script(t)=null;
9349   post_script(t)=null;
9350   tx_val(t)=0; ty_val(t)=0;
9351   txx_val(t)=unity; txy_val(t)=0;
9352   tyx_val(t)=0; tyy_val(t)=unity;
9353   mp_set_text_box(mp, t); /* this finds the bounding box */
9354   return t;
9355 }
9356
9357 @ The last two types of graphical objects that can occur in an edge structure
9358 are clipping paths and \&{setbounds} paths.  These are slightly more difficult
9359 @:set_bounds_}{\&{setbounds} primitive@>
9360 to implement because we must keep track of exactly what is being clipped or
9361 bounded when pictures get merged together.  For this reason, each clipping or
9362 \&{setbounds} operation is represented by a pair of nodes:  first comes a
9363 two-word node whose |path_p| gives the relevant path, then there is the list
9364 of objects to clip or bound followed by a two-word node whose second word is
9365 unused.
9366
9367 Using at least two words for each graphical object node allows them all to be
9368 allocated and deallocated similarly with a global array |gr_object_size| to
9369 give the size in words for each object type.
9370
9371 @d start_clip_size 2
9372 @d start_bounds_size 2
9373 @d stop_clip_size 2 /* the second word is not used here */
9374 @d stop_bounds_size 2 /* the second word is not used here */
9375 @#
9376 @d stop_type(A) ((A)+2)
9377   /* matching |type| for |start_clip_code| or |start_bounds_code| */
9378 @d has_color(A) (type((A))<mp_start_clip_code)
9379   /* does a graphical object have color fields? */
9380 @d has_pen(A) (type((A))<mp_text_code)
9381   /* does a graphical object have a |pen_p| field? */
9382 @d is_start_or_stop(A) (type((A))>=mp_start_clip_code)
9383 @d is_stop(A) (type((A))>=mp_stop_clip_code)
9384
9385 @ @<Graphical object codes@>=
9386 mp_start_clip_code=4, /* |type| of a node that starts clipping */
9387 mp_start_bounds_code=5, /* |type| of a node that gives a \&{setbounds} path */
9388 mp_stop_clip_code=6, /* |type| of a node that stops clipping */
9389 mp_stop_bounds_code=7, /* |type| of a node that stops \&{setbounds} */
9390
9391 @ @c 
9392 pointer mp_new_bounds_node (MP mp,pointer p, small_number  c) {
9393   /* make a node of type |c| where |p| is the clipping or \&{setbounds} path */
9394   pointer t; /* the new node */
9395   t=mp_get_node(mp, mp->gr_object_size[c]);
9396   type(t)=c;
9397   path_p(t)=p;
9398   return t;
9399 };
9400
9401 @ We need an array to keep track of the sizes of graphical objects.
9402
9403 @<Glob...@>=
9404 small_number gr_object_size[mp_stop_bounds_code+1];
9405
9406 @ @<Set init...@>=
9407 mp->gr_object_size[mp_fill_code]=fill_node_size;
9408 mp->gr_object_size[mp_stroked_code]=stroked_node_size;
9409 mp->gr_object_size[mp_text_code]=text_node_size;
9410 mp->gr_object_size[mp_start_clip_code]=start_clip_size;
9411 mp->gr_object_size[mp_stop_clip_code]=stop_clip_size;
9412 mp->gr_object_size[mp_start_bounds_code]=start_bounds_size;
9413 mp->gr_object_size[mp_stop_bounds_code]=stop_bounds_size;
9414
9415 @ All the essential information in an edge structure is encoded as a linked list
9416 of graphical objects as we have just seen, but it is helpful to add some
9417 redundant information.  A single edge structure might be used as a dash pattern
9418 many times, and it would be nice to avoid scanning the same structure
9419 repeatedly.  Thus, an edge structure known to be a suitable dash pattern
9420 has a header that gives a list of dashes in a sorted order designed for rapid
9421 translation into \ps.
9422
9423 Each dash is represented by a three-word node containing the initial and final
9424 $x$~coordinates as well as the usual |link| field.  The |link| fields points to
9425 the dash node with the next higher $x$-coordinates and the final link points
9426 to a special location called |null_dash|.  (There should be no overlap between
9427 dashes).  Since the $y$~coordinate of the dash pattern is needed to determine
9428 the period of repetition, this needs to be stored in the edge header along
9429 with a pointer to the list of dash nodes.
9430
9431 @d start_x(A) mp->mem[(A)+1].sc  /* the starting $x$~coordinate in a dash node */
9432 @d stop_x(A) mp->mem[(A)+2].sc  /* the ending $x$~coordinate in a dash node */
9433 @d dash_node_size 3
9434 @d dash_list link
9435   /* in an edge header this points to the first dash node */
9436 @d dash_y(A) mp->mem[(A)+1].sc  /* $y$ value for the dash list in an edge header */
9437
9438 @ It is also convenient for an edge header to contain the bounding
9439 box information needed by the \&{llcorner} and \&{urcorner} operators
9440 so that this does not have to be recomputed unnecessarily.  This is done by
9441 adding fields for the $x$~and $y$ extremes as well as a pointer that indicates
9442 how far the bounding box computation has gotten.  Thus if the user asks for
9443 the bounding box and then adds some more text to the picture before asking
9444 for more bounding box information, the second computation need only look at
9445 the additional text.
9446
9447 When the bounding box has not been computed, the |bblast| pointer points
9448 to a dummy link at the head of the graphical object list while the |minx_val|
9449 and |miny_val| fields contain |el_gordo| and the |maxx_val| and |maxy_val|
9450 fields contain |-el_gordo|.
9451
9452 Since the bounding box of pictures containing objects of type
9453 |mp_start_bounds_code| depends on the value of \&{truecorners}, the bounding box
9454 @:mp_true_corners_}{\&{truecorners} primitive@>
9455 data might not be valid for all values of this parameter.  Hence, the |bbtype|
9456 field is needed to keep track of this.
9457
9458 @d minx_val(A) mp->mem[(A)+2].sc
9459 @d miny_val(A) mp->mem[(A)+3].sc
9460 @d maxx_val(A) mp->mem[(A)+4].sc
9461 @d maxy_val(A) mp->mem[(A)+5].sc
9462 @d bblast(A) link((A)+6)  /* last item considered in bounding box computation */
9463 @d bbtype(A) info((A)+6)  /* tells how bounding box data depends on \&{truecorners} */
9464 @d dummy_loc(A) ((A)+7)  /* where the object list begins in an edge header */
9465 @d no_bounds 0
9466   /* |bbtype| value when bounding box data is valid for all \&{truecorners} values */
9467 @d bounds_set 1
9468   /* |bbtype| value when bounding box data is for \&{truecorners}${}\le 0$ */
9469 @d bounds_unset 2
9470   /* |bbtype| value when bounding box data is for \&{truecorners}${}>0$ */
9471
9472 @c 
9473 void mp_init_bbox (MP mp,pointer h) {
9474   /* Initialize the bounding box information in edge structure |h| */
9475   bblast(h)=dummy_loc(h);
9476   bbtype(h)=no_bounds;
9477   minx_val(h)=el_gordo;
9478   miny_val(h)=el_gordo;
9479   maxx_val(h)=-el_gordo;
9480   maxy_val(h)=-el_gordo;
9481 }
9482
9483 @ The only other entries in an edge header are a reference count in the first
9484 word and a pointer to the tail of the object list in the last word.
9485
9486 @d obj_tail(A) info((A)+7)  /* points to the last entry in the object list */
9487 @d edge_header_size 8
9488
9489 @c 
9490 void mp_init_edges (MP mp,pointer h) {
9491   /* initialize an edge header to null values */
9492   dash_list(h)=null_dash;
9493   obj_tail(h)=dummy_loc(h);
9494   link(dummy_loc(h))=null;
9495   ref_count(h)=null;
9496   mp_init_bbox(mp, h);
9497 }
9498
9499 @ Here is how edge structures are deleted.  The process can be recursive because
9500 of the need to dereference edge structures that are used as dash patterns.
9501 @^recursion@>
9502
9503 @d add_edge_ref(A) incr(ref_count(A))
9504 @d delete_edge_ref(A) { 
9505    if ( ref_count((A))==null ) 
9506      mp_toss_edges(mp, A);
9507    else 
9508      decr(ref_count(A)); 
9509    }
9510
9511 @<Declare the recycling subroutines@>=
9512 void mp_flush_dash_list (MP mp,pointer h);
9513 pointer mp_toss_gr_object (MP mp,pointer p) ;
9514 void mp_toss_edges (MP mp,pointer h) ;
9515
9516 @ @c void mp_toss_edges (MP mp,pointer h) {
9517   pointer p,q;  /* pointers that scan the list being recycled */
9518   pointer r; /* an edge structure that object |p| refers to */
9519   mp_flush_dash_list(mp, h);
9520   q=link(dummy_loc(h));
9521   while ( (q!=null) ) { 
9522     p=q; q=link(q);
9523     r=mp_toss_gr_object(mp, p);
9524     if ( r!=null ) delete_edge_ref(r);
9525   }
9526   mp_free_node(mp, h,edge_header_size);
9527 }
9528 void mp_flush_dash_list (MP mp,pointer h) {
9529   pointer p,q;  /* pointers that scan the list being recycled */
9530   q=dash_list(h);
9531   while ( q!=null_dash ) { 
9532     p=q; q=link(q);
9533     mp_free_node(mp, p,dash_node_size);
9534   }
9535   dash_list(h)=null_dash;
9536 }
9537 pointer mp_toss_gr_object (MP mp,pointer p) {
9538   /* returns an edge structure that needs to be dereferenced */
9539   pointer e; /* the edge structure to return */
9540   e=null;
9541   @<Prepare to recycle graphical object |p|@>;
9542   mp_free_node(mp, p,mp->gr_object_size[type(p)]);
9543   return e;
9544 }
9545
9546 @ @<Prepare to recycle graphical object |p|@>=
9547 switch (type(p)) {
9548 case mp_fill_code: 
9549   mp_toss_knot_list(mp, path_p(p));
9550   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9551   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9552   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9553   break;
9554 case mp_stroked_code: 
9555   mp_toss_knot_list(mp, path_p(p));
9556   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9557   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9558   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9559   e=dash_p(p);
9560   break;
9561 case mp_text_code: 
9562   delete_str_ref(text_p(p));
9563   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9564   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9565   break;
9566 case mp_start_clip_code:
9567 case mp_start_bounds_code: 
9568   mp_toss_knot_list(mp, path_p(p));
9569   break;
9570 case mp_stop_clip_code:
9571 case mp_stop_bounds_code: 
9572   break;
9573 } /* there are no other cases */
9574
9575 @ If we use |add_edge_ref| to ``copy'' edge structures, the real copying needs
9576 to be done before making a significant change to an edge structure.  Much of
9577 the work is done in a separate routine |copy_objects| that copies a list of
9578 graphical objects into a new edge header.
9579
9580 @c @<Declare a function called |copy_objects|@>;
9581 pointer mp_private_edges (MP mp,pointer h) {
9582   /* make a private copy of the edge structure headed by |h| */
9583   pointer hh;  /* the edge header for the new copy */
9584   pointer p,pp;  /* pointers for copying the dash list */
9585   if ( ref_count(h)==null ) {
9586     return h;
9587   } else { 
9588     decr(ref_count(h));
9589     hh=mp_copy_objects(mp, link(dummy_loc(h)),null);
9590     @<Copy the dash list from |h| to |hh|@>;
9591     @<Copy the bounding box information from |h| to |hh| and make |bblast(hh)|
9592       point into the new object list@>;
9593     return hh;
9594   }
9595 }
9596
9597 @ Here we use the fact that |dash_list(hh)=link(hh)|.
9598 @^data structure assumptions@>
9599
9600 @<Copy the dash list from |h| to |hh|@>=
9601 pp=hh; p=dash_list(h);
9602 while ( (p!=null_dash) ) { 
9603   link(pp)=mp_get_node(mp, dash_node_size);
9604   pp=link(pp);
9605   start_x(pp)=start_x(p);
9606   stop_x(pp)=stop_x(p);
9607   p=link(p);
9608 }
9609 link(pp)=null_dash;
9610 dash_y(hh)=dash_y(h)
9611
9612
9613 @ |h| is an edge structure
9614
9615 @d gr_start_x(A)    (A)->start_x_field
9616 @d gr_stop_x(A)     (A)->stop_x_field
9617 @d gr_dash_link(A)  (A)->next_field
9618
9619 @d gr_dash_list(A)  (A)->list_field
9620 @d gr_dash_y(A)     (A)->y_field
9621
9622 @c
9623 struct mp_dash_list *mp_export_dashes (MP mp, pointer h) {
9624   struct mp_dash_list *dl;
9625   struct mp_dash_item *dh, *di;
9626   pointer p;
9627   if (h==null ||  dash_list(h)==null_dash) 
9628         return NULL;
9629   p = dash_list(h);
9630   dl = mp_xmalloc(mp,1,sizeof(struct mp_dash_list));
9631   gr_dash_list(dl) = NULL;
9632   gr_dash_y(dl) = dash_y(h);
9633   dh = NULL;
9634   while (p != null_dash) { 
9635     di=mp_xmalloc(mp,1,sizeof(struct mp_dash_item));
9636     gr_dash_link(di) = NULL;
9637     gr_start_x(di) = start_x(p);
9638     gr_stop_x(di) = stop_x(p);
9639     if (dh==NULL) {
9640       gr_dash_list(dl) = di;
9641     } else {
9642       gr_dash_link(dh) = di;
9643     }
9644     dh = di;
9645     p=link(p);
9646   }
9647   return dl;
9648 }
9649
9650
9651 @ @<Copy the bounding box information from |h| to |hh|...@>=
9652 minx_val(hh)=minx_val(h);
9653 miny_val(hh)=miny_val(h);
9654 maxx_val(hh)=maxx_val(h);
9655 maxy_val(hh)=maxy_val(h);
9656 bbtype(hh)=bbtype(h);
9657 p=dummy_loc(h); pp=dummy_loc(hh);
9658 while ((p!=bblast(h)) ) { 
9659   if ( p==null ) mp_confusion(mp, "bblast");
9660 @:this can't happen bblast}{\quad bblast@>
9661   p=link(p); pp=link(pp);
9662 }
9663 bblast(hh)=pp
9664
9665 @ Here is the promised routine for copying graphical objects into a new edge
9666 structure.  It starts copying at object~|p| and stops just before object~|q|.
9667 If |q| is null, it copies the entire sublist headed at |p|.  The resulting edge
9668 structure requires further initialization by |init_bbox|.
9669
9670 @<Declare a function called |copy_objects|@>=
9671 pointer mp_copy_objects (MP mp, pointer p, pointer q) {
9672   pointer hh;  /* the new edge header */
9673   pointer pp;  /* the last newly copied object */
9674   small_number k;  /* temporary register */
9675   hh=mp_get_node(mp, edge_header_size);
9676   dash_list(hh)=null_dash;
9677   ref_count(hh)=null;
9678   pp=dummy_loc(hh);
9679   while ( (p!=q) ) {
9680     @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>;
9681   }
9682   obj_tail(hh)=pp;
9683   link(pp)=null;
9684   return hh;
9685 }
9686
9687 @ @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>=
9688 { k=mp->gr_object_size[type(p)];
9689   link(pp)=mp_get_node(mp, k);
9690   pp=link(pp);
9691   while ( (k>0) ) { decr(k); mp->mem[pp+k]=mp->mem[p+k];  };
9692   @<Fix anything in graphical object |pp| that should differ from the
9693     corresponding field in |p|@>;
9694   p=link(p);
9695 }
9696
9697 @ @<Fix anything in graphical object |pp| that should differ from the...@>=
9698 switch (type(p)) {
9699 case mp_start_clip_code:
9700 case mp_start_bounds_code: 
9701   path_p(pp)=mp_copy_path(mp, path_p(p));
9702   break;
9703 case mp_fill_code: 
9704   path_p(pp)=mp_copy_path(mp, path_p(p));
9705   if ( pen_p(p)!=null ) pen_p(pp)=copy_pen(pen_p(p));
9706   break;
9707 case mp_stroked_code: 
9708   path_p(pp)=mp_copy_path(mp, path_p(p));
9709   pen_p(pp)=copy_pen(pen_p(p));
9710   if ( dash_p(p)!=null ) add_edge_ref(dash_p(pp));
9711   break;
9712 case mp_text_code: 
9713   add_str_ref(text_p(pp));
9714   break;
9715 case mp_stop_clip_code:
9716 case mp_stop_bounds_code: 
9717   break;
9718 }  /* there are no other cases */
9719
9720 @ Here is one way to find an acceptable value for the second argument to
9721 |copy_objects|.  Given a non-null graphical object list, |skip_1component|
9722 skips past one picture component, where a ``picture component'' is a single
9723 graphical object, or a start bounds or start clip object and everything up
9724 through the matching stop bounds or stop clip object.  The macro version avoids
9725 procedure call overhead and error handling: |skip_component(p)(e)| advances |p|
9726 unless |p| points to a stop bounds or stop clip node, in which case it executes
9727 |e| instead.
9728
9729 @d skip_component(A)
9730     if ( ! is_start_or_stop((A)) ) (A)=link((A));
9731     else if ( ! is_stop((A)) ) (A)=mp_skip_1component(mp, (A));
9732     else 
9733
9734 @c 
9735 pointer mp_skip_1component (MP mp,pointer p) {
9736   integer lev; /* current nesting level */
9737   lev=0;
9738   do {  
9739    if ( is_start_or_stop(p) ) {
9740      if ( is_stop(p) ) decr(lev);  else incr(lev);
9741    }
9742    p=link(p);
9743   } while (lev!=0);
9744   return p;
9745 }
9746
9747 @ Here is a diagnostic routine for printing an edge structure in symbolic form.
9748
9749 @<Declare subroutines for printing expressions@>=
9750 @<Declare subroutines needed by |print_edges|@>;
9751 void mp_print_edges (MP mp,pointer h, char *s, boolean nuline) {
9752   pointer p;  /* a graphical object to be printed */
9753   pointer hh,pp;  /* temporary pointers */
9754   scaled scf;  /* a scale factor for the dash pattern */
9755   boolean ok_to_dash;  /* |false| for polygonal pen strokes */
9756   mp_print_diagnostic(mp, "Edge structure",s,nuline);
9757   p=dummy_loc(h);
9758   while ( link(p)!=null ) { 
9759     p=link(p);
9760     mp_print_ln(mp);
9761     switch (type(p)) {
9762       @<Cases for printing graphical object node |p|@>;
9763     default: 
9764           mp_print(mp, "[unknown object type!]");
9765           break;
9766     }
9767   }
9768   mp_print_nl(mp, "End edges");
9769   if ( p!=obj_tail(h) ) mp_print(mp, "?");
9770 @.End edges?@>
9771   mp_end_diagnostic(mp, true);
9772 }
9773
9774 @ @<Cases for printing graphical object node |p|@>=
9775 case mp_fill_code: 
9776   mp_print(mp, "Filled contour ");
9777   mp_print_obj_color(mp, p);
9778   mp_print_char(mp, ':'); mp_print_ln(mp);
9779   mp_pr_path(mp, path_p(p)); mp_print_ln(mp);
9780   if ( (pen_p(p)!=null) ) {
9781     @<Print join type for graphical object |p|@>;
9782     mp_print(mp, " with pen"); mp_print_ln(mp);
9783     mp_pr_pen(mp, pen_p(p));
9784   }
9785   break;
9786
9787 @ @<Print join type for graphical object |p|@>=
9788 switch (ljoin_val(p)) {
9789 case 0:
9790   mp_print(mp, "mitered joins limited ");
9791   mp_print_scaled(mp, miterlim_val(p));
9792   break;
9793 case 1:
9794   mp_print(mp, "round joins");
9795   break;
9796 case 2:
9797   mp_print(mp, "beveled joins");
9798   break;
9799 default: 
9800   mp_print(mp, "?? joins");
9801 @.??@>
9802   break;
9803 }
9804
9805 @ For stroked nodes, we need to print |lcap_val(p)| as well.
9806
9807 @<Print join and cap types for stroked node |p|@>=
9808 switch (lcap_val(p)) {
9809 case 0:mp_print(mp, "butt"); break;
9810 case 1:mp_print(mp, "round"); break;
9811 case 2:mp_print(mp, "square"); break;
9812 default: mp_print(mp, "??"); break;
9813 @.??@>
9814 }
9815 mp_print(mp, " ends, ");
9816 @<Print join type for graphical object |p|@>
9817
9818 @ Here is a routine that prints the color of a graphical object if it isn't
9819 black (the default color).
9820
9821 @<Declare subroutines needed by |print_edges|@>=
9822 @<Declare a procedure called |print_compact_node|@>;
9823 void mp_print_obj_color (MP mp,pointer p) { 
9824   if ( color_model(p)==mp_grey_model ) {
9825     if ( grey_val(p)>0 ) { 
9826       mp_print(mp, "greyed ");
9827       mp_print_compact_node(mp, obj_grey_loc(p),1);
9828     };
9829   } else if ( color_model(p)==mp_cmyk_model ) {
9830     if ( (cyan_val(p)>0) || (magenta_val(p)>0) || 
9831          (yellow_val(p)>0) || (black_val(p)>0) ) { 
9832       mp_print(mp, "processcolored ");
9833       mp_print_compact_node(mp, obj_cyan_loc(p),4);
9834     };
9835   } else if ( color_model(p)==mp_rgb_model ) {
9836     if ( (red_val(p)>0) || (green_val(p)>0) || (blue_val(p)>0) ) { 
9837       mp_print(mp, "colored "); 
9838       mp_print_compact_node(mp, obj_red_loc(p),3);
9839     };
9840   }
9841 }
9842
9843 @ We also need a procedure for printing consecutive scaled values as if they
9844 were a known big node.
9845
9846 @<Declare a procedure called |print_compact_node|@>=
9847 void mp_print_compact_node (MP mp,pointer p, small_number k) {
9848   pointer q;  /* last location to print */
9849   q=p+k-1;
9850   mp_print_char(mp, '(');
9851   while ( p<=q ){ 
9852     mp_print_scaled(mp, mp->mem[p].sc);
9853     if ( p<q ) mp_print_char(mp, ',');
9854     incr(p);
9855   }
9856   mp_print_char(mp, ')');
9857 }
9858
9859 @ @<Cases for printing graphical object node |p|@>=
9860 case mp_stroked_code: 
9861   mp_print(mp, "Filled pen stroke ");
9862   mp_print_obj_color(mp, p);
9863   mp_print_char(mp, ':'); mp_print_ln(mp);
9864   mp_pr_path(mp, path_p(p));
9865   if ( dash_p(p)!=null ) { 
9866     mp_print_nl(mp, "dashed (");
9867     @<Finish printing the dash pattern that |p| refers to@>;
9868   }
9869   mp_print_ln(mp);
9870   @<Print join and cap types for stroked node |p|@>;
9871   mp_print(mp, " with pen"); mp_print_ln(mp);
9872   if ( pen_p(p)==null ) mp_print(mp, "???"); /* shouldn't happen */
9873 @.???@>
9874   else mp_pr_pen(mp, pen_p(p));
9875   break;
9876
9877 @ Normally, the  |dash_list| field in an edge header is set to |null_dash|
9878 when it is not known to define a suitable dash pattern.  This is disallowed
9879 here because the |dash_p| field should never point to such an edge header.
9880 Note that memory is allocated for |start_x(null_dash)| and we are free to
9881 give it any convenient value.
9882
9883 @<Finish printing the dash pattern that |p| refers to@>=
9884 ok_to_dash=pen_is_elliptical(pen_p(p));
9885 if ( ! ok_to_dash ) scf=unity; else scf=dash_scale(p);
9886 hh=dash_p(p);
9887 pp=dash_list(hh);
9888 if ( (pp==null_dash) || (dash_y(hh)<0) ) {
9889   mp_print(mp, " ??");
9890 } else { start_x(null_dash)=start_x(pp)+dash_y(hh);
9891   while ( pp!=null_dash ) { 
9892     mp_print(mp, "on ");
9893     mp_print_scaled(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf));
9894     mp_print(mp, " off ");
9895     mp_print_scaled(mp, mp_take_scaled(mp, start_x(link(pp))-stop_x(pp),scf));
9896     pp = link(pp);
9897     if ( pp!=null_dash ) mp_print_char(mp, ' ');
9898   }
9899   mp_print(mp, ") shifted ");
9900   mp_print_scaled(mp, -mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
9901   if ( ! ok_to_dash || (dash_y(hh)==0) ) mp_print(mp, " (this will be ignored)");
9902 }
9903
9904 @ @<Declare subroutines needed by |print_edges|@>=
9905 scaled mp_dash_offset (MP mp,pointer h) {
9906   scaled x;  /* the answer */
9907   if (dash_list(h)==null_dash || dash_y(h)<0) mp_confusion(mp, "dash0");
9908 @:this can't happen dash0}{\quad dash0@>
9909   if ( dash_y(h)==0 ) {
9910     x=0; 
9911   } else { 
9912     x=-(start_x(dash_list(h)) % dash_y(h));
9913     if ( x<0 ) x=x+dash_y(h);
9914   }
9915   return x;
9916 }
9917
9918 @ @<Cases for printing graphical object node |p|@>=
9919 case mp_text_code: 
9920   mp_print_char(mp, '"'); mp_print_str(mp,text_p(p));
9921   mp_print(mp, "\" infont \""); mp_print(mp, mp->font_name[font_n(p)]);
9922   mp_print_char(mp, '"'); mp_print_ln(mp);
9923   mp_print_obj_color(mp, p);
9924   mp_print(mp, "transformed ");
9925   mp_print_compact_node(mp, text_tx_loc(p),6);
9926   break;
9927
9928 @ @<Cases for printing graphical object node |p|@>=
9929 case mp_start_clip_code: 
9930   mp_print(mp, "clipping path:");
9931   mp_print_ln(mp);
9932   mp_pr_path(mp, path_p(p));
9933   break;
9934 case mp_stop_clip_code: 
9935   mp_print(mp, "stop clipping");
9936   break;
9937
9938 @ @<Cases for printing graphical object node |p|@>=
9939 case mp_start_bounds_code: 
9940   mp_print(mp, "setbounds path:");
9941   mp_print_ln(mp);
9942   mp_pr_path(mp, path_p(p));
9943   break;
9944 case mp_stop_bounds_code: 
9945   mp_print(mp, "end of setbounds");
9946   break;
9947
9948 @ To initialize the |dash_list| field in an edge header~|h|, we need a
9949 subroutine that scans an edge structure and tries to interpret it as a dash
9950 pattern.  This can only be done when there are no filled regions or clipping
9951 paths and all the pen strokes have the same color.  The first step is to let
9952 $y_0$ be the initial $y$~coordinate of the first pen stroke.  Then we implicitly
9953 project all the pen stroke paths onto the line $y=y_0$ and require that there
9954 be no retracing.  If the resulting paths cover a range of $x$~coordinates of
9955 length $\Delta x$, we set |dash_y(h)| to the length of the dash pattern by
9956 finding the maximum of $\Delta x$ and the absolute value of~$y_0$.
9957
9958 @c @<Declare a procedure called |x_retrace_error|@>;
9959 pointer mp_make_dashes (MP mp,pointer h) { /* returns |h| or |null| */
9960   pointer p;  /* this scans the stroked nodes in the object list */
9961   pointer p0;  /* if not |null| this points to the first stroked node */
9962   pointer pp,qq,rr;  /* pointers into |path_p(p)| */
9963   pointer d,dd;  /* pointers used to create the dash list */
9964   @<Other local variables in |make_dashes|@>;
9965   scaled y0=0;  /* the initial $y$ coordinate */
9966   if ( dash_list(h)!=null_dash ) 
9967         return h;
9968   p0=null;
9969   p=link(dummy_loc(h));
9970   while ( p!=null ) { 
9971     if ( type(p)!=mp_stroked_code ) {
9972       @<Compain that the edge structure contains a node of the wrong type
9973         and |goto not_found|@>;
9974     }
9975     pp=path_p(p);
9976     if ( p0==null ){ p0=p; y0=y_coord(pp);  };
9977     @<Make |d| point to a new dash node created from stroke |p| and path |pp|
9978       or |goto not_found| if there is an error@>;
9979     @<Insert |d| into the dash list and |goto not_found| if there is an error@>;
9980     p=link(p);
9981   }
9982   if ( dash_list(h)==null_dash ) 
9983     goto NOT_FOUND; /* No error message */
9984   @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>;
9985   @<Set |dash_y(h)| and merge the first and last dashes if necessary@>;
9986   return h;
9987 NOT_FOUND: 
9988   @<Flush the dash list, recycle |h| and return |null|@>;
9989 };
9990
9991 @ @<Compain that the edge structure contains a node of the wrong type...@>=
9992
9993 print_err("Picture is too complicated to use as a dash pattern");
9994 help3("When you say `dashed p', picture p should not contain any")
9995   ("text, filled regions, or clipping paths.  This time it did")
9996   ("so I'll just make it a solid line instead.");
9997 mp_put_get_error(mp);
9998 goto NOT_FOUND;
9999 }
10000
10001 @ A similar error occurs when monotonicity fails.
10002
10003 @<Declare a procedure called |x_retrace_error|@>=
10004 void mp_x_retrace_error (MP mp) { 
10005 print_err("Picture is too complicated to use as a dash pattern");
10006 help3("When you say `dashed p', every path in p should be monotone")
10007   ("in x and there must be no overlapping.  This failed")
10008   ("so I'll just make it a solid line instead.");
10009 mp_put_get_error(mp);
10010 }
10011
10012 @ We stash |p| in |info(d)| if |dash_p(p)<>0| so that subsequent processing can
10013 handle the case where the pen stroke |p| is itself dashed.
10014
10015 @<Make |d| point to a new dash node created from stroke |p| and path...@>=
10016 @<Make sure |p| and |p0| are the same color and |goto not_found| if there is
10017   an error@>;
10018 rr=pp;
10019 if ( link(pp)!=pp ) {
10020   do {  
10021     qq=rr; rr=link(rr);
10022     @<Check for retracing between knots |qq| and |rr| and |goto not_found|
10023       if there is a problem@>;
10024   } while (right_type(rr)!=mp_endpoint);
10025 }
10026 d=mp_get_node(mp, dash_node_size);
10027 if ( dash_p(p)==0 ) info(d)=0;  else info(d)=p;
10028 if ( x_coord(pp)<x_coord(rr) ) { 
10029   start_x(d)=x_coord(pp);
10030   stop_x(d)=x_coord(rr);
10031 } else { 
10032   start_x(d)=x_coord(rr);
10033   stop_x(d)=x_coord(pp);
10034 }
10035
10036 @ We also need to check for the case where the segment from |qq| to |rr| is
10037 monotone in $x$ but is reversed relative to the path from |pp| to |qq|.
10038
10039 @<Check for retracing between knots |qq| and |rr| and |goto not_found|...@>=
10040 x0=x_coord(qq);
10041 x1=right_x(qq);
10042 x2=left_x(rr);
10043 x3=x_coord(rr);
10044 if ( (x0>x1) || (x1>x2) || (x2>x3) ) {
10045   if ( (x0<x1) || (x1<x2) || (x2<x3) ) {
10046     if ( mp_ab_vs_cd(mp, x2-x1,x2-x1,x1-x0,x3-x2)>0 ) {
10047       mp_x_retrace_error(mp); goto NOT_FOUND;
10048     }
10049   }
10050 }
10051 if ( (x_coord(pp)>x0) || (x0>x3) ) {
10052   if ( (x_coord(pp)<x0) || (x0<x3) ) {
10053     mp_x_retrace_error(mp); goto NOT_FOUND;
10054   }
10055 }
10056
10057 @ @<Other local variables in |make_dashes|@>=
10058   scaled x0,x1,x2,x3;  /* $x$ coordinates of the segment from |qq| to |rr| */
10059
10060 @ @<Make sure |p| and |p0| are the same color and |goto not_found|...@>=
10061 if ( (red_val(p)!=red_val(p0)) || (black_val(p)!=black_val(p0)) ||
10062   (green_val(p)!=green_val(p0)) || (blue_val(p)!=blue_val(p0)) ) {
10063   print_err("Picture is too complicated to use as a dash pattern");
10064   help3("When you say `dashed p', everything in picture p should")
10065     ("be the same color.  I can\'t handle your color changes")
10066     ("so I'll just make it a solid line instead.");
10067   mp_put_get_error(mp);
10068   goto NOT_FOUND;
10069 }
10070
10071 @ @<Insert |d| into the dash list and |goto not_found| if there is an error@>=
10072 start_x(null_dash)=stop_x(d);
10073 dd=h; /* this makes |link(dd)=dash_list(h)| */
10074 while ( start_x(link(dd))<stop_x(d) )
10075   dd=link(dd);
10076 if ( dd!=h ) {
10077   if ( (stop_x(dd)>start_x(d)) )
10078     { mp_x_retrace_error(mp); goto NOT_FOUND;  };
10079 }
10080 link(d)=link(dd);
10081 link(dd)=d
10082
10083 @ @<Set |dash_y(h)| and merge the first and last dashes if necessary@>=
10084 d=dash_list(h);
10085 while ( (link(d)!=null_dash) )
10086   d=link(d);
10087 dd=dash_list(h);
10088 dash_y(h)=stop_x(d)-start_x(dd);
10089 if ( abs(y0)>dash_y(h) ) {
10090   dash_y(h)=abs(y0);
10091 } else if ( d!=dd ) { 
10092   dash_list(h)=link(dd);
10093   stop_x(d)=stop_x(dd)+dash_y(h);
10094   mp_free_node(mp, dd,dash_node_size);
10095 }
10096
10097 @ We get here when the argument is a null picture or when there is an error.
10098 Recovering from an error involves making |dash_list(h)| empty to indicate
10099 that |h| is not known to be a valid dash pattern.  We also dereference |h|
10100 since it is not being used for the return value.
10101
10102 @<Flush the dash list, recycle |h| and return |null|@>=
10103 mp_flush_dash_list(mp, h);
10104 delete_edge_ref(h);
10105 return null
10106
10107 @ Having carefully saved the dashed stroked nodes in the
10108 corresponding dash nodes, we must be prepared to break up these dashes into
10109 smaller dashes.
10110
10111 @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>=
10112 d=h;  /* now |link(d)=dash_list(h)| */
10113 while ( link(d)!=null_dash ) {
10114   ds=info(link(d));
10115   if ( ds==null ) { 
10116     d=link(d);
10117   } else {
10118     hh=dash_p(ds);
10119     hsf=dash_scale(ds);
10120     if ( (hh==null) ) mp_confusion(mp, "dash1");
10121 @:this can't happen dash0}{\quad dash1@>
10122     if ( dash_y(hh)==0 ) {
10123       d=link(d);
10124     } else { 
10125       if ( dash_list(hh)==null ) mp_confusion(mp, "dash1");
10126 @:this can't happen dash0}{\quad dash1@>
10127       @<Replace |link(d)| by a dashed version as determined by edge header
10128           |hh| and scale factor |ds|@>;
10129     }
10130   }
10131 }
10132
10133 @ @<Other local variables in |make_dashes|@>=
10134 pointer dln;  /* |link(d)| */
10135 pointer hh;  /* an edge header that tells how to break up |dln| */
10136 scaled hsf;  /* the dash pattern from |hh| gets scaled by this */
10137 pointer ds;  /* the stroked node from which |hh| and |hsf| are derived */
10138 scaled xoff;  /* added to $x$ values in |dash_list(hh)| to match |dln| */
10139
10140 @ @<Replace |link(d)| by a dashed version as determined by edge header...@>=
10141 dln=link(d);
10142 dd=dash_list(hh);
10143 xoff=start_x(dln)-mp_take_scaled(mp, hsf,start_x(dd))-
10144         mp_take_scaled(mp, hsf,mp_dash_offset(mp, hh));
10145 start_x(null_dash)=mp_take_scaled(mp, hsf,start_x(dd))
10146                    +mp_take_scaled(mp, hsf,dash_y(hh));
10147 stop_x(null_dash)=start_x(null_dash);
10148 @<Advance |dd| until finding the first dash that overlaps |dln| when
10149   offset by |xoff|@>;
10150 while ( start_x(dln)<=stop_x(dln) ) {
10151   @<If |dd| has `fallen off the end', back up to the beginning and fix |xoff|@>;
10152   @<Insert a dash between |d| and |dln| for the overlap with the offset version
10153     of |dd|@>;
10154   dd=link(dd);
10155   start_x(dln)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
10156 }
10157 link(d)=link(dln);
10158 mp_free_node(mp, dln,dash_node_size)
10159
10160 @ The name of this module is a bit of a lie because we actually just find the
10161 first |dd| where |take_scaled (hsf, stop_x(dd))| is large enough to make an
10162 overlap possible.  It could be that the unoffset version of dash |dln| falls
10163 in the gap between |dd| and its predecessor.
10164
10165 @<Advance |dd| until finding the first dash that overlaps |dln| when...@>=
10166 while ( xoff+mp_take_scaled(mp, hsf,stop_x(dd))<start_x(dln) ) {
10167   dd=link(dd);
10168 }
10169
10170 @ @<If |dd| has `fallen off the end', back up to the beginning and fix...@>=
10171 if ( dd==null_dash ) { 
10172   dd=dash_list(hh);
10173   xoff=xoff+mp_take_scaled(mp, hsf,dash_y(hh));
10174 }
10175
10176 @ At this point we already know that
10177 |start_x(dln)<=xoff+take_scaled(hsf,stop_x(dd))|.
10178
10179 @<Insert a dash between |d| and |dln| for the overlap with the offset...@>=
10180 if ( (xoff+mp_take_scaled(mp, hsf,start_x(dd)))<=stop_x(dln) ) {
10181   link(d)=mp_get_node(mp, dash_node_size);
10182   d=link(d);
10183   link(d)=dln;
10184   if ( start_x(dln)>(xoff+mp_take_scaled(mp, hsf,start_x(dd))))
10185     start_x(d)=start_x(dln);
10186   else 
10187     start_x(d)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
10188   if ( stop_x(dln)<(xoff+mp_take_scaled(mp, hsf,stop_x(dd)))) 
10189     stop_x(d)=stop_x(dln);
10190   else 
10191     stop_x(d)=xoff+mp_take_scaled(mp, hsf,stop_x(dd));
10192 }
10193
10194 @ The next major task is to update the bounding box information in an edge
10195 header~|h|. This is done via a procedure |adjust_bbox| that enlarges an edge
10196 header's bounding box to accommodate the box computed by |path_bbox| or
10197 |pen_bbox|. (This is stored in global variables |minx|, |miny|, |maxx|, and
10198 |maxy|.)
10199
10200 @c void mp_adjust_bbox (MP mp,pointer h) { 
10201   if ( minx<minx_val(h) ) minx_val(h)=minx;
10202   if ( miny<miny_val(h) ) miny_val(h)=miny;
10203   if ( maxx>maxx_val(h) ) maxx_val(h)=maxx;
10204   if ( maxy>maxy_val(h) ) maxy_val(h)=maxy;
10205 }
10206
10207 @ Here is a special routine for updating the bounding box information in
10208 edge header~|h| to account for the squared-off ends of a non-cyclic path~|p|
10209 that is to be stroked with the pen~|pp|.
10210
10211 @c void mp_box_ends (MP mp, pointer p, pointer pp, pointer h) {
10212   pointer q;  /* a knot node adjacent to knot |p| */
10213   fraction dx,dy;  /* a unit vector in the direction out of the path at~|p| */
10214   scaled d;  /* a factor for adjusting the length of |(dx,dy)| */
10215   scaled z;  /* a coordinate being tested against the bounding box */
10216   scaled xx,yy;  /* the extreme pen vertex in the |(dx,dy)| direction */
10217   integer i; /* a loop counter */
10218   if ( right_type(p)!=mp_endpoint ) { 
10219     q=link(p);
10220     while (1) { 
10221       @<Make |(dx,dy)| the final direction for the path segment from
10222         |q| to~|p|; set~|d|@>;
10223       d=mp_pyth_add(mp, dx,dy);
10224       if ( d>0 ) { 
10225          @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>;
10226          for (i=1;i<= 2;i++) { 
10227            @<Use |(dx,dy)| to generate a vertex of the square end cap and
10228              update the bounding box to accommodate it@>;
10229            dx=-dx; dy=-dy; 
10230         }
10231       }
10232       if ( right_type(p)==mp_endpoint ) {
10233          return;
10234       } else {
10235         @<Advance |p| to the end of the path and make |q| the previous knot@>;
10236       } 
10237     }
10238   }
10239 }
10240
10241 @ @<Make |(dx,dy)| the final direction for the path segment from...@>=
10242 if ( q==link(p) ) { 
10243   dx=x_coord(p)-right_x(p);
10244   dy=y_coord(p)-right_y(p);
10245   if ( (dx==0)&&(dy==0) ) {
10246     dx=x_coord(p)-left_x(q);
10247     dy=y_coord(p)-left_y(q);
10248   }
10249 } else { 
10250   dx=x_coord(p)-left_x(p);
10251   dy=y_coord(p)-left_y(p);
10252   if ( (dx==0)&&(dy==0) ) {
10253     dx=x_coord(p)-right_x(q);
10254     dy=y_coord(p)-right_y(q);
10255   }
10256 }
10257 dx=x_coord(p)-x_coord(q);
10258 dy=y_coord(p)-y_coord(q)
10259
10260 @ @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>=
10261 dx=mp_make_fraction(mp, dx,d);
10262 dy=mp_make_fraction(mp, dy,d);
10263 mp_find_offset(mp, -dy,dx,pp);
10264 xx=mp->cur_x; yy=mp->cur_y
10265
10266 @ @<Use |(dx,dy)| to generate a vertex of the square end cap and...@>=
10267 mp_find_offset(mp, dx,dy,pp);
10268 d=mp_take_fraction(mp, xx-mp->cur_x,dx)+mp_take_fraction(mp, yy-mp->cur_y,dy);
10269 if ( ((d<0)&&(i==1)) || ((d>0)&&(i==2))) 
10270   mp_confusion(mp, "box_ends");
10271 @:this can't happen box ends}{\quad\\{box\_ends}@>
10272 z=x_coord(p)+mp->cur_x+mp_take_fraction(mp, d,dx);
10273 if ( z<minx_val(h) ) minx_val(h)=z;
10274 if ( z>maxx_val(h) ) maxx_val(h)=z;
10275 z=y_coord(p)+mp->cur_y+mp_take_fraction(mp, d,dy);
10276 if ( z<miny_val(h) ) miny_val(h)=z;
10277 if ( z>maxy_val(h) ) maxy_val(h)=z
10278
10279 @ @<Advance |p| to the end of the path and make |q| the previous knot@>=
10280 do {  
10281   q=p;
10282   p=link(p);
10283 } while (right_type(p)!=mp_endpoint)
10284
10285 @ The major difficulty in finding the bounding box of an edge structure is the
10286 effect of clipping paths.  We treat them conservatively by only clipping to the
10287 clipping path's bounding box, but this still
10288 requires recursive calls to |set_bbox| in order to find the bounding box of
10289 @^recursion@>
10290 the objects to be clipped.  Such calls are distinguished by the fact that the
10291 boolean parameter |top_level| is false.
10292
10293 @c void mp_set_bbox (MP mp,pointer h, boolean top_level) {
10294   pointer p;  /* a graphical object being considered */
10295   scaled sminx,sminy,smaxx,smaxy;
10296   /* for saving the bounding box during recursive calls */
10297   scaled x0,x1,y0,y1;  /* temporary registers */
10298   integer lev;  /* nesting level for |mp_start_bounds_code| nodes */
10299   @<Wipe out any existing bounding box information if |bbtype(h)| is
10300   incompatible with |internal[mp_true_corners]|@>;
10301   while ( link(bblast(h))!=null ) { 
10302     p=link(bblast(h));
10303     bblast(h)=p;
10304     switch (type(p)) {
10305     case mp_stop_clip_code: 
10306       if ( top_level ) mp_confusion(mp, "bbox");  else return;
10307 @:this can't happen bbox}{\quad bbox@>
10308       break;
10309     @<Other cases for updating the bounding box based on the type of object |p|@>;
10310     } /* all cases are enumerated above */
10311   }
10312   if ( ! top_level ) mp_confusion(mp, "bbox");
10313 }
10314
10315 @ @<Internal library declarations@>=
10316 void mp_set_bbox (MP mp,pointer h, boolean top_level);
10317
10318 @ @<Wipe out any existing bounding box information if |bbtype(h)| is...@>=
10319 switch (bbtype(h)) {
10320 case no_bounds: 
10321   break;
10322 case bounds_set: 
10323   if ( mp->internal[mp_true_corners]>0 ) mp_init_bbox(mp, h);
10324   break;
10325 case bounds_unset: 
10326   if ( mp->internal[mp_true_corners]<=0 ) mp_init_bbox(mp, h);
10327   break;
10328 } /* there are no other cases */
10329
10330 @ @<Other cases for updating the bounding box...@>=
10331 case mp_fill_code: 
10332   mp_path_bbox(mp, path_p(p));
10333   if ( pen_p(p)!=null ) { 
10334     x0=minx; y0=miny;
10335     x1=maxx; y1=maxy;
10336     mp_pen_bbox(mp, pen_p(p));
10337     minx=minx+x0;
10338     miny=miny+y0;
10339     maxx=maxx+x1;
10340     maxy=maxy+y1;
10341   }
10342   mp_adjust_bbox(mp, h);
10343   break;
10344
10345 @ @<Other cases for updating the bounding box...@>=
10346 case mp_start_bounds_code: 
10347   if ( mp->internal[mp_true_corners]>0 ) {
10348     bbtype(h)=bounds_unset;
10349   } else { 
10350     bbtype(h)=bounds_set;
10351     mp_path_bbox(mp, path_p(p));
10352     mp_adjust_bbox(mp, h);
10353     @<Scan to the matching |mp_stop_bounds_code| node and update |p| and
10354       |bblast(h)|@>;
10355   }
10356   break;
10357 case mp_stop_bounds_code: 
10358   if ( mp->internal[mp_true_corners]<=0 ) mp_confusion(mp, "bbox2");
10359 @:this can't happen bbox2}{\quad bbox2@>
10360   break;
10361
10362 @ @<Scan to the matching |mp_stop_bounds_code| node and update |p| and...@>=
10363 lev=1;
10364 while ( lev!=0 ) { 
10365   if ( link(p)==null ) mp_confusion(mp, "bbox2");
10366 @:this can't happen bbox2}{\quad bbox2@>
10367   p=link(p);
10368   if ( type(p)==mp_start_bounds_code ) incr(lev);
10369   else if ( type(p)==mp_stop_bounds_code ) decr(lev);
10370 }
10371 bblast(h)=p
10372
10373 @ It saves a lot of grief here to be slightly conservative and not account for
10374 omitted parts of dashed lines.  We also don't worry about the material omitted
10375 when using butt end caps.  The basic computation is for round end caps and
10376 |box_ends| augments it for square end caps.
10377
10378 @<Other cases for updating the bounding box...@>=
10379 case mp_stroked_code: 
10380   mp_path_bbox(mp, path_p(p));
10381   x0=minx; y0=miny;
10382   x1=maxx; y1=maxy;
10383   mp_pen_bbox(mp, pen_p(p));
10384   minx=minx+x0;
10385   miny=miny+y0;
10386   maxx=maxx+x1;
10387   maxy=maxy+y1;
10388   mp_adjust_bbox(mp, h);
10389   if ( (left_type(path_p(p))==mp_endpoint)&&(lcap_val(p)==2) )
10390     mp_box_ends(mp, path_p(p), pen_p(p), h);
10391   break;
10392
10393 @ The height width and depth information stored in a text node determines a
10394 rectangle that needs to be transformed according to the transformation
10395 parameters stored in the text node.
10396
10397 @<Other cases for updating the bounding box...@>=
10398 case mp_text_code: 
10399   x1=mp_take_scaled(mp, txx_val(p),width_val(p));
10400   y0=mp_take_scaled(mp, txy_val(p),-depth_val(p));
10401   y1=mp_take_scaled(mp, txy_val(p),height_val(p));
10402   minx=tx_val(p);
10403   maxx=minx;
10404   if ( y0<y1 ) { minx=minx+y0; maxx=maxx+y1;  }
10405   else         { minx=minx+y1; maxx=maxx+y0;  }
10406   if ( x1<0 ) minx=minx+x1;  else maxx=maxx+x1;
10407   x1=mp_take_scaled(mp, tyx_val(p),width_val(p));
10408   y0=mp_take_scaled(mp, tyy_val(p),-depth_val(p));
10409   y1=mp_take_scaled(mp, tyy_val(p),height_val(p));
10410   miny=ty_val(p);
10411   maxy=miny;
10412   if ( y0<y1 ) { miny=miny+y0; maxy=maxy+y1;  }
10413   else         { miny=miny+y1; maxy=maxy+y0;  }
10414   if ( x1<0 ) miny=miny+x1;  else maxy=maxy+x1;
10415   mp_adjust_bbox(mp, h);
10416   break;
10417
10418 @ This case involves a recursive call that advances |bblast(h)| to the node of
10419 type |mp_stop_clip_code| that matches |p|.
10420
10421 @<Other cases for updating the bounding box...@>=
10422 case mp_start_clip_code: 
10423   mp_path_bbox(mp, path_p(p));
10424   x0=minx; y0=miny;
10425   x1=maxx; y1=maxy;
10426   sminx=minx_val(h); sminy=miny_val(h);
10427   smaxx=maxx_val(h); smaxy=maxy_val(h);
10428   @<Reinitialize the bounding box in header |h| and call |set_bbox| recursively
10429     starting at |link(p)|@>;
10430   @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,
10431     |y0|, |y1|@>;
10432   minx=sminx; miny=sminy;
10433   maxx=smaxx; maxy=smaxy;
10434   mp_adjust_bbox(mp, h);
10435   break;
10436
10437 @ @<Reinitialize the bounding box in header |h| and call |set_bbox|...@>=
10438 minx_val(h)=el_gordo;
10439 miny_val(h)=el_gordo;
10440 maxx_val(h)=-el_gordo;
10441 maxy_val(h)=-el_gordo;
10442 mp_set_bbox(mp, h,false)
10443
10444 @ @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,...@>=
10445 if ( minx_val(h)<x0 ) minx_val(h)=x0;
10446 if ( miny_val(h)<y0 ) miny_val(h)=y0;
10447 if ( maxx_val(h)>x1 ) maxx_val(h)=x1;
10448 if ( maxy_val(h)>y1 ) maxy_val(h)=y1
10449
10450 @* \[22] Finding an envelope.
10451 When \MP\ has a path and a polygonal pen, it needs to express the desired
10452 shape in terms of things \ps\ can understand.  The present task is to compute
10453 a new path that describes the region to be filled.  It is convenient to
10454 define this as a two step process where the first step is determining what
10455 offset to use for each segment of the path.
10456
10457 @ Given a pointer |c| to a cyclic path,
10458 and a pointer~|h| to the first knot of a pen polygon,
10459 the |offset_prep| routine changes the path into cubics that are
10460 associated with particular pen offsets. Thus if the cubic between |p|
10461 and~|q| is associated with the |k|th offset and the cubic between |q| and~|r|
10462 has offset |l| then |info(q)=zero_off+l-k|. (The constant |zero_off| is added
10463 to because |l-k| could be negative.)
10464
10465 After overwriting the type information with offset differences, we no longer
10466 have a true path so we refer to the knot list returned by |offset_prep| as an
10467 ``envelope spec.''
10468 @^envelope spec@>
10469 Since an envelope spec only determines relative changes in pen offsets,
10470 |offset_prep| sets a global variable |spec_offset| to the relative change from
10471 |h| to the first offset.
10472
10473 @d zero_off 16384 /* added to offset changes to make them positive */
10474
10475 @<Glob...@>=
10476 integer spec_offset; /* number of pen edges between |h| and the initial offset */
10477
10478 @ @c @<Declare subroutines needed by |offset_prep|@>;
10479 pointer mp_offset_prep (MP mp,pointer c, pointer h) {
10480   halfword n; /* the number of vertices in the pen polygon */
10481   pointer p,q,q0,r,w, ww; /* for list manipulation */
10482   integer k_needed; /* amount to be added to |info(p)| when it is computed */
10483   pointer w0; /* a pointer to pen offset to use just before |p| */
10484   scaled dxin,dyin; /* the direction into knot |p| */
10485   integer turn_amt; /* change in pen offsets for the current cubic */
10486   @<Other local variables for |offset_prep|@>;
10487   dx0=0; dy0=0;
10488   @<Initialize the pen size~|n|@>;
10489   @<Initialize the incoming direction and pen offset at |c|@>;
10490   p=c; k_needed=0;
10491   do {  
10492     q=link(p);
10493     @<Split the cubic between |p| and |q|, if necessary, into cubics
10494       associated with single offsets, after which |q| should
10495       point to the end of the final such cubic@>;
10496   NOT_FOUND:
10497     @<Advance |p| to node |q|, removing any ``dead'' cubics that
10498       might have been introduced by the splitting process@>;
10499   } while (q!=c);
10500   @<Fix the offset change in |info(c)| and set |c| to the return value of
10501     |offset_prep|@>;
10502   return c;
10503 }
10504
10505 @ We shall want to keep track of where certain knots on the cyclic path
10506 wind up in the envelope spec.  It doesn't suffice just to keep pointers to
10507 knot nodes because some nodes are deleted while removing dead cubics.  Thus
10508 |offset_prep| updates the following pointers
10509
10510 @<Glob...@>=
10511 pointer spec_p1;
10512 pointer spec_p2; /* pointers to distinguished knots */
10513
10514 @ @<Set init...@>=
10515 mp->spec_p1=null; mp->spec_p2=null;
10516
10517 @ @<Initialize the pen size~|n|@>=
10518 n=0; p=h;
10519 do {  
10520   incr(n);
10521   p=link(p);
10522 } while (p!=h)
10523
10524 @ Since the true incoming direction isn't known yet, we just pick a direction
10525 consistent with the pen offset~|h|.  If this is wrong, it can be corrected
10526 later.
10527
10528 @<Initialize the incoming direction and pen offset at |c|@>=
10529 dxin=x_coord(link(h))-x_coord(knil(h));
10530 dyin=y_coord(link(h))-y_coord(knil(h));
10531 if ( (dxin==0)&&(dyin==0) ) {
10532   dxin=y_coord(knil(h))-y_coord(h);
10533   dyin=x_coord(h)-x_coord(knil(h));
10534 }
10535 w0=h
10536
10537 @ We must be careful not to remove the only cubic in a cycle.
10538
10539 But we must also be careful for another reason. If the user-supplied
10540 path starts with a set of degenerate cubics, the target node |q| can
10541 be collapsed to the initial node |p| which might be the same as the
10542 initial node |c| of the curve. This would cause the |offset_prep| routine
10543 to bail out too early, causing distress later on. (See for example
10544 the testcase reported by Bogus\l{}aw Jackowski in tracker id 267, case 52c
10545 on Sarovar.)
10546
10547 @<Advance |p| to node |q|, removing any ``dead'' cubics...@>=
10548 q0=q;
10549 do { 
10550   r=link(p);
10551   if ( x_coord(p)==right_x(p) && y_coord(p)==right_y(p) &&
10552        x_coord(p)==left_x(r)  && y_coord(p)==left_y(r) &&
10553        x_coord(p)==x_coord(r) && y_coord(p)==y_coord(r) &&
10554        r!=p ) {
10555       @<Remove the cubic following |p| and update the data structures
10556         to merge |r| into |p|@>;
10557   }
10558   p=r;
10559 } while (p!=q);
10560 /* Check if we removed too much */
10561 if(q!=q0)
10562   q = link(q)
10563
10564 @ @<Remove the cubic following |p| and update the data structures...@>=
10565 { k_needed=info(p)-zero_off;
10566   if ( r==q ) { 
10567     q=p;
10568   } else { 
10569     info(p)=k_needed+info(r);
10570     k_needed=0;
10571   };
10572   if ( r==c ) { info(p)=info(c); c=p; };
10573   if ( r==mp->spec_p1 ) mp->spec_p1=p;
10574   if ( r==mp->spec_p2 ) mp->spec_p2=p;
10575   r=p; mp_remove_cubic(mp, p);
10576 }
10577
10578 @ Not setting the |info| field of the newly created knot allows the splitting
10579 routine to work for paths.
10580
10581 @<Declare subroutines needed by |offset_prep|@>=
10582 void mp_split_cubic (MP mp,pointer p, fraction t) { /* splits the cubic after |p| */
10583   scaled v; /* an intermediate value */
10584   pointer q,r; /* for list manipulation */
10585   q=link(p); r=mp_get_node(mp, knot_node_size); link(p)=r; link(r)=q;
10586   originator(r)=mp_program_code;
10587   left_type(r)=mp_explicit; right_type(r)=mp_explicit;
10588   v=t_of_the_way(right_x(p),left_x(q));
10589   right_x(p)=t_of_the_way(x_coord(p),right_x(p));
10590   left_x(q)=t_of_the_way(left_x(q),x_coord(q));
10591   left_x(r)=t_of_the_way(right_x(p),v);
10592   right_x(r)=t_of_the_way(v,left_x(q));
10593   x_coord(r)=t_of_the_way(left_x(r),right_x(r));
10594   v=t_of_the_way(right_y(p),left_y(q));
10595   right_y(p)=t_of_the_way(y_coord(p),right_y(p));
10596   left_y(q)=t_of_the_way(left_y(q),y_coord(q));
10597   left_y(r)=t_of_the_way(right_y(p),v);
10598   right_y(r)=t_of_the_way(v,left_y(q));
10599   y_coord(r)=t_of_the_way(left_y(r),right_y(r));
10600 }
10601
10602 @ This does not set |info(p)| or |right_type(p)|.
10603
10604 @<Declare subroutines needed by |offset_prep|@>=
10605 void mp_remove_cubic (MP mp,pointer p) { /* removes the dead cubic following~|p| */
10606   pointer q; /* the node that disappears */
10607   q=link(p); link(p)=link(q);
10608   right_x(p)=right_x(q); right_y(p)=right_y(q);
10609   mp_free_node(mp, q,knot_node_size);
10610 }
10611
10612 @ Let $d\prec d'$ mean that the counter-clockwise angle from $d$ to~$d'$ is
10613 strictly between zero and $180^\circ$.  Then we can define $d\preceq d'$ to
10614 mean that the angle could be zero or $180^\circ$. If $w_k=(u_k,v_k)$ is the
10615 $k$th pen offset, the $k$th pen edge direction is defined by the formula
10616 $$d_k=(u\k-u_k,\,v\k-v_k).$$
10617 When listed by increasing $k$, these directions occur in counter-clockwise
10618 order so that $d_k\preceq d\k$ for all~$k$.
10619 The goal of |offset_prep| is to find an offset index~|k| to associate with
10620 each cubic, such that the direction $d(t)$ of the cubic satisfies
10621 $$d_{k-1}\preceq d(t)\preceq d_k\qquad\hbox{for $0\le t\le 1$.}\eqno(*)$$
10622 We may have to split a cubic into many pieces before each
10623 piece corresponds to a unique offset.
10624
10625 @<Split the cubic between |p| and |q|, if necessary, into cubics...@>=
10626 info(p)=zero_off+k_needed;
10627 k_needed=0;
10628 @<Prepare for derivative computations;
10629   |goto not_found| if the current cubic is dead@>;
10630 @<Find the initial direction |(dx,dy)|@>;
10631 @<Update |info(p)| and find the offset $w_k$ such that
10632   $d_{k-1}\preceq(\\{dx},\\{dy})\prec d_k$; also advance |w0| for
10633   the direction change at |p|@>;
10634 @<Find the final direction |(dxin,dyin)|@>;
10635 @<Decide on the net change in pen offsets and set |turn_amt|@>;
10636 @<Complete the offset splitting process@>;
10637 w0=mp_pen_walk(mp, w0,turn_amt)
10638
10639 @ @<Declare subroutines needed by |offset_prep|@>=
10640 pointer mp_pen_walk (MP mp,pointer w, integer k) {
10641   /* walk |k| steps around a pen from |w| */
10642   while ( k>0 ) { w=link(w); decr(k);  };
10643   while ( k<0 ) { w=knil(w); incr(k);  };
10644   return w;
10645 }
10646
10647 @ The direction of a cubic $B(z_0,z_1,z_2,z_3;t)=\bigl(x(t),y(t)\bigr)$ can be
10648 calculated from the quadratic polynomials
10649 ${1\over3}x'(t)=B(x_1-x_0,x_2-x_1,x_3-x_2;t)$ and
10650 ${1\over3}y'(t)=B(y_1-y_0,y_2-y_1,y_3-y_2;t)$.
10651 Since we may be calculating directions from several cubics
10652 split from the current one, it is desirable to do these calculations
10653 without losing too much precision. ``Scaled up'' values of the
10654 derivatives, which will be less tainted by accumulated errors than
10655 derivatives found from the cubics themselves, are maintained in
10656 local variables |x0|, |x1|, and |x2|, representing $X_0=2^l(x_1-x_0)$,
10657 $X_1=2^l(x_2-x_1)$, and $X_2=2^l(x_3-x_2)$; similarly |y0|, |y1|, and~|y2|
10658 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)$.
10659
10660 @<Other local variables for |offset_prep|@>=
10661 integer x0,x1,x2,y0,y1,y2; /* representatives of derivatives */
10662 integer t0,t1,t2; /* coefficients of polynomial for slope testing */
10663 integer du,dv,dx,dy; /* for directions of the pen and the curve */
10664 integer dx0,dy0; /* initial direction for the first cubic in the curve */
10665 integer max_coef; /* used while scaling */
10666 integer x0a,x1a,x2a,y0a,y1a,y2a; /* intermediate values */
10667 fraction t; /* where the derivative passes through zero */
10668 fraction s; /* a temporary value */
10669
10670 @ @<Prepare for derivative computations...@>=
10671 x0=right_x(p)-x_coord(p);
10672 x2=x_coord(q)-left_x(q);
10673 x1=left_x(q)-right_x(p);
10674 y0=right_y(p)-y_coord(p); y2=y_coord(q)-left_y(q);
10675 y1=left_y(q)-right_y(p);
10676 max_coef=abs(x0);
10677 if ( abs(x1)>max_coef ) max_coef=abs(x1);
10678 if ( abs(x2)>max_coef ) max_coef=abs(x2);
10679 if ( abs(y0)>max_coef ) max_coef=abs(y0);
10680 if ( abs(y1)>max_coef ) max_coef=abs(y1);
10681 if ( abs(y2)>max_coef ) max_coef=abs(y2);
10682 if ( max_coef==0 ) goto NOT_FOUND;
10683 while ( max_coef<fraction_half ) {
10684   double(max_coef);
10685   double(x0); double(x1); double(x2);
10686   double(y0); double(y1); double(y2);
10687 }
10688
10689 @ Let us first solve a special case of the problem: Suppose we
10690 know an index~$k$ such that either (i)~$d(t)\succeq d_{k-1}$ for all~$t$
10691 and $d(0)\prec d_k$, or (ii)~$d(t)\preceq d_k$ for all~$t$ and
10692 $d(0)\succ d_{k-1}$.
10693 Then, in a sense, we're halfway done, since one of the two relations
10694 in $(*)$ is satisfied, and the other couldn't be satisfied for
10695 any other value of~|k|.
10696
10697 Actually, the conditions can be relaxed somewhat since a relation such as
10698 $d(t)\succeq d_{k-1}$ restricts $d(t)$ to a half plane when all that really
10699 matters is whether $d(t)$ crosses the ray in the $d_{k-1}$ direction from
10700 the origin.  The condition for case~(i) becomes $d_{k-1}\preceq d(0)\prec d_k$
10701 and $d(t)$ never crosses the $d_{k-1}$ ray in the clockwise direction.
10702 Case~(ii) is similar except $d(t)$ cannot cross the $d_k$ ray in the
10703 counterclockwise direction.
10704
10705 The |fin_offset_prep| subroutine solves the stated subproblem.
10706 It has a parameter called |rise| that is |1| in
10707 case~(i), |-1| in case~(ii). Parameters |x0| through |y2| represent
10708 the derivative of the cubic following |p|.
10709 The |w| parameter should point to offset~$w_k$ and |info(p)| should already
10710 be set properly.  The |turn_amt| parameter gives the absolute value of the
10711 overall net change in pen offsets.
10712
10713 @<Declare subroutines needed by |offset_prep|@>=
10714 void mp_fin_offset_prep (MP mp,pointer p, pointer w, integer 
10715   x0,integer x1, integer x2, integer y0, integer y1, integer y2, 
10716   integer rise, integer turn_amt)  {
10717   pointer ww; /* for list manipulation */
10718   scaled du,dv; /* for slope calculation */
10719   integer t0,t1,t2; /* test coefficients */
10720   fraction t; /* place where the derivative passes a critical slope */
10721   fraction s; /* slope or reciprocal slope */
10722   integer v; /* intermediate value for updating |x0..y2| */
10723   pointer q; /* original |link(p)| */
10724   q=link(p);
10725   while (1)  { 
10726     if ( rise>0 ) ww=link(w); /* a pointer to $w\k$ */
10727     else  ww=knil(w); /* a pointer to $w_{k-1}$ */
10728     @<Compute test coefficients |(t0,t1,t2)|
10729       for $d(t)$ versus $d_k$ or $d_{k-1}$@>;
10730     t=mp_crossing_point(mp, t0,t1,t2);
10731     if ( t>=fraction_one ) {
10732       if ( turn_amt>0 ) t=fraction_one;  else return;
10733     }
10734     @<Split the cubic at $t$,
10735       and split off another cubic if the derivative crosses back@>;
10736     w=ww;
10737   }
10738 }
10739
10740 @ We want $B(\\{t0},\\{t1},\\{t2};t)$ to be the dot product of $d(t)$ with a
10741 $-90^\circ$ rotation of the vector from |w| to |ww|.  This makes the resulting
10742 function cross from positive to negative when $d_{k-1}\preceq d(t)\preceq d_k$
10743 begins to fail.
10744
10745 @<Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...@>=
10746 du=x_coord(ww)-x_coord(w); dv=y_coord(ww)-y_coord(w);
10747 if ( abs(du)>=abs(dv) ) {
10748   s=mp_make_fraction(mp, dv,du);
10749   t0=mp_take_fraction(mp, x0,s)-y0;
10750   t1=mp_take_fraction(mp, x1,s)-y1;
10751   t2=mp_take_fraction(mp, x2,s)-y2;
10752   if ( du<0 ) { negate(t0); negate(t1); negate(t2);  }
10753 } else { 
10754   s=mp_make_fraction(mp, du,dv);
10755   t0=x0-mp_take_fraction(mp, y0,s);
10756   t1=x1-mp_take_fraction(mp, y1,s);
10757   t2=x2-mp_take_fraction(mp, y2,s);
10758   if ( dv<0 ) { negate(t0); negate(t1); negate(t2);  }
10759 }
10760 if ( t0<0 ) t0=0 /* should be positive without rounding error */
10761
10762 @ The curve has crossed $d_k$ or $d_{k-1}$; its initial segment satisfies
10763 $(*)$, and it might cross again, yielding another solution of $(*)$.
10764
10765 @<Split the cubic at $t$, and split off another...@>=
10766
10767 mp_split_cubic(mp, p,t); p=link(p); info(p)=zero_off+rise;
10768 decr(turn_amt);
10769 v=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10770 x0=t_of_the_way(v,x1);
10771 v=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10772 y0=t_of_the_way(v,y1);
10773 if ( turn_amt<0 ) {
10774   t1=t_of_the_way(t1,t2);
10775   if ( t1>0 ) t1=0; /* without rounding error, |t1| would be |<=0| */
10776   t=mp_crossing_point(mp, 0,-t1,-t2);
10777   if ( t>fraction_one ) t=fraction_one;
10778   incr(turn_amt);
10779   if ( (t==fraction_one)&&(link(p)!=q) ) {
10780     info(link(p))=info(link(p))-rise;
10781   } else { 
10782     mp_split_cubic(mp, p,t); info(link(p))=zero_off-rise;
10783     v=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10784     x2=t_of_the_way(x1,v);
10785     v=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10786     y2=t_of_the_way(y1,v);
10787   }
10788 }
10789 }
10790
10791 @ Now we must consider the general problem of |offset_prep|, when
10792 nothing is known about a given cubic. We start by finding its
10793 direction in the vicinity of |t=0|.
10794
10795 If $z'(t)=0$, the given cubic is numerically unstable but |offset_prep|
10796 has not yet introduced any more numerical errors.  Thus we can compute
10797 the true initial direction for the given cubic, even if it is almost
10798 degenerate.
10799
10800 @<Find the initial direction |(dx,dy)|@>=
10801 dx=x0; dy=y0;
10802 if ( dx==0 && dy==0 ) { 
10803   dx=x1; dy=y1;
10804   if ( dx==0 && dy==0 ) { 
10805     dx=x2; dy=y2;
10806   }
10807 }
10808 if ( p==c ) { dx0=dx; dy0=dy;  }
10809
10810 @ @<Find the final direction |(dxin,dyin)|@>=
10811 dxin=x2; dyin=y2;
10812 if ( dxin==0 && dyin==0 ) {
10813   dxin=x1; dyin=y1;
10814   if ( dxin==0 && dyin==0 ) {
10815     dxin=x0; dyin=y0;
10816   }
10817 }
10818
10819 @ The next step is to bracket the initial direction between consecutive
10820 edges of the pen polygon.  We must be careful to turn clockwise only if
10821 this makes the turn less than $180^\circ$. (A $180^\circ$ turn must be
10822 counter-clockwise in order to make \&{doublepath} envelopes come out
10823 @:double_path_}{\&{doublepath} primitive@>
10824 right.) This code depends on |w0| being the offset for |(dxin,dyin)|.
10825
10826 @<Update |info(p)| and find the offset $w_k$ such that...@>=
10827 turn_amt=mp_get_turn_amt(mp,w0,dx,dy,(mp_ab_vs_cd(mp, dy,dxin,dx,dyin)>=0));
10828 w=mp_pen_walk(mp, w0, turn_amt);
10829 w0=w;
10830 info(p)=info(p)+turn_amt
10831
10832 @ Decide how many pen offsets to go away from |w| in order to find the offset
10833 for |(dx,dy)|, going counterclockwise if |ccw| is |true|.  This assumes that
10834 |w| is the offset for some direction $(x',y')$ from which the angle to |(dx,dy)|
10835 in the sense determined by |ccw| is less than or equal to $180^\circ$.
10836
10837 If the pen polygon has only two edges, they could both be parallel
10838 to |(dx,dy)|.  In this case, we must be careful to stop after crossing the first
10839 such edge in order to avoid an infinite loop.
10840
10841 @<Declare subroutines needed by |offset_prep|@>=
10842 integer mp_get_turn_amt (MP mp,pointer w, scaled  dx,
10843                          scaled dy, boolean  ccw) {
10844   pointer ww; /* a neighbor of knot~|w| */
10845   integer s; /* turn amount so far */
10846   integer t; /* |ab_vs_cd| result */
10847   s=0;
10848   if ( ccw ) { 
10849     ww=link(w);
10850     do {  
10851       t=mp_ab_vs_cd(mp, dy,(x_coord(ww)-x_coord(w)),
10852                         dx,(y_coord(ww)-y_coord(w)));
10853       if ( t<0 ) break;
10854       incr(s);
10855       w=ww; ww=link(ww);
10856     } while (t>0);
10857   } else { 
10858     ww=knil(w);
10859     while ( mp_ab_vs_cd(mp, dy,(x_coord(w)-x_coord(ww)),
10860                             dx,(y_coord(w)-y_coord(ww))) < 0) { 
10861       decr(s);
10862       w=ww; ww=knil(ww);
10863     }
10864   }
10865   return s;
10866 }
10867
10868 @ When we're all done, the final offset is |w0| and the final curve direction
10869 is |(dxin,dyin)|.  With this knowledge of the incoming direction at |c|, we
10870 can correct |info(c)| which was erroneously based on an incoming offset
10871 of~|h|.
10872
10873 @d fix_by(A) info(c)=info(c)+(A)
10874
10875 @<Fix the offset change in |info(c)| and set |c| to the return value of...@>=
10876 mp->spec_offset=info(c)-zero_off;
10877 if ( link(c)==c ) {
10878   info(c)=zero_off+n;
10879 } else { 
10880   fix_by(k_needed);
10881   while ( w0!=h ) { fix_by(1); w0=link(w0);  };
10882   while ( info(c)<=zero_off-n ) fix_by(n);
10883   while ( info(c)>zero_off ) fix_by(-n);
10884   if ( (info(c)!=zero_off)&&(mp_ab_vs_cd(mp, dy0,dxin,dx0,dyin)>=0) ) fix_by(n);
10885 }
10886 return c
10887
10888 @ Finally we want to reduce the general problem to situations that
10889 |fin_offset_prep| can handle. We split the cubic into at most three parts
10890 with respect to $d_{k-1}$, and apply |fin_offset_prep| to each part.
10891
10892 @<Complete the offset splitting process@>=
10893 ww=knil(w);
10894 @<Compute test coeff...@>;
10895 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set
10896   |t:=fraction_one+1|@>;
10897 if ( t>fraction_one ) {
10898   mp_fin_offset_prep(mp, p,w,x0,x1,x2,y0,y1,y2,1,turn_amt);
10899 } else {
10900   mp_split_cubic(mp, p,t); r=link(p);
10901   x1a=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10902   x2a=t_of_the_way(x1a,x1);
10903   y1a=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10904   y2a=t_of_the_way(y1a,y1);
10905   mp_fin_offset_prep(mp, p,w,x0,x1a,x2a,y0,y1a,y2a,1,0); x0=x2a; y0=y2a;
10906   info(r)=zero_off-1;
10907   if ( turn_amt>=0 ) {
10908     t1=t_of_the_way(t1,t2);
10909     if ( t1>0 ) t1=0;
10910     t=mp_crossing_point(mp, 0,-t1,-t2);
10911     if ( t>fraction_one ) t=fraction_one;
10912     @<Split off another rising cubic for |fin_offset_prep|@>;
10913     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,0);
10914   } else {
10915     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,(-1-turn_amt));
10916   }
10917 }
10918
10919 @ @<Split off another rising cubic for |fin_offset_prep|@>=
10920 mp_split_cubic(mp, r,t); info(link(r))=zero_off+1;
10921 x1a=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10922 x0a=t_of_the_way(x1,x1a);
10923 y1a=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10924 y0a=t_of_the_way(y1,y1a);
10925 mp_fin_offset_prep(mp, link(r),w,x0a,x1a,x2,y0a,y1a,y2,1,turn_amt);
10926 x2=x0a; y2=y0a
10927
10928 @ At this point, the direction of the incoming pen edge is |(-du,-dv)|.
10929 When the component of $d(t)$ perpendicular to |(-du,-dv)| crosses zero, we
10930 need to decide whether the directions are parallel or antiparallel.  We
10931 can test this by finding the dot product of $d(t)$ and |(-du,-dv)|, but this
10932 should be avoided when the value of |turn_amt| already determines the
10933 answer.  If |t2<0|, there is one crossing and it is antiparallel only if
10934 |turn_amt>=0|.  If |turn_amt<0|, there should always be at least one
10935 crossing and the first crossing cannot be antiparallel.
10936
10937 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set...@>=
10938 t=mp_crossing_point(mp, t0,t1,t2);
10939 if ( turn_amt>=0 ) {
10940   if ( t2<0 ) {
10941     t=fraction_one+1;
10942   } else { 
10943     u0=t_of_the_way(x0,x1);
10944     u1=t_of_the_way(x1,x2);
10945     ss=mp_take_fraction(mp, -du,t_of_the_way(u0,u1));
10946     v0=t_of_the_way(y0,y1);
10947     v1=t_of_the_way(y1,y2);
10948     ss=ss+mp_take_fraction(mp, -dv,t_of_the_way(v0,v1));
10949     if ( ss<0 ) t=fraction_one+1;
10950   }
10951 } else if ( t>fraction_one ) {
10952   t=fraction_one;
10953 }
10954
10955 @ @<Other local variables for |offset_prep|@>=
10956 integer u0,u1,v0,v1; /* intermediate values for $d(t)$ calculation */
10957 integer ss = 0; /* the part of the dot product computed so far */
10958 int d_sign; /* sign of overall change in direction for this cubic */
10959
10960 @ If the cubic almost has a cusp, it is a numerically ill-conditioned
10961 problem to decide which way it loops around but that's OK as long we're
10962 consistent.  To make \&{doublepath} envelopes work properly, reversing
10963 the path should always change the sign of |turn_amt|.
10964
10965 @<Decide on the net change in pen offsets and set |turn_amt|@>=
10966 d_sign=mp_ab_vs_cd(mp, dx,dyin, dxin,dy);
10967 if ( d_sign==0 ) {
10968   @<Check rotation direction based on node position@>
10969 }
10970 if ( d_sign==0 ) {
10971   if ( dx==0 ) {
10972     if ( dy>0 ) d_sign=1;  else d_sign=-1;
10973   } else {
10974     if ( dx>0 ) d_sign=1;  else d_sign=-1; 
10975   }
10976 }
10977 @<Make |ss| negative if and only if the total change in direction is
10978   more than $180^\circ$@>;
10979 turn_amt=mp_get_turn_amt(mp, w, dxin, dyin, (d_sign>0));
10980 if ( ss<0 ) turn_amt=turn_amt-d_sign*n
10981
10982 @ We check rotation direction by looking at the vector connecting the current
10983 node with the next. If its angle with incoming and outgoing tangents has the
10984 same sign, we pick this as |d_sign|, since it means we have a flex, not a cusp.
10985 Otherwise we proceed to the cusp code.
10986
10987 @<Check rotation direction based on node position@>=
10988 u0=x_coord(q)-x_coord(p);
10989 u1=y_coord(q)-y_coord(p);
10990 d_sign = half(mp_ab_vs_cd(mp, dx, u1, u0, dy)+
10991   mp_ab_vs_cd(mp, u0, dyin, dxin, u1));
10992
10993 @ In order to be invariant under path reversal, the result of this computation
10994 should not change when |x0|, |y0|, $\ldots$ are all negated and |(x0,y0)| is
10995 then swapped with |(x2,y2)|.  We make use of the identities
10996 |take_fraction(-a,-b)=take_fraction(a,b)| and
10997 |t_of_the_way(-a,-b)=-(t_of_the_way(a,b))|.
10998
10999 @<Make |ss| negative if and only if the total change in direction is...@>=
11000 t0=half(mp_take_fraction(mp, x0,y2))-half(mp_take_fraction(mp, x2,y0));
11001 t1=half(mp_take_fraction(mp, x1,(y0+y2)))-half(mp_take_fraction(mp, y1,(x0+x2)));
11002 if ( t0==0 ) t0=d_sign; /* path reversal always negates |d_sign| */
11003 if ( t0>0 ) {
11004   t=mp_crossing_point(mp, t0,t1,-t0);
11005   u0=t_of_the_way(x0,x1);
11006   u1=t_of_the_way(x1,x2);
11007   v0=t_of_the_way(y0,y1);
11008   v1=t_of_the_way(y1,y2);
11009 } else { 
11010   t=mp_crossing_point(mp, -t0,t1,t0);
11011   u0=t_of_the_way(x2,x1);
11012   u1=t_of_the_way(x1,x0);
11013   v0=t_of_the_way(y2,y1);
11014   v1=t_of_the_way(y1,y0);
11015 }
11016 ss=mp_take_fraction(mp, (x0+x2),t_of_the_way(u0,u1))+
11017    mp_take_fraction(mp, (y0+y2),t_of_the_way(v0,v1))
11018
11019 @ Here's a routine that prints an envelope spec in symbolic form.  It assumes
11020 that the |cur_pen| has not been walked around to the first offset.
11021
11022 @c 
11023 void mp_print_spec (MP mp,pointer cur_spec, pointer cur_pen, char *s) {
11024   pointer p,q; /* list traversal */
11025   pointer w; /* the current pen offset */
11026   mp_print_diagnostic(mp, "Envelope spec",s,true);
11027   p=cur_spec; w=mp_pen_walk(mp, cur_pen,mp->spec_offset);
11028   mp_print_ln(mp);
11029   mp_print_two(mp, x_coord(cur_spec),y_coord(cur_spec));
11030   mp_print(mp, " % beginning with offset ");
11031   mp_print_two(mp, x_coord(w),y_coord(w));
11032   do { 
11033     while (1) {  
11034       q=link(p);
11035       @<Print the cubic between |p| and |q|@>;
11036       p=q;
11037           if ((p==cur_spec) || (info(p)!=zero_off)) 
11038         break;
11039     }
11040     if ( info(p)!=zero_off ) {
11041       @<Update |w| as indicated by |info(p)| and print an explanation@>;
11042     }
11043   } while (p!=cur_spec);
11044   mp_print_nl(mp, " & cycle");
11045   mp_end_diagnostic(mp, true);
11046 }
11047
11048 @ @<Update |w| as indicated by |info(p)| and print an explanation@>=
11049
11050   w=mp_pen_walk(mp, w, (info(p)-zero_off));
11051   mp_print(mp, " % ");
11052   if ( info(p)>zero_off ) mp_print(mp, "counter");
11053   mp_print(mp, "clockwise to offset ");
11054   mp_print_two(mp, x_coord(w),y_coord(w));
11055 }
11056
11057 @ @<Print the cubic between |p| and |q|@>=
11058
11059   mp_print_nl(mp, "   ..controls ");
11060   mp_print_two(mp, right_x(p),right_y(p));
11061   mp_print(mp, " and ");
11062   mp_print_two(mp, left_x(q),left_y(q));
11063   mp_print_nl(mp, " ..");
11064   mp_print_two(mp, x_coord(q),y_coord(q));
11065 }
11066
11067 @ Once we have an envelope spec, the remaining task to construct the actual
11068 envelope by offsetting each cubic as determined by the |info| fields in
11069 the knots.  First we use |offset_prep| to convert the |c| into an envelope
11070 spec. Then we add the offsets so that |c| becomes a cyclic path that represents
11071 the envelope.
11072
11073 The |ljoin| and |miterlim| parameters control the treatment of points where the
11074 pen offset changes, and |lcap| controls the endpoints of a \&{doublepath}.
11075 The endpoints are easily located because |c| is given in undoubled form
11076 and then doubled in this procedure.  We use |spec_p1| and |spec_p2| to keep
11077 track of the endpoints and treat them like very sharp corners.
11078 Butt end caps are treated like beveled joins; round end caps are treated like
11079 round joins; and square end caps are achieved by setting |join_type:=3|.
11080
11081 None of these parameters apply to inside joins where the convolution tracing
11082 has retrograde lines.  In such cases we use a simple connect-the-endpoints
11083 approach that is achieved by setting |join_type:=2|.
11084
11085 @c @<Declare a function called |insert_knot|@>;
11086 pointer mp_make_envelope (MP mp,pointer c, pointer h, small_number ljoin,
11087   small_number lcap, scaled miterlim) {
11088   pointer p,q,r,q0; /* for manipulating the path */
11089   int join_type=0; /* codes |0..3| for mitered, round, beveled, or square */
11090   pointer w,w0; /* the pen knot for the current offset */
11091   scaled qx,qy; /* unshifted coordinates of |q| */
11092   halfword k,k0; /* controls pen edge insertion */
11093   @<Other local variables for |make_envelope|@>;
11094   dxin=0; dyin=0; dxout=0; dyout=0;
11095   mp->spec_p1=null; mp->spec_p2=null;
11096   @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>;
11097   @<Use |offset_prep| to compute the envelope spec then walk |h| around to
11098     the initial offset@>;
11099   w=h;
11100   p=c;
11101   do {  
11102     q=link(p); q0=q;
11103     qx=x_coord(q); qy=y_coord(q);
11104     k=info(q);
11105     k0=k; w0=w;
11106     if ( k!=zero_off ) {
11107       @<Set |join_type| to indicate how to handle offset changes at~|q|@>;
11108     }
11109     @<Add offset |w| to the cubic from |p| to |q|@>;
11110     while ( k!=zero_off ) { 
11111       @<Step |w| and move |k| one step closer to |zero_off|@>;
11112       if ( (join_type==1)||(k==zero_off) )
11113          q=mp_insert_knot(mp, q,qx+x_coord(w),qy+y_coord(w));
11114     };
11115     if ( q!=link(p) ) {
11116       @<Set |p=link(p)| and add knots between |p| and |q| as
11117         required by |join_type|@>;
11118     }
11119     p=q;
11120   } while (q0!=c);
11121   return c;
11122 }
11123
11124 @ @<Use |offset_prep| to compute the envelope spec then walk |h| around to...@>=
11125 c=mp_offset_prep(mp, c,h);
11126 if ( mp->internal[mp_tracing_specs]>0 ) 
11127   mp_print_spec(mp, c,h,"");
11128 h=mp_pen_walk(mp, h,mp->spec_offset)
11129
11130 @ Mitered and squared-off joins depend on path directions that are difficult to
11131 compute for degenerate cubics.  The envelope spec computed by |offset_prep| can
11132 have degenerate cubics only if the entire cycle collapses to a single
11133 degenerate cubic.  Setting |join_type:=2| in this case makes the computed
11134 envelope degenerate as well.
11135
11136 @<Set |join_type| to indicate how to handle offset changes at~|q|@>=
11137 if ( k<zero_off ) {
11138   join_type=2;
11139 } else {
11140   if ( (q!=mp->spec_p1)&&(q!=mp->spec_p2) ) join_type=ljoin;
11141   else if ( lcap==2 ) join_type=3;
11142   else join_type=2-lcap;
11143   if ( (join_type==0)||(join_type==3) ) {
11144     @<Set the incoming and outgoing directions at |q|; in case of
11145       degeneracy set |join_type:=2|@>;
11146     if ( join_type==0 ) {
11147       @<If |miterlim| is less than the secant of half the angle at |q|
11148         then set |join_type:=2|@>;
11149     }
11150   }
11151 }
11152
11153 @ @<If |miterlim| is less than the secant of half the angle at |q|...@>=
11154
11155   tmp=mp_take_fraction(mp, miterlim,fraction_half+
11156       half(mp_take_fraction(mp, dxin,dxout)+mp_take_fraction(mp, dyin,dyout)));
11157   if ( tmp<unity )
11158     if ( mp_take_scaled(mp, miterlim,tmp)<unity ) join_type=2;
11159 }
11160
11161 @ @<Other local variables for |make_envelope|@>=
11162 fraction dxin,dyin,dxout,dyout; /* directions at |q| when square or mitered */
11163 scaled tmp; /* a temporary value */
11164
11165 @ The coordinates of |p| have already been shifted unless |p| is the first
11166 knot in which case they get shifted at the very end.
11167
11168 @<Add offset |w| to the cubic from |p| to |q|@>=
11169 right_x(p)=right_x(p)+x_coord(w);
11170 right_y(p)=right_y(p)+y_coord(w);
11171 left_x(q)=left_x(q)+x_coord(w);
11172 left_y(q)=left_y(q)+y_coord(w);
11173 x_coord(q)=x_coord(q)+x_coord(w);
11174 y_coord(q)=y_coord(q)+y_coord(w);
11175 left_type(q)=mp_explicit;
11176 right_type(q)=mp_explicit
11177
11178 @ @<Step |w| and move |k| one step closer to |zero_off|@>=
11179 if ( k>zero_off ){ w=link(w); decr(k);  }
11180 else { w=knil(w); incr(k);  }
11181
11182 @ The cubic from |q| to the new knot at |(x,y)| becomes a line segment and
11183 the |right_x| and |right_y| fields of |r| are set from |q|.  This is done in
11184 case the cubic containing these control points is ``yet to be examined.''
11185
11186 @<Declare a function called |insert_knot|@>=
11187 pointer mp_insert_knot (MP mp,pointer q, scaled x, scaled y) {
11188   /* returns the inserted knot */
11189   pointer r; /* the new knot */
11190   r=mp_get_node(mp, knot_node_size);
11191   link(r)=link(q); link(q)=r;
11192   right_x(r)=right_x(q);
11193   right_y(r)=right_y(q);
11194   x_coord(r)=x;
11195   y_coord(r)=y;
11196   right_x(q)=x_coord(q);
11197   right_y(q)=y_coord(q);
11198   left_x(r)=x_coord(r);
11199   left_y(r)=y_coord(r);
11200   left_type(r)=mp_explicit;
11201   right_type(r)=mp_explicit;
11202   originator(r)=mp_program_code;
11203   return r;
11204 }
11205
11206 @ After setting |p:=link(p)|, either |join_type=1| or |q=link(p)|.
11207
11208 @<Set |p=link(p)| and add knots between |p| and |q| as...@>=
11209
11210   p=link(p);
11211   if ( (join_type==0)||(join_type==3) ) {
11212     if ( join_type==0 ) {
11213       @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>
11214     } else {
11215       @<Make |r| the last of two knots inserted between |p| and |q| to form a
11216         squared join@>;
11217     }
11218     if ( r!=null ) { 
11219       right_x(r)=x_coord(r);
11220       right_y(r)=y_coord(r);
11221     }
11222   }
11223 }
11224
11225 @ For very small angles, adding a knot is unnecessary and would cause numerical
11226 problems, so we just set |r:=null| in that case.
11227
11228 @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>=
11229
11230   det=mp_take_fraction(mp, dyout,dxin)-mp_take_fraction(mp, dxout,dyin);
11231   if ( abs(det)<26844 ) { 
11232      r=null; /* sine $<10^{-4}$ */
11233   } else { 
11234     tmp=mp_take_fraction(mp, x_coord(q)-x_coord(p),dyout)-
11235         mp_take_fraction(mp, y_coord(q)-y_coord(p),dxout);
11236     tmp=mp_make_fraction(mp, tmp,det);
11237     r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
11238       y_coord(p)+mp_take_fraction(mp, tmp,dyin));
11239   }
11240 }
11241
11242 @ @<Other local variables for |make_envelope|@>=
11243 fraction det; /* a determinant used for mitered join calculations */
11244
11245 @ @<Make |r| the last of two knots inserted between |p| and |q| to form a...@>=
11246
11247   ht_x=y_coord(w)-y_coord(w0);
11248   ht_y=x_coord(w0)-x_coord(w);
11249   while ( (abs(ht_x)<fraction_half)&&(abs(ht_y)<fraction_half) ) { 
11250     ht_x+=ht_x; ht_y+=ht_y;
11251   }
11252   @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range dot
11253     product with |(ht_x,ht_y)|@>;
11254   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxin,ht_x)+
11255                                   mp_take_fraction(mp, dyin,ht_y));
11256   r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
11257                          y_coord(p)+mp_take_fraction(mp, tmp,dyin));
11258   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxout,ht_x)+
11259                                   mp_take_fraction(mp, dyout,ht_y));
11260   r=mp_insert_knot(mp, r,x_coord(q)+mp_take_fraction(mp, tmp,dxout),
11261                          y_coord(q)+mp_take_fraction(mp, tmp,dyout));
11262 }
11263
11264 @ @<Other local variables for |make_envelope|@>=
11265 fraction ht_x,ht_y; /* perpendicular to the segment from |p| to |q| */
11266 scaled max_ht; /* maximum height of the pen polygon above the |w0|-|w| line */
11267 halfword kk; /* keeps track of the pen vertices being scanned */
11268 pointer ww; /* the pen vertex being tested */
11269
11270 @ The dot product of the vector from |w0| to |ww| with |(ht_x,ht_y)| ranges
11271 from zero to |max_ht|.
11272
11273 @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range...@>=
11274 max_ht=0;
11275 kk=zero_off;
11276 ww=w;
11277 while (1)  { 
11278   @<Step |ww| and move |kk| one step closer to |k0|@>;
11279   if ( kk==k0 ) break;
11280   tmp=mp_take_fraction(mp, (x_coord(ww)-x_coord(w0)),ht_x)+
11281       mp_take_fraction(mp, (y_coord(ww)-y_coord(w0)),ht_y);
11282   if ( tmp>max_ht ) max_ht=tmp;
11283 }
11284
11285
11286 @ @<Step |ww| and move |kk| one step closer to |k0|@>=
11287 if ( kk>k0 ) { ww=link(ww); decr(kk);  }
11288 else { ww=knil(ww); incr(kk);  }
11289
11290 @ @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>=
11291 if ( left_type(c)==mp_endpoint ) { 
11292   mp->spec_p1=mp_htap_ypoc(mp, c);
11293   mp->spec_p2=mp->path_tail;
11294   originator(mp->spec_p1)=mp_program_code;
11295   link(mp->spec_p2)=link(mp->spec_p1);
11296   link(mp->spec_p1)=c;
11297   mp_remove_cubic(mp, mp->spec_p1);
11298   c=mp->spec_p1;
11299   if ( c!=link(c) ) {
11300     originator(mp->spec_p2)=mp_program_code;
11301     mp_remove_cubic(mp, mp->spec_p2);
11302   } else {
11303     @<Make |c| look like a cycle of length one@>;
11304   }
11305 }
11306
11307 @ @<Make |c| look like a cycle of length one@>=
11308
11309   left_type(c)=mp_explicit; right_type(c)=mp_explicit;
11310   left_x(c)=x_coord(c); left_y(c)=y_coord(c);
11311   right_x(c)=x_coord(c); right_y(c)=y_coord(c);
11312 }
11313
11314 @ In degenerate situations we might have to look at the knot preceding~|q|.
11315 That knot is |p| but if |p<>c|, its coordinates have already been offset by |w|.
11316
11317 @<Set the incoming and outgoing directions at |q|; in case of...@>=
11318 dxin=x_coord(q)-left_x(q);
11319 dyin=y_coord(q)-left_y(q);
11320 if ( (dxin==0)&&(dyin==0) ) {
11321   dxin=x_coord(q)-right_x(p);
11322   dyin=y_coord(q)-right_y(p);
11323   if ( (dxin==0)&&(dyin==0) ) {
11324     dxin=x_coord(q)-x_coord(p);
11325     dyin=y_coord(q)-y_coord(p);
11326     if ( p!=c ) { /* the coordinates of |p| have been offset by |w| */
11327       dxin=dxin+x_coord(w);
11328       dyin=dyin+y_coord(w);
11329     }
11330   }
11331 }
11332 tmp=mp_pyth_add(mp, dxin,dyin);
11333 if ( tmp==0 ) {
11334   join_type=2;
11335 } else { 
11336   dxin=mp_make_fraction(mp, dxin,tmp);
11337   dyin=mp_make_fraction(mp, dyin,tmp);
11338   @<Set the outgoing direction at |q|@>;
11339 }
11340
11341 @ If |q=c| then the coordinates of |r| and the control points between |q|
11342 and~|r| have already been offset by |h|.
11343
11344 @<Set the outgoing direction at |q|@>=
11345 dxout=right_x(q)-x_coord(q);
11346 dyout=right_y(q)-y_coord(q);
11347 if ( (dxout==0)&&(dyout==0) ) {
11348   r=link(q);
11349   dxout=left_x(r)-x_coord(q);
11350   dyout=left_y(r)-y_coord(q);
11351   if ( (dxout==0)&&(dyout==0) ) {
11352     dxout=x_coord(r)-x_coord(q);
11353     dyout=y_coord(r)-y_coord(q);
11354   }
11355 }
11356 if ( q==c ) {
11357   dxout=dxout-x_coord(h);
11358   dyout=dyout-y_coord(h);
11359 }
11360 tmp=mp_pyth_add(mp, dxout,dyout);
11361 if ( tmp==0 ) mp_confusion(mp, "degenerate spec");
11362 @:this can't happen degerate spec}{\quad degenerate spec@>
11363 dxout=mp_make_fraction(mp, dxout,tmp);
11364 dyout=mp_make_fraction(mp, dyout,tmp)
11365
11366 @* \[23] Direction and intersection times.
11367 A path of length $n$ is defined parametrically by functions $x(t)$ and
11368 $y(t)$, for |0<=t<=n|; we can regard $t$ as the ``time'' at which the path
11369 reaches the point $\bigl(x(t),y(t)\bigr)$.  In this section of the program
11370 we shall consider operations that determine special times associated with
11371 given paths: the first time that a path travels in a given direction, and
11372 a pair of times at which two paths cross each other.
11373
11374 @ Let's start with the easier task. The function |find_direction_time| is
11375 given a direction |(x,y)| and a path starting at~|h|. If the path never
11376 travels in direction |(x,y)|, the direction time will be~|-1|; otherwise
11377 it will be nonnegative.
11378
11379 Certain anomalous cases can arise: If |(x,y)=(0,0)|, so that the given
11380 direction is undefined, the direction time will be~0. If $\bigl(x'(t),
11381 y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be
11382 assumed to match any given direction at time~|t|.
11383
11384 The routine solves this problem in nondegenerate cases by rotating the path
11385 and the given direction so that |(x,y)=(1,0)|; i.e., the main task will be
11386 to find when a given path first travels ``due east.''
11387
11388 @c 
11389 scaled mp_find_direction_time (MP mp,scaled x, scaled y, pointer h) {
11390   scaled max; /* $\max\bigl(\vert x\vert,\vert y\vert\bigr)$ */
11391   pointer p,q; /* for list traversal */
11392   scaled n; /* the direction time at knot |p| */
11393   scaled tt; /* the direction time within a cubic */
11394   @<Other local variables for |find_direction_time|@>;
11395   @<Normalize the given direction for better accuracy;
11396     but |return| with zero result if it's zero@>;
11397   n=0; p=h; phi=0;
11398   while (1) { 
11399     if ( right_type(p)==mp_endpoint ) break;
11400     q=link(p);
11401     @<Rotate the cubic between |p| and |q|; then
11402       |goto found| if the rotated cubic travels due east at some time |tt|;
11403       but |break| if an entire cyclic path has been traversed@>;
11404     p=q; n=n+unity;
11405   }
11406   return (-unity);
11407 FOUND: 
11408   return (n+tt);
11409 }
11410
11411 @ @<Normalize the given direction for better accuracy...@>=
11412 if ( abs(x)<abs(y) ) { 
11413   x=mp_make_fraction(mp, x,abs(y));
11414   if ( y>0 ) y=fraction_one; else y=-fraction_one;
11415 } else if ( x==0 ) { 
11416   return 0;
11417 } else  { 
11418   y=mp_make_fraction(mp, y,abs(x));
11419   if ( x>0 ) x=fraction_one; else x=-fraction_one;
11420 }
11421
11422 @ Since we're interested in the tangent directions, we work with the
11423 derivative $${\textstyle1\over3}B'(x_0,x_1,x_2,x_3;t)=
11424 B(x_1-x_0,x_2-x_1,x_3-x_2;t)$$ instead of
11425 $B(x_0,x_1,x_2,x_3;t)$ itself. The derived coefficients are also scaled up
11426 in order to achieve better accuracy.
11427
11428 The given path may turn abruptly at a knot, and it might pass the critical
11429 tangent direction at such a time. Therefore we remember the direction |phi|
11430 in which the previous rotated cubic was traveling. (The value of |phi| will be
11431 undefined on the first cubic, i.e., when |n=0|.)
11432
11433 @<Rotate the cubic between |p| and |q|; then...@>=
11434 tt=0;
11435 @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples of the control
11436   points of the rotated derivatives@>;
11437 if ( y1==0 ) if ( x1>=0 ) goto FOUND;
11438 if ( n>0 ) { 
11439   @<Exit to |found| if an eastward direction occurs at knot |p|@>;
11440   if ( p==h ) break;
11441   };
11442 if ( (x3!=0)||(y3!=0) ) phi=mp_n_arg(mp, x3,y3);
11443 @<Exit to |found| if the curve whose derivatives are specified by
11444   |x1,x2,x3,y1,y2,y3| travels eastward at some time~|tt|@>
11445
11446 @ @<Other local variables for |find_direction_time|@>=
11447 scaled x1,x2,x3,y1,y2,y3;  /* multiples of rotated derivatives */
11448 angle theta,phi; /* angles of exit and entry at a knot */
11449 fraction t; /* temp storage */
11450
11451 @ @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples...@>=
11452 x1=right_x(p)-x_coord(p); x2=left_x(q)-right_x(p);
11453 x3=x_coord(q)-left_x(q);
11454 y1=right_y(p)-y_coord(p); y2=left_y(q)-right_y(p);
11455 y3=y_coord(q)-left_y(q);
11456 max=abs(x1);
11457 if ( abs(x2)>max ) max=abs(x2);
11458 if ( abs(x3)>max ) max=abs(x3);
11459 if ( abs(y1)>max ) max=abs(y1);
11460 if ( abs(y2)>max ) max=abs(y2);
11461 if ( abs(y3)>max ) max=abs(y3);
11462 if ( max==0 ) goto FOUND;
11463 while ( max<fraction_half ){ 
11464   max+=max; x1+=x1; x2+=x2; x3+=x3;
11465   y1+=y1; y2+=y2; y3+=y3;
11466 }
11467 t=x1; x1=mp_take_fraction(mp, x1,x)+mp_take_fraction(mp, y1,y);
11468 y1=mp_take_fraction(mp, y1,x)-mp_take_fraction(mp, t,y);
11469 t=x2; x2=mp_take_fraction(mp, x2,x)+mp_take_fraction(mp, y2,y);
11470 y2=mp_take_fraction(mp, y2,x)-mp_take_fraction(mp, t,y);
11471 t=x3; x3=mp_take_fraction(mp, x3,x)+mp_take_fraction(mp, y3,y);
11472 y3=mp_take_fraction(mp, y3,x)-mp_take_fraction(mp, t,y)
11473
11474 @ @<Exit to |found| if an eastward direction occurs at knot |p|@>=
11475 theta=mp_n_arg(mp, x1,y1);
11476 if ( theta>=0 ) if ( phi<=0 ) if ( phi>=theta-one_eighty_deg ) goto FOUND;
11477 if ( theta<=0 ) if ( phi>=0 ) if ( phi<=theta+one_eighty_deg ) goto FOUND
11478
11479 @ In this step we want to use the |crossing_point| routine to find the
11480 roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$.
11481 Several complications arise: If the quadratic equation has a double root,
11482 the curve never crosses zero, and |crossing_point| will find nothing;
11483 this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic
11484 equation has simple roots, or only one root, we may have to negate it
11485 so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root.
11486 And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is
11487 identically zero.
11488
11489 @ @<Exit to |found| if the curve whose derivatives are specified by...@>=
11490 if ( x1<0 ) if ( x2<0 ) if ( x3<0 ) goto DONE;
11491 if ( mp_ab_vs_cd(mp, y1,y3,y2,y2)==0 ) {
11492   @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11493     either |goto found| or |goto done|@>;
11494 }
11495 if ( y1<=0 ) {
11496   if ( y1<0 ) { y1=-y1; y2=-y2; y3=-y3; }
11497   else if ( y2>0 ){ y2=-y2; y3=-y3; };
11498 }
11499 @<Check the places where $B(y_1,y_2,y_3;t)=0$ to see if
11500   $B(x_1,x_2,x_3;t)\ge0$@>;
11501 DONE:
11502
11503 @ The quadratic polynomial $B(y_1,y_2,y_3;t)$ begins |>=0| and has at most
11504 two roots, because we know that it isn't identically zero.
11505
11506 It must be admitted that the |crossing_point| routine is not perfectly accurate;
11507 rounding errors might cause it to find a root when $y_1y_3>y_2^2$, or to
11508 miss the roots when $y_1y_3<y_2^2$. The rotation process is itself
11509 subject to rounding errors. Yet this code optimistically tries to
11510 do the right thing.
11511
11512 @d we_found_it { tt=(t+04000) / 010000; goto FOUND; }
11513
11514 @<Check the places where $B(y_1,y_2,y_3;t)=0$...@>=
11515 t=mp_crossing_point(mp, y1,y2,y3);
11516 if ( t>fraction_one ) goto DONE;
11517 y2=t_of_the_way(y2,y3);
11518 x1=t_of_the_way(x1,x2);
11519 x2=t_of_the_way(x2,x3);
11520 x1=t_of_the_way(x1,x2);
11521 if ( x1>=0 ) we_found_it;
11522 if ( y2>0 ) y2=0;
11523 tt=t; t=mp_crossing_point(mp, 0,-y2,-y3);
11524 if ( t>fraction_one ) goto DONE;
11525 x1=t_of_the_way(x1,x2);
11526 x2=t_of_the_way(x2,x3);
11527 if ( t_of_the_way(x1,x2)>=0 ) { 
11528   t=t_of_the_way(tt,fraction_one); we_found_it;
11529 }
11530
11531 @ @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11532     either |goto found| or |goto done|@>=
11533
11534   if ( mp_ab_vs_cd(mp, y1,y2,0,0)<0 ) {
11535     t=mp_make_fraction(mp, y1,y1-y2);
11536     x1=t_of_the_way(x1,x2);
11537     x2=t_of_the_way(x2,x3);
11538     if ( t_of_the_way(x1,x2)>=0 ) we_found_it;
11539   } else if ( y3==0 ) {
11540     if ( y1==0 ) {
11541       @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|@>;
11542     } else if ( x3>=0 ) {
11543       tt=unity; goto FOUND;
11544     }
11545   }
11546   goto DONE;
11547 }
11548
11549 @ At this point we know that the derivative of |y(t)| is identically zero,
11550 and that |x1<0|; but either |x2>=0| or |x3>=0|, so there's some hope of
11551 traveling east.
11552
11553 @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|...@>=
11554
11555   t=mp_crossing_point(mp, -x1,-x2,-x3);
11556   if ( t<=fraction_one ) we_found_it;
11557   if ( mp_ab_vs_cd(mp, x1,x3,x2,x2)<=0 ) { 
11558     t=mp_make_fraction(mp, x1,x1-x2); we_found_it;
11559   }
11560 }
11561
11562 @ The intersection of two cubics can be found by an interesting variant
11563 of the general bisection scheme described in the introduction to
11564 |crossing_point|.\
11565 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)$,
11566 we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$,
11567 if an intersection exists. First we find the smallest rectangle that
11568 encloses the points $\{w_0,w_1,w_2,w_3\}$ and check that it overlaps
11569 the smallest rectangle that encloses
11570 $\{z_0,z_1,z_2,z_3\}$; if not, the cubics certainly don't intersect.
11571 But if the rectangles do overlap, we bisect the intervals, getting
11572 new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first
11573 tries for an intersection between $w'$ and~$z'$, then (if unsuccessful)
11574 between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$,
11575 finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful
11576 levels of bisection we will have determined the intersection times $t_1$
11577 and~$t_2$ to $l$~bits of accuracy.
11578
11579 \def\submin{_{\rm min}} \def\submax{_{\rm max}}
11580 As before, it is better to work with the numbers $W_k=2^l(w_k-w_{k-1})$
11581 and $Z_k=2^l(z_k-z_{k-1})$ rather than the coefficients $w_k$ and $z_k$
11582 themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$,
11583 to determine when the enclosing rectangles overlap. Here's why:
11584 The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$,
11585 and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$,
11586 if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin=
11587 \min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates
11588 overlap if and only if $u\submin\L x\submax$ and
11589 $x\submin\L u\submax$. Letting
11590 $$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\;
11591   U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$
11592 we have $u\submin=2^lu_0+U\submin$, etc.; the condition for overlap
11593 reduces to
11594 $$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$
11595 Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly,
11596 the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The
11597 coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases,
11598 because of the overlap condition; i.e., we know that $X\submin$,
11599 $X\submax$, and their relatives are bounded, hence $X\submax-
11600 U\submin$ and $X\submin-U\submax$ are bounded.
11601
11602 @ Incidentally, if the given cubics intersect more than once, the process
11603 just sketched will not necessarily find the lexicographically smallest pair
11604 $(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled
11605 order''; i.e., if $t_1=(.a_1a_2\ldots a_{16})_2$ and
11606 $t_2=(.b_1b_2\ldots b_{16})_2$, then we will minimize
11607 $a_1b_1a_2b_2\ldots a_{16}b_{16}$, not
11608 $a_1a_2\ldots a_{16}b_1b_2\ldots b_{16}$.
11609 Shuffled order agrees with lexicographic order if all pairs of solutions
11610 $(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff
11611 $t_2<t_2'$; but in general, lexicographic order can be quite different,
11612 and the bisection algorithm would be substantially less efficient if it were
11613 constrained by lexicographic order.
11614
11615 For example, suppose that an overlap has been found for $l=3$ and
11616 $(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by
11617 either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4.
11618 Then there is probably an intersection in one of the subintervals
11619 $(.1011,.011x)$; but lexicographic order would require us to explore
11620 $(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't
11621 want to store all of the subdivision data for the second path, so the
11622 subdivisions would have to be regenerated many times. Such inefficiencies
11623 would be associated with every `1' in the binary representation of~$t_1$.
11624
11625 @ The subdivision process introduces rounding errors, hence we need to
11626 make a more liberal test for overlap. It is not hard to show that the
11627 computed values of $U_i$ differ from the truth by at most~$l$, on
11628 level~$l$, hence $U\submin$ and $U\submax$ will be at most $3l$ in error.
11629 If $\beta$ is an upper bound on the absolute error in the computed
11630 components of $\Delta=(|delx|,|dely|)$ on level~$l$, we will replace
11631 the test `$X\submin-U\submax\L|delx|$' by the more liberal test
11632 `$X\submin-U\submax\L|delx|+|tol|$', where $|tol|=6l+\beta$.
11633
11634 More accuracy is obtained if we try the algorithm first with |tol=0|;
11635 the more liberal tolerance is used only if an exact approach fails.
11636 It is convenient to do this double-take by letting `3' in the preceding
11637 paragraph be a parameter, which is first 0, then 3.
11638
11639 @<Glob...@>=
11640 unsigned int tol_step; /* either 0 or 3, usually */
11641
11642 @ We shall use an explicit stack to implement the recursive bisection
11643 method described above. The |bisect_stack| array will contain numerous 5-word
11644 packets like $(U_1,U_2,U_3,U\submin,U\submax)$, as well as 20-word packets
11645 comprising the 5-word packets for $U$, $V$, $X$, and~$Y$.
11646
11647 The following macros define the allocation of stack positions to
11648 the quantities needed for bisection-intersection.
11649
11650 @d stack_1(A) mp->bisect_stack[(A)] /* $U_1$, $V_1$, $X_1$, or $Y_1$ */
11651 @d stack_2(A) mp->bisect_stack[(A)+1] /* $U_2$, $V_2$, $X_2$, or $Y_2$ */
11652 @d stack_3(A) mp->bisect_stack[(A)+2] /* $U_3$, $V_3$, $X_3$, or $Y_3$ */
11653 @d stack_min(A) mp->bisect_stack[(A)+3]
11654   /* $U\submin$, $V\submin$, $X\submin$, or $Y\submin$ */
11655 @d stack_max(A) mp->bisect_stack[(A)+4]
11656   /* $U\submax$, $V\submax$, $X\submax$, or $Y\submax$ */
11657 @d int_packets 20 /* number of words to represent $U_k$, $V_k$, $X_k$, and $Y_k$ */
11658 @#
11659 @d u_packet(A) ((A)-5)
11660 @d v_packet(A) ((A)-10)
11661 @d x_packet(A) ((A)-15)
11662 @d y_packet(A) ((A)-20)
11663 @d l_packets (mp->bisect_ptr-int_packets)
11664 @d r_packets mp->bisect_ptr
11665 @d ul_packet u_packet(l_packets) /* base of $U'_k$ variables */
11666 @d vl_packet v_packet(l_packets) /* base of $V'_k$ variables */
11667 @d xl_packet x_packet(l_packets) /* base of $X'_k$ variables */
11668 @d yl_packet y_packet(l_packets) /* base of $Y'_k$ variables */
11669 @d ur_packet u_packet(r_packets) /* base of $U''_k$ variables */
11670 @d vr_packet v_packet(r_packets) /* base of $V''_k$ variables */
11671 @d xr_packet x_packet(r_packets) /* base of $X''_k$ variables */
11672 @d yr_packet y_packet(r_packets) /* base of $Y''_k$ variables */
11673 @#
11674 @d u1l stack_1(ul_packet) /* $U'_1$ */
11675 @d u2l stack_2(ul_packet) /* $U'_2$ */
11676 @d u3l stack_3(ul_packet) /* $U'_3$ */
11677 @d v1l stack_1(vl_packet) /* $V'_1$ */
11678 @d v2l stack_2(vl_packet) /* $V'_2$ */
11679 @d v3l stack_3(vl_packet) /* $V'_3$ */
11680 @d x1l stack_1(xl_packet) /* $X'_1$ */
11681 @d x2l stack_2(xl_packet) /* $X'_2$ */
11682 @d x3l stack_3(xl_packet) /* $X'_3$ */
11683 @d y1l stack_1(yl_packet) /* $Y'_1$ */
11684 @d y2l stack_2(yl_packet) /* $Y'_2$ */
11685 @d y3l stack_3(yl_packet) /* $Y'_3$ */
11686 @d u1r stack_1(ur_packet) /* $U''_1$ */
11687 @d u2r stack_2(ur_packet) /* $U''_2$ */
11688 @d u3r stack_3(ur_packet) /* $U''_3$ */
11689 @d v1r stack_1(vr_packet) /* $V''_1$ */
11690 @d v2r stack_2(vr_packet) /* $V''_2$ */
11691 @d v3r stack_3(vr_packet) /* $V''_3$ */
11692 @d x1r stack_1(xr_packet) /* $X''_1$ */
11693 @d x2r stack_2(xr_packet) /* $X''_2$ */
11694 @d x3r stack_3(xr_packet) /* $X''_3$ */
11695 @d y1r stack_1(yr_packet) /* $Y''_1$ */
11696 @d y2r stack_2(yr_packet) /* $Y''_2$ */
11697 @d y3r stack_3(yr_packet) /* $Y''_3$ */
11698 @#
11699 @d stack_dx mp->bisect_stack[mp->bisect_ptr] /* stacked value of |delx| */
11700 @d stack_dy mp->bisect_stack[mp->bisect_ptr+1] /* stacked value of |dely| */
11701 @d stack_tol mp->bisect_stack[mp->bisect_ptr+2] /* stacked value of |tol| */
11702 @d stack_uv mp->bisect_stack[mp->bisect_ptr+3] /* stacked value of |uv| */
11703 @d stack_xy mp->bisect_stack[mp->bisect_ptr+4] /* stacked value of |xy| */
11704 @d int_increment (int_packets+int_packets+5) /* number of stack words per level */
11705
11706 @<Glob...@>=
11707 integer *bisect_stack;
11708 unsigned int bisect_ptr;
11709
11710 @ @<Allocate or initialize ...@>=
11711 mp->bisect_stack = xmalloc((bistack_size+1),sizeof(integer));
11712
11713 @ @<Dealloc variables@>=
11714 xfree(mp->bisect_stack);
11715
11716 @ @<Check the ``constant''...@>=
11717 if ( int_packets+17*int_increment>bistack_size ) mp->bad=19;
11718
11719 @ Computation of the min and max is a tedious but fairly fast sequence of
11720 instructions; exactly four comparisons are made in each branch.
11721
11722 @d set_min_max(A) 
11723   if ( stack_1((A))<0 ) {
11724     if ( stack_3((A))>=0 ) {
11725       if ( stack_2((A))<0 ) stack_min((A))=stack_1((A))+stack_2((A));
11726       else stack_min((A))=stack_1((A));
11727       stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11728       if ( stack_max((A))<0 ) stack_max((A))=0;
11729     } else { 
11730       stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11731       if ( stack_min((A))>stack_1((A)) ) stack_min((A))=stack_1((A));
11732       stack_max((A))=stack_1((A))+stack_2((A));
11733       if ( stack_max((A))<0 ) stack_max((A))=0;
11734     }
11735   } else if ( stack_3((A))<=0 ) {
11736     if ( stack_2((A))>0 ) stack_max((A))=stack_1((A))+stack_2((A));
11737     else stack_max((A))=stack_1((A));
11738     stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11739     if ( stack_min((A))>0 ) stack_min((A))=0;
11740   } else  { 
11741     stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11742     if ( stack_max((A))<stack_1((A)) ) stack_max((A))=stack_1((A));
11743     stack_min((A))=stack_1((A))+stack_2((A));
11744     if ( stack_min((A))>0 ) stack_min((A))=0;
11745   }
11746
11747 @ It's convenient to keep the current values of $l$, $t_1$, and $t_2$ in
11748 the integer form $2^l+2^lt_1$ and $2^l+2^lt_2$. The |cubic_intersection|
11749 routine uses global variables |cur_t| and |cur_tt| for this purpose;
11750 after successful completion, |cur_t| and |cur_tt| will contain |unity|
11751 plus the |scaled| values of $t_1$ and~$t_2$.
11752
11753 The values of |cur_t| and |cur_tt| will be set to zero if |cubic_intersection|
11754 finds no intersection. The routine gives up and gives an approximate answer
11755 if it has backtracked
11756 more than 5000 times (otherwise there are cases where several minutes
11757 of fruitless computation would be possible).
11758
11759 @d max_patience 5000
11760
11761 @<Glob...@>=
11762 integer cur_t;integer cur_tt; /* controls and results of |cubic_intersection| */
11763 integer time_to_go; /* this many backtracks before giving up */
11764 integer max_t; /* maximum of $2^{l+1}$ so far achieved */
11765
11766 @ The given cubics $B(w_0,w_1,w_2,w_3;t)$ and
11767 $B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes |(p,link(p))|
11768 and |(pp,link(pp))|, respectively.
11769
11770 @c void mp_cubic_intersection (MP mp,pointer p, pointer pp) {
11771   pointer q,qq; /* |link(p)|, |link(pp)| */
11772   mp->time_to_go=max_patience; mp->max_t=2;
11773   @<Initialize for intersections at level zero@>;
11774 CONTINUE:
11775   while (1) { 
11776     if ( mp->delx-mp->tol<=stack_max(x_packet(mp->xy))-stack_min(u_packet(mp->uv)))
11777     if ( mp->delx+mp->tol>=stack_min(x_packet(mp->xy))-stack_max(u_packet(mp->uv)))
11778     if ( mp->dely-mp->tol<=stack_max(y_packet(mp->xy))-stack_min(v_packet(mp->uv)))
11779     if ( mp->dely+mp->tol>=stack_min(y_packet(mp->xy))-stack_max(v_packet(mp->uv))) 
11780     { 
11781       if ( mp->cur_t>=mp->max_t ){ 
11782         if ( mp->max_t==two ) { /* we've done 17 bisections */ 
11783            mp->cur_t=halfp(mp->cur_t+1); mp->cur_tt=halfp(mp->cur_tt+1); return;
11784         }
11785         mp->max_t+=mp->max_t; mp->appr_t=mp->cur_t; mp->appr_tt=mp->cur_tt;
11786       }
11787       @<Subdivide for a new level of intersection@>;
11788       goto CONTINUE;
11789     }
11790     if ( mp->time_to_go>0 ) {
11791       decr(mp->time_to_go);
11792     } else { 
11793       while ( mp->appr_t<unity ) { 
11794         mp->appr_t+=mp->appr_t; mp->appr_tt+=mp->appr_tt;
11795       }
11796       mp->cur_t=mp->appr_t; mp->cur_tt=mp->appr_tt; return;
11797     }
11798     @<Advance to the next pair |(cur_t,cur_tt)|@>;
11799   }
11800 }
11801
11802 @ The following variables are global, although they are used only by
11803 |cubic_intersection|, because it is necessary on some machines to
11804 split |cubic_intersection| up into two procedures.
11805
11806 @<Glob...@>=
11807 integer delx;integer dely; /* the components of $\Delta=2^l(w_0-z_0)$ */
11808 integer tol; /* bound on the uncertainly in the overlap test */
11809 unsigned int uv;
11810 unsigned int xy; /* pointers to the current packets of interest */
11811 integer three_l; /* |tol_step| times the bisection level */
11812 integer appr_t;integer appr_tt; /* best approximations known to the answers */
11813
11814 @ We shall assume that the coordinates are sufficiently non-extreme that
11815 integer overflow will not occur.
11816
11817 @<Initialize for intersections at level zero@>=
11818 q=link(p); qq=link(pp); mp->bisect_ptr=int_packets;
11819 u1r=right_x(p)-x_coord(p); u2r=left_x(q)-right_x(p);
11820 u3r=x_coord(q)-left_x(q); set_min_max(ur_packet);
11821 v1r=right_y(p)-y_coord(p); v2r=left_y(q)-right_y(p);
11822 v3r=y_coord(q)-left_y(q); set_min_max(vr_packet);
11823 x1r=right_x(pp)-x_coord(pp); x2r=left_x(qq)-right_x(pp);
11824 x3r=x_coord(qq)-left_x(qq); set_min_max(xr_packet);
11825 y1r=right_y(pp)-y_coord(pp); y2r=left_y(qq)-right_y(pp);
11826 y3r=y_coord(qq)-left_y(qq); set_min_max(yr_packet);
11827 mp->delx=x_coord(p)-x_coord(pp); mp->dely=y_coord(p)-y_coord(pp);
11828 mp->tol=0; mp->uv=r_packets; mp->xy=r_packets; 
11829 mp->three_l=0; mp->cur_t=1; mp->cur_tt=1
11830
11831 @ @<Subdivide for a new level of intersection@>=
11832 stack_dx=mp->delx; stack_dy=mp->dely; stack_tol=mp->tol; 
11833 stack_uv=mp->uv; stack_xy=mp->xy;
11834 mp->bisect_ptr=mp->bisect_ptr+int_increment;
11835 mp->cur_t+=mp->cur_t; mp->cur_tt+=mp->cur_tt;
11836 u1l=stack_1(u_packet(mp->uv)); u3r=stack_3(u_packet(mp->uv));
11837 u2l=half(u1l+stack_2(u_packet(mp->uv)));
11838 u2r=half(u3r+stack_2(u_packet(mp->uv)));
11839 u3l=half(u2l+u2r); u1r=u3l;
11840 set_min_max(ul_packet); set_min_max(ur_packet);
11841 v1l=stack_1(v_packet(mp->uv)); v3r=stack_3(v_packet(mp->uv));
11842 v2l=half(v1l+stack_2(v_packet(mp->uv)));
11843 v2r=half(v3r+stack_2(v_packet(mp->uv)));
11844 v3l=half(v2l+v2r); v1r=v3l;
11845 set_min_max(vl_packet); set_min_max(vr_packet);
11846 x1l=stack_1(x_packet(mp->xy)); x3r=stack_3(x_packet(mp->xy));
11847 x2l=half(x1l+stack_2(x_packet(mp->xy)));
11848 x2r=half(x3r+stack_2(x_packet(mp->xy)));
11849 x3l=half(x2l+x2r); x1r=x3l;
11850 set_min_max(xl_packet); set_min_max(xr_packet);
11851 y1l=stack_1(y_packet(mp->xy)); y3r=stack_3(y_packet(mp->xy));
11852 y2l=half(y1l+stack_2(y_packet(mp->xy)));
11853 y2r=half(y3r+stack_2(y_packet(mp->xy)));
11854 y3l=half(y2l+y2r); y1r=y3l;
11855 set_min_max(yl_packet); set_min_max(yr_packet);
11856 mp->uv=l_packets; mp->xy=l_packets;
11857 mp->delx+=mp->delx; mp->dely+=mp->dely;
11858 mp->tol=mp->tol-mp->three_l+mp->tol_step; 
11859 mp->tol+=mp->tol; mp->three_l=mp->three_l+mp->tol_step
11860
11861 @ @<Advance to the next pair |(cur_t,cur_tt)|@>=
11862 NOT_FOUND: 
11863 if ( odd(mp->cur_tt) ) {
11864   if ( odd(mp->cur_t) ) {
11865      @<Descend to the previous level and |goto not_found|@>;
11866   } else { 
11867     incr(mp->cur_t);
11868     mp->delx=mp->delx+stack_1(u_packet(mp->uv))+stack_2(u_packet(mp->uv))
11869       +stack_3(u_packet(mp->uv));
11870     mp->dely=mp->dely+stack_1(v_packet(mp->uv))+stack_2(v_packet(mp->uv))
11871       +stack_3(v_packet(mp->uv));
11872     mp->uv=mp->uv+int_packets; /* switch from |l_packet| to |r_packet| */
11873     decr(mp->cur_tt); mp->xy=mp->xy-int_packets; 
11874          /* switch from |r_packet| to |l_packet| */
11875     mp->delx=mp->delx+stack_1(x_packet(mp->xy))+stack_2(x_packet(mp->xy))
11876       +stack_3(x_packet(mp->xy));
11877     mp->dely=mp->dely+stack_1(y_packet(mp->xy))+stack_2(y_packet(mp->xy))
11878       +stack_3(y_packet(mp->xy));
11879   }
11880 } else { 
11881   incr(mp->cur_tt); mp->tol=mp->tol+mp->three_l;
11882   mp->delx=mp->delx-stack_1(x_packet(mp->xy))-stack_2(x_packet(mp->xy))
11883     -stack_3(x_packet(mp->xy));
11884   mp->dely=mp->dely-stack_1(y_packet(mp->xy))-stack_2(y_packet(mp->xy))
11885     -stack_3(y_packet(mp->xy));
11886   mp->xy=mp->xy+int_packets; /* switch from |l_packet| to |r_packet| */
11887 }
11888
11889 @ @<Descend to the previous level...@>=
11890
11891   mp->cur_t=halfp(mp->cur_t); mp->cur_tt=halfp(mp->cur_tt);
11892   if ( mp->cur_t==0 ) return;
11893   mp->bisect_ptr=mp->bisect_ptr-int_increment; 
11894   mp->three_l=mp->three_l-mp->tol_step;
11895   mp->delx=stack_dx; mp->dely=stack_dy; mp->tol=stack_tol; 
11896   mp->uv=stack_uv; mp->xy=stack_xy;
11897   goto NOT_FOUND;
11898 }
11899
11900 @ The |path_intersection| procedure is much simpler.
11901 It invokes |cubic_intersection| in lexicographic order until finding a
11902 pair of cubics that intersect. The final intersection times are placed in
11903 |cur_t| and~|cur_tt|.
11904
11905 @c void mp_path_intersection (MP mp,pointer h, pointer hh) {
11906   pointer p,pp; /* link registers that traverse the given paths */
11907   integer n,nn; /* integer parts of intersection times, minus |unity| */
11908   @<Change one-point paths into dead cycles@>;
11909   mp->tol_step=0;
11910   do {  
11911     n=-unity; p=h;
11912     do {  
11913       if ( right_type(p)!=mp_endpoint ) { 
11914         nn=-unity; pp=hh;
11915         do {  
11916           if ( right_type(pp)!=mp_endpoint )  { 
11917             mp_cubic_intersection(mp, p,pp);
11918             if ( mp->cur_t>0 ) { 
11919               mp->cur_t=mp->cur_t+n; mp->cur_tt=mp->cur_tt+nn; 
11920               return;
11921             }
11922           }
11923           nn=nn+unity; pp=link(pp);
11924         } while (pp!=hh);
11925       }
11926       n=n+unity; p=link(p);
11927     } while (p!=h);
11928     mp->tol_step=mp->tol_step+3;
11929   } while (mp->tol_step<=3);
11930   mp->cur_t=-unity; mp->cur_tt=-unity;
11931 }
11932
11933 @ @<Change one-point paths...@>=
11934 if ( right_type(h)==mp_endpoint ) {
11935   right_x(h)=x_coord(h); left_x(h)=x_coord(h);
11936   right_y(h)=y_coord(h); left_y(h)=y_coord(h); right_type(h)=mp_explicit;
11937 }
11938 if ( right_type(hh)==mp_endpoint ) {
11939   right_x(hh)=x_coord(hh); left_x(hh)=x_coord(hh);
11940   right_y(hh)=y_coord(hh); left_y(hh)=y_coord(hh); right_type(hh)=mp_explicit;
11941 }
11942
11943 @* \[24] Dynamic linear equations.
11944 \MP\ users define variables implicitly by stating equations that should be
11945 satisfied; the computer is supposed to be smart enough to solve those equations.
11946 And indeed, the computer tries valiantly to do so, by distinguishing five
11947 different types of numeric values:
11948
11949 \smallskip\hang
11950 |type(p)=mp_known| is the nice case, when |value(p)| is the |scaled| value
11951 of the variable whose address is~|p|.
11952
11953 \smallskip\hang
11954 |type(p)=mp_dependent| means that |value(p)| is not present, but |dep_list(p)|
11955 points to a {\sl dependency list\/} that expresses the value of variable~|p|
11956 as a |scaled| number plus a sum of independent variables with |fraction|
11957 coefficients.
11958
11959 \smallskip\hang
11960 |type(p)=mp_independent| means that |value(p)=64s+m|, where |s>0| is a ``serial
11961 number'' reflecting the time this variable was first used in an equation;
11962 also |0<=m<64|, and each dependent variable
11963 that refers to this one is actually referring to the future value of
11964 this variable times~$2^m$. (Usually |m=0|, but higher degrees of
11965 scaling are sometimes needed to keep the coefficients in dependency lists
11966 from getting too large. The value of~|m| will always be even.)
11967
11968 \smallskip\hang
11969 |type(p)=mp_numeric_type| means that variable |p| hasn't appeared in an
11970 equation before, but it has been explicitly declared to be numeric.
11971
11972 \smallskip\hang
11973 |type(p)=undefined| means that variable |p| hasn't appeared before.
11974
11975 \smallskip\noindent
11976 We have actually discussed these five types in the reverse order of their
11977 history during a computation: Once |known|, a variable never again
11978 becomes |dependent|; once |dependent|, it almost never again becomes
11979 |mp_independent|; once |mp_independent|, it never again becomes |mp_numeric_type|;
11980 and once |mp_numeric_type|, it never again becomes |undefined| (except
11981 of course when the user specifically decides to scrap the old value
11982 and start again). A backward step may, however, take place: Sometimes
11983 a |dependent| variable becomes |mp_independent| again, when one of the
11984 independent variables it depends on is reverting to |undefined|.
11985
11986
11987 The next patch detects overflow of independent-variable serial
11988 numbers. Diagnosed and patched by Thorsten Dahlheimer.
11989
11990 @d s_scale 64 /* the serial numbers are multiplied by this factor */
11991 @d max_indep_vars 0177777777 /* $2^{25}-1$ */
11992 @d max_serial_no 017777777700 /* |max_indep_vars*s_scale| */
11993 @d new_indep(A)  /* create a new independent variable */
11994   { if ( mp->serial_no==max_serial_no )
11995     mp_fatal_error(mp, "variable instance identifiers exhausted");
11996   type((A))=mp_independent; mp->serial_no=mp->serial_no+s_scale;
11997   value((A))=mp->serial_no;
11998   }
11999
12000 @<Glob...@>=
12001 integer serial_no; /* the most recent serial number, times |s_scale| */
12002
12003 @ @<Make variable |q+s| newly independent@>=new_indep(q+s)
12004
12005 @ But how are dependency lists represented? It's simple: The linear combination
12006 $\alpha_1v_1+\cdots+\alpha_kv_k+\beta$ appears in |k+1| value nodes. If
12007 |q=dep_list(p)| points to this list, and if |k>0|, then |value(q)=
12008 @t$\alpha_1$@>| (which is a |fraction|); |info(q)| points to the location
12009 of $\alpha_1$; and |link(p)| points to the dependency list
12010 $\alpha_2v_2+\cdots+\alpha_kv_k+\beta$. On the other hand if |k=0|,
12011 then |value(q)=@t$\beta$@>| (which is |scaled|) and |info(q)=null|.
12012 The independent variables $v_1$, \dots,~$v_k$ have been sorted so that
12013 they appear in decreasing order of their |value| fields (i.e., of
12014 their serial numbers). \ (It is convenient to use decreasing order,
12015 since |value(null)=0|. If the independent variables were not sorted by
12016 serial number but by some other criterion, such as their location in |mem|,
12017 the equation-solving mechanism would be too system-dependent, because
12018 the ordering can affect the computed results.)
12019
12020 The |link| field in the node that contains the constant term $\beta$ is
12021 called the {\sl final link\/} of the dependency list. \MP\ maintains
12022 a doubly-linked master list of all dependency lists, in terms of a permanently
12023 allocated node
12024 in |mem| called |dep_head|. If there are no dependencies, we have
12025 |link(dep_head)=dep_head| and |prev_dep(dep_head)=dep_head|;
12026 otherwise |link(dep_head)| points to the first dependent variable, say~|p|,
12027 and |prev_dep(p)=dep_head|. We have |type(p)=mp_dependent|, and |dep_list(p)|
12028 points to its dependency list. If the final link of that dependency list
12029 occurs in location~|q|, then |link(q)| points to the next dependent
12030 variable (say~|r|); and we have |prev_dep(r)=q|, etc.
12031
12032 @d dep_list(A) link(value_loc((A)))
12033   /* half of the |value| field in a |dependent| variable */
12034 @d prev_dep(A) info(value_loc((A)))
12035   /* the other half; makes a doubly linked list */
12036 @d dep_node_size 2 /* the number of words per dependency node */
12037
12038 @<Initialize table entries...@>= mp->serial_no=0;
12039 link(dep_head)=dep_head; prev_dep(dep_head)=dep_head;
12040 info(dep_head)=null; dep_list(dep_head)=null;
12041
12042 @ Actually the description above contains a little white lie. There's
12043 another kind of variable called |mp_proto_dependent|, which is
12044 just like a |dependent| one except that the $\alpha$ coefficients
12045 in its dependency list are |scaled| instead of being fractions.
12046 Proto-dependency lists are mixed with dependency lists in the
12047 nodes reachable from |dep_head|.
12048
12049 @ Here is a procedure that prints a dependency list in symbolic form.
12050 The second parameter should be either |dependent| or |mp_proto_dependent|,
12051 to indicate the scaling of the coefficients.
12052
12053 @<Declare subroutines for printing expressions@>=
12054 void mp_print_dependency (MP mp,pointer p, small_number t) {
12055   integer v; /* a coefficient */
12056   pointer pp,q; /* for list manipulation */
12057   pp=p;
12058   while (1) { 
12059     v=abs(value(p)); q=info(p);
12060     if ( q==null ) { /* the constant term */
12061       if ( (v!=0)||(p==pp) ) {
12062          if ( value(p)>0 ) if ( p!=pp ) mp_print_char(mp, '+');
12063          mp_print_scaled(mp, value(p));
12064       }
12065       return;
12066     }
12067     @<Print the coefficient, unless it's $\pm1.0$@>;
12068     if ( type(q)!=mp_independent ) mp_confusion(mp, "dep");
12069 @:this can't happen dep}{\quad dep@>
12070     mp_print_variable_name(mp, q); v=value(q) % s_scale;
12071     while ( v>0 ) { mp_print(mp, "*4"); v=v-2; }
12072     p=link(p);
12073   }
12074 }
12075
12076 @ @<Print the coefficient, unless it's $\pm1.0$@>=
12077 if ( value(p)<0 ) mp_print_char(mp, '-');
12078 else if ( p!=pp ) mp_print_char(mp, '+');
12079 if ( t==mp_dependent ) v=mp_round_fraction(mp, v);
12080 if ( v!=unity ) mp_print_scaled(mp, v)
12081
12082 @ The maximum absolute value of a coefficient in a given dependency list
12083 is returned by the following simple function.
12084
12085 @c fraction mp_max_coef (MP mp,pointer p) {
12086   fraction x; /* the maximum so far */
12087   x=0;
12088   while ( info(p)!=null ) {
12089     if ( abs(value(p))>x ) x=abs(value(p));
12090     p=link(p);
12091   }
12092   return x;
12093 }
12094
12095 @ One of the main operations needed on dependency lists is to add a multiple
12096 of one list to the other; we call this |p_plus_fq|, where |p| and~|q| point
12097 to dependency lists and |f| is a fraction.
12098
12099 If the coefficient of any independent variable becomes |coef_bound| or
12100 more, in absolute value, this procedure changes the type of that variable
12101 to `|independent_needing_fix|', and sets the global variable |fix_needed|
12102 to~|true|. The value of $|coef_bound|=\mu$ is chosen so that
12103 $\mu^2+\mu<8$; this means that the numbers we deal with won't
12104 get too large. (Instead of the ``optimum'' $\mu=(\sqrt{33}-1)/2\approx
12105 2.3723$, the safer value 7/3 is taken as the threshold.)
12106
12107 The changes mentioned in the preceding paragraph are actually done only if
12108 the global variable |watch_coefs| is |true|. But it usually is; in fact,
12109 it is |false| only when \MP\ is making a dependency list that will soon
12110 be equated to zero.
12111
12112 Several procedures that act on dependency lists, including |p_plus_fq|,
12113 set the global variable |dep_final| to the final (constant term) node of
12114 the dependency list that they produce.
12115
12116 @d coef_bound 04525252525 /* |fraction| approximation to 7/3 */
12117 @d independent_needing_fix 0
12118
12119 @<Glob...@>=
12120 boolean fix_needed; /* does at least one |independent| variable need scaling? */
12121 boolean watch_coefs; /* should we scale coefficients that exceed |coef_bound|? */
12122 pointer dep_final; /* location of the constant term and final link */
12123
12124 @ @<Set init...@>=
12125 mp->fix_needed=false; mp->watch_coefs=true;
12126
12127 @ The |p_plus_fq| procedure has a fourth parameter, |t|, that should be
12128 set to |mp_proto_dependent| if |p| is a proto-dependency list. In this
12129 case |f| will be |scaled|, not a |fraction|. Similarly, the fifth parameter~|tt|
12130 should be |mp_proto_dependent| if |q| is a proto-dependency list.
12131
12132 List |q| is unchanged by the operation; but list |p| is totally destroyed.
12133
12134 The final link of the dependency list or proto-dependency list returned
12135 by |p_plus_fq| is the same as the original final link of~|p|. Indeed, the
12136 constant term of the result will be located in the same |mem| location
12137 as the original constant term of~|p|.
12138
12139 Coefficients of the result are assumed to be zero if they are less than
12140 a certain threshold. This compensates for inevitable rounding errors,
12141 and tends to make more variables `|known|'. The threshold is approximately
12142 $10^{-5}$ in the case of normal dependency lists, $10^{-4}$ for
12143 proto-dependencies.
12144
12145 @d fraction_threshold 2685 /* a |fraction| coefficient less than this is zeroed */
12146 @d half_fraction_threshold 1342 /* half of |fraction_threshold| */
12147 @d scaled_threshold 8 /* a |scaled| coefficient less than this is zeroed */
12148 @d half_scaled_threshold 4 /* half of |scaled_threshold| */
12149
12150 @<Declare basic dependency-list subroutines@>=
12151 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
12152                       pointer q, small_number t, small_number tt) ;
12153
12154 @ @c
12155 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
12156                       pointer q, small_number t, small_number tt) {
12157   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
12158   pointer r,s; /* for list manipulation */
12159   integer mp_threshold; /* defines a neighborhood of zero */
12160   integer v; /* temporary register */
12161   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
12162   else mp_threshold=scaled_threshold;
12163   r=temp_head; pp=info(p); qq=info(q);
12164   while (1) {
12165     if ( pp==qq ) {
12166       if ( pp==null ) {
12167        break;
12168       } else {
12169         @<Contribute a term from |p|, plus |f| times the
12170           corresponding term from |q|@>
12171       }
12172     } else if ( value(pp)<value(qq) ) {
12173       @<Contribute a term from |q|, multiplied by~|f|@>
12174     } else { 
12175      link(r)=p; r=p; p=link(p); pp=info(p);
12176     }
12177   }
12178   if ( t==mp_dependent )
12179     value(p)=mp_slow_add(mp, value(p),mp_take_fraction(mp, value(q),f));
12180   else  
12181     value(p)=mp_slow_add(mp, value(p),mp_take_scaled(mp, value(q),f));
12182   link(r)=p; mp->dep_final=p; 
12183   return link(temp_head);
12184 }
12185
12186 @ @<Contribute a term from |p|, plus |f|...@>=
12187
12188   if ( tt==mp_dependent ) v=value(p)+mp_take_fraction(mp, f,value(q));
12189   else v=value(p)+mp_take_scaled(mp, f,value(q));
12190   value(p)=v; s=p; p=link(p);
12191   if ( abs(v)<mp_threshold ) {
12192     mp_free_node(mp, s,dep_node_size);
12193   } else {
12194     if ( (abs(v)>=coef_bound)  && mp->watch_coefs ) { 
12195       type(qq)=independent_needing_fix; mp->fix_needed=true;
12196     }
12197     link(r)=s; r=s;
12198   };
12199   pp=info(p); q=link(q); qq=info(q);
12200 }
12201
12202 @ @<Contribute a term from |q|, multiplied by~|f|@>=
12203
12204   if ( tt==mp_dependent ) v=mp_take_fraction(mp, f,value(q));
12205   else v=mp_take_scaled(mp, f,value(q));
12206   if ( abs(v)>halfp(mp_threshold) ) { 
12207     s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=v;
12208     if ( (abs(v)>=coef_bound) && mp->watch_coefs ) { 
12209       type(qq)=independent_needing_fix; mp->fix_needed=true;
12210     }
12211     link(r)=s; r=s;
12212   }
12213   q=link(q); qq=info(q);
12214 }
12215
12216 @ It is convenient to have another subroutine for the special case
12217 of |p_plus_fq| when |f=1.0|. In this routine lists |p| and |q| are
12218 both of the same type~|t| (either |dependent| or |mp_proto_dependent|).
12219
12220 @c pointer mp_p_plus_q (MP mp,pointer p, pointer q, small_number t) {
12221   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
12222   pointer r,s; /* for list manipulation */
12223   integer mp_threshold; /* defines a neighborhood of zero */
12224   integer v; /* temporary register */
12225   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
12226   else mp_threshold=scaled_threshold;
12227   r=temp_head; pp=info(p); qq=info(q);
12228   while (1) {
12229     if ( pp==qq ) {
12230       if ( pp==null ) {
12231         break;
12232       } else {
12233         @<Contribute a term from |p|, plus the
12234           corresponding term from |q|@>
12235       }
12236     } else if ( value(pp)<value(qq) ) {
12237       s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=value(q);
12238       q=link(q); qq=info(q); link(r)=s; r=s;
12239     } else { 
12240       link(r)=p; r=p; p=link(p); pp=info(p);
12241     }
12242   }
12243   value(p)=mp_slow_add(mp, value(p),value(q));
12244   link(r)=p; mp->dep_final=p; 
12245   return link(temp_head);
12246 }
12247
12248 @ @<Contribute a term from |p|, plus the...@>=
12249
12250   v=value(p)+value(q);
12251   value(p)=v; s=p; p=link(p); pp=info(p);
12252   if ( abs(v)<mp_threshold ) {
12253     mp_free_node(mp, s,dep_node_size);
12254   } else { 
12255     if ( (abs(v)>=coef_bound ) && mp->watch_coefs ) {
12256       type(qq)=independent_needing_fix; mp->fix_needed=true;
12257     }
12258     link(r)=s; r=s;
12259   }
12260   q=link(q); qq=info(q);
12261 }
12262
12263 @ A somewhat simpler routine will multiply a dependency list
12264 by a given constant~|v|. The constant is either a |fraction| less than
12265 |fraction_one|, or it is |scaled|. In the latter case we might be forced to
12266 convert a dependency list to a proto-dependency list.
12267 Parameters |t0| and |t1| are the list types before and after;
12268 they should agree unless |t0=mp_dependent| and |t1=mp_proto_dependent|
12269 and |v_is_scaled=true|.
12270
12271 @c pointer mp_p_times_v (MP mp,pointer p, integer v, small_number t0,
12272                          small_number t1, boolean v_is_scaled) {
12273   pointer r,s; /* for list manipulation */
12274   integer w; /* tentative coefficient */
12275   integer mp_threshold;
12276   boolean scaling_down;
12277   if ( t0!=t1 ) scaling_down=true; else scaling_down=! v_is_scaled;
12278   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12279   else mp_threshold=half_scaled_threshold;
12280   r=temp_head;
12281   while ( info(p)!=null ) {    
12282     if ( scaling_down ) w=mp_take_fraction(mp, v,value(p));
12283     else w=mp_take_scaled(mp, v,value(p));
12284     if ( abs(w)<=mp_threshold ) { 
12285       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12286     } else {
12287       if ( abs(w)>=coef_bound ) { 
12288         mp->fix_needed=true; type(info(p))=independent_needing_fix;
12289       }
12290       link(r)=p; r=p; value(p)=w; p=link(p);
12291     }
12292   }
12293   link(r)=p;
12294   if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
12295   else value(p)=mp_take_fraction(mp, value(p),v);
12296   return link(temp_head);
12297 };
12298
12299 @ Similarly, we sometimes need to divide a dependency list
12300 by a given |scaled| constant.
12301
12302 @<Declare basic dependency-list subroutines@>=
12303 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12304   t0, small_number t1) ;
12305
12306 @ @c
12307 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12308   t0, small_number t1) {
12309   pointer r,s; /* for list manipulation */
12310   integer w; /* tentative coefficient */
12311   integer mp_threshold;
12312   boolean scaling_down;
12313   if ( t0!=t1 ) scaling_down=true; else scaling_down=false;
12314   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12315   else mp_threshold=half_scaled_threshold;
12316   r=temp_head;
12317   while ( info( p)!=null ) {
12318     if ( scaling_down ) {
12319       if ( abs(v)<02000000 ) w=mp_make_scaled(mp, value(p),v*010000);
12320       else w=mp_make_scaled(mp, mp_round_fraction(mp, value(p)),v);
12321     } else {
12322       w=mp_make_scaled(mp, value(p),v);
12323     }
12324     if ( abs(w)<=mp_threshold ) {
12325       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12326     } else { 
12327       if ( abs(w)>=coef_bound ) {
12328          mp->fix_needed=true; type(info(p))=independent_needing_fix;
12329       }
12330       link(r)=p; r=p; value(p)=w; p=link(p);
12331     }
12332   }
12333   link(r)=p; value(p)=mp_make_scaled(mp, value(p),v);
12334   return link(temp_head);
12335 };
12336
12337 @ Here's another utility routine for dependency lists. When an independent
12338 variable becomes dependent, we want to remove it from all existing
12339 dependencies. The |p_with_x_becoming_q| function computes the
12340 dependency list of~|p| after variable~|x| has been replaced by~|q|.
12341
12342 This procedure has basically the same calling conventions as |p_plus_fq|:
12343 List~|q| is unchanged; list~|p| is destroyed; the constant node and the
12344 final link are inherited from~|p|; and the fourth parameter tells whether
12345 or not |p| is |mp_proto_dependent|. However, the global variable |dep_final|
12346 is not altered if |x| does not occur in list~|p|.
12347
12348 @c pointer mp_p_with_x_becoming_q (MP mp,pointer p,
12349            pointer x, pointer q, small_number t) {
12350   pointer r,s; /* for list manipulation */
12351   integer v; /* coefficient of |x| */
12352   integer sx; /* serial number of |x| */
12353   s=p; r=temp_head; sx=value(x);
12354   while ( value(info(s))>sx ) { r=s; s=link(s); };
12355   if ( info(s)!=x ) { 
12356     return p;
12357   } else { 
12358     link(temp_head)=p; link(r)=link(s); v=value(s);
12359     mp_free_node(mp, s,dep_node_size);
12360     return mp_p_plus_fq(mp, link(temp_head),v,q,t,mp_dependent);
12361   }
12362 }
12363
12364 @ Here's a simple procedure that reports an error when a variable
12365 has just received a known value that's out of the required range.
12366
12367 @<Declare basic dependency-list subroutines@>=
12368 void mp_val_too_big (MP mp,scaled x) ;
12369
12370 @ @c void mp_val_too_big (MP mp,scaled x) { 
12371   if ( mp->internal[mp_warning_check]>0 ) { 
12372     print_err("Value is too large ("); mp_print_scaled(mp, x); mp_print_char(mp, ')');
12373 @.Value is too large@>
12374     help4("The equation I just processed has given some variable")
12375       ("a value of 4096 or more. Continue and I'll try to cope")
12376       ("with that big value; but it might be dangerous.")
12377       ("(Set warningcheck:=0 to suppress this message.)");
12378     mp_error(mp);
12379   }
12380 }
12381
12382 @ When a dependent variable becomes known, the following routine
12383 removes its dependency list. Here |p| points to the variable, and
12384 |q| points to the dependency list (which is one node long).
12385
12386 @<Declare basic dependency-list subroutines@>=
12387 void mp_make_known (MP mp,pointer p, pointer q) ;
12388
12389 @ @c void mp_make_known (MP mp,pointer p, pointer q) {
12390   int t; /* the previous type */
12391   prev_dep(link(q))=prev_dep(p);
12392   link(prev_dep(p))=link(q); t=type(p);
12393   type(p)=mp_known; value(p)=value(q); mp_free_node(mp, q,dep_node_size);
12394   if ( abs(value(p))>=fraction_one ) mp_val_too_big(mp, value(p));
12395   if (( mp->internal[mp_tracing_equations]>0) && mp_interesting(mp, p) ) {
12396     mp_begin_diagnostic(mp); mp_print_nl(mp, "#### ");
12397 @:]]]\#\#\#\#_}{\.{\#\#\#\#}@>
12398     mp_print_variable_name(mp, p); 
12399     mp_print_char(mp, '='); mp_print_scaled(mp, value(p));
12400     mp_end_diagnostic(mp, false);
12401   }
12402   if (( mp->cur_exp==p ) && mp->cur_type==t ) {
12403     mp->cur_type=mp_known; mp->cur_exp=value(p);
12404     mp_free_node(mp, p,value_node_size);
12405   }
12406 }
12407
12408 @ The |fix_dependencies| routine is called into action when |fix_needed|
12409 has been triggered. The program keeps a list~|s| of independent variables
12410 whose coefficients must be divided by~4.
12411
12412 In unusual cases, this fixup process might reduce one or more coefficients
12413 to zero, so that a variable will become known more or less by default.
12414
12415 @<Declare basic dependency-list subroutines@>=
12416 void mp_fix_dependencies (MP mp);
12417
12418 @ @c void mp_fix_dependencies (MP mp) {
12419   pointer p,q,r,s,t; /* list manipulation registers */
12420   pointer x; /* an independent variable */
12421   r=link(dep_head); s=null;
12422   while ( r!=dep_head ){ 
12423     t=r;
12424     @<Run through the dependency list for variable |t|, fixing
12425       all nodes, and ending with final link~|q|@>;
12426     r=link(q);
12427     if ( q==dep_list(t) ) mp_make_known(mp, t,q);
12428   }
12429   while ( s!=null ) { 
12430     p=link(s); x=info(s); free_avail(s); s=p;
12431     type(x)=mp_independent; value(x)=value(x)+2;
12432   }
12433   mp->fix_needed=false;
12434 }
12435
12436 @ @d independent_being_fixed 1 /* this variable already appears in |s| */
12437
12438 @<Run through the dependency list for variable |t|...@>=
12439 r=value_loc(t); /* |link(r)=dep_list(t)| */
12440 while (1) { 
12441   q=link(r); x=info(q);
12442   if ( x==null ) break;
12443   if ( type(x)<=independent_being_fixed ) {
12444     if ( type(x)<independent_being_fixed ) {
12445       p=mp_get_avail(mp); link(p)=s; s=p;
12446       info(s)=x; type(x)=independent_being_fixed;
12447     }
12448     value(q)=value(q) / 4;
12449     if ( value(q)==0 ) {
12450       link(r)=link(q); mp_free_node(mp, q,dep_node_size); q=r;
12451     }
12452   }
12453   r=q;
12454 }
12455
12456
12457 @ The |new_dep| routine installs a dependency list~|p| into the value node~|q|,
12458 linking it into the list of all known dependencies. We assume that
12459 |dep_final| points to the final node of list~|p|.
12460
12461 @c void mp_new_dep (MP mp,pointer q, pointer p) {
12462   pointer r; /* what used to be the first dependency */
12463   dep_list(q)=p; prev_dep(q)=dep_head;
12464   r=link(dep_head); link(mp->dep_final)=r; prev_dep(r)=mp->dep_final;
12465   link(dep_head)=q;
12466 }
12467
12468 @ Here is one of the ways a dependency list gets started.
12469 The |const_dependency| routine produces a list that has nothing but
12470 a constant term.
12471
12472 @c pointer mp_const_dependency (MP mp, scaled v) {
12473   mp->dep_final=mp_get_node(mp, dep_node_size);
12474   value(mp->dep_final)=v; info(mp->dep_final)=null;
12475   return mp->dep_final;
12476 }
12477
12478 @ And here's a more interesting way to start a dependency list from scratch:
12479 The parameter to |single_dependency| is the location of an
12480 independent variable~|x|, and the result is the simple dependency list
12481 `|x+0|'.
12482
12483 In the unlikely event that the given independent variable has been doubled so
12484 often that we can't refer to it with a nonzero coefficient,
12485 |single_dependency| returns the simple list `0'.  This case can be
12486 recognized by testing that the returned list pointer is equal to
12487 |dep_final|.
12488
12489 @c pointer mp_single_dependency (MP mp,pointer p) {
12490   pointer q; /* the new dependency list */
12491   integer m; /* the number of doublings */
12492   m=value(p) % s_scale;
12493   if ( m>28 ) {
12494     return mp_const_dependency(mp, 0);
12495   } else { 
12496     q=mp_get_node(mp, dep_node_size);
12497     value(q)=two_to_the(28-m); info(q)=p;
12498     link(q)=mp_const_dependency(mp, 0);
12499     return q;
12500   }
12501 }
12502
12503 @ We sometimes need to make an exact copy of a dependency list.
12504
12505 @c pointer mp_copy_dep_list (MP mp,pointer p) {
12506   pointer q; /* the new dependency list */
12507   q=mp_get_node(mp, dep_node_size); mp->dep_final=q;
12508   while (1) { 
12509     info(mp->dep_final)=info(p); value(mp->dep_final)=value(p);
12510     if ( info(mp->dep_final)==null ) break;
12511     link(mp->dep_final)=mp_get_node(mp, dep_node_size);
12512     mp->dep_final=link(mp->dep_final); p=link(p);
12513   }
12514   return q;
12515 }
12516
12517 @ But how do variables normally become known? Ah, now we get to the heart of the
12518 equation-solving mechanism. The |linear_eq| procedure is given a |dependent|
12519 or |mp_proto_dependent| list,~|p|, in which at least one independent variable
12520 appears. It equates this list to zero, by choosing an independent variable
12521 with the largest coefficient and making it dependent on the others. The
12522 newly dependent variable is eliminated from all current dependencies,
12523 thereby possibly making other dependent variables known.
12524
12525 The given list |p| is, of course, totally destroyed by all this processing.
12526
12527 @c void mp_linear_eq (MP mp, pointer p, small_number t) {
12528   pointer q,r,s; /* for link manipulation */
12529   pointer x; /* the variable that loses its independence */
12530   integer n; /* the number of times |x| had been halved */
12531   integer v; /* the coefficient of |x| in list |p| */
12532   pointer prev_r; /* lags one step behind |r| */
12533   pointer final_node; /* the constant term of the new dependency list */
12534   integer w; /* a tentative coefficient */
12535    @<Find a node |q| in list |p| whose coefficient |v| is largest@>;
12536   x=info(q); n=value(x) % s_scale;
12537   @<Divide list |p| by |-v|, removing node |q|@>;
12538   if ( mp->internal[mp_tracing_equations]>0 ) {
12539     @<Display the new dependency@>;
12540   }
12541   @<Simplify all existing dependencies by substituting for |x|@>;
12542   @<Change variable |x| from |independent| to |dependent| or |known|@>;
12543   if ( mp->fix_needed ) mp_fix_dependencies(mp);
12544 }
12545
12546 @ @<Find a node |q| in list |p| whose coefficient |v| is largest@>=
12547 q=p; r=link(p); v=value(q);
12548 while ( info(r)!=null ) { 
12549   if ( abs(value(r))>abs(v) ) { q=r; v=value(r); };
12550   r=link(r);
12551 }
12552
12553 @ Here we want to change the coefficients from |scaled| to |fraction|,
12554 except in the constant term. In the common case of a trivial equation
12555 like `\.{x=3.14}', we will have |v=-fraction_one|, |q=p|, and |t=mp_dependent|.
12556
12557 @<Divide list |p| by |-v|, removing node |q|@>=
12558 s=temp_head; link(s)=p; r=p;
12559 do { 
12560   if ( r==q ) {
12561     link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12562   } else  { 
12563     w=mp_make_fraction(mp, value(r),v);
12564     if ( abs(w)<=half_fraction_threshold ) {
12565       link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12566     } else { 
12567       value(r)=-w; s=r;
12568     }
12569   }
12570   r=link(s);
12571 } while (info(r)!=null);
12572 if ( t==mp_proto_dependent ) {
12573   value(r)=-mp_make_scaled(mp, value(r),v);
12574 } else if ( v!=-fraction_one ) {
12575   value(r)=-mp_make_fraction(mp, value(r),v);
12576 }
12577 final_node=r; p=link(temp_head)
12578
12579 @ @<Display the new dependency@>=
12580 if ( mp_interesting(mp, x) ) {
12581   mp_begin_diagnostic(mp); mp_print_nl(mp, "## "); 
12582   mp_print_variable_name(mp, x);
12583 @:]]]\#\#_}{\.{\#\#}@>
12584   w=n;
12585   while ( w>0 ) { mp_print(mp, "*4"); w=w-2;  };
12586   mp_print_char(mp, '='); mp_print_dependency(mp, p,mp_dependent); 
12587   mp_end_diagnostic(mp, false);
12588 }
12589
12590 @ @<Simplify all existing dependencies by substituting for |x|@>=
12591 prev_r=dep_head; r=link(dep_head);
12592 while ( r!=dep_head ) {
12593   s=dep_list(r); q=mp_p_with_x_becoming_q(mp, s,x,p,type(r));
12594   if ( info(q)==null ) {
12595     mp_make_known(mp, r,q);
12596   } else { 
12597     dep_list(r)=q;
12598     do {  q=link(q); } while (info(q)!=null);
12599     prev_r=q;
12600   }
12601   r=link(prev_r);
12602 }
12603
12604 @ @<Change variable |x| from |independent| to |dependent| or |known|@>=
12605 if ( n>0 ) @<Divide list |p| by $2^n$@>;
12606 if ( info(p)==null ) {
12607   type(x)=mp_known;
12608   value(x)=value(p);
12609   if ( abs(value(x))>=fraction_one ) mp_val_too_big(mp, value(x));
12610   mp_free_node(mp, p,dep_node_size);
12611   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) {
12612     mp->cur_exp=value(x); mp->cur_type=mp_known;
12613     mp_free_node(mp, x,value_node_size);
12614   }
12615 } else { 
12616   type(x)=mp_dependent; mp->dep_final=final_node; mp_new_dep(mp, x,p);
12617   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) mp->cur_type=mp_dependent;
12618 }
12619
12620 @ @<Divide list |p| by $2^n$@>=
12621
12622   s=temp_head; link(temp_head)=p; r=p;
12623   do {  
12624     if ( n>30 ) w=0;
12625     else w=value(r) / two_to_the(n);
12626     if ( (abs(w)<=half_fraction_threshold)&&(info(r)!=null) ) {
12627       link(s)=link(r);
12628       mp_free_node(mp, r,dep_node_size);
12629     } else { 
12630       value(r)=w; s=r;
12631     }
12632     r=link(s);
12633   } while (info(s)!=null);
12634   p=link(temp_head);
12635 }
12636
12637 @ The |check_mem| procedure, which is used only when \MP\ is being
12638 debugged, makes sure that the current dependency lists are well formed.
12639
12640 @<Check the list of linear dependencies@>=
12641 q=dep_head; p=link(q);
12642 while ( p!=dep_head ) {
12643   if ( prev_dep(p)!=q ) {
12644     mp_print_nl(mp, "Bad PREVDEP at "); mp_print_int(mp, p);
12645 @.Bad PREVDEP...@>
12646   }
12647   p=dep_list(p);
12648   while (1) {
12649     r=info(p); q=p; p=link(q);
12650     if ( r==null ) break;
12651     if ( value(info(p))>=value(r) ) {
12652       mp_print_nl(mp, "Out of order at "); mp_print_int(mp, p);
12653 @.Out of order...@>
12654     }
12655   }
12656 }
12657
12658 @* \[25] Dynamic nonlinear equations.
12659 Variables of numeric type are maintained by the general scheme of
12660 independent, dependent, and known values that we have just studied;
12661 and the components of pair and transform variables are handled in the
12662 same way. But \MP\ also has five other types of values: \&{boolean},
12663 \&{string}, \&{pen}, \&{path}, and \&{picture}; what about them?
12664
12665 Equations are allowed between nonlinear quantities, but only in a
12666 simple form. Two variables that haven't yet been assigned values are
12667 either equal to each other, or they're not.
12668
12669 Before a boolean variable has received a value, its type is |mp_unknown_boolean|;
12670 similarly, there are variables whose type is |mp_unknown_string|, |mp_unknown_pen|,
12671 |mp_unknown_path|, and |mp_unknown_picture|. In such cases the value is either
12672 |null| (which means that no other variables are equivalent to this one), or
12673 it points to another variable of the same undefined type. The pointers in the
12674 latter case form a cycle of nodes, which we shall call a ``ring.''
12675 Rings of undefined variables may include capsules, which arise as
12676 intermediate results within expressions or as \&{expr} parameters to macros.
12677
12678 When one member of a ring receives a value, the same value is given to
12679 all the other members. In the case of paths and pictures, this implies
12680 making separate copies of a potentially large data structure; users should
12681 restrain their enthusiasm for such generality, unless they have lots and
12682 lots of memory space.
12683
12684 @ The following procedure is called when a capsule node is being
12685 added to a ring (e.g., when an unknown variable is mentioned in an expression).
12686
12687 @c pointer mp_new_ring_entry (MP mp,pointer p) {
12688   pointer q; /* the new capsule node */
12689   q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
12690   type(q)=type(p);
12691   if ( value(p)==null ) value(q)=p; else value(q)=value(p);
12692   value(p)=q;
12693   return q;
12694 }
12695
12696 @ Conversely, we might delete a capsule or a variable before it becomes known.
12697 The following procedure simply detaches a quantity from its ring,
12698 without recycling the storage.
12699
12700 @<Declare the recycling subroutines@>=
12701 void mp_ring_delete (MP mp,pointer p) {
12702   pointer q; 
12703   q=value(p);
12704   if ( q!=null ) if ( q!=p ){ 
12705     while ( value(q)!=p ) q=value(q);
12706     value(q)=value(p);
12707   }
12708 }
12709
12710 @ Eventually there might be an equation that assigns values to all of the
12711 variables in a ring. The |nonlinear_eq| subroutine does the necessary
12712 propagation of values.
12713
12714 If the parameter |flush_p| is |true|, node |p| itself needn't receive a
12715 value, it will soon be recycled.
12716
12717 @c void mp_nonlinear_eq (MP mp,integer v, pointer p, boolean flush_p) {
12718   small_number t; /* the type of ring |p| */
12719   pointer q,r; /* link manipulation registers */
12720   t=type(p)-unknown_tag; q=value(p);
12721   if ( flush_p ) type(p)=mp_vacuous; else p=q;
12722   do {  
12723     r=value(q); type(q)=t;
12724     switch (t) {
12725     case mp_boolean_type: value(q)=v; break;
12726     case mp_string_type: value(q)=v; add_str_ref(v); break;
12727     case mp_pen_type: value(q)=copy_pen(v); break;
12728     case mp_path_type: value(q)=mp_copy_path(mp, v); break;
12729     case mp_picture_type: value(q)=v; add_edge_ref(v); break;
12730     } /* there ain't no more cases */
12731     q=r;
12732   } while (q!=p);
12733 }
12734
12735 @ If two members of rings are equated, and if they have the same type,
12736 the |ring_merge| procedure is called on to make them equivalent.
12737
12738 @c void mp_ring_merge (MP mp,pointer p, pointer q) {
12739   pointer r; /* traverses one list */
12740   r=value(p);
12741   while ( r!=p ) {
12742     if ( r==q ) {
12743       @<Exclaim about a redundant equation@>;
12744       return;
12745     };
12746     r=value(r);
12747   }
12748   r=value(p); value(p)=value(q); value(q)=r;
12749 }
12750
12751 @ @<Exclaim about a redundant equation@>=
12752
12753   print_err("Redundant equation");
12754 @.Redundant equation@>
12755   help2("I already knew that this equation was true.")
12756    ("But perhaps no harm has been done; let's continue.");
12757   mp_put_get_error(mp);
12758 }
12759
12760 @* \[26] Introduction to the syntactic routines.
12761 Let's pause a moment now and try to look at the Big Picture.
12762 The \MP\ program consists of three main parts: syntactic routines,
12763 semantic routines, and output routines. The chief purpose of the
12764 syntactic routines is to deliver the user's input to the semantic routines,
12765 while parsing expressions and locating operators and operands. The
12766 semantic routines act as an interpreter responding to these operators,
12767 which may be regarded as commands. And the output routines are
12768 periodically called on to produce compact font descriptions that can be
12769 used for typesetting or for making interim proof drawings. We have
12770 discussed the basic data structures and many of the details of semantic
12771 operations, so we are good and ready to plunge into the part of \MP\ that
12772 actually controls the activities.
12773
12774 Our current goal is to come to grips with the |get_next| procedure,
12775 which is the keystone of \MP's input mechanism. Each call of |get_next|
12776 sets the value of three variables |cur_cmd|, |cur_mod|, and |cur_sym|,
12777 representing the next input token.
12778 $$\vbox{\halign{#\hfil\cr
12779   \hbox{|cur_cmd| denotes a command code from the long list of codes
12780    given earlier;}\cr
12781   \hbox{|cur_mod| denotes a modifier of the command code;}\cr
12782   \hbox{|cur_sym| is the hash address of the symbolic token that was
12783    just scanned,}\cr
12784   \hbox{\qquad or zero in the case of a numeric or string
12785    or capsule token.}\cr}}$$
12786 Underlying this external behavior of |get_next| is all the machinery
12787 necessary to convert from character files to tokens. At a given time we
12788 may be only partially finished with the reading of several files (for
12789 which \&{input} was specified), and partially finished with the expansion
12790 of some user-defined macros and/or some macro parameters, and partially
12791 finished reading some text that the user has inserted online,
12792 and so on. When reading a character file, the characters must be
12793 converted to tokens; comments and blank spaces must
12794 be removed, numeric and string tokens must be evaluated.
12795
12796 To handle these situations, which might all be present simultaneously,
12797 \MP\ uses various stacks that hold information about the incomplete
12798 activities, and there is a finite state control for each level of the
12799 input mechanism. These stacks record the current state of an implicitly
12800 recursive process, but the |get_next| procedure is not recursive.
12801
12802 @<Glob...@>=
12803 eight_bits cur_cmd; /* current command set by |get_next| */
12804 integer cur_mod; /* operand of current command */
12805 halfword cur_sym; /* hash address of current symbol */
12806
12807 @ The |print_cmd_mod| routine prints a symbolic interpretation of a
12808 command code and its modifier.
12809 It consists of a rather tedious sequence of print
12810 commands, and most of it is essentially an inverse to the |primitive|
12811 routine that enters a \MP\ primitive into |hash| and |eqtb|. Therefore almost
12812 all of this procedure appears elsewhere in the program, together with the
12813 corresponding |primitive| calls.
12814
12815 @<Declare the procedure called |print_cmd_mod|@>=
12816 void mp_print_cmd_mod (MP mp,integer c, integer m) { 
12817  switch (c) {
12818   @<Cases of |print_cmd_mod| for symbolic printing of primitives@>
12819   default: mp_print(mp, "[unknown command code!]"); break;
12820   }
12821 }
12822
12823 @ Here is a procedure that displays a given command in braces, in the
12824 user's transcript file.
12825
12826 @d show_cur_cmd_mod mp_show_cmd_mod(mp, mp->cur_cmd,mp->cur_mod)
12827
12828 @c 
12829 void mp_show_cmd_mod (MP mp,integer c, integer m) { 
12830   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
12831   mp_print_cmd_mod(mp, c,m); mp_print_char(mp, '}');
12832   mp_end_diagnostic(mp, false);
12833 }
12834
12835 @* \[27] Input stacks and states.
12836 The state of \MP's input mechanism appears in the input stack, whose
12837 entries are records with five fields, called |index|, |start|, |loc|,
12838 |limit|, and |name|. The top element of this stack is maintained in a
12839 global variable for which no subscripting needs to be done; the other
12840 elements of the stack appear in an array. Hence the stack is declared thus:
12841
12842 @<Types...@>=
12843 typedef struct {
12844   quarterword index_field;
12845   halfword start_field, loc_field, limit_field, name_field;
12846 } in_state_record;
12847
12848 @ @<Glob...@>=
12849 in_state_record *input_stack;
12850 integer input_ptr; /* first unused location of |input_stack| */
12851 integer max_in_stack; /* largest value of |input_ptr| when pushing */
12852 in_state_record cur_input; /* the ``top'' input state */
12853 int stack_size; /* maximum number of simultaneous input sources */
12854
12855 @ @<Allocate or initialize ...@>=
12856 mp->stack_size = 300;
12857 mp->input_stack = xmalloc((mp->stack_size+1),sizeof(in_state_record));
12858
12859 @ @<Dealloc variables@>=
12860 xfree(mp->input_stack);
12861
12862 @ We've already defined the special variable |loc==cur_input.loc_field|
12863 in our discussion of basic input-output routines. The other components of
12864 |cur_input| are defined in the same way:
12865
12866 @d index mp->cur_input.index_field /* reference for buffer information */
12867 @d start mp->cur_input.start_field /* starting position in |buffer| */
12868 @d limit mp->cur_input.limit_field /* end of current line in |buffer| */
12869 @d name mp->cur_input.name_field /* name of the current file */
12870
12871 @ Let's look more closely now at the five control variables
12872 (|index|,~|start|,~|loc|,~|limit|,~|name|),
12873 assuming that \MP\ is reading a line of characters that have been input
12874 from some file or from the user's terminal. There is an array called
12875 |buffer| that acts as a stack of all lines of characters that are
12876 currently being read from files, including all lines on subsidiary
12877 levels of the input stack that are not yet completed. \MP\ will return to
12878 the other lines when it is finished with the present input file.
12879
12880 (Incidentally, on a machine with byte-oriented addressing, it would be
12881 appropriate to combine |buffer| with the |str_pool| array,
12882 letting the buffer entries grow downward from the top of the string pool
12883 and checking that these two tables don't bump into each other.)
12884
12885 The line we are currently working on begins in position |start| of the
12886 buffer; the next character we are about to read is |buffer[loc]|; and
12887 |limit| is the location of the last character present. We always have
12888 |loc<=limit|. For convenience, |buffer[limit]| has been set to |"%"|, so
12889 that the end of a line is easily sensed.
12890
12891 The |name| variable is a string number that designates the name of
12892 the current file, if we are reading an ordinary text file.  Special codes
12893 |is_term..max_spec_src| indicate other sources of input text.
12894
12895 @d is_term 0 /* |name| value when reading from the terminal for normal input */
12896 @d is_read 1 /* |name| value when executing a \&{readstring} or \&{readfrom} */
12897 @d is_scantok 2 /* |name| value when reading text generated by \&{scantokens} */
12898 @d max_spec_src is_scantok
12899
12900 @ Additional information about the current line is available via the
12901 |index| variable, which counts how many lines of characters are present
12902 in the buffer below the current level. We have |index=0| when reading
12903 from the terminal and prompting the user for each line; then if the user types,
12904 e.g., `\.{input figs}', we will have |index=1| while reading
12905 the file \.{figs.mp}. However, it does not follow that |index| is the
12906 same as the input stack pointer, since many of the levels on the input
12907 stack may come from token lists and some |index| values may correspond
12908 to \.{MPX} files that are not currently on the stack.
12909
12910 The global variable |in_open| is equal to the highest |index| value counting
12911 \.{MPX} files but excluding token-list input levels.  Thus, the number of
12912 partially read lines in the buffer is |in_open+1| and we have |in_open>=index|
12913 when we are not reading a token list.
12914
12915 If we are not currently reading from the terminal,
12916 we are reading from the file variable |input_file[index]|. We use
12917 the notation |terminal_input| as a convenient abbreviation for |name=is_term|,
12918 and |cur_file| as an abbreviation for |input_file[index]|.
12919
12920 When \MP\ is not reading from the terminal, the global variable |line| contains
12921 the line number in the current file, for use in error messages. More precisely,
12922 |line| is a macro for |line_stack[index]| and the |line_stack| array gives
12923 the line number for each file in the |input_file| array.
12924
12925 When an \.{MPX} file is opened the file name is stored in the |mpx_name|
12926 array so that the name doesn't get lost when the file is temporarily removed
12927 from the input stack.
12928 Thus when |input_file[k]| is an \.{MPX} file, its name is |mpx_name[k]|
12929 and it contains translated \TeX\ pictures for |input_file[k-1]|.
12930 Since this is not an \.{MPX} file, we have
12931 $$ \hbox{|mpx_name[k-1]<=absent|}. $$
12932 This |name| field is set to |finished| when |input_file[k]| is completely
12933 read.
12934
12935 If more information about the input state is needed, it can be
12936 included in small arrays like those shown here. For example,
12937 the current page or segment number in the input file might be put
12938 into a variable |page|, that is really a macro for the current entry
12939 in `\ignorespaces|page_stack:array[0..max_in_open] of integer|\unskip'
12940 by analogy with |line_stack|.
12941 @^system dependencies@>
12942
12943 @d terminal_input (name==is_term) /* are we reading from the terminal? */
12944 @d cur_file mp->input_file[index] /* the current |void *| variable */
12945 @d line mp->line_stack[index] /* current line number in the current source file */
12946 @d in_name mp->iname_stack[index] /* a string used to construct \.{MPX} file names */
12947 @d in_area mp->iarea_stack[index] /* another string for naming \.{MPX} files */
12948 @d absent 1 /* |name_field| value for unused |mpx_in_stack| entries */
12949 @d mpx_reading (mp->mpx_name[index]>absent)
12950   /* when reading a file, is it an \.{MPX} file? */
12951 @d finished 0
12952   /* |name_field| value when the corresponding \.{MPX} file is finished */
12953
12954 @<Glob...@>=
12955 integer in_open; /* the number of lines in the buffer, less one */
12956 unsigned int open_parens; /* the number of open text files */
12957 void  * *input_file ;
12958 integer *line_stack ; /* the line number for each file */
12959 char *  *iname_stack; /* used for naming \.{MPX} files */
12960 char *  *iarea_stack; /* used for naming \.{MPX} files */
12961 halfword*mpx_name  ;
12962
12963 @ @<Allocate or ...@>=
12964 mp->input_file  = xmalloc((mp->max_in_open+1),sizeof(void *));
12965 mp->line_stack  = xmalloc((mp->max_in_open+1),sizeof(integer));
12966 mp->iname_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12967 mp->iarea_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12968 mp->mpx_name    = xmalloc((mp->max_in_open+1),sizeof(halfword));
12969 {
12970   int k;
12971   for (k=0;k<=mp->max_in_open;k++) {
12972     mp->iname_stack[k] =NULL;
12973     mp->iarea_stack[k] =NULL;
12974   }
12975 }
12976
12977 @ @<Dealloc variables@>=
12978 {
12979   int l;
12980   for (l=0;l<=mp->max_in_open;l++) {
12981     xfree(mp->iname_stack[l]);
12982     xfree(mp->iarea_stack[l]);
12983   }
12984 }
12985 xfree(mp->input_file);
12986 xfree(mp->line_stack);
12987 xfree(mp->iname_stack);
12988 xfree(mp->iarea_stack);
12989 xfree(mp->mpx_name);
12990
12991
12992 @ However, all this discussion about input state really applies only to the
12993 case that we are inputting from a file. There is another important case,
12994 namely when we are currently getting input from a token list. In this case
12995 |index>max_in_open|, and the conventions about the other state variables
12996 are different:
12997
12998 \yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
12999 the node that will be read next. If |loc=null|, the token list has been
13000 fully read.
13001
13002 \yskip\hang|start| points to the first node of the token list; this node
13003 may or may not contain a reference count, depending on the type of token
13004 list involved.
13005
13006 \yskip\hang|token_type|, which takes the place of |index| in the
13007 discussion above, is a code number that explains what kind of token list
13008 is being scanned.
13009
13010 \yskip\hang|name| points to the |eqtb| address of the control sequence
13011 being expanded, if the current token list is a macro not defined by
13012 \&{vardef}. Macros defined by \&{vardef} have |name=null|; their name
13013 can be deduced by looking at their first two parameters.
13014
13015 \yskip\hang|param_start|, which takes the place of |limit|, tells where
13016 the parameters of the current macro or loop text begin in the |param_stack|.
13017
13018 \yskip\noindent The |token_type| can take several values, depending on
13019 where the current token list came from:
13020
13021 \yskip
13022 \indent|forever_text|, if the token list being scanned is the body of
13023 a \&{forever} loop;
13024
13025 \indent|loop_text|, if the token list being scanned is the body of
13026 a \&{for} or \&{forsuffixes} loop;
13027
13028 \indent|parameter|, if a \&{text} or \&{suffix} parameter is being scanned;
13029
13030 \indent|backed_up|, if the token list being scanned has been inserted as
13031 `to be read again'.
13032
13033 \indent|inserted|, if the token list being scanned has been inserted as
13034 part of error recovery;
13035
13036 \indent|macro|, if the expansion of a user-defined symbolic token is being
13037 scanned.
13038
13039 \yskip\noindent
13040 The token list begins with a reference count if and only if |token_type=
13041 macro|.
13042 @^reference counts@>
13043
13044 @d token_type index /* type of current token list */
13045 @d token_state (index>(int)mp->max_in_open) /* are we scanning a token list? */
13046 @d file_state (index<=(int)mp->max_in_open) /* are we scanning a file line? */
13047 @d param_start limit /* base of macro parameters in |param_stack| */
13048 @d forever_text (mp->max_in_open+1) /* |token_type| code for loop texts */
13049 @d loop_text (mp->max_in_open+2) /* |token_type| code for loop texts */
13050 @d parameter (mp->max_in_open+3) /* |token_type| code for parameter texts */
13051 @d backed_up (mp->max_in_open+4) /* |token_type| code for texts to be reread */
13052 @d inserted (mp->max_in_open+5) /* |token_type| code for inserted texts */
13053 @d macro (mp->max_in_open+6) /* |token_type| code for macro replacement texts */
13054
13055 @ The |param_stack| is an auxiliary array used to hold pointers to the token
13056 lists for parameters at the current level and subsidiary levels of input.
13057 This stack grows at a different rate from the others.
13058
13059 @<Glob...@>=
13060 pointer *param_stack;  /* token list pointers for parameters */
13061 integer param_ptr; /* first unused entry in |param_stack| */
13062 integer max_param_stack;  /* largest value of |param_ptr| */
13063
13064 @ @<Allocate or initialize ...@>=
13065 mp->param_stack = xmalloc((mp->param_size+1),sizeof(pointer));
13066
13067 @ @<Dealloc variables@>=
13068 xfree(mp->param_stack);
13069
13070 @ Notice that the |line| isn't valid when |token_state| is true because it
13071 depends on |index|.  If we really need to know the line number for the
13072 topmost file in the index stack we use the following function.  If a page
13073 number or other information is needed, this routine should be modified to
13074 compute it as well.
13075 @^system dependencies@>
13076
13077 @<Declare a function called |true_line|@>=
13078 integer mp_true_line (MP mp) {
13079   int k; /* an index into the input stack */
13080   if ( file_state && (name>max_spec_src) ) {
13081      return line;
13082   } else { 
13083     k=mp->input_ptr;
13084     while ((k>0) &&
13085            ((mp->input_stack[(k-1)].index_field>mp->max_in_open)||
13086             (mp->input_stack[(k-1)].name_field<=max_spec_src))) {
13087       decr(k);
13088     }
13089     return mp->line_stack[(k-1)];
13090   }
13091   return 0; 
13092 }
13093
13094 @ Thus, the ``current input state'' can be very complicated indeed; there
13095 can be many levels and each level can arise in a variety of ways. The
13096 |show_context| procedure, which is used by \MP's error-reporting routine to
13097 print out the current input state on all levels down to the most recent
13098 line of characters from an input file, illustrates most of these conventions.
13099 The global variable |file_ptr| contains the lowest level that was
13100 displayed by this procedure.
13101
13102 @<Glob...@>=
13103 integer file_ptr; /* shallowest level shown by |show_context| */
13104
13105 @ The status at each level is indicated by printing two lines, where the first
13106 line indicates what was read so far and the second line shows what remains
13107 to be read. The context is cropped, if necessary, so that the first line
13108 contains at most |half_error_line| characters, and the second contains
13109 at most |error_line|. Non-current input levels whose |token_type| is
13110 `|backed_up|' are shown only if they have not been fully read.
13111
13112 @c void mp_show_context (MP mp) { /* prints where the scanner is */
13113   int old_setting; /* saved |selector| setting */
13114   @<Local variables for formatting calculations@>
13115   mp->file_ptr=mp->input_ptr; mp->input_stack[mp->file_ptr]=mp->cur_input;
13116   /* store current state */
13117   while (1) { 
13118     mp->cur_input=mp->input_stack[mp->file_ptr]; /* enter into the context */
13119     @<Display the current context@>;
13120     if ( file_state )
13121       if ( (name>max_spec_src) || (mp->file_ptr==0) ) break;
13122     decr(mp->file_ptr);
13123   }
13124   mp->cur_input=mp->input_stack[mp->input_ptr]; /* restore original state */
13125 }
13126
13127 @ @<Display the current context@>=
13128 if ( (mp->file_ptr==mp->input_ptr) || file_state ||
13129    (token_type!=backed_up) || (loc!=null) ) {
13130     /* we omit backed-up token lists that have already been read */
13131   mp->tally=0; /* get ready to count characters */
13132   old_setting=mp->selector;
13133   if ( file_state ) {
13134     @<Print location of current line@>;
13135     @<Pseudoprint the line@>;
13136   } else { 
13137     @<Print type of token list@>;
13138     @<Pseudoprint the token list@>;
13139   }
13140   mp->selector=old_setting; /* stop pseudoprinting */
13141   @<Print two lines using the tricky pseudoprinted information@>;
13142 }
13143
13144 @ This routine should be changed, if necessary, to give the best possible
13145 indication of where the current line resides in the input file.
13146 For example, on some systems it is best to print both a page and line number.
13147 @^system dependencies@>
13148
13149 @<Print location of current line@>=
13150 if ( name>max_spec_src ) {
13151   mp_print_nl(mp, "l."); mp_print_int(mp, mp_true_line(mp));
13152 } else if ( terminal_input ) {
13153   if ( mp->file_ptr==0 ) mp_print_nl(mp, "<*>");
13154   else mp_print_nl(mp, "<insert>");
13155 } else if ( name==is_scantok ) {
13156   mp_print_nl(mp, "<scantokens>");
13157 } else {
13158   mp_print_nl(mp, "<read>");
13159 }
13160 mp_print_char(mp, ' ')
13161
13162 @ Can't use case statement here because the |token_type| is not
13163 a constant expression.
13164
13165 @<Print type of token list@>=
13166 {
13167   if(token_type==forever_text) {
13168     mp_print_nl(mp, "<forever> ");
13169   } else if (token_type==loop_text) {
13170     @<Print the current loop value@>;
13171   } else if (token_type==parameter) {
13172     mp_print_nl(mp, "<argument> "); 
13173   } else if (token_type==backed_up) { 
13174     if ( loc==null ) mp_print_nl(mp, "<recently read> ");
13175     else mp_print_nl(mp, "<to be read again> ");
13176   } else if (token_type==inserted) {
13177     mp_print_nl(mp, "<inserted text> ");
13178   } else if (token_type==macro) {
13179     mp_print_ln(mp);
13180     if ( name!=null ) mp_print_text(name);
13181     else @<Print the name of a \&{vardef}'d macro@>;
13182     mp_print(mp, "->");
13183   } else {
13184     mp_print_nl(mp, "?");/* this should never happen */
13185 @.?\relax@>
13186   }
13187 }
13188
13189 @ The parameter that corresponds to a loop text is either a token list
13190 (in the case of \&{forsuffixes}) or a ``capsule'' (in the case of \&{for}).
13191 We'll discuss capsules later; for now, all we need to know is that
13192 the |link| field in a capsule parameter is |void| and that
13193 |print_exp(p,0)| displays the value of capsule~|p| in abbreviated form.
13194
13195 @<Print the current loop value@>=
13196 { mp_print_nl(mp, "<for("); p=mp->param_stack[param_start];
13197   if ( p!=null ) {
13198     if ( link(p)==mp_void ) mp_print_exp(mp, p,0); /* we're in a \&{for} loop */
13199     else mp_show_token_list(mp, p,null,20,mp->tally);
13200   }
13201   mp_print(mp, ")> ");
13202 }
13203
13204 @ The first two parameters of a macro defined by \&{vardef} will be token
13205 lists representing the macro's prefix and ``at point.'' By putting these
13206 together, we get the macro's full name.
13207
13208 @<Print the name of a \&{vardef}'d macro@>=
13209 { p=mp->param_stack[param_start];
13210   if ( p==null ) {
13211     mp_show_token_list(mp, mp->param_stack[param_start+1],null,20,mp->tally);
13212   } else { 
13213     q=p;
13214     while ( link(q)!=null ) q=link(q);
13215     link(q)=mp->param_stack[param_start+1];
13216     mp_show_token_list(mp, p,null,20,mp->tally);
13217     link(q)=null;
13218   }
13219 }
13220
13221 @ Now it is necessary to explain a little trick. We don't want to store a long
13222 string that corresponds to a token list, because that string might take up
13223 lots of memory; and we are printing during a time when an error message is
13224 being given, so we dare not do anything that might overflow one of \MP's
13225 tables. So `pseudoprinting' is the answer: We enter a mode of printing
13226 that stores characters into a buffer of length |error_line|, where character
13227 $k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
13228 |k<trick_count|, otherwise character |k| is dropped. Initially we set
13229 |tally:=0| and |trick_count:=1000000|; then when we reach the
13230 point where transition from line 1 to line 2 should occur, we
13231 set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
13232 tally+1+error_line-half_error_line)|. At the end of the
13233 pseudoprinting, the values of |first_count|, |tally|, and
13234 |trick_count| give us all the information we need to print the two lines,
13235 and all of the necessary text is in |trick_buf|.
13236
13237 Namely, let |l| be the length of the descriptive information that appears
13238 on the first line. The length of the context information gathered for that
13239 line is |k=first_count|, and the length of the context information
13240 gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
13241 where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
13242 descriptive information on line~1, and set |n:=l+k|; here |n| is the
13243 length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
13244 and print `\.{...}' followed by
13245 $$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
13246 where subscripts of |trick_buf| are circular modulo |error_line|. The
13247 second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
13248 unless |n+m>error_line|; in the latter case, further cropping is done.
13249 This is easier to program than to explain.
13250
13251 @<Local variables for formatting...@>=
13252 int i; /* index into |buffer| */
13253 integer l; /* length of descriptive information on line 1 */
13254 integer m; /* context information gathered for line 2 */
13255 int n; /* length of line 1 */
13256 integer p; /* starting or ending place in |trick_buf| */
13257 integer q; /* temporary index */
13258
13259 @ The following code tells the print routines to gather
13260 the desired information.
13261
13262 @d begin_pseudoprint { 
13263   l=mp->tally; mp->tally=0; mp->selector=pseudo;
13264   mp->trick_count=1000000;
13265 }
13266 @d set_trick_count {
13267   mp->first_count=mp->tally;
13268   mp->trick_count=mp->tally+1+mp->error_line-mp->half_error_line;
13269   if ( mp->trick_count<mp->error_line ) mp->trick_count=mp->error_line;
13270 }
13271
13272 @ And the following code uses the information after it has been gathered.
13273
13274 @<Print two lines using the tricky pseudoprinted information@>=
13275 if ( mp->trick_count==1000000 ) set_trick_count;
13276   /* |set_trick_count| must be performed */
13277 if ( mp->tally<mp->trick_count ) m=mp->tally-mp->first_count;
13278 else m=mp->trick_count-mp->first_count; /* context on line 2 */
13279 if ( l+mp->first_count<=mp->half_error_line ) {
13280   p=0; n=l+mp->first_count;
13281 } else  { 
13282   mp_print(mp, "..."); p=l+mp->first_count-mp->half_error_line+3;
13283   n=mp->half_error_line;
13284 }
13285 for (q=p;q<=mp->first_count-1;q++) {
13286   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13287 }
13288 mp_print_ln(mp);
13289 for (q=1;q<=n;q++) {
13290   mp_print_char(mp, ' '); /* print |n| spaces to begin line~2 */
13291 }
13292 if ( m+n<=mp->error_line ) p=mp->first_count+m; 
13293 else p=mp->first_count+(mp->error_line-n-3);
13294 for (q=mp->first_count;q<=p-1;q++) {
13295   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13296 }
13297 if ( m+n>mp->error_line ) mp_print(mp, "...")
13298
13299 @ But the trick is distracting us from our current goal, which is to
13300 understand the input state. So let's concentrate on the data structures that
13301 are being pseudoprinted as we finish up the |show_context| procedure.
13302
13303 @<Pseudoprint the line@>=
13304 begin_pseudoprint;
13305 if ( limit>0 ) {
13306   for (i=start;i<=limit-1;i++) {
13307     if ( i==loc ) set_trick_count;
13308     mp_print_str(mp, mp->buffer[i]);
13309   }
13310 }
13311
13312 @ @<Pseudoprint the token list@>=
13313 begin_pseudoprint;
13314 if ( token_type!=macro ) mp_show_token_list(mp, start,loc,100000,0);
13315 else mp_show_macro(mp, start,loc,100000)
13316
13317 @ Here is the missing piece of |show_token_list| that is activated when the
13318 token beginning line~2 is about to be shown:
13319
13320 @<Do magic computation@>=set_trick_count
13321
13322 @* \[28] Maintaining the input stacks.
13323 The following subroutines change the input status in commonly needed ways.
13324
13325 First comes |push_input|, which stores the current state and creates a
13326 new level (having, initially, the same properties as the old).
13327
13328 @d push_input  { /* enter a new input level, save the old */
13329   if ( mp->input_ptr>mp->max_in_stack ) {
13330     mp->max_in_stack=mp->input_ptr;
13331     if ( mp->input_ptr==mp->stack_size ) {
13332       int l = (mp->stack_size+(mp->stack_size>>2));
13333       XREALLOC(mp->input_stack, l, in_state_record);
13334       mp->stack_size = l;
13335     }         
13336   }
13337   mp->input_stack[mp->input_ptr]=mp->cur_input; /* stack the record */
13338   incr(mp->input_ptr);
13339 }
13340
13341 @ And of course what goes up must come down.
13342
13343 @d pop_input { /* leave an input level, re-enter the old */
13344     decr(mp->input_ptr); mp->cur_input=mp->input_stack[mp->input_ptr];
13345   }
13346
13347 @ Here is a procedure that starts a new level of token-list input, given
13348 a token list |p| and its type |t|. If |t=macro|, the calling routine should
13349 set |name|, reset~|loc|, and increase the macro's reference count.
13350
13351 @d back_list(A) mp_begin_token_list(mp, (A),backed_up) /* backs up a simple token list */
13352
13353 @c void mp_begin_token_list (MP mp,pointer p, quarterword t)  { 
13354   push_input; start=p; token_type=t;
13355   param_start=mp->param_ptr; loc=p;
13356 }
13357
13358 @ When a token list has been fully scanned, the following computations
13359 should be done as we leave that level of input.
13360 @^inner loop@>
13361
13362 @c void mp_end_token_list (MP mp) { /* leave a token-list input level */
13363   pointer p; /* temporary register */
13364   if ( token_type>=backed_up ) { /* token list to be deleted */
13365     if ( token_type<=inserted ) { 
13366       mp_flush_token_list(mp, start); goto DONE;
13367     } else {
13368       mp_delete_mac_ref(mp, start); /* update reference count */
13369     }
13370   }
13371   while ( mp->param_ptr>param_start ) { /* parameters must be flushed */
13372     decr(mp->param_ptr);
13373     p=mp->param_stack[mp->param_ptr];
13374     if ( p!=null ) {
13375       if ( link(p)==mp_void ) { /* it's an \&{expr} parameter */
13376         mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
13377       } else {
13378         mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
13379       }
13380     }
13381   }
13382 DONE: 
13383   pop_input; check_interrupt;
13384 }
13385
13386 @ The contents of |cur_cmd,cur_mod,cur_sym| are placed into an equivalent
13387 token by the |cur_tok| routine.
13388 @^inner loop@>
13389
13390 @c @<Declare the procedure called |make_exp_copy|@>;
13391 pointer mp_cur_tok (MP mp) {
13392   pointer p; /* a new token node */
13393   small_number save_type; /* |cur_type| to be restored */
13394   integer save_exp; /* |cur_exp| to be restored */
13395   if ( mp->cur_sym==0 ) {
13396     if ( mp->cur_cmd==capsule_token ) {
13397       save_type=mp->cur_type; save_exp=mp->cur_exp;
13398       mp_make_exp_copy(mp, mp->cur_mod); p=mp_stash_cur_exp(mp); link(p)=null;
13399       mp->cur_type=save_type; mp->cur_exp=save_exp;
13400     } else { 
13401       p=mp_get_node(mp, token_node_size);
13402       value(p)=mp->cur_mod; name_type(p)=mp_token;
13403       if ( mp->cur_cmd==numeric_token ) type(p)=mp_known;
13404       else type(p)=mp_string_type;
13405     }
13406   } else { 
13407     fast_get_avail(p); info(p)=mp->cur_sym;
13408   }
13409   return p;
13410 }
13411
13412 @ Sometimes \MP\ has read too far and wants to ``unscan'' what it has
13413 seen. The |back_input| procedure takes care of this by putting the token
13414 just scanned back into the input stream, ready to be read again.
13415 If |cur_sym<>0|, the values of |cur_cmd| and |cur_mod| are irrelevant.
13416
13417 @<Declarations@>= 
13418 void mp_back_input (MP mp);
13419
13420 @ @c void mp_back_input (MP mp) {/* undoes one token of input */
13421   pointer p; /* a token list of length one */
13422   p=mp_cur_tok(mp);
13423   while ( token_state &&(loc==null) ) 
13424     mp_end_token_list(mp); /* conserve stack space */
13425   back_list(p);
13426 }
13427
13428 @ The |back_error| routine is used when we want to restore or replace an
13429 offending token just before issuing an error message.  We disable interrupts
13430 during the call of |back_input| so that the help message won't be lost.
13431
13432 @<Declarations@>=
13433 void mp_error (MP mp);
13434 void mp_back_error (MP mp);
13435
13436 @ @c void mp_back_error (MP mp) { /* back up one token and call |error| */
13437   mp->OK_to_interrupt=false; 
13438   mp_back_input(mp); 
13439   mp->OK_to_interrupt=true; mp_error(mp);
13440 }
13441 void mp_ins_error (MP mp) { /* back up one inserted token and call |error| */
13442   mp->OK_to_interrupt=false; 
13443   mp_back_input(mp); token_type=inserted;
13444   mp->OK_to_interrupt=true; mp_error(mp);
13445 }
13446
13447 @ The |begin_file_reading| procedure starts a new level of input for lines
13448 of characters to be read from a file, or as an insertion from the
13449 terminal. It does not take care of opening the file, nor does it set |loc|
13450 or |limit| or |line|.
13451 @^system dependencies@>
13452
13453 @c void mp_begin_file_reading (MP mp) { 
13454   if ( mp->in_open==mp->max_in_open ) 
13455     mp_overflow(mp, "text input levels",mp->max_in_open);
13456 @:MetaPost capacity exceeded text input levels}{\quad text input levels@>
13457   if ( mp->first==mp->buf_size ) 
13458     mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13459   incr(mp->in_open); push_input; index=mp->in_open;
13460   mp->mpx_name[index]=absent;
13461   start=mp->first;
13462   name=is_term; /* |terminal_input| is now |true| */
13463 }
13464
13465 @ Conversely, the variables must be downdated when such a level of input
13466 is finished.  Any associated \.{MPX} file must also be closed and popped
13467 off the file stack.
13468
13469 @c void mp_end_file_reading (MP mp) { 
13470   if ( mp->in_open>index ) {
13471     if ( (mp->mpx_name[mp->in_open]==absent)||(name<=max_spec_src) ) {
13472       mp_confusion(mp, "endinput");
13473 @:this can't happen endinput}{\quad endinput@>
13474     } else { 
13475       (mp->close_file)(mp->input_file[mp->in_open]); /* close an \.{MPX} file */
13476       delete_str_ref(mp->mpx_name[mp->in_open]);
13477       decr(mp->in_open);
13478     }
13479   }
13480   mp->first=start;
13481   if ( index!=mp->in_open ) mp_confusion(mp, "endinput");
13482   if ( name>max_spec_src ) {
13483     (mp->close_file)(cur_file);
13484     delete_str_ref(name);
13485     xfree(in_name); 
13486     xfree(in_area);
13487   }
13488   pop_input; decr(mp->in_open);
13489 }
13490
13491 @ Here is a function that tries to resume input from an \.{MPX} file already
13492 associated with the current input file.  It returns |false| if this doesn't
13493 work.
13494
13495 @c boolean mp_begin_mpx_reading (MP mp) { 
13496   if ( mp->in_open!=index+1 ) {
13497      return false;
13498   } else { 
13499     if ( mp->mpx_name[mp->in_open]<=absent ) mp_confusion(mp, "mpx");
13500 @:this can't happen mpx}{\quad mpx@>
13501     if ( mp->first==mp->buf_size ) 
13502       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13503     push_input; index=mp->in_open;
13504     start=mp->first;
13505     name=mp->mpx_name[mp->in_open]; add_str_ref(name);
13506     @<Put an empty line in the input buffer@>;
13507     return true;
13508   }
13509 }
13510
13511 @ This procedure temporarily stops reading an \.{MPX} file.
13512
13513 @c void mp_end_mpx_reading (MP mp) { 
13514   if ( mp->in_open!=index ) mp_confusion(mp, "mpx");
13515 @:this can't happen mpx}{\quad mpx@>
13516   if ( loc<limit ) {
13517     @<Complain that we are not at the end of a line in the \.{MPX} file@>;
13518   }
13519   mp->first=start;
13520   pop_input;
13521 }
13522
13523 @ Here we enforce a restriction that simplifies the input stacks considerably.
13524 This should not inconvenience the user because \.{MPX} files are generated
13525 by an auxiliary program called \.{DVItoMP}.
13526
13527 @ @<Complain that we are not at the end of a line in the \.{MPX} file@>=
13528
13529 print_err("`mpxbreak' must be at the end of a line");
13530 help4("This file contains picture expressions for btex...etex")
13531   ("blocks.  Such files are normally generated automatically")
13532   ("but this one seems to be messed up.  I'm going to ignore")
13533   ("the rest of this line.");
13534 mp_error(mp);
13535 }
13536
13537 @ In order to keep the stack from overflowing during a long sequence of
13538 inserted `\.{show}' commands, the following routine removes completed
13539 error-inserted lines from memory.
13540
13541 @c void mp_clear_for_error_prompt (MP mp) { 
13542   while ( file_state && terminal_input &&
13543     (mp->input_ptr>0)&&(loc==limit) ) mp_end_file_reading(mp);
13544   mp_print_ln(mp); clear_terminal;
13545 }
13546
13547 @ To get \MP's whole input mechanism going, we perform the following
13548 actions.
13549
13550 @<Initialize the input routines@>=
13551 { mp->input_ptr=0; mp->max_in_stack=0;
13552   mp->in_open=0; mp->open_parens=0; mp->max_buf_stack=0;
13553   mp->param_ptr=0; mp->max_param_stack=0;
13554   mp->first=1;
13555   start=1; index=0; line=0; name=is_term;
13556   mp->mpx_name[0]=absent;
13557   mp->force_eof=false;
13558   if ( ! mp_init_terminal(mp) ) mp_jump_out(mp);
13559   limit=mp->last; mp->first=mp->last+1; 
13560   /* |init_terminal| has set |loc| and |last| */
13561 }
13562
13563 @* \[29] Getting the next token.
13564 The heart of \MP's input mechanism is the |get_next| procedure, which
13565 we shall develop in the next few sections of the program. Perhaps we
13566 shouldn't actually call it the ``heart,'' however; it really acts as \MP's
13567 eyes and mouth, reading the source files and gobbling them up. And it also
13568 helps \MP\ to regurgitate stored token lists that are to be processed again.
13569
13570 The main duty of |get_next| is to input one token and to set |cur_cmd|
13571 and |cur_mod| to that token's command code and modifier. Furthermore, if
13572 the input token is a symbolic token, that token's |hash| address
13573 is stored in |cur_sym|; otherwise |cur_sym| is set to zero.
13574
13575 Underlying this simple description is a certain amount of complexity
13576 because of all the cases that need to be handled.
13577 However, the inner loop of |get_next| is reasonably short and fast.
13578
13579 @ Before getting into |get_next|, we need to consider a mechanism by which
13580 \MP\ helps keep errors from propagating too far. Whenever the program goes
13581 into a mode where it keeps calling |get_next| repeatedly until a certain
13582 condition is met, it sets |scanner_status| to some value other than |normal|.
13583 Then if an input file ends, or if an `\&{outer}' symbol appears,
13584 an appropriate error recovery will be possible.
13585
13586 The global variable |warning_info| helps in this error recovery by providing
13587 additional information. For example, |warning_info| might indicate the
13588 name of a macro whose replacement text is being scanned.
13589
13590 @d normal 0 /* |scanner_status| at ``quiet times'' */
13591 @d skipping 1 /* |scanner_status| when false conditional text is being skipped */
13592 @d flushing 2 /* |scanner_status| when junk after a statement is being ignored */
13593 @d absorbing 3 /* |scanner_status| when a \&{text} parameter is being scanned */
13594 @d var_defining 4 /* |scanner_status| when a \&{vardef} is being scanned */
13595 @d op_defining 5 /* |scanner_status| when a macro \&{def} is being scanned */
13596 @d loop_defining 6 /* |scanner_status| when a \&{for} loop is being scanned */
13597 @d tex_flushing 7 /* |scanner_status| when skipping \TeX\ material */
13598
13599 @<Glob...@>=
13600 integer scanner_status; /* are we scanning at high speed? */
13601 integer warning_info; /* if so, what else do we need to know,
13602     in case an error occurs? */
13603
13604 @ @<Initialize the input routines@>=
13605 mp->scanner_status=normal;
13606
13607 @ The following subroutine
13608 is called when an `\&{outer}' symbolic token has been scanned or
13609 when the end of a file has been reached. These two cases are distinguished
13610 by |cur_sym|, which is zero at the end of a file.
13611
13612 @c boolean mp_check_outer_validity (MP mp) {
13613   pointer p; /* points to inserted token list */
13614   if ( mp->scanner_status==normal ) {
13615     return true;
13616   } else if ( mp->scanner_status==tex_flushing ) {
13617     @<Check if the file has ended while flushing \TeX\ material and set the
13618       result value for |check_outer_validity|@>;
13619   } else { 
13620     mp->deletions_allowed=false;
13621     @<Back up an outer symbolic token so that it can be reread@>;
13622     if ( mp->scanner_status>skipping ) {
13623       @<Tell the user what has run away and try to recover@>;
13624     } else { 
13625       print_err("Incomplete if; all text was ignored after line ");
13626 @.Incomplete if...@>
13627       mp_print_int(mp, mp->warning_info);
13628       help3("A forbidden `outer' token occurred in skipped text.")
13629         ("This kind of error happens when you say `if...' and forget")
13630         ("the matching `fi'. I've inserted a `fi'; this might work.");
13631       if ( mp->cur_sym==0 ) 
13632         mp->help_line[2]="The file ended while I was skipping conditional text.";
13633       mp->cur_sym=frozen_fi; mp_ins_error(mp);
13634     }
13635     mp->deletions_allowed=true; 
13636         return false;
13637   }
13638 }
13639
13640 @ @<Check if the file has ended while flushing \TeX\ material and set...@>=
13641 if ( mp->cur_sym!=0 ) { 
13642    return true;
13643 } else { 
13644   mp->deletions_allowed=false;
13645   print_err("TeX mode didn't end; all text was ignored after line ");
13646   mp_print_int(mp, mp->warning_info);
13647   help2("The file ended while I was looking for the `etex' to")
13648     ("finish this TeX material.  I've inserted `etex' now.");
13649   mp->cur_sym = frozen_etex;
13650   mp_ins_error(mp);
13651   mp->deletions_allowed=true;
13652   return false;
13653 }
13654
13655 @ @<Back up an outer symbolic token so that it can be reread@>=
13656 if ( mp->cur_sym!=0 ) {
13657   p=mp_get_avail(mp); info(p)=mp->cur_sym;
13658   back_list(p); /* prepare to read the symbolic token again */
13659 }
13660
13661 @ @<Tell the user what has run away...@>=
13662
13663   mp_runaway(mp); /* print the definition-so-far */
13664   if ( mp->cur_sym==0 ) {
13665     print_err("File ended");
13666 @.File ended while scanning...@>
13667   } else { 
13668     print_err("Forbidden token found");
13669 @.Forbidden token found...@>
13670   }
13671   mp_print(mp, " while scanning ");
13672   help4("I suspect you have forgotten an `enddef',")
13673     ("causing me to read past where you wanted me to stop.")
13674     ("I'll try to recover; but if the error is serious,")
13675     ("you'd better type `E' or `X' now and fix your file.");
13676   switch (mp->scanner_status) {
13677     @<Complete the error message,
13678       and set |cur_sym| to a token that might help recover from the error@>
13679   } /* there are no other cases */
13680   mp_ins_error(mp);
13681 }
13682
13683 @ As we consider various kinds of errors, it is also appropriate to
13684 change the first line of the help message just given; |help_line[3]|
13685 points to the string that might be changed.
13686
13687 @<Complete the error message,...@>=
13688 case flushing: 
13689   mp_print(mp, "to the end of the statement");
13690   mp->help_line[3]="A previous error seems to have propagated,";
13691   mp->cur_sym=frozen_semicolon;
13692   break;
13693 case absorbing: 
13694   mp_print(mp, "a text argument");
13695   mp->help_line[3]="It seems that a right delimiter was left out,";
13696   if ( mp->warning_info==0 ) {
13697     mp->cur_sym=frozen_end_group;
13698   } else { 
13699     mp->cur_sym=frozen_right_delimiter;
13700     equiv(frozen_right_delimiter)=mp->warning_info;
13701   }
13702   break;
13703 case var_defining:
13704 case op_defining: 
13705   mp_print(mp, "the definition of ");
13706   if ( mp->scanner_status==op_defining ) 
13707      mp_print_text(mp->warning_info);
13708   else 
13709      mp_print_variable_name(mp, mp->warning_info);
13710   mp->cur_sym=frozen_end_def;
13711   break;
13712 case loop_defining: 
13713   mp_print(mp, "the text of a "); 
13714   mp_print_text(mp->warning_info);
13715   mp_print(mp, " loop");
13716   mp->help_line[3]="I suspect you have forgotten an `endfor',";
13717   mp->cur_sym=frozen_end_for;
13718   break;
13719
13720 @ The |runaway| procedure displays the first part of the text that occurred
13721 when \MP\ began its special |scanner_status|, if that text has been saved.
13722
13723 @<Declare the procedure called |runaway|@>=
13724 void mp_runaway (MP mp) { 
13725   if ( mp->scanner_status>flushing ) { 
13726      mp_print_nl(mp, "Runaway ");
13727          switch (mp->scanner_status) { 
13728          case absorbing: mp_print(mp, "text?"); break;
13729          case var_defining: 
13730      case op_defining: mp_print(mp,"definition?"); break;
13731      case loop_defining: mp_print(mp, "loop?"); break;
13732      } /* there are no other cases */
13733      mp_print_ln(mp); 
13734      mp_show_token_list(mp, link(hold_head),null,mp->error_line-10,0);
13735   }
13736 }
13737
13738 @ We need to mention a procedure that may be called by |get_next|.
13739
13740 @<Declarations@>= 
13741 void mp_firm_up_the_line (MP mp);
13742
13743 @ And now we're ready to take the plunge into |get_next| itself.
13744 Note that the behavior depends on the |scanner_status| because percent signs
13745 and double quotes need to be passed over when skipping TeX material.
13746
13747 @c 
13748 void mp_get_next (MP mp) {
13749   /* sets |cur_cmd|, |cur_mod|, |cur_sym| to next token */
13750 @^inner loop@>
13751   /*restart*/ /* go here to get the next input token */
13752   /*exit*/ /* go here when the next input token has been got */
13753   /*|common_ending|*/ /* go here to finish getting a symbolic token */
13754   /*found*/ /* go here when the end of a symbolic token has been found */
13755   /*switch*/ /* go here to branch on the class of an input character */
13756   /*|start_numeric_token|,|start_decimal_token|,|fin_numeric_token|,|done|*/
13757     /* go here at crucial stages when scanning a number */
13758   int k; /* an index into |buffer| */
13759   ASCII_code c; /* the current character in the buffer */
13760   ASCII_code class; /* its class number */
13761   integer n,f; /* registers for decimal-to-binary conversion */
13762 RESTART: 
13763   mp->cur_sym=0;
13764   if ( file_state ) {
13765     @<Input from external file; |goto restart| if no input found,
13766     or |return| if a non-symbolic token is found@>;
13767   } else {
13768     @<Input from token list; |goto restart| if end of list or
13769       if a parameter needs to be expanded,
13770       or |return| if a non-symbolic token is found@>;
13771   }
13772 COMMON_ENDING: 
13773   @<Finish getting the symbolic token in |cur_sym|;
13774    |goto restart| if it is illegal@>;
13775 }
13776
13777 @ When a symbolic token is declared to be `\&{outer}', its command code
13778 is increased by |outer_tag|.
13779 @^inner loop@>
13780
13781 @<Finish getting the symbolic token in |cur_sym|...@>=
13782 mp->cur_cmd=eq_type(mp->cur_sym); mp->cur_mod=equiv(mp->cur_sym);
13783 if ( mp->cur_cmd>=outer_tag ) {
13784   if ( mp_check_outer_validity(mp) ) 
13785     mp->cur_cmd=mp->cur_cmd-outer_tag;
13786   else 
13787     goto RESTART;
13788 }
13789
13790 @ A percent sign appears in |buffer[limit]|; this makes it unnecessary
13791 to have a special test for end-of-line.
13792 @^inner loop@>
13793
13794 @<Input from external file;...@>=
13795
13796 SWITCH: 
13797   c=mp->buffer[loc]; incr(loc); class=mp->char_class[c];
13798   switch (class) {
13799   case digit_class: goto START_NUMERIC_TOKEN; break;
13800   case period_class: 
13801     class=mp->char_class[mp->buffer[loc]];
13802     if ( class>period_class ) {
13803       goto SWITCH;
13804     } else if ( class<period_class ) { /* |class=digit_class| */
13805       n=0; goto START_DECIMAL_TOKEN;
13806     }
13807 @:. }{\..\ token@>
13808     break;
13809   case space_class: goto SWITCH; break;
13810   case percent_class: 
13811     if ( mp->scanner_status==tex_flushing ) {
13812       if ( loc<limit ) goto SWITCH;
13813     }
13814     @<Move to next line of file, or |goto restart| if there is no next line@>;
13815     check_interrupt;
13816     goto SWITCH;
13817     break;
13818   case string_class: 
13819     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13820     else @<Get a string token and |return|@>;
13821     break;
13822   case isolated_classes: 
13823     k=loc-1; goto FOUND; break;
13824   case invalid_class: 
13825     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13826     else @<Decry the invalid character and |goto restart|@>;
13827     break;
13828   default: break; /* letters, etc. */
13829   }
13830   k=loc-1;
13831   while ( mp->char_class[mp->buffer[loc]]==class ) incr(loc);
13832   goto FOUND;
13833 START_NUMERIC_TOKEN:
13834   @<Get the integer part |n| of a numeric token;
13835     set |f:=0| and |goto fin_numeric_token| if there is no decimal point@>;
13836 START_DECIMAL_TOKEN:
13837   @<Get the fraction part |f| of a numeric token@>;
13838 FIN_NUMERIC_TOKEN:
13839   @<Pack the numeric and fraction parts of a numeric token
13840     and |return|@>;
13841 FOUND: 
13842   mp->cur_sym=mp_id_lookup(mp, k,loc-k);
13843 }
13844
13845 @ We go to |restart| instead of to |SWITCH|, because |state| might equal
13846 |token_list| after the error has been dealt with
13847 (cf.\ |clear_for_error_prompt|).
13848
13849 @<Decry the invalid...@>=
13850
13851   print_err("Text line contains an invalid character");
13852 @.Text line contains...@>
13853   help2("A funny symbol that I can\'t read has just been input.")
13854     ("Continue, and I'll forget that it ever happened.");
13855   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13856   goto RESTART;
13857 }
13858
13859 @ @<Get a string token and |return|@>=
13860
13861   if ( mp->buffer[loc]=='"' ) {
13862     mp->cur_mod=rts("");
13863   } else { 
13864     k=loc; mp->buffer[limit+1]='"';
13865     do {  
13866      incr(loc);
13867     } while (mp->buffer[loc]!='"');
13868     if ( loc>limit ) {
13869       @<Decry the missing string delimiter and |goto restart|@>;
13870     }
13871     if ( loc==k+1 ) {
13872       mp->cur_mod=mp->buffer[k];
13873     } else { 
13874       str_room(loc-k);
13875       do {  
13876         append_char(mp->buffer[k]); incr(k);
13877       } while (k!=loc);
13878       mp->cur_mod=mp_make_string(mp);
13879     }
13880   }
13881   incr(loc); mp->cur_cmd=string_token; 
13882   return;
13883 }
13884
13885 @ We go to |restart| after this error message, not to |SWITCH|,
13886 because the |clear_for_error_prompt| routine might have reinstated
13887 |token_state| after |error| has finished.
13888
13889 @<Decry the missing string delimiter and |goto restart|@>=
13890
13891   loc=limit; /* the next character to be read on this line will be |"%"| */
13892   print_err("Incomplete string token has been flushed");
13893 @.Incomplete string token...@>
13894   help3("Strings should finish on the same line as they began.")
13895     ("I've deleted the partial string; you might want to")
13896     ("insert another by typing, e.g., `I\"new string\"'.");
13897   mp->deletions_allowed=false; mp_error(mp);
13898   mp->deletions_allowed=true; 
13899   goto RESTART;
13900 }
13901
13902 @ @<Get the integer part |n| of a numeric token...@>=
13903 n=c-'0';
13904 while ( mp->char_class[mp->buffer[loc]]==digit_class ) {
13905   if ( n<32768 ) n=10*n+mp->buffer[loc]-'0';
13906   incr(loc);
13907 }
13908 if ( mp->buffer[loc]=='.' ) 
13909   if ( mp->char_class[mp->buffer[loc+1]]==digit_class ) 
13910     goto DONE;
13911 f=0; 
13912 goto FIN_NUMERIC_TOKEN;
13913 DONE: incr(loc)
13914
13915 @ @<Get the fraction part |f| of a numeric token@>=
13916 k=0;
13917 do { 
13918   if ( k<17 ) { /* digits for |k>=17| cannot affect the result */
13919     mp->dig[k]=mp->buffer[loc]-'0'; incr(k);
13920   }
13921   incr(loc);
13922 } while (mp->char_class[mp->buffer[loc]]==digit_class);
13923 f=mp_round_decimals(mp, k);
13924 if ( f==unity ) {
13925   incr(n); f=0;
13926 }
13927
13928 @ @<Pack the numeric and fraction parts of a numeric token and |return|@>=
13929 if ( n<32768 ) {
13930   @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>;
13931 } else if ( mp->scanner_status!=tex_flushing ) {
13932   print_err("Enormous number has been reduced");
13933 @.Enormous number...@>
13934   help2("I can\'t handle numbers bigger than 32767.99998;")
13935     ("so I've changed your constant to that maximum amount.");
13936   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13937   mp->cur_mod=el_gordo;
13938 }
13939 mp->cur_cmd=numeric_token; return
13940
13941 @ @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>=
13942
13943   mp->cur_mod=n*unity+f;
13944   if ( mp->cur_mod>=fraction_one ) {
13945     if ( (mp->internal[mp_warning_check]>0) &&
13946          (mp->scanner_status!=tex_flushing) ) {
13947       print_err("Number is too large (");
13948       mp_print_scaled(mp, mp->cur_mod);
13949       mp_print_char(mp, ')');
13950       help3("It is at least 4096. Continue and I'll try to cope")
13951       ("with that big value; but it might be dangerous.")
13952       ("(Set warningcheck:=0 to suppress this message.)");
13953       mp_error(mp);
13954     }
13955   }
13956 }
13957
13958 @ Let's consider now what happens when |get_next| is looking at a token list.
13959 @^inner loop@>
13960
13961 @<Input from token list;...@>=
13962 if ( loc>=mp->hi_mem_min ) { /* one-word token */
13963   mp->cur_sym=info(loc); loc=link(loc); /* move to next */
13964   if ( mp->cur_sym>=expr_base ) {
13965     if ( mp->cur_sym>=suffix_base ) {
13966       @<Insert a suffix or text parameter and |goto restart|@>;
13967     } else { 
13968       mp->cur_cmd=capsule_token;
13969       mp->cur_mod=mp->param_stack[param_start+mp->cur_sym-(expr_base)];
13970       mp->cur_sym=0; return;
13971     }
13972   }
13973 } else if ( loc>null ) {
13974   @<Get a stored numeric or string or capsule token and |return|@>
13975 } else { /* we are done with this token list */
13976   mp_end_token_list(mp); goto RESTART; /* resume previous level */
13977 }
13978
13979 @ @<Insert a suffix or text parameter...@>=
13980
13981   if ( mp->cur_sym>=text_base ) mp->cur_sym=mp->cur_sym-mp->param_size;
13982   /* |param_size=text_base-suffix_base| */
13983   mp_begin_token_list(mp,
13984                       mp->param_stack[param_start+mp->cur_sym-(suffix_base)],
13985                       parameter);
13986   goto RESTART;
13987 }
13988
13989 @ @<Get a stored numeric or string or capsule token...@>=
13990
13991   if ( name_type(loc)==mp_token ) {
13992     mp->cur_mod=value(loc);
13993     if ( type(loc)==mp_known ) {
13994       mp->cur_cmd=numeric_token;
13995     } else { 
13996       mp->cur_cmd=string_token; add_str_ref(mp->cur_mod);
13997     }
13998   } else { 
13999     mp->cur_mod=loc; mp->cur_cmd=capsule_token;
14000   };
14001   loc=link(loc); return;
14002 }
14003
14004 @ All of the easy branches of |get_next| have now been taken care of.
14005 There is one more branch.
14006
14007 @<Move to next line of file, or |goto restart|...@>=
14008 if ( name>max_spec_src ) {
14009   @<Read next line of file into |buffer|, or
14010     |goto restart| if the file has ended@>;
14011 } else { 
14012   if ( mp->input_ptr>0 ) {
14013      /* text was inserted during error recovery or by \&{scantokens} */
14014     mp_end_file_reading(mp); goto RESTART; /* resume previous level */
14015   }
14016   if ( mp->selector<log_only || mp->selector>=write_file) mp_open_log_file(mp);
14017   if ( mp->interaction>mp_nonstop_mode ) {
14018     if ( limit==start ) /* previous line was empty */
14019       mp_print_nl(mp, "(Please type a command or say `end')");
14020 @.Please type...@>
14021     mp_print_ln(mp); mp->first=start;
14022     prompt_input("*"); /* input on-line into |buffer| */
14023 @.*\relax@>
14024     limit=mp->last; mp->buffer[limit]='%';
14025     mp->first=limit+1; loc=start;
14026   } else {
14027     mp_fatal_error(mp, "*** (job aborted, no legal end found)");
14028 @.job aborted@>
14029     /* nonstop mode, which is intended for overnight batch processing,
14030     never waits for on-line input */
14031   }
14032 }
14033
14034 @ The global variable |force_eof| is normally |false|; it is set |true|
14035 by an \&{endinput} command.
14036
14037 @<Glob...@>=
14038 boolean force_eof; /* should the next \&{input} be aborted early? */
14039
14040 @ We must decrement |loc| in order to leave the buffer in a valid state
14041 when an error condition causes us to |goto restart| without calling
14042 |end_file_reading|.
14043
14044 @<Read next line of file into |buffer|, or
14045   |goto restart| if the file has ended@>=
14046
14047   incr(line); mp->first=start;
14048   if ( ! mp->force_eof ) {
14049     if ( mp_input_ln(mp, cur_file ) ) /* not end of file */
14050       mp_firm_up_the_line(mp); /* this sets |limit| */
14051     else 
14052       mp->force_eof=true;
14053   };
14054   if ( mp->force_eof ) {
14055     mp->force_eof=false;
14056     decr(loc);
14057     if ( mpx_reading ) {
14058       @<Complain that the \.{MPX} file ended unexpectly; then set
14059         |cur_sym:=frozen_mpx_break| and |goto comon_ending|@>;
14060     } else { 
14061       mp_print_char(mp, ')'); decr(mp->open_parens);
14062       update_terminal; /* show user that file has been read */
14063       mp_end_file_reading(mp); /* resume previous level */
14064       if ( mp_check_outer_validity(mp) ) goto  RESTART;  
14065       else goto RESTART;
14066     }
14067   }
14068   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; /* ready to read */
14069 }
14070
14071 @ We should never actually come to the end of an \.{MPX} file because such
14072 files should have an \&{mpxbreak} after the translation of the last
14073 \&{btex}$\,\ldots\,$\&{etex} block.
14074
14075 @<Complain that the \.{MPX} file ended unexpectly; then set...@>=
14076
14077   mp->mpx_name[index]=finished;
14078   print_err("mpx file ended unexpectedly");
14079   help4("The file had too few picture expressions for btex...etex")
14080     ("blocks.  Such files are normally generated automatically")
14081     ("but this one got messed up.  You might want to insert a")
14082     ("picture expression now.");
14083   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
14084   mp->cur_sym=frozen_mpx_break; goto COMMON_ENDING;
14085 }
14086
14087 @ Sometimes we want to make it look as though we have just read a blank line
14088 without really doing so.
14089
14090 @<Put an empty line in the input buffer@>=
14091 mp->last=mp->first; limit=mp->last; /* simulate |input_ln| and |firm_up_the_line| */
14092 mp->buffer[limit]='%'; mp->first=limit+1; loc=start
14093
14094 @ If the user has set the |mp_pausing| parameter to some positive value,
14095 and if nonstop mode has not been selected, each line of input is displayed
14096 on the terminal and the transcript file, followed by `\.{=>}'.
14097 \MP\ waits for a response. If the response is null (i.e., if nothing is
14098 typed except perhaps a few blank spaces), the original
14099 line is accepted as it stands; otherwise the line typed is
14100 used instead of the line in the file.
14101
14102 @c void mp_firm_up_the_line (MP mp) {
14103   size_t k; /* an index into |buffer| */
14104   limit=mp->last;
14105   if ( mp->internal[mp_pausing]>0) if ( mp->interaction>mp_nonstop_mode ) {
14106     wake_up_terminal; mp_print_ln(mp);
14107     if ( start<limit ) {
14108       for (k=(size_t)start;k<=(size_t)(limit-1);k++) {
14109         mp_print_str(mp, mp->buffer[k]);
14110       } 
14111     }
14112     mp->first=limit; prompt_input("=>"); /* wait for user response */
14113 @.=>@>
14114     if ( mp->last>mp->first ) {
14115       for (k=mp->first;k<=mp->last-1;k++) { /* move line down in buffer */
14116         mp->buffer[k+start-mp->first]=mp->buffer[k];
14117       }
14118       limit=start+mp->last-mp->first;
14119     }
14120   }
14121 }
14122
14123 @* \[30] Dealing with \TeX\ material.
14124 The \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}$\,\ldots\,$\&{etex}
14125 features need to be implemented at a low level in the scanning process
14126 so that \MP\ can stay in synch with the a preprocessor that treats
14127 blocks of \TeX\ material as they occur in the input file without trying
14128 to expand \MP\ macros.  Thus we need a special version of |get_next|
14129 that does not expand macros and such but does handle \&{btex},
14130 \&{verbatimtex}, etc.
14131
14132 The special version of |get_next| is called |get_t_next|.  It works by flushing
14133 \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}\allowbreak
14134 $\,\ldots\,$\&{etex} blocks, switching to the \.{MPX} file when it sees
14135 \&{btex}, and switching back when it sees \&{mpxbreak}.
14136
14137 @d btex_code 0
14138 @d verbatim_code 1
14139
14140 @ @<Put each...@>=
14141 mp_primitive(mp, "btex",start_tex,btex_code);
14142 @:btex_}{\&{btex} primitive@>
14143 mp_primitive(mp, "verbatimtex",start_tex,verbatim_code);
14144 @:verbatimtex_}{\&{verbatimtex} primitive@>
14145 mp_primitive(mp, "etex",etex_marker,0); mp->eqtb[frozen_etex]=mp->eqtb[mp->cur_sym];
14146 @:etex_}{\&{etex} primitive@>
14147 mp_primitive(mp, "mpxbreak",mpx_break,0); mp->eqtb[frozen_mpx_break]=mp->eqtb[mp->cur_sym];
14148 @:mpx_break_}{\&{mpxbreak} primitive@>
14149
14150 @ @<Cases of |print_cmd...@>=
14151 case start_tex: if ( m==btex_code ) mp_print(mp, "btex");
14152   else mp_print(mp, "verbatimtex"); break;
14153 case etex_marker: mp_print(mp, "etex"); break;
14154 case mpx_break: mp_print(mp, "mpxbreak"); break;
14155
14156 @ Actually, |get_t_next| is a macro that avoids procedure overhead except
14157 in the unusual case where \&{btex}, \&{verbatimtex}, \&{etex}, or \&{mpxbreak}
14158 is encountered.
14159
14160 @d get_t_next {mp_get_next(mp); if ( mp->cur_cmd<=max_pre_command ) mp_t_next(mp); }
14161
14162 @<Declarations@>=
14163 void mp_start_mpx_input (MP mp);
14164
14165 @ @c 
14166 void mp_t_next (MP mp) {
14167   int old_status; /* saves the |scanner_status| */
14168   integer old_info; /* saves the |warning_info| */
14169   while ( mp->cur_cmd<=max_pre_command ) {
14170     if ( mp->cur_cmd==mpx_break ) {
14171       if ( ! file_state || (mp->mpx_name[index]==absent) ) {
14172         @<Complain about a misplaced \&{mpxbreak}@>;
14173       } else { 
14174         mp_end_mpx_reading(mp); 
14175         goto TEX_FLUSH;
14176       }
14177     } else if ( mp->cur_cmd==start_tex ) {
14178       if ( token_state || (name<=max_spec_src) ) {
14179         @<Complain that we are not reading a file@>;
14180       } else if ( mpx_reading ) {
14181         @<Complain that \.{MPX} files cannot contain \TeX\ material@>;
14182       } else if ( (mp->cur_mod!=verbatim_code)&&
14183                   (mp->mpx_name[index]!=finished) ) {
14184         if ( ! mp_begin_mpx_reading(mp) ) mp_start_mpx_input(mp);
14185       } else {
14186         goto TEX_FLUSH;
14187       }
14188     } else {
14189        @<Complain about a misplaced \&{etex}@>;
14190     }
14191     goto COMMON_ENDING;
14192   TEX_FLUSH: 
14193     @<Flush the \TeX\ material@>;
14194   COMMON_ENDING: 
14195     mp_get_next(mp);
14196   }
14197 }
14198
14199 @ We could be in the middle of an operation such as skipping false conditional
14200 text when \TeX\ material is encountered, so we must be careful to save the
14201 |scanner_status|.
14202
14203 @<Flush the \TeX\ material@>=
14204 old_status=mp->scanner_status;
14205 old_info=mp->warning_info;
14206 mp->scanner_status=tex_flushing;
14207 mp->warning_info=line;
14208 do {  mp_get_next(mp); } while (mp->cur_cmd!=etex_marker);
14209 mp->scanner_status=old_status;
14210 mp->warning_info=old_info
14211
14212 @ @<Complain that \.{MPX} files cannot contain \TeX\ material@>=
14213 { print_err("An mpx file cannot contain btex or verbatimtex blocks");
14214 help4("This file contains picture expressions for btex...etex")
14215   ("blocks.  Such files are normally generated automatically")
14216   ("but this one seems to be messed up.  I'll just keep going")
14217   ("and hope for the best.");
14218 mp_error(mp);
14219 }
14220
14221 @ @<Complain that we are not reading a file@>=
14222 { print_err("You can only use `btex' or `verbatimtex' in a file");
14223 help3("I'll have to ignore this preprocessor command because it")
14224   ("only works when there is a file to preprocess.  You might")
14225   ("want to delete everything up to the next `etex`.");
14226 mp_error(mp);
14227 }
14228
14229 @ @<Complain about a misplaced \&{mpxbreak}@>=
14230 { print_err("Misplaced mpxbreak");
14231 help2("I'll ignore this preprocessor command because it")
14232   ("doesn't belong here");
14233 mp_error(mp);
14234 }
14235
14236 @ @<Complain about a misplaced \&{etex}@>=
14237 { print_err("Extra etex will be ignored");
14238 help1("There is no btex or verbatimtex for this to match");
14239 mp_error(mp);
14240 }
14241
14242 @* \[31] Scanning macro definitions.
14243 \MP\ has a variety of ways to tuck tokens away into token lists for later
14244 use: Macros can be defined with \&{def}, \&{vardef}, \&{primarydef}, etc.;
14245 repeatable code can be defined with \&{for}, \&{forever}, \&{forsuffixes}.
14246 All such operations are handled by the routines in this part of the program.
14247
14248 The modifier part of each command code is zero for the ``ending delimiters''
14249 like \&{enddef} and \&{endfor}.
14250
14251 @d start_def 1 /* command modifier for \&{def} */
14252 @d var_def 2 /* command modifier for \&{vardef} */
14253 @d end_def 0 /* command modifier for \&{enddef} */
14254 @d start_forever 1 /* command modifier for \&{forever} */
14255 @d end_for 0 /* command modifier for \&{endfor} */
14256
14257 @<Put each...@>=
14258 mp_primitive(mp, "def",macro_def,start_def);
14259 @:def_}{\&{def} primitive@>
14260 mp_primitive(mp, "vardef",macro_def,var_def);
14261 @:var_def_}{\&{vardef} primitive@>
14262 mp_primitive(mp, "primarydef",macro_def,secondary_primary_macro);
14263 @:primary_def_}{\&{primarydef} primitive@>
14264 mp_primitive(mp, "secondarydef",macro_def,tertiary_secondary_macro);
14265 @:secondary_def_}{\&{secondarydef} primitive@>
14266 mp_primitive(mp, "tertiarydef",macro_def,expression_tertiary_macro);
14267 @:tertiary_def_}{\&{tertiarydef} primitive@>
14268 mp_primitive(mp, "enddef",macro_def,end_def); mp->eqtb[frozen_end_def]=mp->eqtb[mp->cur_sym];
14269 @:end_def_}{\&{enddef} primitive@>
14270 @#
14271 mp_primitive(mp, "for",iteration,expr_base);
14272 @:for_}{\&{for} primitive@>
14273 mp_primitive(mp, "forsuffixes",iteration,suffix_base);
14274 @:for_suffixes_}{\&{forsuffixes} primitive@>
14275 mp_primitive(mp, "forever",iteration,start_forever);
14276 @:forever_}{\&{forever} primitive@>
14277 mp_primitive(mp, "endfor",iteration,end_for); mp->eqtb[frozen_end_for]=mp->eqtb[mp->cur_sym];
14278 @:end_for_}{\&{endfor} primitive@>
14279
14280 @ @<Cases of |print_cmd...@>=
14281 case macro_def:
14282   if ( m<=var_def ) {
14283     if ( m==start_def ) mp_print(mp, "def");
14284     else if ( m<start_def ) mp_print(mp, "enddef");
14285     else mp_print(mp, "vardef");
14286   } else if ( m==secondary_primary_macro ) { 
14287     mp_print(mp, "primarydef");
14288   } else if ( m==tertiary_secondary_macro ) { 
14289     mp_print(mp, "secondarydef");
14290   } else { 
14291     mp_print(mp, "tertiarydef");
14292   }
14293   break;
14294 case iteration: 
14295   if ( m<=start_forever ) {
14296     if ( m==start_forever ) mp_print(mp, "forever"); 
14297     else mp_print(mp, "endfor");
14298   } else if ( m==expr_base ) {
14299     mp_print(mp, "for"); 
14300   } else { 
14301     mp_print(mp, "forsuffixes");
14302   }
14303   break;
14304
14305 @ Different macro-absorbing operations have different syntaxes, but they
14306 also have a lot in common. There is a list of special symbols that are to
14307 be replaced by parameter tokens; there is a special command code that
14308 ends the definition; the quotation conventions are identical.  Therefore
14309 it makes sense to have most of the work done by a single subroutine. That
14310 subroutine is called |scan_toks|.
14311
14312 The first parameter to |scan_toks| is the command code that will
14313 terminate scanning (either |macro_def|, |loop_repeat|, or |iteration|).
14314
14315 The second parameter, |subst_list|, points to a (possibly empty) list
14316 of two-word nodes whose |info| and |value| fields specify symbol tokens
14317 before and after replacement. The list will be returned to free storage
14318 by |scan_toks|.
14319
14320 The third parameter is simply appended to the token list that is built.
14321 And the final parameter tells how many of the special operations
14322 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#} are to be replaced by suffix parameters.
14323 When such parameters are present, they are called \.{(SUFFIX0)},
14324 \.{(SUFFIX1)}, and \.{(SUFFIX2)}.
14325
14326 @c pointer mp_scan_toks (MP mp,command_code terminator, pointer 
14327   subst_list, pointer tail_end, small_number suffix_count) {
14328   pointer p; /* tail of the token list being built */
14329   pointer q; /* temporary for link management */
14330   integer balance; /* left delimiters minus right delimiters */
14331   p=hold_head; balance=1; link(hold_head)=null;
14332   while (1) { 
14333     get_t_next;
14334     if ( mp->cur_sym>0 ) {
14335       @<Substitute for |cur_sym|, if it's on the |subst_list|@>;
14336       if ( mp->cur_cmd==terminator ) {
14337         @<Adjust the balance; |break| if it's zero@>;
14338       } else if ( mp->cur_cmd==macro_special ) {
14339         @<Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}@>;
14340       }
14341     }
14342     link(p)=mp_cur_tok(mp); p=link(p);
14343   }
14344   link(p)=tail_end; mp_flush_node_list(mp, subst_list);
14345   return link(hold_head);
14346 }
14347
14348 @ @<Substitute for |cur_sym|...@>=
14349
14350   q=subst_list;
14351   while ( q!=null ) {
14352     if ( info(q)==mp->cur_sym ) {
14353       mp->cur_sym=value(q); mp->cur_cmd=relax; break;
14354     }
14355     q=link(q);
14356   }
14357 }
14358
14359 @ @<Adjust the balance; |break| if it's zero@>=
14360 if ( mp->cur_mod>0 ) {
14361   incr(balance);
14362 } else { 
14363   decr(balance);
14364   if ( balance==0 )
14365     break;
14366 }
14367
14368 @ Four commands are intended to be used only within macro texts: \&{quote},
14369 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#}. They are variants of a single command
14370 code called |macro_special|.
14371
14372 @d quote 0 /* |macro_special| modifier for \&{quote} */
14373 @d macro_prefix 1 /* |macro_special| modifier for \.{\#\AT!} */
14374 @d macro_at 2 /* |macro_special| modifier for \.{\AT!} */
14375 @d macro_suffix 3 /* |macro_special| modifier for \.{\AT!\#} */
14376
14377 @<Put each...@>=
14378 mp_primitive(mp, "quote",macro_special,quote);
14379 @:quote_}{\&{quote} primitive@>
14380 mp_primitive(mp, "#@@",macro_special,macro_prefix);
14381 @:]]]\#\AT!_}{\.{\#\AT!} primitive@>
14382 mp_primitive(mp, "@@",macro_special,macro_at);
14383 @:]]]\AT!_}{\.{\AT!} primitive@>
14384 mp_primitive(mp, "@@#",macro_special,macro_suffix);
14385 @:]]]\AT!\#_}{\.{\AT!\#} primitive@>
14386
14387 @ @<Cases of |print_cmd...@>=
14388 case macro_special: 
14389   switch (m) {
14390   case macro_prefix: mp_print(mp, "#@@"); break;
14391   case macro_at: mp_print_char(mp, '@@'); break;
14392   case macro_suffix: mp_print(mp, "@@#"); break;
14393   default: mp_print(mp, "quote"); break;
14394   }
14395   break;
14396
14397 @ @<Handle quoted...@>=
14398
14399   if ( mp->cur_mod==quote ) { get_t_next; } 
14400   else if ( mp->cur_mod<=suffix_count ) 
14401     mp->cur_sym=suffix_base-1+mp->cur_mod;
14402 }
14403
14404 @ Here is a routine that's used whenever a token will be redefined. If
14405 the user's token is unredefinable, the `|frozen_inaccessible|' token is
14406 substituted; the latter is redefinable but essentially impossible to use,
14407 hence \MP's tables won't get fouled up.
14408
14409 @c void mp_get_symbol (MP mp) { /* sets |cur_sym| to a safe symbol */
14410 RESTART: 
14411   get_t_next;
14412   if ( (mp->cur_sym==0)||(mp->cur_sym>frozen_inaccessible) ) {
14413     print_err("Missing symbolic token inserted");
14414 @.Missing symbolic token...@>
14415     help3("Sorry: You can\'t redefine a number, string, or expr.")
14416       ("I've inserted an inaccessible symbol so that your")
14417       ("definition will be completed without mixing me up too badly.");
14418     if ( mp->cur_sym>0 )
14419       mp->help_line[2]="Sorry: You can\'t redefine my error-recovery tokens.";
14420     else if ( mp->cur_cmd==string_token ) 
14421       delete_str_ref(mp->cur_mod);
14422     mp->cur_sym=frozen_inaccessible; mp_ins_error(mp); goto RESTART;
14423   }
14424 }
14425
14426 @ Before we actually redefine a symbolic token, we need to clear away its
14427 former value, if it was a variable. The following stronger version of
14428 |get_symbol| does that.
14429
14430 @c void mp_get_clear_symbol (MP mp) { 
14431   mp_get_symbol(mp); mp_clear_symbol(mp, mp->cur_sym,false);
14432 }
14433
14434 @ Here's another little subroutine; it checks that an equals sign
14435 or assignment sign comes along at the proper place in a macro definition.
14436
14437 @c void mp_check_equals (MP mp) { 
14438   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
14439      mp_missing_err(mp, "=");
14440 @.Missing `='@>
14441     help5("The next thing in this `def' should have been `=',")
14442       ("because I've already looked at the definition heading.")
14443       ("But don't worry; I'll pretend that an equals sign")
14444       ("was present. Everything from here to `enddef'")
14445       ("will be the replacement text of this macro.");
14446     mp_back_error(mp);
14447   }
14448 }
14449
14450 @ A \&{primarydef}, \&{secondarydef}, or \&{tertiarydef} is rather easily
14451 handled now that we have |scan_toks|.  In this case there are
14452 two parameters, which will be \.{EXPR0} and \.{EXPR1} (i.e.,
14453 |expr_base| and |expr_base+1|).
14454
14455 @c void mp_make_op_def (MP mp) {
14456   command_code m; /* the type of definition */
14457   pointer p,q,r; /* for list manipulation */
14458   m=mp->cur_mod;
14459   mp_get_symbol(mp); q=mp_get_node(mp, token_node_size);
14460   info(q)=mp->cur_sym; value(q)=expr_base;
14461   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym;
14462   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
14463   info(p)=mp->cur_sym; value(p)=expr_base+1; link(p)=q;
14464   get_t_next; mp_check_equals(mp);
14465   mp->scanner_status=op_defining; q=mp_get_avail(mp); ref_count(q)=null;
14466   r=mp_get_avail(mp); link(q)=r; info(r)=general_macro;
14467   link(r)=mp_scan_toks(mp, macro_def,p,null,0);
14468   mp->scanner_status=normal; eq_type(mp->warning_info)=m;
14469   equiv(mp->warning_info)=q; mp_get_x_next(mp);
14470 }
14471
14472 @ Parameters to macros are introduced by the keywords \&{expr},
14473 \&{suffix}, \&{text}, \&{primary}, \&{secondary}, and \&{tertiary}.
14474
14475 @<Put each...@>=
14476 mp_primitive(mp, "expr",param_type,expr_base);
14477 @:expr_}{\&{expr} primitive@>
14478 mp_primitive(mp, "suffix",param_type,suffix_base);
14479 @:suffix_}{\&{suffix} primitive@>
14480 mp_primitive(mp, "text",param_type,text_base);
14481 @:text_}{\&{text} primitive@>
14482 mp_primitive(mp, "primary",param_type,primary_macro);
14483 @:primary_}{\&{primary} primitive@>
14484 mp_primitive(mp, "secondary",param_type,secondary_macro);
14485 @:secondary_}{\&{secondary} primitive@>
14486 mp_primitive(mp, "tertiary",param_type,tertiary_macro);
14487 @:tertiary_}{\&{tertiary} primitive@>
14488
14489 @ @<Cases of |print_cmd...@>=
14490 case param_type:
14491   if ( m>=expr_base ) {
14492     if ( m==expr_base ) mp_print(mp, "expr");
14493     else if ( m==suffix_base ) mp_print(mp, "suffix");
14494     else mp_print(mp, "text");
14495   } else if ( m<secondary_macro ) {
14496     mp_print(mp, "primary");
14497   } else if ( m==secondary_macro ) {
14498     mp_print(mp, "secondary");
14499   } else {
14500     mp_print(mp, "tertiary");
14501   }
14502   break;
14503
14504 @ Let's turn next to the more complex processing associated with \&{def}
14505 and \&{vardef}. When the following procedure is called, |cur_mod|
14506 should be either |start_def| or |var_def|.
14507
14508 @c @<Declare the procedure called |check_delimiter|@>;
14509 @<Declare the function called |scan_declared_variable|@>;
14510 void mp_scan_def (MP mp) {
14511   int m; /* the type of definition */
14512   int n; /* the number of special suffix parameters */
14513   int k; /* the total number of parameters */
14514   int c; /* the kind of macro we're defining */
14515   pointer r; /* parameter-substitution list */
14516   pointer q; /* tail of the macro token list */
14517   pointer p; /* temporary storage */
14518   halfword base; /* |expr_base|, |suffix_base|, or |text_base| */
14519   pointer l_delim,r_delim; /* matching delimiters */
14520   m=mp->cur_mod; c=general_macro; link(hold_head)=null;
14521   q=mp_get_avail(mp); ref_count(q)=null; r=null;
14522   @<Scan the token or variable to be defined;
14523     set |n|, |scanner_status|, and |warning_info|@>;
14524   k=n;
14525   if ( mp->cur_cmd==left_delimiter ) {
14526     @<Absorb delimited parameters, putting them into lists |q| and |r|@>;
14527   }
14528   if ( mp->cur_cmd==param_type ) {
14529     @<Absorb undelimited parameters, putting them into list |r|@>;
14530   }
14531   mp_check_equals(mp);
14532   p=mp_get_avail(mp); info(p)=c; link(q)=p;
14533   @<Attach the replacement text to the tail of node |p|@>;
14534   mp->scanner_status=normal; mp_get_x_next(mp);
14535 }
14536
14537 @ We don't put `|frozen_end_group|' into the replacement text of
14538 a \&{vardef}, because the user may want to redefine `\.{endgroup}'.
14539
14540 @<Attach the replacement text to the tail of node |p|@>=
14541 if ( m==start_def ) {
14542   link(p)=mp_scan_toks(mp, macro_def,r,null,n);
14543 } else { 
14544   q=mp_get_avail(mp); info(q)=mp->bg_loc; link(p)=q;
14545   p=mp_get_avail(mp); info(p)=mp->eg_loc;
14546   link(q)=mp_scan_toks(mp, macro_def,r,p,n);
14547 }
14548 if ( mp->warning_info==bad_vardef ) 
14549   mp_flush_token_list(mp, value(bad_vardef))
14550
14551 @ @<Glob...@>=
14552 int bg_loc;
14553 int eg_loc; /* hash addresses of `\.{begingroup}' and `\.{endgroup}' */
14554
14555 @ @<Scan the token or variable to be defined;...@>=
14556 if ( m==start_def ) {
14557   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym; get_t_next;
14558   mp->scanner_status=op_defining; n=0;
14559   eq_type(mp->warning_info)=defined_macro; equiv(mp->warning_info)=q;
14560 } else { 
14561   p=mp_scan_declared_variable(mp);
14562   mp_flush_variable(mp, equiv(info(p)),link(p),true);
14563   mp->warning_info=mp_find_variable(mp, p); mp_flush_list(mp, p);
14564   if ( mp->warning_info==null ) @<Change to `\.{a bad variable}'@>;
14565   mp->scanner_status=var_defining; n=2;
14566   if ( mp->cur_cmd==macro_special ) if ( mp->cur_mod==macro_suffix ) {/* \.{\AT!\#} */
14567     n=3; get_t_next;
14568   }
14569   type(mp->warning_info)=mp_unsuffixed_macro-2+n; value(mp->warning_info)=q;
14570 } /* |mp_suffixed_macro=mp_unsuffixed_macro+1| */
14571
14572 @ @<Change to `\.{a bad variable}'@>=
14573
14574   print_err("This variable already starts with a macro");
14575 @.This variable already...@>
14576   help2("After `vardef a' you can\'t say `vardef a.b'.")
14577     ("So I'll have to discard this definition.");
14578   mp_error(mp); mp->warning_info=bad_vardef;
14579 }
14580
14581 @ @<Initialize table entries...@>=
14582 name_type(bad_vardef)=mp_root; link(bad_vardef)=frozen_bad_vardef;
14583 equiv(frozen_bad_vardef)=bad_vardef; eq_type(frozen_bad_vardef)=tag_token;
14584
14585 @ @<Absorb delimited parameters, putting them into lists |q| and |r|@>=
14586 do {  
14587   l_delim=mp->cur_sym; r_delim=mp->cur_mod; get_t_next;
14588   if ( (mp->cur_cmd==param_type)&&(mp->cur_mod>=expr_base) ) {
14589    base=mp->cur_mod;
14590   } else { 
14591     print_err("Missing parameter type; `expr' will be assumed");
14592 @.Missing parameter type@>
14593     help1("You should've had `expr' or `suffix' or `text' here.");
14594     mp_back_error(mp); base=expr_base;
14595   }
14596   @<Absorb parameter tokens for type |base|@>;
14597   mp_check_delimiter(mp, l_delim,r_delim);
14598   get_t_next;
14599 } while (mp->cur_cmd==left_delimiter)
14600
14601 @ @<Absorb parameter tokens for type |base|@>=
14602 do { 
14603   link(q)=mp_get_avail(mp); q=link(q); info(q)=base+k;
14604   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size); 
14605   value(p)=base+k; info(p)=mp->cur_sym;
14606   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14607 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14608   incr(k); link(p)=r; r=p; get_t_next;
14609 } while (mp->cur_cmd==comma)
14610
14611 @ @<Absorb undelimited parameters, putting them into list |r|@>=
14612
14613   p=mp_get_node(mp, token_node_size);
14614   if ( mp->cur_mod<expr_base ) {
14615     c=mp->cur_mod; value(p)=expr_base+k;
14616   } else { 
14617     value(p)=mp->cur_mod+k;
14618     if ( mp->cur_mod==expr_base ) c=expr_macro;
14619     else if ( mp->cur_mod==suffix_base ) c=suffix_macro;
14620     else c=text_macro;
14621   }
14622   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14623   incr(k); mp_get_symbol(mp); info(p)=mp->cur_sym; link(p)=r; r=p; get_t_next;
14624   if ( c==expr_macro ) if ( mp->cur_cmd==of_token ) {
14625     c=of_macro; p=mp_get_node(mp, token_node_size);
14626     if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14627     value(p)=expr_base+k; mp_get_symbol(mp); info(p)=mp->cur_sym;
14628     link(p)=r; r=p; get_t_next;
14629   }
14630 }
14631
14632 @* \[32] Expanding the next token.
14633 Only a few command codes |<min_command| can possibly be returned by
14634 |get_t_next|; in increasing order, they are
14635 |if_test|, |fi_or_else|, |input|, |iteration|, |repeat_loop|,
14636 |exit_test|, |relax|, |scan_tokens|, |expand_after|, and |defined_macro|.
14637
14638 \MP\ usually gets the next token of input by saying |get_x_next|. This is
14639 like |get_t_next| except that it keeps getting more tokens until
14640 finding |cur_cmd>=min_command|. In other words, |get_x_next| expands
14641 macros and removes conditionals or iterations or input instructions that
14642 might be present.
14643
14644 It follows that |get_x_next| might invoke itself recursively. In fact,
14645 there is massive recursion, since macro expansion can involve the
14646 scanning of arbitrarily complex expressions, which in turn involve
14647 macro expansion and conditionals, etc.
14648 @^recursion@>
14649
14650 Therefore it's necessary to declare a whole bunch of |forward|
14651 procedures at this point, and to insert some other procedures
14652 that will be invoked by |get_x_next|.
14653
14654 @<Declarations@>= 
14655 void mp_scan_primary (MP mp);
14656 void mp_scan_secondary (MP mp);
14657 void mp_scan_tertiary (MP mp);
14658 void mp_scan_expression (MP mp);
14659 void mp_scan_suffix (MP mp);
14660 @<Declare the procedure called |macro_call|@>;
14661 void mp_get_boolean (MP mp);
14662 void mp_pass_text (MP mp);
14663 void mp_conditional (MP mp);
14664 void mp_start_input (MP mp);
14665 void mp_begin_iteration (MP mp);
14666 void mp_resume_iteration (MP mp);
14667 void mp_stop_iteration (MP mp);
14668
14669 @ An auxiliary subroutine called |expand| is used by |get_x_next|
14670 when it has to do exotic expansion commands.
14671
14672 @c void mp_expand (MP mp) {
14673   pointer p; /* for list manipulation */
14674   size_t k; /* something that we hope is |<=buf_size| */
14675   pool_pointer j; /* index into |str_pool| */
14676   if ( mp->internal[mp_tracing_commands]>unity ) 
14677     if ( mp->cur_cmd!=defined_macro )
14678       show_cur_cmd_mod;
14679   switch (mp->cur_cmd)  {
14680   case if_test:
14681     mp_conditional(mp); /* this procedure is discussed in Part 36 below */
14682     break;
14683   case fi_or_else:
14684     @<Terminate the current conditional and skip to \&{fi}@>;
14685     break;
14686   case input:
14687     @<Initiate or terminate input from a file@>;
14688     break;
14689   case iteration:
14690     if ( mp->cur_mod==end_for ) {
14691       @<Scold the user for having an extra \&{endfor}@>;
14692     } else {
14693       mp_begin_iteration(mp); /* this procedure is discussed in Part 37 below */
14694     }
14695     break;
14696   case repeat_loop: 
14697     @<Repeat a loop@>;
14698     break;
14699   case exit_test: 
14700     @<Exit a loop if the proper time has come@>;
14701     break;
14702   case relax: 
14703     break;
14704   case expand_after: 
14705     @<Expand the token after the next token@>;
14706     break;
14707   case scan_tokens: 
14708     @<Put a string into the input buffer@>;
14709     break;
14710   case defined_macro:
14711    mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14712    break;
14713   }; /* there are no other cases */
14714 };
14715
14716 @ @<Scold the user...@>=
14717
14718   print_err("Extra `endfor'");
14719 @.Extra `endfor'@>
14720   help2("I'm not currently working on a for loop,")
14721     ("so I had better not try to end anything.");
14722   mp_error(mp);
14723 }
14724
14725 @ The processing of \&{input} involves the |start_input| subroutine,
14726 which will be declared later; the processing of \&{endinput} is trivial.
14727
14728 @<Put each...@>=
14729 mp_primitive(mp, "input",input,0);
14730 @:input_}{\&{input} primitive@>
14731 mp_primitive(mp, "endinput",input,1);
14732 @:end_input_}{\&{endinput} primitive@>
14733
14734 @ @<Cases of |print_cmd_mod|...@>=
14735 case input: 
14736   if ( m==0 ) mp_print(mp, "input");
14737   else mp_print(mp, "endinput");
14738   break;
14739
14740 @ @<Initiate or terminate input...@>=
14741 if ( mp->cur_mod>0 ) mp->force_eof=true;
14742 else mp_start_input(mp)
14743
14744 @ We'll discuss the complicated parts of loop operations later. For now
14745 it suffices to know that there's a global variable called |loop_ptr|
14746 that will be |null| if no loop is in progress.
14747
14748 @<Repeat a loop@>=
14749 { while ( token_state &&(loc==null) ) 
14750     mp_end_token_list(mp); /* conserve stack space */
14751   if ( mp->loop_ptr==null ) {
14752     print_err("Lost loop");
14753 @.Lost loop@>
14754     help2("I'm confused; after exiting from a loop, I still seem")
14755       ("to want to repeat it. I'll try to forget the problem.");
14756     mp_error(mp);
14757   } else {
14758     mp_resume_iteration(mp); /* this procedure is in Part 37 below */
14759   }
14760 }
14761
14762 @ @<Exit a loop if the proper time has come@>=
14763 { mp_get_boolean(mp);
14764   if ( mp->internal[mp_tracing_commands]>unity ) 
14765     mp_show_cmd_mod(mp, nullary,mp->cur_exp);
14766   if ( mp->cur_exp==true_code ) {
14767     if ( mp->loop_ptr==null ) {
14768       print_err("No loop is in progress");
14769 @.No loop is in progress@>
14770       help1("Why say `exitif' when there's nothing to exit from?");
14771       if ( mp->cur_cmd==semicolon ) mp_error(mp); else mp_back_error(mp);
14772     } else {
14773      @<Exit prematurely from an iteration@>;
14774     }
14775   } else if ( mp->cur_cmd!=semicolon ) {
14776     mp_missing_err(mp, ";");
14777 @.Missing `;'@>
14778     help2("After `exitif <boolean exp>' I expect to see a semicolon.")
14779     ("I shall pretend that one was there."); mp_back_error(mp);
14780   }
14781 }
14782
14783 @ Here we use the fact that |forever_text| is the only |token_type| that
14784 is less than |loop_text|.
14785
14786 @<Exit prematurely...@>=
14787 { p=null;
14788   do {  
14789     if ( file_state ) {
14790       mp_end_file_reading(mp);
14791     } else { 
14792       if ( token_type<=loop_text ) p=start;
14793       mp_end_token_list(mp);
14794     }
14795   } while (p==null);
14796   if ( p!=info(mp->loop_ptr) ) mp_fatal_error(mp, "*** (loop confusion)");
14797 @.loop confusion@>
14798   mp_stop_iteration(mp); /* this procedure is in Part 34 below */
14799 }
14800
14801 @ @<Expand the token after the next token@>=
14802 { get_t_next;
14803   p=mp_cur_tok(mp); get_t_next;
14804   if ( mp->cur_cmd<min_command ) mp_expand(mp); 
14805   else mp_back_input(mp);
14806   back_list(p);
14807 }
14808
14809 @ @<Put a string into the input buffer@>=
14810 { mp_get_x_next(mp); mp_scan_primary(mp);
14811   if ( mp->cur_type!=mp_string_type ) {
14812     mp_disp_err(mp, null,"Not a string");
14813 @.Not a string@>
14814     help2("I'm going to flush this expression, since")
14815        ("scantokens should be followed by a known string.");
14816     mp_put_get_flush_error(mp, 0);
14817   } else { 
14818     mp_back_input(mp);
14819     if ( length(mp->cur_exp)>0 )
14820        @<Pretend we're reading a new one-line file@>;
14821   }
14822 }
14823
14824 @ @<Pretend we're reading a new one-line file@>=
14825 { mp_begin_file_reading(mp); name=is_scantok;
14826   k=mp->first+length(mp->cur_exp);
14827   if ( k>=mp->max_buf_stack ) {
14828     while ( k>=mp->buf_size ) {
14829       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
14830     }
14831     mp->max_buf_stack=k+1;
14832   }
14833   j=mp->str_start[mp->cur_exp]; limit=k;
14834   while ( mp->first<(size_t)limit ) {
14835     mp->buffer[mp->first]=mp->str_pool[j]; incr(j); incr(mp->first);
14836   }
14837   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; 
14838   mp_flush_cur_exp(mp, 0);
14839 }
14840
14841 @ Here finally is |get_x_next|.
14842
14843 The expression scanning routines to be considered later
14844 communicate via the global quantities |cur_type| and |cur_exp|;
14845 we must be very careful to save and restore these quantities while
14846 macros are being expanded.
14847 @^inner loop@>
14848
14849 @<Declarations@>=
14850 void mp_get_x_next (MP mp);
14851
14852 @ @c void mp_get_x_next (MP mp) {
14853   pointer save_exp; /* a capsule to save |cur_type| and |cur_exp| */
14854   get_t_next;
14855   if ( mp->cur_cmd<min_command ) {
14856     save_exp=mp_stash_cur_exp(mp);
14857     do {  
14858       if ( mp->cur_cmd==defined_macro ) 
14859         mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14860       else 
14861         mp_expand(mp);
14862       get_t_next;
14863      } while (mp->cur_cmd<min_command);
14864      mp_unstash_cur_exp(mp, save_exp); /* that restores |cur_type| and |cur_exp| */
14865   }
14866 }
14867
14868 @ Now let's consider the |macro_call| procedure, which is used to start up
14869 all user-defined macros. Since the arguments to a macro might be expressions,
14870 |macro_call| is recursive.
14871 @^recursion@>
14872
14873 The first parameter to |macro_call| points to the reference count of the
14874 token list that defines the macro. The second parameter contains any
14875 arguments that have already been parsed (see below).  The third parameter
14876 points to the symbolic token that names the macro. If the third parameter
14877 is |null|, the macro was defined by \&{vardef}, so its name can be
14878 reconstructed from the prefix and ``at'' arguments found within the
14879 second parameter.
14880
14881 What is this second parameter? It's simply a linked list of one-word items,
14882 whose |info| fields point to the arguments. In other words, if |arg_list=null|,
14883 no arguments have been scanned yet; otherwise |info(arg_list)| points to
14884 the first scanned argument, and |link(arg_list)| points to the list of
14885 further arguments (if any).
14886
14887 Arguments of type \&{expr} are so-called capsules, which we will
14888 discuss later when we concentrate on expressions; they can be
14889 recognized easily because their |link| field is |void|. Arguments of type
14890 \&{suffix} and \&{text} are token lists without reference counts.
14891
14892 @ After argument scanning is complete, the arguments are moved to the
14893 |param_stack|. (They can't be put on that stack any sooner, because
14894 the stack is growing and shrinking in unpredictable ways as more arguments
14895 are being acquired.)  Then the macro body is fed to the scanner; i.e.,
14896 the replacement text of the macro is placed at the top of the \MP's
14897 input stack, so that |get_t_next| will proceed to read it next.
14898
14899 @<Declare the procedure called |macro_call|@>=
14900 @<Declare the procedure called |print_macro_name|@>;
14901 @<Declare the procedure called |print_arg|@>;
14902 @<Declare the procedure called |scan_text_arg|@>;
14903 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14904                     pointer macro_name) ;
14905
14906 @ @c
14907 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14908                     pointer macro_name) {
14909   /* invokes a user-defined control sequence */
14910   pointer r; /* current node in the macro's token list */
14911   pointer p,q; /* for list manipulation */
14912   integer n; /* the number of arguments */
14913   pointer tail = 0; /* tail of the argument list */
14914   pointer l_delim=0,r_delim=0; /* a delimiter pair */
14915   r=link(def_ref); add_mac_ref(def_ref);
14916   if ( arg_list==null ) {
14917     n=0;
14918   } else {
14919    @<Determine the number |n| of arguments already supplied,
14920     and set |tail| to the tail of |arg_list|@>;
14921   }
14922   if ( mp->internal[mp_tracing_macros]>0 ) {
14923     @<Show the text of the macro being expanded, and the existing arguments@>;
14924   }
14925   @<Scan the remaining arguments, if any; set |r| to the first token
14926     of the replacement text@>;
14927   @<Feed the arguments and replacement text to the scanner@>;
14928 }
14929
14930 @ @<Show the text of the macro...@>=
14931 mp_begin_diagnostic(mp); mp_print_ln(mp); 
14932 mp_print_macro_name(mp, arg_list,macro_name);
14933 if ( n==3 ) mp_print(mp, "@@#"); /* indicate a suffixed macro */
14934 mp_show_macro(mp, def_ref,null,100000);
14935 if ( arg_list!=null ) {
14936   n=0; p=arg_list;
14937   do {  
14938     q=info(p);
14939     mp_print_arg(mp, q,n,0);
14940     incr(n); p=link(p);
14941   } while (p!=null);
14942 }
14943 mp_end_diagnostic(mp, false)
14944
14945
14946 @ @<Declare the procedure called |print_macro_name|@>=
14947 void mp_print_macro_name (MP mp,pointer a, pointer n);
14948
14949 @ @c
14950 void mp_print_macro_name (MP mp,pointer a, pointer n) {
14951   pointer p,q; /* they traverse the first part of |a| */
14952   if ( n!=null ) {
14953     mp_print_text(n);
14954   } else  { 
14955     p=info(a);
14956     if ( p==null ) {
14957       mp_print_text(info(info(link(a))));
14958     } else { 
14959       q=p;
14960       while ( link(q)!=null ) q=link(q);
14961       link(q)=info(link(a));
14962       mp_show_token_list(mp, p,null,1000,0);
14963       link(q)=null;
14964     }
14965   }
14966 }
14967
14968 @ @<Declare the procedure called |print_arg|@>=
14969 void mp_print_arg (MP mp,pointer q, integer n, pointer b) ;
14970
14971 @ @c
14972 void mp_print_arg (MP mp,pointer q, integer n, pointer b) {
14973   if ( link(q)==mp_void ) mp_print_nl(mp, "(EXPR");
14974   else if ( (b<text_base)&&(b!=text_macro) ) mp_print_nl(mp, "(SUFFIX");
14975   else mp_print_nl(mp, "(TEXT");
14976   mp_print_int(mp, n); mp_print(mp, ")<-");
14977   if ( link(q)==mp_void ) mp_print_exp(mp, q,1);
14978   else mp_show_token_list(mp, q,null,1000,0);
14979 }
14980
14981 @ @<Determine the number |n| of arguments already supplied...@>=
14982 {  
14983   n=1; tail=arg_list;
14984   while ( link(tail)!=null ) { 
14985     incr(n); tail=link(tail);
14986   }
14987 }
14988
14989 @ @<Scan the remaining arguments, if any; set |r|...@>=
14990 mp->cur_cmd=comma+1; /* anything |<>comma| will do */
14991 while ( info(r)>=expr_base ) { 
14992   @<Scan the delimited argument represented by |info(r)|@>;
14993   r=link(r);
14994 };
14995 if ( mp->cur_cmd==comma ) {
14996   print_err("Too many arguments to ");
14997 @.Too many arguments...@>
14998   mp_print_macro_name(mp, arg_list,macro_name); mp_print_char(mp, ';');
14999   mp_print_nl(mp, "  Missing `"); mp_print_text(r_delim);
15000 @.Missing `)'...@>
15001   mp_print(mp, "' has been inserted");
15002   help3("I'm going to assume that the comma I just read was a")
15003    ("right delimiter, and then I'll begin expanding the macro.")
15004    ("You might want to delete some tokens before continuing.");
15005   mp_error(mp);
15006 }
15007 if ( info(r)!=general_macro ) {
15008   @<Scan undelimited argument(s)@>;
15009 }
15010 r=link(r)
15011
15012 @ At this point, the reader will find it advisable to review the explanation
15013 of token list format that was presented earlier, paying special attention to
15014 the conventions that apply only at the beginning of a macro's token list.
15015
15016 On the other hand, the reader will have to take the expression-parsing
15017 aspects of the following program on faith; we will explain |cur_type|
15018 and |cur_exp| later. (Several things in this program depend on each other,
15019 and it's necessary to jump into the circle somewhere.)
15020
15021 @<Scan the delimited argument represented by |info(r)|@>=
15022 if ( mp->cur_cmd!=comma ) {
15023   mp_get_x_next(mp);
15024   if ( mp->cur_cmd!=left_delimiter ) {
15025     print_err("Missing argument to ");
15026 @.Missing argument...@>
15027     mp_print_macro_name(mp, arg_list,macro_name);
15028     help3("That macro has more parameters than you thought.")
15029      ("I'll continue by pretending that each missing argument")
15030      ("is either zero or null.");
15031     if ( info(r)>=suffix_base ) {
15032       mp->cur_exp=null; mp->cur_type=mp_token_list;
15033     } else { 
15034       mp->cur_exp=0; mp->cur_type=mp_known;
15035     }
15036     mp_back_error(mp); mp->cur_cmd=right_delimiter; 
15037     goto FOUND;
15038   }
15039   l_delim=mp->cur_sym; r_delim=mp->cur_mod;
15040 }
15041 @<Scan the argument represented by |info(r)|@>;
15042 if ( mp->cur_cmd!=comma ) 
15043   @<Check that the proper right delimiter was present@>;
15044 FOUND:  
15045 @<Append the current expression to |arg_list|@>
15046
15047 @ @<Check that the proper right delim...@>=
15048 if ( (mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
15049   if ( info(link(r))>=expr_base ) {
15050     mp_missing_err(mp, ",");
15051 @.Missing `,'@>
15052     help3("I've finished reading a macro argument and am about to")
15053       ("read another; the arguments weren't delimited correctly.")
15054        ("You might want to delete some tokens before continuing.");
15055     mp_back_error(mp); mp->cur_cmd=comma;
15056   } else { 
15057     mp_missing_err(mp, str(text(r_delim)));
15058 @.Missing `)'@>
15059     help2("I've gotten to the end of the macro parameter list.")
15060        ("You might want to delete some tokens before continuing.");
15061     mp_back_error(mp);
15062   }
15063 }
15064
15065 @ A \&{suffix} or \&{text} parameter will be have been scanned as
15066 a token list pointed to by |cur_exp|, in which case we will have
15067 |cur_type=token_list|.
15068
15069 @<Append the current expression to |arg_list|@>=
15070
15071   p=mp_get_avail(mp);
15072   if ( mp->cur_type==mp_token_list ) info(p)=mp->cur_exp;
15073   else info(p)=mp_stash_cur_exp(mp);
15074   if ( mp->internal[mp_tracing_macros]>0 ) {
15075     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,info(r)); 
15076     mp_end_diagnostic(mp, false);
15077   }
15078   if ( arg_list==null ) arg_list=p;
15079   else link(tail)=p;
15080   tail=p; incr(n);
15081 }
15082
15083 @ @<Scan the argument represented by |info(r)|@>=
15084 if ( info(r)>=text_base ) {
15085   mp_scan_text_arg(mp, l_delim,r_delim);
15086 } else { 
15087   mp_get_x_next(mp);
15088   if ( info(r)>=suffix_base ) mp_scan_suffix(mp);
15089   else mp_scan_expression(mp);
15090 }
15091
15092 @ The parameters to |scan_text_arg| are either a pair of delimiters
15093 or zero; the latter case is for undelimited text arguments, which
15094 end with the first semicolon or \&{endgroup} or \&{end} that is not
15095 contained in a group.
15096
15097 @<Declare the procedure called |scan_text_arg|@>=
15098 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) ;
15099
15100 @ @c
15101 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) {
15102   integer balance; /* excess of |l_delim| over |r_delim| */
15103   pointer p; /* list tail */
15104   mp->warning_info=l_delim; mp->scanner_status=absorbing;
15105   p=hold_head; balance=1; link(hold_head)=null;
15106   while (1)  { 
15107     get_t_next;
15108     if ( l_delim==0 ) {
15109       @<Adjust the balance for an undelimited argument; |break| if done@>;
15110     } else {
15111           @<Adjust the balance for a delimited argument; |break| if done@>;
15112     }
15113     link(p)=mp_cur_tok(mp); p=link(p);
15114   }
15115   mp->cur_exp=link(hold_head); mp->cur_type=mp_token_list;
15116   mp->scanner_status=normal;
15117 };
15118
15119 @ @<Adjust the balance for a delimited argument...@>=
15120 if ( mp->cur_cmd==right_delimiter ) { 
15121   if ( mp->cur_mod==l_delim ) { 
15122     decr(balance);
15123     if ( balance==0 ) break;
15124   }
15125 } else if ( mp->cur_cmd==left_delimiter ) {
15126   if ( mp->cur_mod==r_delim ) incr(balance);
15127 }
15128
15129 @ @<Adjust the balance for an undelimited...@>=
15130 if ( end_of_statement ) { /* |cur_cmd=semicolon|, |end_group|, or |stop| */
15131   if ( balance==1 ) { break; }
15132   else  { if ( mp->cur_cmd==end_group ) decr(balance); }
15133 } else if ( mp->cur_cmd==begin_group ) { 
15134   incr(balance); 
15135 }
15136
15137 @ @<Scan undelimited argument(s)@>=
15138
15139   if ( info(r)<text_macro ) {
15140     mp_get_x_next(mp);
15141     if ( info(r)!=suffix_macro ) {
15142       if ( (mp->cur_cmd==equals)||(mp->cur_cmd==assignment) ) mp_get_x_next(mp);
15143     }
15144   }
15145   switch (info(r)) {
15146   case primary_macro:mp_scan_primary(mp); break;
15147   case secondary_macro:mp_scan_secondary(mp); break;
15148   case tertiary_macro:mp_scan_tertiary(mp); break;
15149   case expr_macro:mp_scan_expression(mp); break;
15150   case of_macro:
15151     @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>;
15152     break;
15153   case suffix_macro:
15154     @<Scan a suffix with optional delimiters@>;
15155     break;
15156   case text_macro:mp_scan_text_arg(mp, 0,0); break;
15157   } /* there are no other cases */
15158   mp_back_input(mp); 
15159   @<Append the current expression to |arg_list|@>;
15160 }
15161
15162 @ @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>=
15163
15164   mp_scan_expression(mp); p=mp_get_avail(mp); info(p)=mp_stash_cur_exp(mp);
15165   if ( mp->internal[mp_tracing_macros]>0 ) { 
15166     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,0); 
15167     mp_end_diagnostic(mp, false);
15168   }
15169   if ( arg_list==null ) arg_list=p; else link(tail)=p;
15170   tail=p;incr(n);
15171   if ( mp->cur_cmd!=of_token ) {
15172     mp_missing_err(mp, "of"); mp_print(mp, " for ");
15173 @.Missing `of'@>
15174     mp_print_macro_name(mp, arg_list,macro_name);
15175     help1("I've got the first argument; will look now for the other.");
15176     mp_back_error(mp);
15177   }
15178   mp_get_x_next(mp); mp_scan_primary(mp);
15179 }
15180
15181 @ @<Scan a suffix with optional delimiters@>=
15182
15183   if ( mp->cur_cmd!=left_delimiter ) {
15184     l_delim=null;
15185   } else { 
15186     l_delim=mp->cur_sym; r_delim=mp->cur_mod; mp_get_x_next(mp);
15187   };
15188   mp_scan_suffix(mp);
15189   if ( l_delim!=null ) {
15190     if ((mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
15191       mp_missing_err(mp, str(text(r_delim)));
15192 @.Missing `)'@>
15193       help2("I've gotten to the end of the macro parameter list.")
15194          ("You might want to delete some tokens before continuing.");
15195       mp_back_error(mp);
15196     }
15197     mp_get_x_next(mp);
15198   }
15199 }
15200
15201 @ Before we put a new token list on the input stack, it is wise to clean off
15202 all token lists that have recently been depleted. Then a user macro that ends
15203 with a call to itself will not require unbounded stack space.
15204
15205 @<Feed the arguments and replacement text to the scanner@>=
15206 while ( token_state &&(loc==null) ) mp_end_token_list(mp); /* conserve stack space */
15207 if ( mp->param_ptr+n>mp->max_param_stack ) {
15208   mp->max_param_stack=mp->param_ptr+n;
15209   if ( mp->max_param_stack>mp->param_size )
15210     mp_overflow(mp, "parameter stack size",mp->param_size);
15211 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
15212 }
15213 mp_begin_token_list(mp, def_ref,macro); name=macro_name; loc=r;
15214 if ( n>0 ) {
15215   p=arg_list;
15216   do {  
15217    mp->param_stack[mp->param_ptr]=info(p); incr(mp->param_ptr); p=link(p);
15218   } while (p!=null);
15219   mp_flush_list(mp, arg_list);
15220 }
15221
15222 @ It's sometimes necessary to put a single argument onto |param_stack|.
15223 The |stack_argument| subroutine does this.
15224
15225 @c void mp_stack_argument (MP mp,pointer p) { 
15226   if ( mp->param_ptr==mp->max_param_stack ) {
15227     incr(mp->max_param_stack);
15228     if ( mp->max_param_stack>mp->param_size )
15229       mp_overflow(mp, "parameter stack size",mp->param_size);
15230 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
15231   }
15232   mp->param_stack[mp->param_ptr]=p; incr(mp->param_ptr);
15233 }
15234
15235 @* \[33] Conditional processing.
15236 Let's consider now the way \&{if} commands are handled.
15237
15238 Conditions can be inside conditions, and this nesting has a stack
15239 that is independent of other stacks.
15240 Four global variables represent the top of the condition stack:
15241 |cond_ptr| points to pushed-down entries, if~any; |cur_if| tells whether
15242 we are processing \&{if} or \&{elseif}; |if_limit| specifies
15243 the largest code of a |fi_or_else| command that is syntactically legal;
15244 and |if_line| is the line number at which the current conditional began.
15245
15246 If no conditions are currently in progress, the condition stack has the
15247 special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
15248 Otherwise |cond_ptr| points to a two-word node; the |type|, |name_type|, and
15249 |link| fields of the first word contain |if_limit|, |cur_if|, and
15250 |cond_ptr| at the next level, and the second word contains the
15251 corresponding |if_line|.
15252
15253 @d if_node_size 2 /* number of words in stack entry for conditionals */
15254 @d if_line_field(A) mp->mem[(A)+1].cint
15255 @d if_code 1 /* code for \&{if} being evaluated */
15256 @d fi_code 2 /* code for \&{fi} */
15257 @d else_code 3 /* code for \&{else} */
15258 @d else_if_code 4 /* code for \&{elseif} */
15259
15260 @<Glob...@>=
15261 pointer cond_ptr; /* top of the condition stack */
15262 integer if_limit; /* upper bound on |fi_or_else| codes */
15263 small_number cur_if; /* type of conditional being worked on */
15264 integer if_line; /* line where that conditional began */
15265
15266 @ @<Set init...@>=
15267 mp->cond_ptr=null; mp->if_limit=normal; mp->cur_if=0; mp->if_line=0;
15268
15269 @ @<Put each...@>=
15270 mp_primitive(mp, "if",if_test,if_code);
15271 @:if_}{\&{if} primitive@>
15272 mp_primitive(mp, "fi",fi_or_else,fi_code); mp->eqtb[frozen_fi]=mp->eqtb[mp->cur_sym];
15273 @:fi_}{\&{fi} primitive@>
15274 mp_primitive(mp, "else",fi_or_else,else_code);
15275 @:else_}{\&{else} primitive@>
15276 mp_primitive(mp, "elseif",fi_or_else,else_if_code);
15277 @:else_if_}{\&{elseif} primitive@>
15278
15279 @ @<Cases of |print_cmd_mod|...@>=
15280 case if_test:
15281 case fi_or_else: 
15282   switch (m) {
15283   case if_code:mp_print(mp, "if"); break;
15284   case fi_code:mp_print(mp, "fi");  break;
15285   case else_code:mp_print(mp, "else"); break;
15286   default: mp_print(mp, "elseif"); break;
15287   }
15288   break;
15289
15290 @ Here is a procedure that ignores text until coming to an \&{elseif},
15291 \&{else}, or \&{fi} at level zero of $\&{if}\ldots\&{fi}$
15292 nesting. After it has acted, |cur_mod| will indicate the token that
15293 was found.
15294
15295 \MP's smallest two command codes are |if_test| and |fi_or_else|; this
15296 makes the skipping process a bit simpler.
15297
15298 @c 
15299 void mp_pass_text (MP mp) {
15300   integer l = 0;
15301   mp->scanner_status=skipping;
15302   mp->warning_info=mp_true_line(mp);
15303   while (1)  { 
15304     get_t_next;
15305     if ( mp->cur_cmd<=fi_or_else ) {
15306       if ( mp->cur_cmd<fi_or_else ) {
15307         incr(l);
15308       } else { 
15309         if ( l==0 ) break;
15310         if ( mp->cur_mod==fi_code ) decr(l);
15311       }
15312     } else {
15313       @<Decrease the string reference count,
15314        if the current token is a string@>;
15315     }
15316   }
15317   mp->scanner_status=normal;
15318 }
15319
15320 @ @<Decrease the string reference count...@>=
15321 if ( mp->cur_cmd==string_token ) { delete_str_ref(mp->cur_mod); }
15322
15323 @ When we begin to process a new \&{if}, we set |if_limit:=if_code|; then
15324 if \&{elseif} or \&{else} or \&{fi} occurs before the current \&{if}
15325 condition has been evaluated, a colon will be inserted.
15326 A construction like `\.{if fi}' would otherwise get \MP\ confused.
15327
15328 @<Push the condition stack@>=
15329 { p=mp_get_node(mp, if_node_size); link(p)=mp->cond_ptr; type(p)=mp->if_limit;
15330   name_type(p)=mp->cur_if; if_line_field(p)=mp->if_line;
15331   mp->cond_ptr=p; mp->if_limit=if_code; mp->if_line=mp_true_line(mp); 
15332   mp->cur_if=if_code;
15333 }
15334
15335 @ @<Pop the condition stack@>=
15336 { p=mp->cond_ptr; mp->if_line=if_line_field(p);
15337   mp->cur_if=name_type(p); mp->if_limit=type(p); mp->cond_ptr=link(p);
15338   mp_free_node(mp, p,if_node_size);
15339 }
15340
15341 @ Here's a procedure that changes the |if_limit| code corresponding to
15342 a given value of |cond_ptr|.
15343
15344 @c void mp_change_if_limit (MP mp,small_number l, pointer p) {
15345   pointer q;
15346   if ( p==mp->cond_ptr ) {
15347     mp->if_limit=l; /* that's the easy case */
15348   } else  { 
15349     q=mp->cond_ptr;
15350     while (1) { 
15351       if ( q==null ) mp_confusion(mp, "if");
15352 @:this can't happen if}{\quad if@>
15353       if ( link(q)==p ) { 
15354         type(q)=l; return;
15355       }
15356       q=link(q);
15357     }
15358   }
15359 }
15360
15361 @ The user is supposed to put colons into the proper parts of conditional
15362 statements. Therefore, \MP\ has to check for their presence.
15363
15364 @c 
15365 void mp_check_colon (MP mp) { 
15366   if ( mp->cur_cmd!=colon ) { 
15367     mp_missing_err(mp, ":");
15368 @.Missing `:'@>
15369     help2("There should've been a colon after the condition.")
15370          ("I shall pretend that one was there.");;
15371     mp_back_error(mp);
15372   }
15373 }
15374
15375 @ A condition is started when the |get_x_next| procedure encounters
15376 an |if_test| command; in that case |get_x_next| calls |conditional|,
15377 which is a recursive procedure.
15378 @^recursion@>
15379
15380 @c void mp_conditional (MP mp) {
15381   pointer save_cond_ptr; /* |cond_ptr| corresponding to this conditional */
15382   int new_if_limit; /* future value of |if_limit| */
15383   pointer p; /* temporary register */
15384   @<Push the condition stack@>; 
15385   save_cond_ptr=mp->cond_ptr;
15386 RESWITCH: 
15387   mp_get_boolean(mp); new_if_limit=else_if_code;
15388   if ( mp->internal[mp_tracing_commands]>unity ) {
15389     @<Display the boolean value of |cur_exp|@>;
15390   }
15391 FOUND: 
15392   mp_check_colon(mp);
15393   if ( mp->cur_exp==true_code ) {
15394     mp_change_if_limit(mp, new_if_limit,save_cond_ptr);
15395     return; /* wait for \&{elseif}, \&{else}, or \&{fi} */
15396   };
15397   @<Skip to \&{elseif} or \&{else} or \&{fi}, then |goto done|@>;
15398 DONE: 
15399   mp->cur_if=mp->cur_mod; mp->if_line=mp_true_line(mp);
15400   if ( mp->cur_mod==fi_code ) {
15401     @<Pop the condition stack@>
15402   } else if ( mp->cur_mod==else_if_code ) {
15403     goto RESWITCH;
15404   } else  { 
15405     mp->cur_exp=true_code; new_if_limit=fi_code; mp_get_x_next(mp); 
15406     goto FOUND;
15407   }
15408 }
15409
15410 @ In a construction like `\&{if} \&{if} \&{true}: $0=1$: \\{foo}
15411 \&{else}: \\{bar} \&{fi}', the first \&{else}
15412 that we come to after learning that the \&{if} is false is not the
15413 \&{else} we're looking for. Hence the following curious logic is needed.
15414
15415 @<Skip to \&{elseif}...@>=
15416 while (1) { 
15417   mp_pass_text(mp);
15418   if ( mp->cond_ptr==save_cond_ptr ) goto DONE;
15419   else if ( mp->cur_mod==fi_code ) @<Pop the condition stack@>;
15420 }
15421
15422
15423 @ @<Display the boolean value...@>=
15424 { mp_begin_diagnostic(mp);
15425   if ( mp->cur_exp==true_code ) mp_print(mp, "{true}");
15426   else mp_print(mp, "{false}");
15427   mp_end_diagnostic(mp, false);
15428 }
15429
15430 @ The processing of conditionals is complete except for the following
15431 code, which is actually part of |get_x_next|. It comes into play when
15432 \&{elseif}, \&{else}, or \&{fi} is scanned.
15433
15434 @<Terminate the current conditional and skip to \&{fi}@>=
15435 if ( mp->cur_mod>mp->if_limit ) {
15436   if ( mp->if_limit==if_code ) { /* condition not yet evaluated */
15437     mp_missing_err(mp, ":");
15438 @.Missing `:'@>
15439     mp_back_input(mp); mp->cur_sym=frozen_colon; mp_ins_error(mp);
15440   } else  { 
15441     print_err("Extra "); mp_print_cmd_mod(mp, fi_or_else,mp->cur_mod);
15442 @.Extra else@>
15443 @.Extra elseif@>
15444 @.Extra fi@>
15445     help1("I'm ignoring this; it doesn't match any if.");
15446     mp_error(mp);
15447   }
15448 } else  { 
15449   while ( mp->cur_mod!=fi_code ) mp_pass_text(mp); /* skip to \&{fi} */
15450   @<Pop the condition stack@>;
15451 }
15452
15453 @* \[34] Iterations.
15454 To bring our treatment of |get_x_next| to a close, we need to consider what
15455 \MP\ does when it sees \&{for}, \&{forsuffixes}, and \&{forever}.
15456
15457 There's a global variable |loop_ptr| that keeps track of the \&{for} loops
15458 that are currently active. If |loop_ptr=null|, no loops are in progress;
15459 otherwise |info(loop_ptr)| points to the iterative text of the current
15460 (innermost) loop, and |link(loop_ptr)| points to the data for any other
15461 loops that enclose the current one.
15462
15463 A loop-control node also has two other fields, called |loop_type| and
15464 |loop_list|, whose contents depend on the type of loop:
15465
15466 \yskip\indent|loop_type(loop_ptr)=null| means that |loop_list(loop_ptr)|
15467 points to a list of one-word nodes whose |info| fields point to the
15468 remaining argument values of a suffix list and expression list.
15469
15470 \yskip\indent|loop_type(loop_ptr)=mp_void| means that the current loop is
15471 `\&{forever}'.
15472
15473 \yskip\indent|loop_type(loop_ptr)=progression_flag| means that
15474 |p=loop_list(loop_ptr)| points to a ``progression node'' and |value(p)|,
15475 |step_size(p)|, and |final_value(p)| contain the data for an arithmetic
15476 progression.
15477
15478 \yskip\indent|loop_type(loop_ptr)=p>mp_void| means that |p| points to an edge
15479 header and |loop_list(loop_ptr)| points into the graphical object list for
15480 that edge header.
15481
15482 \yskip\noindent In the case of a progression node, the first word is not used
15483 because the link field of words in the dynamic memory area cannot be arbitrary.
15484
15485 @d loop_list_loc(A) ((A)+1) /* where the |loop_list| field resides */
15486 @d loop_type(A) info(loop_list_loc((A))) /* the type of \&{for} loop */
15487 @d loop_list(A) link(loop_list_loc((A))) /* the remaining list elements */
15488 @d loop_node_size 2 /* the number of words in a loop control node */
15489 @d progression_node_size 4 /* the number of words in a progression node */
15490 @d step_size(A) mp->mem[(A)+2].sc /* the step size in an arithmetic progression */
15491 @d final_value(A) mp->mem[(A)+3].sc /* the final value in an arithmetic progression */
15492 @d progression_flag (null+2)
15493   /* |loop_type| value when |loop_list| points to a progression node */
15494
15495 @<Glob...@>=
15496 pointer loop_ptr; /* top of the loop-control-node stack */
15497
15498 @ @<Set init...@>=
15499 mp->loop_ptr=null;
15500
15501 @ If the expressions that define an arithmetic progression in
15502 a \&{for} loop don't have known numeric values, the |bad_for|
15503 subroutine screams at the user.
15504
15505 @c void mp_bad_for (MP mp, char * s) {
15506   mp_disp_err(mp, null,"Improper "); /* show the bad expression above the message */
15507 @.Improper...replaced by 0@>
15508   mp_print(mp, s); mp_print(mp, " has been replaced by 0");
15509   help4("When you say `for x=a step b until c',")
15510     ("the initial value `a' and the step size `b'")
15511     ("and the final value `c' must have known numeric values.")
15512     ("I'm zeroing this one. Proceed, with fingers crossed.");
15513   mp_put_get_flush_error(mp, 0);
15514 };
15515
15516 @ Here's what \MP\ does when \&{for}, \&{forsuffixes}, or \&{forever}
15517 has just been scanned. (This code requires slight familiarity with
15518 expression-parsing routines that we have not yet discussed; but it seems
15519 to belong in the present part of the program, even though the original author
15520 didn't write it until later. The reader may wish to come back to it.)
15521
15522 @c void mp_begin_iteration (MP mp) {
15523   halfword m; /* |expr_base| (\&{for}) or |suffix_base| (\&{forsuffixes}) */
15524   halfword n; /* hash address of the current symbol */
15525   pointer s; /* the new loop-control node */
15526   pointer p; /* substitution list for |scan_toks| */
15527   pointer q;  /* link manipulation register */
15528   pointer pp; /* a new progression node */
15529   m=mp->cur_mod; n=mp->cur_sym; s=mp_get_node(mp, loop_node_size);
15530   if ( m==start_forever ){ 
15531     loop_type(s)=mp_void; p=null; mp_get_x_next(mp);
15532   } else { 
15533     mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
15534     info(p)=mp->cur_sym; value(p)=m;
15535     mp_get_x_next(mp);
15536     if ( mp->cur_cmd==within_token ) {
15537       @<Set up a picture iteration@>;
15538     } else { 
15539       @<Check for the |"="| or |":="| in a loop header@>;
15540       @<Scan the values to be used in the loop@>;
15541     }
15542   }
15543   @<Check for the presence of a colon@>;
15544   @<Scan the loop text and put it on the loop control stack@>;
15545   mp_resume_iteration(mp);
15546 }
15547
15548 @ @<Check for the |"="| or |":="| in a loop header@>=
15549 if ( (mp->cur_cmd!=equals)&&(mp->cur_cmd!=assignment) ) { 
15550   mp_missing_err(mp, "=");
15551 @.Missing `='@>
15552   help3("The next thing in this loop should have been `=' or `:='.")
15553     ("But don't worry; I'll pretend that an equals sign")
15554     ("was present, and I'll look for the values next.");
15555   mp_back_error(mp);
15556 }
15557
15558 @ @<Check for the presence of a colon@>=
15559 if ( mp->cur_cmd!=colon ) { 
15560   mp_missing_err(mp, ":");
15561 @.Missing `:'@>
15562   help3("The next thing in this loop should have been a `:'.")
15563     ("So I'll pretend that a colon was present;")
15564     ("everything from here to `endfor' will be iterated.");
15565   mp_back_error(mp);
15566 }
15567
15568 @ We append a special |frozen_repeat_loop| token in place of the
15569 `\&{endfor}' at the end of the loop. This will come through \MP's scanner
15570 at the proper time to cause the loop to be repeated.
15571
15572 (If the user tries some shenanigan like `\&{for} $\ldots$ \&{let} \&{endfor}',
15573 he will be foiled by the |get_symbol| routine, which keeps frozen
15574 tokens unchanged. Furthermore the |frozen_repeat_loop| is an \&{outer}
15575 token, so it won't be lost accidentally.)
15576
15577 @ @<Scan the loop text...@>=
15578 q=mp_get_avail(mp); info(q)=frozen_repeat_loop;
15579 mp->scanner_status=loop_defining; mp->warning_info=n;
15580 info(s)=mp_scan_toks(mp, iteration,p,q,0); mp->scanner_status=normal;
15581 link(s)=mp->loop_ptr; mp->loop_ptr=s
15582
15583 @ @<Initialize table...@>=
15584 eq_type(frozen_repeat_loop)=repeat_loop+outer_tag;
15585 text(frozen_repeat_loop)=intern(" ENDFOR");
15586
15587 @ The loop text is inserted into \MP's scanning apparatus by the
15588 |resume_iteration| routine.
15589
15590 @c void mp_resume_iteration (MP mp) {
15591   pointer p,q; /* link registers */
15592   p=loop_type(mp->loop_ptr);
15593   if ( p==progression_flag ) { 
15594     p=loop_list(mp->loop_ptr); /* now |p| points to a progression node */
15595     mp->cur_exp=value(p);
15596     if ( @<The arithmetic progression has ended@> ) {
15597       mp_stop_iteration(mp);
15598       return;
15599     }
15600     mp->cur_type=mp_known; q=mp_stash_cur_exp(mp); /* make |q| an \&{expr} argument */
15601     value(p)=mp->cur_exp+step_size(p); /* set |value(p)| for the next iteration */
15602   } else if ( p==null ) { 
15603     p=loop_list(mp->loop_ptr);
15604     if ( p==null ) {
15605       mp_stop_iteration(mp);
15606       return;
15607     }
15608     loop_list(mp->loop_ptr)=link(p); q=info(p); free_avail(p);
15609   } else if ( p==mp_void ) { 
15610     mp_begin_token_list(mp, info(mp->loop_ptr),forever_text); return;
15611   } else {
15612     @<Make |q| a capsule containing the next picture component from
15613       |loop_list(loop_ptr)| or |goto not_found|@>;
15614   }
15615   mp_begin_token_list(mp, info(mp->loop_ptr),loop_text);
15616   mp_stack_argument(mp, q);
15617   if ( mp->internal[mp_tracing_commands]>unity ) {
15618      @<Trace the start of a loop@>;
15619   }
15620   return;
15621 NOT_FOUND:
15622   mp_stop_iteration(mp);
15623 }
15624
15625 @ @<The arithmetic progression has ended@>=
15626 ((step_size(p)>0)&&(mp->cur_exp>final_value(p)))||
15627  ((step_size(p)<0)&&(mp->cur_exp<final_value(p)))
15628
15629 @ @<Trace the start of a loop@>=
15630
15631   mp_begin_diagnostic(mp); mp_print_nl(mp, "{loop value=");
15632 @.loop value=n@>
15633   if ( (q!=null)&&(link(q)==mp_void) ) mp_print_exp(mp, q,1);
15634   else mp_show_token_list(mp, q,null,50,0);
15635   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
15636 }
15637
15638 @ @<Make |q| a capsule containing the next picture component from...@>=
15639 { q=loop_list(mp->loop_ptr);
15640   if ( q==null ) goto NOT_FOUND;
15641   skip_component(q) goto NOT_FOUND;
15642   mp->cur_exp=mp_copy_objects(mp, loop_list(mp->loop_ptr),q);
15643   mp_init_bbox(mp, mp->cur_exp);
15644   mp->cur_type=mp_picture_type;
15645   loop_list(mp->loop_ptr)=q;
15646   q=mp_stash_cur_exp(mp);
15647 }
15648
15649 @ A level of loop control disappears when |resume_iteration| has decided
15650 not to resume, or when an \&{exitif} construction has removed the loop text
15651 from the input stack.
15652
15653 @c void mp_stop_iteration (MP mp) {
15654   pointer p,q; /* the usual */
15655   p=loop_type(mp->loop_ptr);
15656   if ( p==progression_flag )  {
15657     mp_free_node(mp, loop_list(mp->loop_ptr),progression_node_size);
15658   } else if ( p==null ){ 
15659     q=loop_list(mp->loop_ptr);
15660     while ( q!=null ) {
15661       p=info(q);
15662       if ( p!=null ) {
15663         if ( link(p)==mp_void ) { /* it's an \&{expr} parameter */
15664           mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
15665         } else {
15666           mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
15667         }
15668       }
15669       p=q; q=link(q); free_avail(p);
15670     }
15671   } else if ( p>progression_flag ) {
15672     delete_edge_ref(p);
15673   }
15674   p=mp->loop_ptr; mp->loop_ptr=link(p); mp_flush_token_list(mp, info(p));
15675   mp_free_node(mp, p,loop_node_size);
15676 }
15677
15678 @ Now that we know all about loop control, we can finish up
15679 the missing portion of |begin_iteration| and we'll be done.
15680
15681 The following code is performed after the `\.=' has been scanned in
15682 a \&{for} construction (if |m=expr_base|) or a \&{forsuffixes} construction
15683 (if |m=suffix_base|).
15684
15685 @<Scan the values to be used in the loop@>=
15686 loop_type(s)=null; q=loop_list_loc(s); link(q)=null; /* |link(q)=loop_list(s)| */
15687 do {  
15688   mp_get_x_next(mp);
15689   if ( m!=expr_base ) {
15690     mp_scan_suffix(mp);
15691   } else { 
15692     if ( mp->cur_cmd>=colon ) if ( mp->cur_cmd<=comma ) 
15693           goto CONTINUE;
15694     mp_scan_expression(mp);
15695     if ( mp->cur_cmd==step_token ) if ( q==loop_list_loc(s) ) {
15696       @<Prepare for step-until construction and |break|@>;
15697     }
15698     mp->cur_exp=mp_stash_cur_exp(mp);
15699   }
15700   link(q)=mp_get_avail(mp); q=link(q); 
15701   info(q)=mp->cur_exp; mp->cur_type=mp_vacuous;
15702 CONTINUE:
15703   ;
15704 } while (mp->cur_cmd==comma)
15705
15706 @ @<Prepare for step-until construction and |break|@>=
15707
15708   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "initial value");
15709   pp=mp_get_node(mp, progression_node_size); value(pp)=mp->cur_exp;
15710   mp_get_x_next(mp); mp_scan_expression(mp);
15711   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "step size");
15712   step_size(pp)=mp->cur_exp;
15713   if ( mp->cur_cmd!=until_token ) { 
15714     mp_missing_err(mp, "until");
15715 @.Missing `until'@>
15716     help2("I assume you meant to say `until' after `step'.")
15717       ("So I'll look for the final value and colon next.");
15718     mp_back_error(mp);
15719   }
15720   mp_get_x_next(mp); mp_scan_expression(mp);
15721   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "final value");
15722   final_value(pp)=mp->cur_exp; loop_list(s)=pp;
15723   loop_type(s)=progression_flag; 
15724   break;
15725 }
15726
15727 @ The last case is when we have just seen ``\&{within}'', and we need to
15728 parse a picture expression and prepare to iterate over it.
15729
15730 @<Set up a picture iteration@>=
15731 { mp_get_x_next(mp);
15732   mp_scan_expression(mp);
15733   @<Make sure the current expression is a known picture@>;
15734   loop_type(s)=mp->cur_exp; mp->cur_type=mp_vacuous;
15735   q=link(dummy_loc(mp->cur_exp));
15736   if ( q!= null ) 
15737     if ( is_start_or_stop(q) )
15738       if ( mp_skip_1component(mp, q)==null ) q=link(q);
15739   loop_list(s)=q;
15740 }
15741
15742 @ @<Make sure the current expression is a known picture@>=
15743 if ( mp->cur_type!=mp_picture_type ) {
15744   mp_disp_err(mp, null,"Improper iteration spec has been replaced by nullpicture");
15745   help1("When you say `for x in p', p must be a known picture.");
15746   mp_put_get_flush_error(mp, mp_get_node(mp, edge_header_size));
15747   mp_init_edges(mp, mp->cur_exp); mp->cur_type=mp_picture_type;
15748 }
15749
15750 @* \[35] File names.
15751 It's time now to fret about file names.  Besides the fact that different
15752 operating systems treat files in different ways, we must cope with the
15753 fact that completely different naming conventions are used by different
15754 groups of people. The following programs show what is required for one
15755 particular operating system; similar routines for other systems are not
15756 difficult to devise.
15757 @^system dependencies@>
15758
15759 \MP\ assumes that a file name has three parts: the name proper; its
15760 ``extension''; and a ``file area'' where it is found in an external file
15761 system.  The extension of an input file is assumed to be
15762 `\.{.mp}' unless otherwise specified; it is `\.{.log}' on the
15763 transcript file that records each run of \MP; it is `\.{.tfm}' on the font
15764 metric files that describe characters in any fonts created by \MP; it is
15765 `\.{.ps}' or `.{\it nnn}' for some number {\it nnn} on the \ps\ output files;
15766 and it is `\.{.mem}' on the mem files written by \.{INIMP} to initialize \MP.
15767 The file area can be arbitrary on input files, but files are usually
15768 output to the user's current area.  If an input file cannot be
15769 found on the specified area, \MP\ will look for it on a special system
15770 area; this special area is intended for commonly used input files.
15771
15772 Simple uses of \MP\ refer only to file names that have no explicit
15773 extension or area. For example, a person usually says `\.{input} \.{cmr10}'
15774 instead of `\.{input} \.{cmr10.new}'. Simple file
15775 names are best, because they make the \MP\ source files portable;
15776 whenever a file name consists entirely of letters and digits, it should be
15777 treated in the same way by all implementations of \MP. However, users
15778 need the ability to refer to other files in their environment, especially
15779 when responding to error messages concerning unopenable files; therefore
15780 we want to let them use the syntax that appears in their favorite
15781 operating system.
15782
15783 @ \MP\ uses the same conventions that have proved to be satisfactory for
15784 \TeX\ and \MF. In order to isolate the system-dependent aspects of file names,
15785 @^system dependencies@>
15786 the system-independent parts of \MP\ are expressed in terms
15787 of three system-dependent
15788 procedures called |begin_name|, |more_name|, and |end_name|. In
15789 essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
15790 the system-independent driver program does the operations
15791 $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;|more_name|(c_n);
15792 \,|end_name|.$$
15793 These three procedures communicate with each other via global variables.
15794 Afterwards the file name will appear in the string pool as three strings
15795 called |cur_name|\penalty10000\hskip-.05em,
15796 |cur_area|, and |cur_ext|; the latter two are null (i.e.,
15797 |""|), unless they were explicitly specified by the user.
15798
15799 Actually the situation is slightly more complicated, because \MP\ needs
15800 to know when the file name ends. The |more_name| routine is a function
15801 (with side effects) that returns |true| on the calls |more_name|$(c_1)$,
15802 \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
15803 returns |false|; or, it returns |true| and $c_n$ is the last character
15804 on the current input line. In other words,
15805 |more_name| is supposed to return |true| unless it is sure that the
15806 file name has been completely scanned; and |end_name| is supposed to be able
15807 to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
15808 whether $|more_name|(c_n)$ returned |true| or |false|.
15809
15810 @<Glob...@>=
15811 char * cur_name; /* name of file just scanned */
15812 char * cur_area; /* file area just scanned, or \.{""} */
15813 char * cur_ext; /* file extension just scanned, or \.{""} */
15814
15815 @ It is easier to maintain reference counts if we assign initial values.
15816
15817 @<Set init...@>=
15818 mp->cur_name=xstrdup(""); 
15819 mp->cur_area=xstrdup(""); 
15820 mp->cur_ext=xstrdup("");
15821
15822 @ @<Dealloc variables@>=
15823 xfree(mp->cur_area);
15824 xfree(mp->cur_name);
15825 xfree(mp->cur_ext);
15826
15827 @ The file names we shall deal with for illustrative purposes have the
15828 following structure:  If the name contains `\.>' or `\.:', the file area
15829 consists of all characters up to and including the final such character;
15830 otherwise the file area is null.  If the remaining file name contains
15831 `\..', the file extension consists of all such characters from the first
15832 remaining `\..' to the end, otherwise the file extension is null.
15833 @^system dependencies@>
15834
15835 We can scan such file names easily by using two global variables that keep track
15836 of the occurrences of area and extension delimiters.  Note that these variables
15837 cannot be of type |pool_pointer| because a string pool compaction could occur
15838 while scanning a file name.
15839
15840 @<Glob...@>=
15841 integer area_delimiter;
15842   /* most recent `\.>' or `\.:' relative to |str_start[str_ptr]| */
15843 integer ext_delimiter; /* the relevant `\..', if any */
15844
15845 @ Input files that can't be found in the user's area may appear in standard
15846 system areas called |MP_area| and |MF_area|.  (The latter is used when the file
15847 extension is |".mf"|.)  The standard system area for font metric files
15848 to be read is |MP_font_area|.
15849 This system area name will, of course, vary from place to place.
15850 @^system dependencies@>
15851
15852 @d MP_area "MPinputs:"
15853 @.MPinputs@>
15854 @d MF_area "MFinputs:"
15855 @.MFinputs@>
15856 @d MP_font_area ""
15857 @.TeXfonts@>
15858
15859 @ Here now is the first of the system-dependent routines for file name scanning.
15860 @^system dependencies@>
15861
15862 @<Declare subroutines for parsing file names@>=
15863 void mp_begin_name (MP mp) { 
15864   xfree(mp->cur_name); 
15865   xfree(mp->cur_area); 
15866   xfree(mp->cur_ext);
15867   mp->area_delimiter=-1; 
15868   mp->ext_delimiter=-1;
15869 }
15870
15871 @ And here's the second.
15872 @^system dependencies@>
15873
15874 @<Declare subroutines for parsing file names@>=
15875 boolean mp_more_name (MP mp, ASCII_code c) { 
15876   if (c==' ') {
15877     return false;
15878   } else { 
15879     if ( (c=='>')||(c==':') ) { 
15880       mp->area_delimiter=mp->pool_ptr; 
15881       mp->ext_delimiter=-1;
15882     } else if ( (c=='.')&&(mp->ext_delimiter<0) ) {
15883       mp->ext_delimiter=mp->pool_ptr;
15884     }
15885     str_room(1); append_char(c); /* contribute |c| to the current string */
15886     return true;
15887   }
15888 }
15889
15890 @ The third.
15891 @^system dependencies@>
15892
15893 @d copy_pool_segment(A,B,C) { 
15894       A = xmalloc(C+1,sizeof(char)); 
15895       strncpy(A,(char *)(mp->str_pool+B),C);  
15896       A[C] = 0;}
15897
15898 @<Declare subroutines for parsing file names@>=
15899 void mp_end_name (MP mp) {
15900   pool_pointer s; /* length of area, name, and extension */
15901   unsigned int len;
15902   /* "my/w.mp" */
15903   s = mp->str_start[mp->str_ptr];
15904   if ( mp->area_delimiter<0 ) {    
15905     mp->cur_area=xstrdup("");
15906   } else {
15907     len = mp->area_delimiter-s; 
15908     copy_pool_segment(mp->cur_area,s,len);
15909     s += len+1;
15910   }
15911   if ( mp->ext_delimiter<0 ) {
15912     mp->cur_ext=xstrdup("");
15913     len = mp->pool_ptr-s; 
15914   } else {
15915     copy_pool_segment(mp->cur_ext,mp->ext_delimiter,(mp->pool_ptr-mp->ext_delimiter));
15916     len = mp->ext_delimiter-s;
15917   }
15918   copy_pool_segment(mp->cur_name,s,len);
15919   mp->pool_ptr=s; /* don't need this partial string */
15920 }
15921
15922 @ Conversely, here is a routine that takes three strings and prints a file
15923 name that might have produced them. (The routine is system dependent, because
15924 some operating systems put the file area last instead of first.)
15925 @^system dependencies@>
15926
15927 @<Basic printing...@>=
15928 void mp_print_file_name (MP mp, char * n, char * a, char * e) { 
15929   mp_print(mp, a); mp_print(mp, n); mp_print(mp, e);
15930 };
15931
15932 @ Another system-dependent routine is needed to convert three internal
15933 \MP\ strings
15934 to the |name_of_file| value that is used to open files. The present code
15935 allows both lowercase and uppercase letters in the file name.
15936 @^system dependencies@>
15937
15938 @d append_to_name(A) { c=(A); 
15939   if ( k<file_name_size ) {
15940     mp->name_of_file[k]=xchr(c);
15941     incr(k);
15942   }
15943 }
15944
15945 @<Declare subroutines for parsing file names@>=
15946 void mp_pack_file_name (MP mp, char *n, char *a, char *e) {
15947   integer k; /* number of positions filled in |name_of_file| */
15948   ASCII_code c; /* character being packed */
15949   char *j; /* a character  index */
15950   k=0;
15951   assert(n);
15952   if (a!=NULL) {
15953     for (j=a;*j;j++) { append_to_name(*j); }
15954   }
15955   for (j=n;*j;j++) { append_to_name(*j); }
15956   if (e!=NULL) {
15957     for (j=e;*j;j++) { append_to_name(*j); }
15958   }
15959   mp->name_of_file[k]=0;
15960   mp->name_length=k; 
15961 }
15962
15963 @ @<Internal library declarations@>=
15964 void mp_pack_file_name (MP mp, char *n, char *a, char *e) ;
15965
15966 @ A messier routine is also needed, since mem file names must be scanned
15967 before \MP's string mechanism has been initialized. We shall use the
15968 global variable |MP_mem_default| to supply the text for default system areas
15969 and extensions related to mem files.
15970 @^system dependencies@>
15971
15972 @d mem_default_length 9 /* length of the |MP_mem_default| string */
15973 @d mem_ext_length 4 /* length of its `\.{.mem}' part */
15974 @d mem_extension ".mem" /* the extension, as a \.{WEB} constant */
15975
15976 @<Glob...@>=
15977 char *MP_mem_default;
15978 char *mem_name; /* for commandline */
15979
15980 @ @<Option variables@>=
15981 char *mem_name; /* for commandline */
15982
15983 @ @<Allocate or initialize ...@>=
15984 mp->MP_mem_default = xstrdup("plain.mem");
15985 mp->mem_name = xstrdup(opt->mem_name);
15986 @.plain@>
15987 @^system dependencies@>
15988
15989 @ @<Dealloc variables@>=
15990 xfree(mp->MP_mem_default);
15991 xfree(mp->mem_name);
15992
15993 @ @<Check the ``constant'' values for consistency@>=
15994 if ( mem_default_length>file_name_size ) mp->bad=20;
15995
15996 @ Here is the messy routine that was just mentioned. It sets |name_of_file|
15997 from the first |n| characters of |MP_mem_default|, followed by
15998 |buffer[a..b-1]|, followed by the last |mem_ext_length| characters of
15999 |MP_mem_default|.
16000
16001 We dare not give error messages here, since \MP\ calls this routine before
16002 the |error| routine is ready to roll. Instead, we simply drop excess characters,
16003 since the error will be detected in another way when a strange file name
16004 isn't found.
16005 @^system dependencies@>
16006
16007 @c void mp_pack_buffered_name (MP mp,small_number n, integer a,
16008                                integer b) {
16009   integer k; /* number of positions filled in |name_of_file| */
16010   ASCII_code c; /* character being packed */
16011   integer j; /* index into |buffer| or |MP_mem_default| */
16012   if ( n+b-a+1+mem_ext_length>file_name_size )
16013     b=a+file_name_size-n-1-mem_ext_length;
16014   k=0;
16015   for (j=0;j<n;j++) {
16016     append_to_name(xord((int)mp->MP_mem_default[j]));
16017   }
16018   for (j=a;j<b;j++) {
16019     append_to_name(mp->buffer[j]);
16020   }
16021   for (j=mem_default_length-mem_ext_length;
16022       j<mem_default_length;j++) {
16023     append_to_name(xord((int)mp->MP_mem_default[j]));
16024   } 
16025   mp->name_of_file[k]=0;
16026   mp->name_length=k; 
16027 }
16028
16029 @ Here is the only place we use |pack_buffered_name|. This part of the program
16030 becomes active when a ``virgin'' \MP\ is trying to get going, just after
16031 the preliminary initialization, or when the user is substituting another
16032 mem file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
16033 contains the first line of input in |buffer[loc..(last-1)]|, where
16034 |loc<last| and |buffer[loc]<>" "|.
16035
16036 @<Declarations@>=
16037 boolean mp_open_mem_file (MP mp) ;
16038
16039 @ @c
16040 boolean mp_open_mem_file (MP mp) {
16041   int j; /* the first space after the file name */
16042   if (mp->mem_name!=NULL) {
16043     mp->mem_file = (mp->open_file)(mp->mem_name, "rb", mp_filetype_memfile);
16044     if ( mp->mem_file ) return true;
16045   }
16046   j=loc;
16047   if ( mp->buffer[loc]=='&' ) {
16048     incr(loc); j=loc; mp->buffer[mp->last]=' ';
16049     while ( mp->buffer[j]!=' ' ) incr(j);
16050     mp_pack_buffered_name(mp, 0,loc,j); /* try first without the system file area */
16051     if ( mp_w_open_in(mp, &mp->mem_file) ) goto FOUND;
16052     wake_up_terminal;
16053     wterm_ln("Sorry, I can\'t find that mem file; will try PLAIN.");
16054 @.Sorry, I can't find...@>
16055     update_terminal;
16056   }
16057   /* now pull out all the stops: try for the system \.{plain} file */
16058   mp_pack_buffered_name(mp, mem_default_length-mem_ext_length,0,0);
16059   if ( ! mp_w_open_in(mp, &mp->mem_file) ) {
16060     wake_up_terminal;
16061     wterm_ln("I can\'t find the PLAIN mem file!\n");
16062 @.I can't find PLAIN...@>
16063 @.plain@>
16064     return false;
16065   }
16066 FOUND:
16067   loc=j; return true;
16068 }
16069
16070 @ Operating systems often make it possible to determine the exact name (and
16071 possible version number) of a file that has been opened. The following routine,
16072 which simply makes a \MP\ string from the value of |name_of_file|, should
16073 ideally be changed to deduce the full name of file~|f|, which is the file
16074 most recently opened, if it is possible to do this in a \PASCAL\ program.
16075 @^system dependencies@>
16076
16077 @<Declarations@>=
16078 #define mp_a_make_name_string(A,B)  mp_make_name_string(A)
16079 #define mp_b_make_name_string(A,B)  mp_make_name_string(A)
16080 #define mp_w_make_name_string(A,B)  mp_make_name_string(A)
16081
16082 @ @c 
16083 str_number mp_make_name_string (MP mp) {
16084   int k; /* index into |name_of_file| */
16085   str_room(mp->name_length);
16086   for (k=0;k<mp->name_length;k++) {
16087     append_char(xord((int)mp->name_of_file[k]));
16088   }
16089   return mp_make_string(mp);
16090 }
16091
16092 @ Now let's consider the ``driver''
16093 routines by which \MP\ deals with file names
16094 in a system-independent manner.  First comes a procedure that looks for a
16095 file name in the input by taking the information from the input buffer.
16096 (We can't use |get_next|, because the conversion to tokens would
16097 destroy necessary information.)
16098
16099 This procedure doesn't allow semicolons or percent signs to be part of
16100 file names, because of other conventions of \MP.
16101 {\sl The {\logos METAFONT\/}book} doesn't
16102 use semicolons or percents immediately after file names, but some users
16103 no doubt will find it natural to do so; therefore system-dependent
16104 changes to allow such characters in file names should probably
16105 be made with reluctance, and only when an entire file name that
16106 includes special characters is ``quoted'' somehow.
16107 @^system dependencies@>
16108
16109 @c void mp_scan_file_name (MP mp) { 
16110   mp_begin_name(mp);
16111   while ( mp->buffer[loc]==' ' ) incr(loc);
16112   while (1) { 
16113     if ( (mp->buffer[loc]==';')||(mp->buffer[loc]=='%') ) break;
16114     if ( ! mp_more_name(mp, mp->buffer[loc]) ) break;
16115     incr(loc);
16116   }
16117   mp_end_name(mp);
16118 }
16119
16120 @ Here is another version that takes its input from a string.
16121
16122 @<Declare subroutines for parsing file names@>=
16123 void mp_str_scan_file (MP mp,  str_number s) {
16124   pool_pointer p,q; /* current position and stopping point */
16125   mp_begin_name(mp);
16126   p=mp->str_start[s]; q=str_stop(s);
16127   while ( p<q ){ 
16128     if ( ! mp_more_name(mp, mp->str_pool[p]) ) break;
16129     incr(p);
16130   }
16131   mp_end_name(mp);
16132 }
16133
16134 @ And one that reads from a |char*|.
16135
16136 @<Declare subroutines for parsing file names@>=
16137 void mp_ptr_scan_file (MP mp,  char *s) {
16138   char *p, *q; /* current position and stopping point */
16139   mp_begin_name(mp);
16140   p=s; q=p+strlen(s);
16141   while ( p<q ){ 
16142     if ( ! mp_more_name(mp, *p)) break;
16143     p++;
16144   }
16145   mp_end_name(mp);
16146 }
16147
16148
16149 @ The global variable |job_name| contains the file name that was first
16150 \&{input} by the user. This name is extended by `\.{.log}' and `\.{ps}' and
16151 `\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's output files.
16152
16153 @<Glob...@>=
16154 char *job_name; /* principal file name */
16155 boolean log_opened; /* has the transcript file been opened? */
16156 char *log_name; /* full name of the log file */
16157
16158 @ @<Option variables@>=
16159 char *job_name; /* principal file name */
16160
16161 @ Initially |job_name=NULL|; it becomes nonzero as soon as the true name is known.
16162 We have |job_name=NULL| if and only if the `\.{log}' file has not been opened,
16163 except of course for a short time just after |job_name| has become nonzero.
16164
16165 @<Allocate or ...@>=
16166 mp->job_name=opt->job_name; 
16167 mp->log_opened=false;
16168
16169 @ @<Dealloc variables@>=
16170 xfree(mp->job_name);
16171
16172 @ Here is a routine that manufactures the output file names, assuming that
16173 |job_name<>0|. It ignores and changes the current settings of |cur_area|
16174 and |cur_ext|.
16175
16176 @d pack_cur_name mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext)
16177
16178 @<Declarations@>=
16179 void mp_pack_job_name (MP mp, char *s) ;
16180
16181 @ @c void mp_pack_job_name (MP mp, char  *s) { /* |s = ".log"|, |".mem"|, |".ps"|, or .\\{nnn} */
16182   xfree(mp->cur_name); mp->cur_name=xstrdup(mp->job_name);
16183   xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16184   xfree(mp->cur_ext);  mp->cur_ext=xstrdup(s);
16185   pack_cur_name;
16186 }
16187
16188 @ If some trouble arises when \MP\ tries to open a file, the following
16189 routine calls upon the user to supply another file name. Parameter~|s|
16190 is used in the error message to identify the type of file; parameter~|e|
16191 is the default extension if none is given. Upon exit from the routine,
16192 variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
16193 ready for another attempt at file opening.
16194
16195 @<Declarations@>=
16196 void mp_prompt_file_name (MP mp,char * s, char * e) ;
16197
16198 @ @c void mp_prompt_file_name (MP mp,char * s, char * e) {
16199   size_t k; /* index into |buffer| */
16200   char * saved_cur_name;
16201   if ( mp->interaction==mp_scroll_mode ) 
16202         wake_up_terminal;
16203   if (strcmp(s,"input file name")==0) {
16204         print_err("I can\'t find file `");
16205 @.I can't find file x@>
16206   } else {
16207         print_err("I can\'t write on file `");
16208   }
16209 @.I can't write on file x@>
16210   mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext); 
16211   mp_print(mp, "'.");
16212   if (strcmp(e,"")==0) 
16213         mp_show_context(mp);
16214   mp_print_nl(mp, "Please type another "); mp_print(mp, s);
16215 @.Please type...@>
16216   if ( mp->interaction<mp_scroll_mode )
16217     mp_fatal_error(mp, "*** (job aborted, file error in nonstop mode)");
16218 @.job aborted, file error...@>
16219   saved_cur_name = xstrdup(mp->cur_name);
16220   clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
16221   if (strcmp(mp->cur_ext,"")==0) 
16222         mp->cur_ext=e;
16223   if (strlen(mp->cur_name)==0) {
16224     mp->cur_name=saved_cur_name;
16225   } else {
16226     xfree(saved_cur_name);
16227   }
16228   pack_cur_name;
16229 }
16230
16231 @ @<Scan file name in the buffer@>=
16232
16233   mp_begin_name(mp); k=mp->first;
16234   while ( (mp->buffer[k]==' ')&&(k<mp->last) ) incr(k);
16235   while (1) { 
16236     if ( k==mp->last ) break;
16237     if ( ! mp_more_name(mp, mp->buffer[k]) ) break;
16238     incr(k);
16239   }
16240   mp_end_name(mp);
16241 }
16242
16243 @ The |open_log_file| routine is used to open the transcript file and to help
16244 it catch up to what has previously been printed on the terminal.
16245
16246 @c void mp_open_log_file (MP mp) {
16247   int old_setting; /* previous |selector| setting */
16248   int k; /* index into |months| and |buffer| */
16249   int l; /* end of first input line */
16250   integer m; /* the current month */
16251   char *months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 
16252     /* abbreviations of month names */
16253   old_setting=mp->selector;
16254   if ( mp->job_name==NULL ) {
16255      mp->job_name=xstrdup("mpout");
16256   }
16257   mp_pack_job_name(mp,".log");
16258   while ( ! mp_a_open_out(mp, &mp->log_file, mp_filetype_log) ) {
16259     @<Try to get a different log file name@>;
16260   }
16261   mp->log_name=xstrdup(mp->name_of_file);
16262   mp->selector=log_only; mp->log_opened=true;
16263   @<Print the banner line, including the date and time@>;
16264   mp->input_stack[mp->input_ptr]=mp->cur_input; 
16265     /* make sure bottom level is in memory */
16266   mp_print_nl(mp, "**");
16267 @.**@>
16268   l=mp->input_stack[0].limit_field-1; /* last position of first line */
16269   for (k=0;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
16270   mp_print_ln(mp); /* now the transcript file contains the first line of input */
16271   mp->selector=old_setting+2; /* |log_only| or |term_and_log| */
16272 }
16273
16274 @ @<Dealloc variables@>=
16275 xfree(mp->log_name);
16276
16277 @ Sometimes |open_log_file| is called at awkward moments when \MP\ is
16278 unable to print error messages or even to |show_context|.
16279 The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
16280 routine will not be invoked because |log_opened| will be false.
16281
16282 The normal idea of |mp_batch_mode| is that nothing at all should be written
16283 on the terminal. However, in the unusual case that
16284 no log file could be opened, we make an exception and allow
16285 an explanatory message to be seen.
16286
16287 Incidentally, the program always refers to the log file as a `\.{transcript
16288 file}', because some systems cannot use the extension `\.{.log}' for
16289 this file.
16290
16291 @<Try to get a different log file name@>=
16292 {  
16293   mp->selector=term_only;
16294   mp_prompt_file_name(mp, "transcript file name",".log");
16295 }
16296
16297 @ @<Print the banner...@>=
16298
16299   wlog(banner);
16300   mp_print(mp, mp->mem_ident); mp_print(mp, "  ");
16301   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_day])); 
16302   mp_print_char(mp, ' ');
16303   m=mp_round_unscaled(mp, mp->internal[mp_month]);
16304   for (k=3*m-3;k<3*m;k++) { wlog_chr(months[k]); }
16305   mp_print_char(mp, ' '); 
16306   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_year])); 
16307   mp_print_char(mp, ' ');
16308   m=mp_round_unscaled(mp, mp->internal[mp_time]);
16309   mp_print_dd(mp, m / 60); mp_print_char(mp, ':'); mp_print_dd(mp, m % 60);
16310 }
16311
16312 @ The |try_extension| function tries to open an input file determined by
16313 |cur_name|, |cur_area|, and the argument |ext|.  It returns |false| if it
16314 can't find the file in |cur_area| or the appropriate system area.
16315
16316 @c boolean mp_try_extension (MP mp,char *ext) { 
16317   mp_pack_file_name(mp, mp->cur_name,mp->cur_area, ext);
16318   in_name=xstrdup(mp->cur_name); 
16319   in_area=xstrdup(mp->cur_area);
16320   if ( mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16321     return true;
16322   } else { 
16323     if (strcmp(ext,".mf")==0 ) in_area=xstrdup(MF_area);
16324     else in_area=xstrdup(MP_area);
16325     mp_pack_file_name(mp, mp->cur_name,in_area,ext);
16326     return mp_a_open_in(mp, &cur_file, mp_filetype_program);
16327   }
16328   return false;
16329 }
16330
16331 @ Let's turn now to the procedure that is used to initiate file reading
16332 when an `\.{input}' command is being processed.
16333
16334 @c void mp_start_input (MP mp) { /* \MP\ will \.{input} something */
16335   char *fname = NULL;
16336   @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>;
16337   while (1) { 
16338     mp_begin_file_reading(mp); /* set up |cur_file| and new level of input */
16339     if ( strlen(mp->cur_ext)==0 ) {
16340       if ( mp_try_extension(mp, ".mp") ) break;
16341       else if ( mp_try_extension(mp, "") ) break;
16342       else if ( mp_try_extension(mp, ".mf") ) break;
16343       /* |else do_nothing; | */
16344     } else if ( mp_try_extension(mp, mp->cur_ext) ) {
16345       break;
16346     }
16347     mp_end_file_reading(mp); /* remove the level that didn't work */
16348     mp_prompt_file_name(mp, "input file name","");
16349   }
16350   name=mp_a_make_name_string(mp, cur_file);
16351   fname = xstrdup(mp->name_of_file);
16352   if ( mp->job_name==NULL ) {
16353     mp->job_name=xstrdup(mp->cur_name); 
16354     mp_open_log_file(mp);
16355   } /* |open_log_file| doesn't |show_context|, so |limit|
16356         and |loc| needn't be set to meaningful values yet */
16357   if ( ((int)mp->term_offset+(int)strlen(fname)) > (mp->max_print_line-2)) mp_print_ln(mp);
16358   else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
16359   mp_print_char(mp, '('); incr(mp->open_parens); mp_print(mp, fname); 
16360   xfree(fname);
16361   update_terminal;
16362   @<Flush |name| and replace it with |cur_name| if it won't be needed@>;
16363   @<Read the first line of the new file@>;
16364 }
16365
16366 @ This code should be omitted if |a_make_name_string| returns something other
16367 than just a copy of its argument and the full file name is needed for opening
16368 \.{MPX} files or implementing the switch-to-editor option.
16369 @^system dependencies@>
16370
16371 @<Flush |name| and replace it with |cur_name| if it won't be needed@>=
16372 mp_flush_string(mp, name); name=rts(mp->cur_name); xfree(mp->cur_name)
16373
16374 @ If the file is empty, it is considered to contain a single blank line,
16375 so there is no need to test the return value.
16376
16377 @<Read the first line...@>=
16378
16379   line=1;
16380   (void)mp_input_ln(mp, cur_file ); 
16381   mp_firm_up_the_line(mp);
16382   mp->buffer[limit]='%'; mp->first=limit+1; loc=start;
16383 }
16384
16385 @ @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>=
16386 while ( token_state &&(loc==null) ) mp_end_token_list(mp);
16387 if ( token_state ) { 
16388   print_err("File names can't appear within macros");
16389 @.File names can't...@>
16390   help3("Sorry...I've converted what follows to tokens,")
16391     ("possibly garbaging the name you gave.")
16392     ("Please delete the tokens and insert the name again.");
16393   mp_error(mp);
16394 }
16395 if ( file_state ) {
16396   mp_scan_file_name(mp);
16397 } else { 
16398    xfree(mp->cur_name); mp->cur_name=xstrdup(""); 
16399    xfree(mp->cur_ext);  mp->cur_ext =xstrdup(""); 
16400    xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16401 }
16402
16403 @ Sometimes we need to deal with two file names at once.  This procedure
16404 copies the given string into a special array for an old file name.
16405
16406 @c void mp_copy_old_name (MP mp,str_number s) {
16407   integer k; /* number of positions filled in |old_file_name| */
16408   pool_pointer j; /* index into |str_pool| */
16409   k=0;
16410   for (j=mp->str_start[s];j<=str_stop(s)-1;j++) { 
16411     incr(k);
16412     if ( k<=file_name_size ) 
16413       mp->old_file_name[k]=xchr(mp->str_pool[j]);
16414   }
16415   mp->old_file_name[++k] = 0;
16416 }
16417
16418 @ @<Glob...@>=
16419 char old_file_name[file_name_size+1];  /* analogous to |name_of_file| */
16420
16421 @ The following simple routine starts reading the \.{MPX} file associated
16422 with the current input file.
16423
16424 @c void mp_start_mpx_input (MP mp) {
16425   mp_pack_file_name(mp, in_name, in_area, ".mpx");
16426   @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16427     |goto not_found| if there is a problem@>;
16428   mp_begin_file_reading(mp);
16429   if ( ! mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16430     mp_end_file_reading(mp);
16431     goto NOT_FOUND;
16432   }
16433   name=mp_a_make_name_string(mp, cur_file);
16434   mp->mpx_name[index]=name; add_str_ref(name);
16435   @<Read the first line of the new file@>;
16436   return;
16437 NOT_FOUND: 
16438     @<Explain that the \.{MPX} file can't be read and |succumb|@>;
16439 }
16440
16441 @ This should ideally be changed to do whatever is necessary to create the
16442 \.{MPX} file given by |name_of_file| if it does not exist or if it is out
16443 of date.  This requires invoking \.{MPtoTeX} on the |old_file_name| and passing
16444 the results through \TeX\ and \.{DVItoMP}.  (It is possible to use a
16445 completely different typesetting program if suitable postprocessor is
16446 available to perform the function of \.{DVItoMP}.)
16447 @^system dependencies@>
16448
16449 @ @<Exported types@>=
16450 typedef int (*mp_run_make_mpx_command)(MP mp, char *origname, char *mtxname);
16451
16452 @ @<Glob...@>=
16453 mp_run_make_mpx_command run_make_mpx;
16454
16455 @ @<Option variables@>=
16456 mp_run_make_mpx_command run_make_mpx;
16457
16458 @ @<Allocate or initialize ...@>=
16459 set_callback_option(run_make_mpx);
16460
16461 @ @<Internal library declarations@>=
16462 int mp_run_make_mpx (MP mp, char *origname, char *mtxname);
16463
16464 @ The default does nothing.
16465 @c 
16466 int mp_run_make_mpx (MP mp, char *origname, char *mtxname) {
16467   if (mp && origname && mtxname) /* for -W */
16468     return false;
16469   return false;
16470 }
16471
16472
16473
16474 @ @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16475   |goto not_found| if there is a problem@>=
16476 mp_copy_old_name(mp, name);
16477 if (!(mp->run_make_mpx)(mp, mp->old_file_name, mp->name_of_file))
16478    goto NOT_FOUND
16479
16480 @ @<Explain that the \.{MPX} file can't be read and |succumb|@>=
16481 if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16482 mp_print_nl(mp, ">> ");
16483 mp_print(mp, mp->old_file_name);
16484 mp_print_nl(mp, ">> ");
16485 mp_print(mp, mp->name_of_file);
16486 mp_print_nl(mp, "! Unable to make mpx file");
16487 help4("The two files given above are one of your source files")
16488   ("and an auxiliary file I need to read to find out what your")
16489   ("btex..etex blocks mean. If you don't know why I had trouble,")
16490   ("try running it manually through MPtoTeX, TeX, and DVItoMP");
16491 succumb;
16492
16493 @ The last file-opening commands are for files accessed via the \&{readfrom}
16494 @:read_from_}{\&{readfrom} primitive@>
16495 operator and the \&{write} command.  Such files are stored in separate arrays.
16496 @:write_}{\&{write} primitive@>
16497
16498 @<Types in the outer block@>=
16499 typedef unsigned int readf_index; /* |0..max_read_files| */
16500 typedef unsigned int write_index;  /* |0..max_write_files| */
16501
16502 @ @<Glob...@>=
16503 readf_index max_read_files; /* maximum number of simultaneously open \&{readfrom} files */
16504 void ** rd_file; /* \&{readfrom} files */
16505 char ** rd_fname; /* corresponding file name or 0 if file not open */
16506 readf_index read_files; /* number of valid entries in the above arrays */
16507 write_index max_write_files; /* maximum number of simultaneously open \&{write} */
16508 void ** wr_file; /* \&{write} files */
16509 char ** wr_fname; /* corresponding file name or 0 if file not open */
16510 write_index write_files; /* number of valid entries in the above arrays */
16511
16512 @ @<Allocate or initialize ...@>=
16513 mp->max_read_files=8;
16514 mp->rd_file = xmalloc((mp->max_read_files+1),sizeof(void *));
16515 mp->rd_fname = xmalloc((mp->max_read_files+1),sizeof(char *));
16516 memset(mp->rd_fname, 0, sizeof(char *)*(mp->max_read_files+1));
16517 mp->read_files=0;
16518 mp->max_write_files=8;
16519 mp->wr_file = xmalloc((mp->max_write_files+1),sizeof(void *));
16520 mp->wr_fname = xmalloc((mp->max_write_files+1),sizeof(char *));
16521 memset(mp->wr_fname, 0, sizeof(char *)*(mp->max_write_files+1));
16522 mp->write_files=0;
16523
16524
16525 @ This routine starts reading the file named by string~|s| without setting
16526 |loc|, |limit|, or |name|.  It returns |false| if the file is empty or cannot
16527 be opened.  Otherwise it updates |rd_file[n]| and |rd_fname[n]|.
16528
16529 @c boolean mp_start_read_input (MP mp,char *s, readf_index  n) {
16530   mp_ptr_scan_file(mp, s);
16531   pack_cur_name;
16532   mp_begin_file_reading(mp);
16533   if ( ! mp_a_open_in(mp, &mp->rd_file[n], (mp_filetype_text+n)) ) 
16534         goto NOT_FOUND;
16535   if ( ! mp_input_ln(mp, mp->rd_file[n] ) ) {
16536     (mp->close_file)(mp->rd_file[n]); 
16537         goto NOT_FOUND; 
16538   }
16539   mp->rd_fname[n]=xstrdup(mp->name_of_file);
16540   return true;
16541 NOT_FOUND: 
16542   mp_end_file_reading(mp);
16543   return false;
16544 }
16545
16546 @ Open |wr_file[n]| using file name~|s| and update |wr_fname[n]|.
16547
16548 @<Declarations@>=
16549 void mp_open_write_file (MP mp, char *s, readf_index  n) ;
16550
16551 @ @c void mp_open_write_file (MP mp,char *s, readf_index  n) {
16552   mp_ptr_scan_file(mp, s);
16553   pack_cur_name;
16554   while ( ! mp_a_open_out(mp, &mp->wr_file[n], (mp_filetype_text+n)) )
16555     mp_prompt_file_name(mp, "file name for write output","");
16556   mp->wr_fname[n]=xstrdup(mp->name_of_file);
16557 }
16558
16559
16560 @* \[36] Introduction to the parsing routines.
16561 We come now to the central nervous system that sparks many of \MP's activities.
16562 By evaluating expressions, from their primary constituents to ever larger
16563 subexpressions, \MP\ builds the structures that ultimately define complete
16564 pictures or fonts of type.
16565
16566 Four mutually recursive subroutines are involved in this process: We call them
16567 $$\hbox{|scan_primary|, |scan_secondary|, |scan_tertiary|,
16568 and |scan_expression|.}$$
16569 @^recursion@>
16570 Each of them is parameterless and begins with the first token to be scanned
16571 already represented in |cur_cmd|, |cur_mod|, and |cur_sym|. After execution,
16572 the value of the primary or secondary or tertiary or expression that was
16573 found will appear in the global variables |cur_type| and |cur_exp|. The
16574 token following the expression will be represented in |cur_cmd|, |cur_mod|,
16575 and |cur_sym|.
16576
16577 Technically speaking, the parsing algorithms are ``LL(1),'' more or less;
16578 backup mechanisms have been added in order to provide reasonable error
16579 recovery.
16580
16581 @<Glob...@>=
16582 small_number cur_type; /* the type of the expression just found */
16583 integer cur_exp; /* the value of the expression just found */
16584
16585 @ @<Set init...@>=
16586 mp->cur_exp=0;
16587
16588 @ Many different kinds of expressions are possible, so it is wise to have
16589 precise descriptions of what |cur_type| and |cur_exp| mean in all cases:
16590
16591 \smallskip\hang
16592 |cur_type=mp_vacuous| means that this expression didn't turn out to have a
16593 value at all, because it arose from a \&{begingroup}$\,\ldots\,$\&{endgroup}
16594 construction in which there was no expression before the \&{endgroup}.
16595 In this case |cur_exp| has some irrelevant value.
16596
16597 \smallskip\hang
16598 |cur_type=mp_boolean_type| means that |cur_exp| is either |true_code|
16599 or |false_code|.
16600
16601 \smallskip\hang
16602 |cur_type=mp_unknown_boolean| means that |cur_exp| points to a capsule
16603 node that is in the ring of variables equivalent
16604 to at least one undefined boolean variable.
16605
16606 \smallskip\hang
16607 |cur_type=mp_string_type| means that |cur_exp| is a string number (i.e., an
16608 integer in the range |0<=cur_exp<str_ptr|). That string's reference count
16609 includes this particular reference.
16610
16611 \smallskip\hang
16612 |cur_type=mp_unknown_string| means that |cur_exp| points to a capsule
16613 node that is in the ring of variables equivalent
16614 to at least one undefined string variable.
16615
16616 \smallskip\hang
16617 |cur_type=mp_pen_type| means that |cur_exp| points to a node in a pen.  Nobody
16618 else points to any of the nodes in this pen.  The pen may be polygonal or
16619 elliptical.
16620
16621 \smallskip\hang
16622 |cur_type=mp_unknown_pen| means that |cur_exp| points to a capsule
16623 node that is in the ring of variables equivalent
16624 to at least one undefined pen variable.
16625
16626 \smallskip\hang
16627 |cur_type=mp_path_type| means that |cur_exp| points to a the first node of
16628 a path; nobody else points to this particular path. The control points of
16629 the path will have been chosen.
16630
16631 \smallskip\hang
16632 |cur_type=mp_unknown_path| means that |cur_exp| points to a capsule
16633 node that is in the ring of variables equivalent
16634 to at least one undefined path variable.
16635
16636 \smallskip\hang
16637 |cur_type=mp_picture_type| means that |cur_exp| points to an edge header node.
16638 There may be other pointers to this particular set of edges.  The header node
16639 contains a reference count that includes this particular reference.
16640
16641 \smallskip\hang
16642 |cur_type=mp_unknown_picture| means that |cur_exp| points to a capsule
16643 node that is in the ring of variables equivalent
16644 to at least one undefined picture variable.
16645
16646 \smallskip\hang
16647 |cur_type=mp_transform_type| means that |cur_exp| points to a |mp_transform_type|
16648 capsule node. The |value| part of this capsule
16649 points to a transform node that contains six numeric values,
16650 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16651
16652 \smallskip\hang
16653 |cur_type=mp_color_type| means that |cur_exp| points to a |color_type|
16654 capsule node. The |value| part of this capsule
16655 points to a color node that contains three numeric values,
16656 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16657
16658 \smallskip\hang
16659 |cur_type=mp_cmykcolor_type| means that |cur_exp| points to a |mp_cmykcolor_type|
16660 capsule node. The |value| part of this capsule
16661 points to a color node that contains four numeric values,
16662 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16663
16664 \smallskip\hang
16665 |cur_type=mp_pair_type| means that |cur_exp| points to a capsule
16666 node whose type is |mp_pair_type|. The |value| part of this capsule
16667 points to a pair node that contains two numeric values,
16668 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16669
16670 \smallskip\hang
16671 |cur_type=mp_known| means that |cur_exp| is a |scaled| value.
16672
16673 \smallskip\hang
16674 |cur_type=mp_dependent| means that |cur_exp| points to a capsule node whose type
16675 is |dependent|. The |dep_list| field in this capsule points to the associated
16676 dependency list.
16677
16678 \smallskip\hang
16679 |cur_type=mp_proto_dependent| means that |cur_exp| points to a |mp_proto_dependent|
16680 capsule node. The |dep_list| field in this capsule
16681 points to the associated dependency list.
16682
16683 \smallskip\hang
16684 |cur_type=independent| means that |cur_exp| points to a capsule node
16685 whose type is |independent|. This somewhat unusual case can arise, for
16686 example, in the expression
16687 `$x+\&{begingroup}\penalty0\,\&{string}\,x; 0\,\&{endgroup}$'.
16688
16689 \smallskip\hang
16690 |cur_type=mp_token_list| means that |cur_exp| points to a linked list of
16691 tokens. This case arises only on the left-hand side of an assignment
16692 (`\.{:=}') operation, under very special circumstances.
16693
16694 \smallskip\noindent
16695 The possible settings of |cur_type| have been listed here in increasing
16696 numerical order. Notice that |cur_type| will never be |mp_numeric_type| or
16697 |suffixed_macro| or |mp_unsuffixed_macro|, although variables of those types
16698 are allowed.  Conversely, \MP\ has no variables of type |mp_vacuous| or
16699 |token_list|.
16700
16701 @ Capsules are two-word nodes that have a similar meaning
16702 to |cur_type| and |cur_exp|. Such nodes have |name_type=capsule|
16703 and |link<=mp_void|; and their |type| field is one of the possibilities for
16704 |cur_type| listed above.
16705
16706 The |value| field of a capsule is, in most cases, the value that
16707 corresponds to its |type|, as |cur_exp| corresponds to |cur_type|.
16708 However, when |cur_exp| would point to a capsule,
16709 no extra layer of indirection is present; the |value|
16710 field is what would have been called |value(cur_exp)| if it had not been
16711 encapsulated.  Furthermore, if the type is |dependent| or
16712 |mp_proto_dependent|, the |value| field of a capsule is replaced by
16713 |dep_list| and |prev_dep| fields, since dependency lists in capsules are
16714 always part of the general |dep_list| structure.
16715
16716 The |get_x_next| routine is careful not to change the values of |cur_type|
16717 and |cur_exp| when it gets an expanded token. However, |get_x_next| might
16718 call a macro, which might parse an expression, which might execute lots of
16719 commands in a group; hence it's possible that |cur_type| might change
16720 from, say, |mp_unknown_boolean| to |mp_boolean_type|, or from |dependent| to
16721 |known| or |independent|, during the time |get_x_next| is called. The
16722 programs below are careful to stash sensitive intermediate results in
16723 capsules, so that \MP's generality doesn't cause trouble.
16724
16725 Here's a procedure that illustrates these conventions. It takes
16726 the contents of $(|cur_type|\kern-.3pt,|cur_exp|\kern-.3pt)$
16727 and stashes them away in a
16728 capsule. It is not used when |cur_type=mp_token_list|.
16729 After the operation, |cur_type=mp_vacuous|; hence there is no need to
16730 copy path lists or to update reference counts, etc.
16731
16732 The special link |mp_void| is put on the capsule returned by
16733 |stash_cur_exp|, because this procedure is used to store macro parameters
16734 that must be easily distinguishable from token lists.
16735
16736 @<Declare the stashing/unstashing routines@>=
16737 pointer mp_stash_cur_exp (MP mp) {
16738   pointer p; /* the capsule that will be returned */
16739   switch (mp->cur_type) {
16740   case unknown_types:
16741   case mp_transform_type:
16742   case mp_color_type:
16743   case mp_pair_type:
16744   case mp_dependent:
16745   case mp_proto_dependent:
16746   case mp_independent: 
16747   case mp_cmykcolor_type:
16748     p=mp->cur_exp;
16749     break;
16750   default: 
16751     p=mp_get_node(mp, value_node_size); name_type(p)=mp_capsule;
16752     type(p)=mp->cur_type; value(p)=mp->cur_exp;
16753     break;
16754   }
16755   mp->cur_type=mp_vacuous; link(p)=mp_void; 
16756   return p;
16757 }
16758
16759 @ The inverse of |stash_cur_exp| is the following procedure, which
16760 deletes an unnecessary capsule and puts its contents into |cur_type|
16761 and |cur_exp|.
16762
16763 The program steps of \MP\ can be divided into two categories: those in
16764 which |cur_type| and |cur_exp| are ``alive'' and those in which they are
16765 ``dead,'' in the sense that |cur_type| and |cur_exp| contain relevant
16766 information or not. It's important not to ignore them when they're alive,
16767 and it's important not to pay attention to them when they're dead.
16768
16769 There's also an intermediate category: If |cur_type=mp_vacuous|, then
16770 |cur_exp| is irrelevant, hence we can proceed without caring if |cur_type|
16771 and |cur_exp| are alive or dead. In such cases we say that |cur_type|
16772 and |cur_exp| are {\sl dormant}. It is permissible to call |get_x_next|
16773 only when they are alive or dormant.
16774
16775 The \\{stash} procedure above assumes that |cur_type| and |cur_exp|
16776 are alive or dormant. The \\{unstash} procedure assumes that they are
16777 dead or dormant; it resuscitates them.
16778
16779 @<Declare the stashing/unstashing...@>=
16780 void mp_unstash_cur_exp (MP mp,pointer p) ;
16781
16782 @ @c
16783 void mp_unstash_cur_exp (MP mp,pointer p) { 
16784   mp->cur_type=type(p);
16785   switch (mp->cur_type) {
16786   case unknown_types:
16787   case mp_transform_type:
16788   case mp_color_type:
16789   case mp_pair_type:
16790   case mp_dependent: 
16791   case mp_proto_dependent:
16792   case mp_independent:
16793   case mp_cmykcolor_type: 
16794     mp->cur_exp=p;
16795     break;
16796   default:
16797     mp->cur_exp=value(p);
16798     mp_free_node(mp, p,value_node_size);
16799     break;
16800   }
16801 }
16802
16803 @ The following procedure prints the values of expressions in an
16804 abbreviated format. If its first parameter |p| is null, the value of
16805 |(cur_type,cur_exp)| is displayed; otherwise |p| should be a capsule
16806 containing the desired value. The second parameter controls the amount of
16807 output. If it is~0, dependency lists will be abbreviated to
16808 `\.{linearform}' unless they consist of a single term.  If it is greater
16809 than~1, complicated structures (pens, pictures, and paths) will be displayed
16810 in full.
16811
16812 @<Declare subroutines for printing expressions@>=
16813 @<Declare the procedure called |print_dp|@>;
16814 @<Declare the stashing/unstashing routines@>;
16815 void mp_print_exp (MP mp,pointer p, small_number verbosity) {
16816   boolean restore_cur_exp; /* should |cur_exp| be restored? */
16817   small_number t; /* the type of the expression */
16818   pointer q; /* a big node being displayed */
16819   integer v=0; /* the value of the expression */
16820   if ( p!=null ) {
16821     restore_cur_exp=false;
16822   } else { 
16823     p=mp_stash_cur_exp(mp); restore_cur_exp=true;
16824   }
16825   t=type(p);
16826   if ( t<mp_dependent ) v=value(p); else if ( t<mp_independent ) v=dep_list(p);
16827   @<Print an abbreviated value of |v| with format depending on |t|@>;
16828   if ( restore_cur_exp ) mp_unstash_cur_exp(mp, p);
16829 }
16830
16831 @ @<Print an abbreviated value of |v| with format depending on |t|@>=
16832 switch (t) {
16833 case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
16834 case mp_boolean_type:
16835   if ( v==true_code ) mp_print(mp, "true"); else mp_print(mp, "false");
16836   break;
16837 case unknown_types: case mp_numeric_type:
16838   @<Display a variable that's been declared but not defined@>;
16839   break;
16840 case mp_string_type:
16841   mp_print_char(mp, '"'); mp_print_str(mp, v); mp_print_char(mp, '"');
16842   break;
16843 case mp_pen_type: case mp_path_type: case mp_picture_type:
16844   @<Display a complex type@>;
16845   break;
16846 case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_cmykcolor_type:
16847   if ( v==null ) mp_print_type(mp, t);
16848   else @<Display a big node@>;
16849   break;
16850 case mp_known:mp_print_scaled(mp, v); break;
16851 case mp_dependent: case mp_proto_dependent:
16852   mp_print_dp(mp, t,v,verbosity);
16853   break;
16854 case mp_independent:mp_print_variable_name(mp, p); break;
16855 default: mp_confusion(mp, "exp"); break;
16856 @:this can't happen exp}{\quad exp@>
16857 }
16858
16859 @ @<Display a big node@>=
16860
16861   mp_print_char(mp, '('); q=v+mp->big_node_size[t];
16862   do {  
16863     if ( type(v)==mp_known ) mp_print_scaled(mp, value(v));
16864     else if ( type(v)==mp_independent ) mp_print_variable_name(mp, v);
16865     else mp_print_dp(mp, type(v),dep_list(v),verbosity);
16866     v=v+2;
16867     if ( v!=q ) mp_print_char(mp, ',');
16868   } while (v!=q);
16869   mp_print_char(mp, ')');
16870 }
16871
16872 @ Values of type \&{picture}, \&{path}, and \&{pen} are displayed verbosely
16873 in the log file only, unless the user has given a positive value to
16874 \\{tracingonline}.
16875
16876 @<Display a complex type@>=
16877 if ( verbosity<=1 ) {
16878   mp_print_type(mp, t);
16879 } else { 
16880   if ( mp->selector==term_and_log )
16881    if ( mp->internal[mp_tracing_online]<=0 ) {
16882     mp->selector=term_only;
16883     mp_print_type(mp, t); mp_print(mp, " (see the transcript file)");
16884     mp->selector=term_and_log;
16885   };
16886   switch (t) {
16887   case mp_pen_type:mp_print_pen(mp, v,"",false); break;
16888   case mp_path_type:mp_print_path(mp, v,"",false); break;
16889   case mp_picture_type:mp_print_edges(mp, v,"",false); break;
16890   } /* there are no other cases */
16891 }
16892
16893 @ @<Declare the procedure called |print_dp|@>=
16894 void mp_print_dp (MP mp,small_number t, pointer p, 
16895                   small_number verbosity)  {
16896   pointer q; /* the node following |p| */
16897   q=link(p);
16898   if ( (info(q)==null) || (verbosity>0) ) mp_print_dependency(mp, p,t);
16899   else mp_print(mp, "linearform");
16900 }
16901
16902 @ The displayed name of a variable in a ring will not be a capsule unless
16903 the ring consists entirely of capsules.
16904
16905 @<Display a variable that's been declared but not defined@>=
16906 { mp_print_type(mp, t);
16907 if ( v!=null )
16908   { mp_print_char(mp, ' ');
16909   while ( (name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
16910   mp_print_variable_name(mp, v);
16911   };
16912 }
16913
16914 @ When errors are detected during parsing, it is often helpful to
16915 display an expression just above the error message, using |exp_err|
16916 or |disp_err| instead of |print_err|.
16917
16918 @d exp_err(A) mp_disp_err(mp, null,(A)) /* displays the current expression */
16919
16920 @<Declare subroutines for printing expressions@>=
16921 void mp_disp_err (MP mp,pointer p, char *s) { 
16922   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16923   mp_print_nl(mp, ">> ");
16924 @.>>@>
16925   mp_print_exp(mp, p,1); /* ``medium verbose'' printing of the expression */
16926   if (strlen(s)) { 
16927     mp_print_nl(mp, "! "); mp_print(mp, s);
16928 @.!\relax@>
16929   }
16930 }
16931
16932 @ If |cur_type| and |cur_exp| contain relevant information that should
16933 be recycled, we will use the following procedure, which changes |cur_type|
16934 to |known| and stores a given value in |cur_exp|. We can think of |cur_type|
16935 and |cur_exp| as either alive or dormant after this has been done,
16936 because |cur_exp| will not contain a pointer value.
16937
16938 @ @c void mp_flush_cur_exp (MP mp,scaled v) { 
16939   switch (mp->cur_type) {
16940   case unknown_types: case mp_transform_type: case mp_color_type: case mp_pair_type:
16941   case mp_dependent: case mp_proto_dependent: case mp_independent: case mp_cmykcolor_type:
16942     mp_recycle_value(mp, mp->cur_exp); 
16943     mp_free_node(mp, mp->cur_exp,value_node_size);
16944     break;
16945   case mp_string_type:
16946     delete_str_ref(mp->cur_exp); break;
16947   case mp_pen_type: case mp_path_type: 
16948     mp_toss_knot_list(mp, mp->cur_exp); break;
16949   case mp_picture_type:
16950     delete_edge_ref(mp->cur_exp); break;
16951   default: 
16952     break;
16953   }
16954   mp->cur_type=mp_known; mp->cur_exp=v;
16955 }
16956
16957 @ There's a much more general procedure that is capable of releasing
16958 the storage associated with any two-word value packet.
16959
16960 @<Declare the recycling subroutines@>=
16961 void mp_recycle_value (MP mp,pointer p) ;
16962
16963 @ @c void mp_recycle_value (MP mp,pointer p) {
16964   small_number t; /* a type code */
16965   integer vv; /* another value */
16966   pointer q,r,s,pp; /* link manipulation registers */
16967   integer v=0; /* a value */
16968   t=type(p);
16969   if ( t<mp_dependent ) v=value(p);
16970   switch (t) {
16971   case undefined: case mp_vacuous: case mp_boolean_type: case mp_known:
16972   case mp_numeric_type:
16973     break;
16974   case unknown_types:
16975     mp_ring_delete(mp, p); break;
16976   case mp_string_type:
16977     delete_str_ref(v); break;
16978   case mp_path_type: case mp_pen_type:
16979     mp_toss_knot_list(mp, v); break;
16980   case mp_picture_type:
16981     delete_edge_ref(v); break;
16982   case mp_cmykcolor_type: case mp_pair_type: case mp_color_type:
16983   case mp_transform_type:
16984     @<Recycle a big node@>; break; 
16985   case mp_dependent: case mp_proto_dependent:
16986     @<Recycle a dependency list@>; break;
16987   case mp_independent:
16988     @<Recycle an independent variable@>; break;
16989   case mp_token_list: case mp_structured:
16990     mp_confusion(mp, "recycle"); break;
16991 @:this can't happen recycle}{\quad recycle@>
16992   case mp_unsuffixed_macro: case mp_suffixed_macro:
16993     mp_delete_mac_ref(mp, value(p)); break;
16994   } /* there are no other cases */
16995   type(p)=undefined;
16996 }
16997
16998 @ @<Recycle a big node@>=
16999 if ( v!=null ){ 
17000   q=v+mp->big_node_size[t];
17001   do {  
17002     q=q-2; mp_recycle_value(mp, q);
17003   } while (q!=v);
17004   mp_free_node(mp, v,mp->big_node_size[t]);
17005 }
17006
17007 @ @<Recycle a dependency list@>=
17008
17009   q=dep_list(p);
17010   while ( info(q)!=null ) q=link(q);
17011   link(prev_dep(p))=link(q);
17012   prev_dep(link(q))=prev_dep(p);
17013   link(q)=null; mp_flush_node_list(mp, dep_list(p));
17014 }
17015
17016 @ When an independent variable disappears, it simply fades away, unless
17017 something depends on it. In the latter case, a dependent variable whose
17018 coefficient of dependence is maximal will take its place.
17019 The relevant algorithm is due to Ignacio~A. Zabala, who implemented it
17020 as part of his Ph.D. thesis (Stanford University, December 1982).
17021 @^Zabala Salelles, Ignacio Andres@>
17022
17023 For example, suppose that variable $x$ is being recycled, and that the
17024 only variables depending on~$x$ are $y=2x+a$ and $z=x+b$. In this case
17025 we want to make $y$ independent and $z=.5y-.5a+b$; no other variables
17026 will depend on~$y$. If $\\{tracingequations}>0$ in this situation,
17027 we will print `\.{\#\#\# -2x=-y+a}'.
17028
17029 There's a slight complication, however: An independent variable $x$
17030 can occur both in dependency lists and in proto-dependency lists.
17031 This makes it necessary to be careful when deciding which coefficient
17032 is maximal.
17033
17034 Furthermore, this complication is not so slight when
17035 a proto-dependent variable is chosen to become independent. For example,
17036 suppose that $y=2x+100a$ is proto-dependent while $z=x+b$ is dependent;
17037 then we must change $z=.5y-50a+b$ to a proto-dependency, because of the
17038 large coefficient `50'.
17039
17040 In order to deal with these complications without wasting too much time,
17041 we shall link together the occurrences of~$x$ among all the linear
17042 dependencies, maintaining separate lists for the dependent and
17043 proto-dependent cases.
17044
17045 @<Recycle an independent variable@>=
17046
17047   mp->max_c[mp_dependent]=0; mp->max_c[mp_proto_dependent]=0;
17048   mp->max_link[mp_dependent]=null; mp->max_link[mp_proto_dependent]=null;
17049   q=link(dep_head);
17050   while ( q!=dep_head ) { 
17051     s=value_loc(q); /* now |link(s)=dep_list(q)| */
17052     while (1) { 
17053       r=link(s);
17054       if ( info(r)==null ) break;;
17055       if ( info(r)!=p ) { 
17056        s=r;
17057       } else  { 
17058         t=type(q); link(s)=link(r); info(r)=q;
17059         if ( abs(value(r))>mp->max_c[t] ) {
17060           @<Record a new maximum coefficient of type |t|@>;
17061         } else { 
17062           link(r)=mp->max_link[t]; mp->max_link[t]=r;
17063         }
17064       }
17065     }   
17066     q=link(r);
17067   }
17068   if ( (mp->max_c[mp_dependent]>0)||(mp->max_c[mp_proto_dependent]>0) ) {
17069     @<Choose a dependent variable to take the place of the disappearing
17070     independent variable, and change all remaining dependencies
17071     accordingly@>;
17072   }
17073 }
17074
17075 @ The code for independency removal makes use of three two-word arrays.
17076
17077 @<Glob...@>=
17078 integer max_c[mp_proto_dependent+1];  /* max coefficient magnitude */
17079 pointer max_ptr[mp_proto_dependent+1]; /* where |p| occurs with |max_c| */
17080 pointer max_link[mp_proto_dependent+1]; /* other occurrences of |p| */
17081
17082 @ @<Record a new maximum coefficient...@>=
17083
17084   if ( mp->max_c[t]>0 ) {
17085     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
17086   }
17087   mp->max_c[t]=abs(value(r)); mp->max_ptr[t]=r;
17088 }
17089
17090 @ @<Choose a dependent...@>=
17091
17092   if ( (mp->max_c[mp_dependent] / 010000 >= mp->max_c[mp_proto_dependent]) )
17093     t=mp_dependent;
17094   else 
17095     t=mp_proto_dependent;
17096   @<Determine the dependency list |s| to substitute for the independent
17097     variable~|p|@>;
17098   t=mp_dependent+mp_proto_dependent-t; /* complement |t| */
17099   if ( mp->max_c[t]>0 ) { /* we need to pick up an unchosen dependency */ 
17100     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
17101   }
17102   if ( t!=mp_dependent ) { @<Substitute new dependencies in place of |p|@>; }
17103   else { @<Substitute new proto-dependencies in place of |p|@>;}
17104   mp_flush_node_list(mp, s);
17105   if ( mp->fix_needed ) mp_fix_dependencies(mp);
17106   check_arith;
17107 }
17108
17109 @ Let |s=max_ptr[t]|. At this point we have $|value|(s)=\pm|max_c|[t]$,
17110 and |info(s)| points to the dependent variable~|pp| of type~|t| from
17111 whose dependency list we have removed node~|s|. We must reinsert
17112 node~|s| into the dependency list, with coefficient $-1.0$, and with
17113 |pp| as the new independent variable. Since |pp| will have a larger serial
17114 number than any other variable, we can put node |s| at the head of the
17115 list.
17116
17117 @<Determine the dep...@>=
17118 s=mp->max_ptr[t]; pp=info(s); v=value(s);
17119 if ( t==mp_dependent ) value(s)=-fraction_one; else value(s)=-unity;
17120 r=dep_list(pp); link(s)=r;
17121 while ( info(r)!=null ) r=link(r);
17122 q=link(r); link(r)=null;
17123 prev_dep(q)=prev_dep(pp); link(prev_dep(pp))=q;
17124 new_indep(pp);
17125 if ( mp->cur_exp==pp ) if ( mp->cur_type==t ) mp->cur_type=mp_independent;
17126 if ( mp->internal[mp_tracing_equations]>0 ) { 
17127   @<Show the transformed dependency@>; 
17128 }
17129
17130 @ Now $(-v)$ times the formerly independent variable~|p| is being replaced
17131 by the dependency list~|s|.
17132
17133 @<Show the transformed...@>=
17134 if ( mp_interesting(mp, p) ) {
17135   mp_begin_diagnostic(mp); mp_print_nl(mp, "### ");
17136 @:]]]\#\#\#_}{\.{\#\#\#}@>
17137   if ( v>0 ) mp_print_char(mp, '-');
17138   if ( t==mp_dependent ) vv=mp_round_fraction(mp, mp->max_c[mp_dependent]);
17139   else vv=mp->max_c[mp_proto_dependent];
17140   if ( vv!=unity ) mp_print_scaled(mp, vv);
17141   mp_print_variable_name(mp, p);
17142   while ( value(p) % s_scale>0 ) {
17143     mp_print(mp, "*4"); value(p)=value(p)-2;
17144   }
17145   if ( t==mp_dependent ) mp_print_char(mp, '='); else mp_print(mp, " = ");
17146   mp_print_dependency(mp, s,t);
17147   mp_end_diagnostic(mp, false);
17148 }
17149
17150 @ Finally, there are dependent and proto-dependent variables whose
17151 dependency lists must be brought up to date.
17152
17153 @<Substitute new dependencies...@>=
17154 for (t=mp_dependent;t<=mp_proto_dependent;t++){ 
17155   r=mp->max_link[t];
17156   while ( r!=null ) {
17157     q=info(r);
17158     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
17159      mp_make_fraction(mp, value(r),-v),s,t,mp_dependent);
17160     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
17161     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
17162   }
17163 }
17164
17165 @ @<Substitute new proto...@>=
17166 for (t=mp_dependent;t<=mp_proto_dependent;t++) {
17167   r=mp->max_link[t];
17168   while ( r!=null ) {
17169     q=info(r);
17170     if ( t==mp_dependent ) { /* for safety's sake, we change |q| to |mp_proto_dependent| */
17171       if ( mp->cur_exp==q ) if ( mp->cur_type==mp_dependent )
17172         mp->cur_type=mp_proto_dependent;
17173       dep_list(q)=mp_p_over_v(mp, dep_list(q),unity,mp_dependent,mp_proto_dependent);
17174       type(q)=mp_proto_dependent; value(r)=mp_round_fraction(mp, value(r));
17175     }
17176     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
17177       mp_make_scaled(mp, value(r),-v),s,mp_proto_dependent,mp_proto_dependent);
17178     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
17179     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
17180   }
17181 }
17182
17183 @ Here are some routines that provide handy combinations of actions
17184 that are often needed during error recovery. For example,
17185 `|flush_error|' flushes the current expression, replaces it by
17186 a given value, and calls |error|.
17187
17188 Errors often are detected after an extra token has already been scanned.
17189 The `\\{put\_get}' routines put that token back before calling |error|;
17190 then they get it back again. (Or perhaps they get another token, if
17191 the user has changed things.)
17192
17193 @<Declarations@>=
17194 void mp_flush_error (MP mp,scaled v);
17195 void mp_put_get_error (MP mp);
17196 void mp_put_get_flush_error (MP mp,scaled v) ;
17197
17198 @ @c
17199 void mp_flush_error (MP mp,scaled v) { 
17200   mp_error(mp); mp_flush_cur_exp(mp, v); 
17201 }
17202 void mp_put_get_error (MP mp) { 
17203   mp_back_error(mp); mp_get_x_next(mp); 
17204 }
17205 void mp_put_get_flush_error (MP mp,scaled v) { 
17206   mp_put_get_error(mp);
17207   mp_flush_cur_exp(mp, v); 
17208 }
17209
17210 @ A global variable |var_flag| is set to a special command code
17211 just before \MP\ calls |scan_expression|, if the expression should be
17212 treated as a variable when this command code immediately follows. For
17213 example, |var_flag| is set to |assignment| at the beginning of a
17214 statement, because we want to know the {\sl location\/} of a variable at
17215 the left of `\.{:=}', not the {\sl value\/} of that variable.
17216
17217 The |scan_expression| subroutine calls |scan_tertiary|,
17218 which calls |scan_secondary|, which calls |scan_primary|, which sets
17219 |var_flag:=0|. In this way each of the scanning routines ``knows''
17220 when it has been called with a special |var_flag|, but |var_flag| is
17221 usually zero.
17222
17223 A variable preceding a command that equals |var_flag| is converted to a
17224 token list rather than a value. Furthermore, an `\.{=}' sign following an
17225 expression with |var_flag=assignment| is not considered to be a relation
17226 that produces boolean expressions.
17227
17228
17229 @<Glob...@>=
17230 int var_flag; /* command that wants a variable */
17231
17232 @ @<Set init...@>=
17233 mp->var_flag=0;
17234
17235 @* \[37] Parsing primary expressions.
17236 The first parsing routine, |scan_primary|, is also the most complicated one,
17237 since it involves so many different cases. But each case---with one
17238 exception---is fairly simple by itself.
17239
17240 When |scan_primary| begins, the first token of the primary to be scanned
17241 should already appear in |cur_cmd|, |cur_mod|, and |cur_sym|. The values
17242 of |cur_type| and |cur_exp| should be either dead or dormant, as explained
17243 earlier. If |cur_cmd| is not between |min_primary_command| and
17244 |max_primary_command|, inclusive, a syntax error will be signaled.
17245
17246 @<Declare the basic parsing subroutines@>=
17247 void mp_scan_primary (MP mp) {
17248   pointer p,q,r; /* for list manipulation */
17249   quarterword c; /* a primitive operation code */
17250   int my_var_flag; /* initial value of |my_var_flag| */
17251   pointer l_delim,r_delim; /* hash addresses of a delimiter pair */
17252   @<Other local variables for |scan_primary|@>;
17253   my_var_flag=mp->var_flag; mp->var_flag=0;
17254 RESTART:
17255   check_arith;
17256   @<Supply diagnostic information, if requested@>;
17257   switch (mp->cur_cmd) {
17258   case left_delimiter:
17259     @<Scan a delimited primary@>; break;
17260   case begin_group:
17261     @<Scan a grouped primary@>; break;
17262   case string_token:
17263     @<Scan a string constant@>; break;
17264   case numeric_token:
17265     @<Scan a primary that starts with a numeric token@>; break;
17266   case nullary:
17267     @<Scan a nullary operation@>; break;
17268   case unary: case type_name: case cycle: case plus_or_minus:
17269     @<Scan a unary operation@>; break;
17270   case primary_binary:
17271     @<Scan a binary operation with `\&{of}' between its operands@>; break;
17272   case str_op:
17273     @<Convert a suffix to a string@>; break;
17274   case internal_quantity:
17275     @<Scan an internal numeric quantity@>; break;
17276   case capsule_token:
17277     mp_make_exp_copy(mp, mp->cur_mod); break;
17278   case tag_token:
17279     @<Scan a variable primary; |goto restart| if it turns out to be a macro@>; break;
17280   default: 
17281     mp_bad_exp(mp, "A primary"); goto RESTART; break;
17282 @.A primary expression...@>
17283   }
17284   mp_get_x_next(mp); /* the routines |goto done| if they don't want this */
17285 DONE: 
17286   if ( mp->cur_cmd==left_bracket ) {
17287     if ( mp->cur_type>=mp_known ) {
17288       @<Scan a mediation construction@>;
17289     }
17290   }
17291 }
17292
17293
17294
17295 @ Errors at the beginning of expressions are flagged by |bad_exp|.
17296
17297 @c void mp_bad_exp (MP mp,char * s) {
17298   int save_flag;
17299   print_err(s); mp_print(mp, " expression can't begin with `");
17300   mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); 
17301   mp_print_char(mp, '\'');
17302   help4("I'm afraid I need some sort of value in order to continue,")
17303     ("so I've tentatively inserted `0'. You may want to")
17304     ("delete this zero and insert something else;")
17305     ("see Chapter 27 of The METAFONTbook for an example.");
17306 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17307   mp_back_input(mp); mp->cur_sym=0; mp->cur_cmd=numeric_token; 
17308   mp->cur_mod=0; mp_ins_error(mp);
17309   save_flag=mp->var_flag; mp->var_flag=0; mp_get_x_next(mp);
17310   mp->var_flag=save_flag;
17311 }
17312
17313 @ @<Supply diagnostic information, if requested@>=
17314 #ifdef DEBUG
17315 if ( mp->panicking ) mp_check_mem(mp, false);
17316 #endif
17317 if ( mp->interrupt!=0 ) if ( mp->OK_to_interrupt ) {
17318   mp_back_input(mp); check_interrupt; mp_get_x_next(mp);
17319 }
17320
17321 @ @<Scan a delimited primary@>=
17322
17323   l_delim=mp->cur_sym; r_delim=mp->cur_mod; 
17324   mp_get_x_next(mp); mp_scan_expression(mp);
17325   if ( (mp->cur_cmd==comma) && (mp->cur_type>=mp_known) ) {
17326     @<Scan the rest of a delimited set of numerics@>;
17327   } else {
17328     mp_check_delimiter(mp, l_delim,r_delim);
17329   }
17330 }
17331
17332 @ The |stash_in| subroutine puts the current (numeric) expression into a field
17333 within a ``big node.''
17334
17335 @c void mp_stash_in (MP mp,pointer p) {
17336   pointer q; /* temporary register */
17337   type(p)=mp->cur_type;
17338   if ( mp->cur_type==mp_known ) {
17339     value(p)=mp->cur_exp;
17340   } else { 
17341     if ( mp->cur_type==mp_independent ) {
17342       @<Stash an independent |cur_exp| into a big node@>;
17343     } else { 
17344       mp->mem[value_loc(p)]=mp->mem[value_loc(mp->cur_exp)];
17345       /* |dep_list(p):=dep_list(cur_exp)| and |prev_dep(p):=prev_dep(cur_exp)| */
17346       link(prev_dep(p))=p;
17347     }
17348     mp_free_node(mp, mp->cur_exp,value_node_size);
17349   }
17350   mp->cur_type=mp_vacuous;
17351 }
17352
17353 @ In rare cases the current expression can become |independent|. There
17354 may be many dependency lists pointing to such an independent capsule,
17355 so we can't simply move it into place within a big node. Instead,
17356 we copy it, then recycle it.
17357
17358 @ @<Stash an independent |cur_exp|...@>=
17359
17360   q=mp_single_dependency(mp, mp->cur_exp);
17361   if ( q==mp->dep_final ){ 
17362     type(p)=mp_known; value(p)=0; mp_free_node(mp, q,dep_node_size);
17363   } else { 
17364     type(p)=mp_dependent; mp_new_dep(mp, p,q);
17365   }
17366   mp_recycle_value(mp, mp->cur_exp);
17367 }
17368
17369 @ This code uses the fact that |red_part_loc| and |green_part_loc|
17370 are synonymous with |x_part_loc| and |y_part_loc|.
17371
17372 @<Scan the rest of a delimited set of numerics@>=
17373
17374 p=mp_stash_cur_exp(mp);
17375 mp_get_x_next(mp); mp_scan_expression(mp);
17376 @<Make sure the second part of a pair or color has a numeric type@>;
17377 q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
17378 if ( mp->cur_cmd==comma ) type(q)=mp_color_type;
17379 else type(q)=mp_pair_type;
17380 mp_init_big_node(mp, q); r=value(q);
17381 mp_stash_in(mp, y_part_loc(r));
17382 mp_unstash_cur_exp(mp, p);
17383 mp_stash_in(mp, x_part_loc(r));
17384 if ( mp->cur_cmd==comma ) {
17385   @<Scan the last of a triplet of numerics@>;
17386 }
17387 if ( mp->cur_cmd==comma ) {
17388   type(q)=mp_cmykcolor_type;
17389   mp_init_big_node(mp, q); t=value(q);
17390   mp->mem[cyan_part_loc(t)]=mp->mem[red_part_loc(r)];
17391   value(cyan_part_loc(t))=value(red_part_loc(r));
17392   mp->mem[magenta_part_loc(t)]=mp->mem[green_part_loc(r)];
17393   value(magenta_part_loc(t))=value(green_part_loc(r));
17394   mp->mem[yellow_part_loc(t)]=mp->mem[blue_part_loc(r)];
17395   value(yellow_part_loc(t))=value(blue_part_loc(r));
17396   mp_recycle_value(mp, r);
17397   r=t;
17398   @<Scan the last of a quartet of numerics@>;
17399 }
17400 mp_check_delimiter(mp, l_delim,r_delim);
17401 mp->cur_type=type(q);
17402 mp->cur_exp=q;
17403 }
17404
17405 @ @<Make sure the second part of a pair or color has a numeric type@>=
17406 if ( mp->cur_type<mp_known ) {
17407   exp_err("Nonnumeric ypart has been replaced by 0");
17408 @.Nonnumeric...replaced by 0@>
17409   help4("I've started to scan a pair `(a,b)' or a color `(a,b,c)';")
17410     ("but after finding a nice `a' I found a `b' that isn't")
17411     ("of numeric type. So I've changed that part to zero.")
17412     ("(The b that I didn't like appears above the error message.)");
17413   mp_put_get_flush_error(mp, 0);
17414 }
17415
17416 @ @<Scan the last of a triplet of numerics@>=
17417
17418   mp_get_x_next(mp); mp_scan_expression(mp);
17419   if ( mp->cur_type<mp_known ) {
17420     exp_err("Nonnumeric third part has been replaced by 0");
17421 @.Nonnumeric...replaced by 0@>
17422     help3("I've just scanned a color `(a,b,c)' or cmykcolor(a,b,c,d); but the `c'")
17423       ("isn't of numeric type. So I've changed that part to zero.")
17424       ("(The c that I didn't like appears above the error message.)");
17425     mp_put_get_flush_error(mp, 0);
17426   }
17427   mp_stash_in(mp, blue_part_loc(r));
17428 }
17429
17430 @ @<Scan the last of a quartet of numerics@>=
17431
17432   mp_get_x_next(mp); mp_scan_expression(mp);
17433   if ( mp->cur_type<mp_known ) {
17434     exp_err("Nonnumeric blackpart has been replaced by 0");
17435 @.Nonnumeric...replaced by 0@>
17436     help3("I've just scanned a cmykcolor `(c,m,y,k)'; but the `k' isn't")
17437       ("of numeric type. So I've changed that part to zero.")
17438       ("(The k that I didn't like appears above the error message.)");
17439     mp_put_get_flush_error(mp, 0);
17440   }
17441   mp_stash_in(mp, black_part_loc(r));
17442 }
17443
17444 @ The local variable |group_line| keeps track of the line
17445 where a \&{begingroup} command occurred; this will be useful
17446 in an error message if the group doesn't actually end.
17447
17448 @<Other local variables for |scan_primary|@>=
17449 integer group_line; /* where a group began */
17450
17451 @ @<Scan a grouped primary@>=
17452
17453   group_line=mp_true_line(mp);
17454   if ( mp->internal[mp_tracing_commands]>0 ) show_cur_cmd_mod;
17455   save_boundary_item(p);
17456   do {  
17457     mp_do_statement(mp); /* ends with |cur_cmd>=semicolon| */
17458   } while (! (mp->cur_cmd!=semicolon));
17459   if ( mp->cur_cmd!=end_group ) {
17460     print_err("A group begun on line ");
17461 @.A group...never ended@>
17462     mp_print_int(mp, group_line);
17463     mp_print(mp, " never ended");
17464     help2("I saw a `begingroup' back there that hasn't been matched")
17465          ("by `endgroup'. So I've inserted `endgroup' now.");
17466     mp_back_error(mp); mp->cur_cmd=end_group;
17467   }
17468   mp_unsave(mp); 
17469     /* this might change |cur_type|, if independent variables are recycled */
17470   if ( mp->internal[mp_tracing_commands]>0 ) show_cur_cmd_mod;
17471 }
17472
17473 @ @<Scan a string constant@>=
17474
17475   mp->cur_type=mp_string_type; mp->cur_exp=mp->cur_mod;
17476 }
17477
17478 @ Later we'll come to procedures that perform actual operations like
17479 addition, square root, and so on; our purpose now is to do the parsing.
17480 But we might as well mention those future procedures now, so that the
17481 suspense won't be too bad:
17482
17483 \smallskip
17484 |do_nullary(c)| does primitive operations that have no operands (e.g.,
17485 `\&{true}' or `\&{pencircle}');
17486
17487 \smallskip
17488 |do_unary(c)| applies a primitive operation to the current expression;
17489
17490 \smallskip
17491 |do_binary(p,c)| applies a primitive operation to the capsule~|p|
17492 and the current expression.
17493
17494 @<Scan a nullary operation@>=mp_do_nullary(mp, mp->cur_mod)
17495
17496 @ @<Scan a unary operation@>=
17497
17498   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_primary(mp); 
17499   mp_do_unary(mp, c); goto DONE;
17500 }
17501
17502 @ A numeric token might be a primary by itself, or it might be the
17503 numerator of a fraction composed solely of numeric tokens, or it might
17504 multiply the primary that follows (provided that the primary doesn't begin
17505 with a plus sign or a minus sign). The code here uses the facts that
17506 |max_primary_command=plus_or_minus| and
17507 |max_primary_command-1=numeric_token|. If a fraction is found that is less
17508 than unity, we try to retain higher precision when we use it in scalar
17509 multiplication.
17510
17511 @<Other local variables for |scan_primary|@>=
17512 scaled num,denom; /* for primaries that are fractions, like `1/2' */
17513
17514 @ @<Scan a primary that starts with a numeric token@>=
17515
17516   mp->cur_exp=mp->cur_mod; mp->cur_type=mp_known; mp_get_x_next(mp);
17517   if ( mp->cur_cmd!=slash ) { 
17518     num=0; denom=0;
17519   } else { 
17520     mp_get_x_next(mp);
17521     if ( mp->cur_cmd!=numeric_token ) { 
17522       mp_back_input(mp);
17523       mp->cur_cmd=slash; mp->cur_mod=over; mp->cur_sym=frozen_slash;
17524       goto DONE;
17525     }
17526     num=mp->cur_exp; denom=mp->cur_mod;
17527     if ( denom==0 ) { @<Protest division by zero@>; }
17528     else { mp->cur_exp=mp_make_scaled(mp, num,denom); }
17529     check_arith; mp_get_x_next(mp);
17530   }
17531   if ( mp->cur_cmd>=min_primary_command ) {
17532    if ( mp->cur_cmd<numeric_token ) { /* in particular, |cur_cmd<>plus_or_minus| */
17533      p=mp_stash_cur_exp(mp); mp_scan_primary(mp);
17534      if ( (abs(num)>=abs(denom))||(mp->cur_type<mp_color_type) ) {
17535        mp_do_binary(mp, p,times);
17536      } else {
17537        mp_frac_mult(mp, num,denom);
17538        mp_free_node(mp, p,value_node_size);
17539      }
17540     }
17541   }
17542   goto DONE;
17543 }
17544
17545 @ @<Protest division...@>=
17546
17547   print_err("Division by zero");
17548 @.Division by zero@>
17549   help1("I'll pretend that you meant to divide by 1."); mp_error(mp);
17550 }
17551
17552 @ @<Scan a binary operation with `\&{of}' between its operands@>=
17553
17554   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
17555   if ( mp->cur_cmd!=of_token ) {
17556     mp_missing_err(mp, "of"); mp_print(mp, " for "); 
17557     mp_print_cmd_mod(mp, primary_binary,c);
17558 @.Missing `of'@>
17559     help1("I've got the first argument; will look now for the other.");
17560     mp_back_error(mp);
17561   }
17562   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_primary(mp); 
17563   mp_do_binary(mp, p,c); goto DONE;
17564 }
17565
17566 @ @<Convert a suffix to a string@>=
17567
17568   mp_get_x_next(mp); mp_scan_suffix(mp); 
17569   mp->old_setting=mp->selector; mp->selector=new_string;
17570   mp_show_token_list(mp, mp->cur_exp,null,100000,0); 
17571   mp_flush_token_list(mp, mp->cur_exp);
17572   mp->cur_exp=mp_make_string(mp); mp->selector=mp->old_setting; 
17573   mp->cur_type=mp_string_type;
17574   goto DONE;
17575 }
17576
17577 @ If an internal quantity appears all by itself on the left of an
17578 assignment, we return a token list of length one, containing the address
17579 of the internal quantity plus |hash_end|. (This accords with the conventions
17580 of the save stack, as described earlier.)
17581
17582 @<Scan an internal...@>=
17583
17584   q=mp->cur_mod;
17585   if ( my_var_flag==assignment ) {
17586     mp_get_x_next(mp);
17587     if ( mp->cur_cmd==assignment ) {
17588       mp->cur_exp=mp_get_avail(mp);
17589       info(mp->cur_exp)=q+hash_end; mp->cur_type=mp_token_list; 
17590       goto DONE;
17591     }
17592     mp_back_input(mp);
17593   }
17594   mp->cur_type=mp_known; mp->cur_exp=mp->internal[q];
17595 }
17596
17597 @ The most difficult part of |scan_primary| has been saved for last, since
17598 it was necessary to build up some confidence first. We can now face the task
17599 of scanning a variable.
17600
17601 As we scan a variable, we build a token list containing the relevant
17602 names and subscript values, simultaneously following along in the
17603 ``collective'' structure to see if we are actually dealing with a macro
17604 instead of a value.
17605
17606 The local variables |pre_head| and |post_head| will point to the beginning
17607 of the prefix and suffix lists; |tail| will point to the end of the list
17608 that is currently growing.
17609
17610 Another local variable, |tt|, contains partial information about the
17611 declared type of the variable-so-far. If |tt>=mp_unsuffixed_macro|, the
17612 relation |tt=type(q)| will always hold. If |tt=undefined|, the routine
17613 doesn't bother to update its information about type. And if
17614 |undefined<tt<mp_unsuffixed_macro|, the precise value of |tt| isn't critical.
17615
17616 @ @<Other local variables for |scan_primary|@>=
17617 pointer pre_head,post_head,tail;
17618   /* prefix and suffix list variables */
17619 small_number tt; /* approximation to the type of the variable-so-far */
17620 pointer t; /* a token */
17621 pointer macro_ref = 0; /* reference count for a suffixed macro */
17622
17623 @ @<Scan a variable primary...@>=
17624
17625   fast_get_avail(pre_head); tail=pre_head; post_head=null; tt=mp_vacuous;
17626   while (1) { 
17627     t=mp_cur_tok(mp); link(tail)=t;
17628     if ( tt!=undefined ) {
17629        @<Find the approximate type |tt| and corresponding~|q|@>;
17630       if ( tt>=mp_unsuffixed_macro ) {
17631         @<Either begin an unsuffixed macro call or
17632           prepare for a suffixed one@>;
17633       }
17634     }
17635     mp_get_x_next(mp); tail=t;
17636     if ( mp->cur_cmd==left_bracket ) {
17637       @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>;
17638     }
17639     if ( mp->cur_cmd>max_suffix_token ) break;
17640     if ( mp->cur_cmd<min_suffix_token ) break;
17641   } /* now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| */
17642   @<Handle unusual cases that masquerade as variables, and |goto restart|
17643     or |goto done| if appropriate;
17644     otherwise make a copy of the variable and |goto done|@>;
17645 }
17646
17647 @ @<Either begin an unsuffixed macro call or...@>=
17648
17649   link(tail)=null;
17650   if ( tt>mp_unsuffixed_macro ) { /* |tt=mp_suffixed_macro| */
17651     post_head=mp_get_avail(mp); tail=post_head; link(tail)=t;
17652     tt=undefined; macro_ref=value(q); add_mac_ref(macro_ref);
17653   } else {
17654     @<Set up unsuffixed macro call and |goto restart|@>;
17655   }
17656 }
17657
17658 @ @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>=
17659
17660   mp_get_x_next(mp); mp_scan_expression(mp);
17661   if ( mp->cur_cmd!=right_bracket ) {
17662     @<Put the left bracket and the expression back to be rescanned@>;
17663   } else { 
17664     if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17665     mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp; mp->cur_sym=0;
17666   }
17667 }
17668
17669 @ The left bracket that we thought was introducing a subscript might have
17670 actually been the left bracket in a mediation construction like `\.{x[a,b]}'.
17671 So we don't issue an error message at this point; but we do want to back up
17672 so as to avoid any embarrassment about our incorrect assumption.
17673
17674 @<Put the left bracket and the expression back to be rescanned@>=
17675
17676   mp_back_input(mp); /* that was the token following the current expression */
17677   mp_back_expr(mp); mp->cur_cmd=left_bracket; 
17678   mp->cur_mod=0; mp->cur_sym=frozen_left_bracket;
17679 }
17680
17681 @ Here's a routine that puts the current expression back to be read again.
17682
17683 @c void mp_back_expr (MP mp) {
17684   pointer p; /* capsule token */
17685   p=mp_stash_cur_exp(mp); link(p)=null; back_list(p);
17686 }
17687
17688 @ Unknown subscripts lead to the following error message.
17689
17690 @c void mp_bad_subscript (MP mp) { 
17691   exp_err("Improper subscript has been replaced by zero");
17692 @.Improper subscript...@>
17693   help3("A bracketed subscript must have a known numeric value;")
17694     ("unfortunately, what I found was the value that appears just")
17695     ("above this error message. So I'll try a zero subscript.");
17696   mp_flush_error(mp, 0);
17697 }
17698
17699 @ Every time we call |get_x_next|, there's a chance that the variable we've
17700 been looking at will disappear. Thus, we cannot safely keep |q| pointing
17701 into the variable structure; we need to start searching from the root each time.
17702
17703 @<Find the approximate type |tt| and corresponding~|q|@>=
17704 @^inner loop@>
17705
17706   p=link(pre_head); q=info(p); tt=undefined;
17707   if ( eq_type(q) % outer_tag==tag_token ) {
17708     q=equiv(q);
17709     if ( q==null ) goto DONE2;
17710     while (1) { 
17711       p=link(p);
17712       if ( p==null ) {
17713         tt=type(q); goto DONE2;
17714       };
17715       if ( type(q)!=mp_structured ) goto DONE2;
17716       q=link(attr_head(q)); /* the |collective_subscript| attribute */
17717       if ( p>=mp->hi_mem_min ) { /* it's not a subscript */
17718         do {  q=link(q); } while (! (attr_loc(q)>=info(p)));
17719         if ( attr_loc(q)>info(p) ) goto DONE2;
17720       }
17721     }
17722   }
17723 DONE2:
17724   ;
17725 }
17726
17727 @ How do things stand now? Well, we have scanned an entire variable name,
17728 including possible subscripts and/or attributes; |cur_cmd|, |cur_mod|, and
17729 |cur_sym| represent the token that follows. If |post_head=null|, a
17730 token list for this variable name starts at |link(pre_head)|, with all
17731 subscripts evaluated. But if |post_head<>null|, the variable turned out
17732 to be a suffixed macro; |pre_head| is the head of the prefix list, while
17733 |post_head| is the head of a token list containing both `\.{\AT!}' and
17734 the suffix.
17735
17736 Our immediate problem is to see if this variable still exists. (Variable
17737 structures can change drastically whenever we call |get_x_next|; users
17738 aren't supposed to do this, but the fact that it is possible means that
17739 we must be cautious.)
17740
17741 The following procedure prints an error message when a variable
17742 unexpectedly disappears. Its help message isn't quite right for
17743 our present purposes, but we'll be able to fix that up.
17744
17745 @c 
17746 void mp_obliterated (MP mp,pointer q) { 
17747   print_err("Variable "); mp_show_token_list(mp, q,null,1000,0);
17748   mp_print(mp, " has been obliterated");
17749 @.Variable...obliterated@>
17750   help5("It seems you did a nasty thing---probably by accident,")
17751     ("but nevertheless you nearly hornswoggled me...")
17752     ("While I was evaluating the right-hand side of this")
17753     ("command, something happened, and the left-hand side")
17754     ("is no longer a variable! So I won't change anything.");
17755 }
17756
17757 @ If the variable does exist, we also need to check
17758 for a few other special cases before deciding that a plain old ordinary
17759 variable has, indeed, been scanned.
17760
17761 @<Handle unusual cases that masquerade as variables...@>=
17762 if ( post_head!=null ) {
17763   @<Set up suffixed macro call and |goto restart|@>;
17764 }
17765 q=link(pre_head); free_avail(pre_head);
17766 if ( mp->cur_cmd==my_var_flag ) { 
17767   mp->cur_type=mp_token_list; mp->cur_exp=q; goto DONE;
17768 }
17769 p=mp_find_variable(mp, q);
17770 if ( p!=null ) {
17771   mp_make_exp_copy(mp, p);
17772 } else { 
17773   mp_obliterated(mp, q);
17774   mp->help_line[2]="While I was evaluating the suffix of this variable,";
17775   mp->help_line[1]="something was redefined, and it's no longer a variable!";
17776   mp->help_line[0]="In order to get back on my feet, I've inserted `0' instead.";
17777   mp_put_get_flush_error(mp, 0);
17778 }
17779 mp_flush_node_list(mp, q); 
17780 goto DONE
17781
17782 @ The only complication associated with macro calling is that the prefix
17783 and ``at'' parameters must be packaged in an appropriate list of lists.
17784
17785 @<Set up unsuffixed macro call and |goto restart|@>=
17786
17787   p=mp_get_avail(mp); info(pre_head)=link(pre_head); link(pre_head)=p;
17788   info(p)=t; mp_macro_call(mp, value(q),pre_head,null);
17789   mp_get_x_next(mp); 
17790   goto RESTART;
17791 }
17792
17793 @ If the ``variable'' that turned out to be a suffixed macro no longer exists,
17794 we don't care, because we have reserved a pointer (|macro_ref|) to its
17795 token list.
17796
17797 @<Set up suffixed macro call and |goto restart|@>=
17798
17799   mp_back_input(mp); p=mp_get_avail(mp); q=link(post_head);
17800   info(pre_head)=link(pre_head); link(pre_head)=post_head;
17801   info(post_head)=q; link(post_head)=p; info(p)=link(q); link(q)=null;
17802   mp_macro_call(mp, macro_ref,pre_head,null); decr(ref_count(macro_ref));
17803   mp_get_x_next(mp); goto RESTART;
17804 }
17805
17806 @ Our remaining job is simply to make a copy of the value that has been
17807 found. Some cases are harder than others, but complexity arises solely
17808 because of the multiplicity of possible cases.
17809
17810 @<Declare the procedure called |make_exp_copy|@>=
17811 @<Declare subroutines needed by |make_exp_copy|@>;
17812 void mp_make_exp_copy (MP mp,pointer p) {
17813   pointer q,r,t; /* registers for list manipulation */
17814 RESTART: 
17815   mp->cur_type=type(p);
17816   switch (mp->cur_type) {
17817   case mp_vacuous: case mp_boolean_type: case mp_known:
17818     mp->cur_exp=value(p); break;
17819   case unknown_types:
17820     mp->cur_exp=mp_new_ring_entry(mp, p);
17821     break;
17822   case mp_string_type: 
17823     mp->cur_exp=value(p); add_str_ref(mp->cur_exp);
17824     break;
17825   case mp_picture_type:
17826     mp->cur_exp=value(p);add_edge_ref(mp->cur_exp);
17827     break;
17828   case mp_pen_type:
17829     mp->cur_exp=copy_pen(value(p));
17830     break; 
17831   case mp_path_type:
17832     mp->cur_exp=mp_copy_path(mp, value(p));
17833     break;
17834   case mp_transform_type: case mp_color_type: 
17835   case mp_cmykcolor_type: case mp_pair_type:
17836     @<Copy the big node |p|@>;
17837     break;
17838   case mp_dependent: case mp_proto_dependent:
17839     mp_encapsulate(mp, mp_copy_dep_list(mp, dep_list(p)));
17840     break;
17841   case mp_numeric_type: 
17842     new_indep(p); goto RESTART;
17843     break;
17844   case mp_independent: 
17845     q=mp_single_dependency(mp, p);
17846     if ( q==mp->dep_final ){ 
17847       mp->cur_type=mp_known; mp->cur_exp=0; mp_free_node(mp, q,value_node_size);
17848     } else { 
17849       mp->cur_type=mp_dependent; mp_encapsulate(mp, q);
17850     }
17851     break;
17852   default: 
17853     mp_confusion(mp, "copy");
17854 @:this can't happen copy}{\quad copy@>
17855     break;
17856   }
17857 }
17858
17859 @ The |encapsulate| subroutine assumes that |dep_final| is the
17860 tail of dependency list~|p|.
17861
17862 @<Declare subroutines needed by |make_exp_copy|@>=
17863 void mp_encapsulate (MP mp,pointer p) { 
17864   mp->cur_exp=mp_get_node(mp, value_node_size); type(mp->cur_exp)=mp->cur_type;
17865   name_type(mp->cur_exp)=mp_capsule; mp_new_dep(mp, mp->cur_exp,p);
17866 }
17867
17868 @ The most tedious case arises when the user refers to a
17869 \&{pair}, \&{color}, or \&{transform} variable; we must copy several fields,
17870 each of which can be |independent|, |dependent|, |mp_proto_dependent|,
17871 or |known|.
17872
17873 @<Copy the big node |p|@>=
17874
17875   if ( value(p)==null ) 
17876     mp_init_big_node(mp, p);
17877   t=mp_get_node(mp, value_node_size); name_type(t)=mp_capsule; type(t)=mp->cur_type;
17878   mp_init_big_node(mp, t);
17879   q=value(p)+mp->big_node_size[mp->cur_type]; 
17880   r=value(t)+mp->big_node_size[mp->cur_type];
17881   do {  
17882     q=q-2; r=r-2; mp_install(mp, r,q);
17883   } while (q!=value(p));
17884   mp->cur_exp=t;
17885 }
17886
17887 @ The |install| procedure copies a numeric field~|q| into field~|r| of
17888 a big node that will be part of a capsule.
17889
17890 @<Declare subroutines needed by |make_exp_copy|@>=
17891 void mp_install (MP mp,pointer r, pointer q) {
17892   pointer p; /* temporary register */
17893   if ( type(q)==mp_known ){ 
17894     value(r)=value(q); type(r)=mp_known;
17895   } else  if ( type(q)==mp_independent ) {
17896     p=mp_single_dependency(mp, q);
17897     if ( p==mp->dep_final ) {
17898       type(r)=mp_known; value(r)=0; mp_free_node(mp, p,value_node_size);
17899     } else  { 
17900       type(r)=mp_dependent; mp_new_dep(mp, r,p);
17901     }
17902   } else {
17903     type(r)=type(q); mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(q)));
17904   }
17905 }
17906
17907 @ Expressions of the form `\.{a[b,c]}' are converted into
17908 `\.{b+a*(c-b)}', without checking the types of \.b~or~\.c,
17909 provided that \.a is numeric.
17910
17911 @<Scan a mediation...@>=
17912
17913   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17914   if ( mp->cur_cmd!=comma ) {
17915     @<Put the left bracket and the expression back...@>;
17916     mp_unstash_cur_exp(mp, p);
17917   } else { 
17918     q=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17919     if ( mp->cur_cmd!=right_bracket ) {
17920       mp_missing_err(mp, "]");
17921 @.Missing `]'@>
17922       help3("I've scanned an expression of the form `a[b,c',")
17923       ("so a right bracket should have come next.")
17924       ("I shall pretend that one was there.");
17925       mp_back_error(mp);
17926     }
17927     r=mp_stash_cur_exp(mp); mp_make_exp_copy(mp, q);
17928     mp_do_binary(mp, r,minus); mp_do_binary(mp, p,times); 
17929     mp_do_binary(mp, q,plus); mp_get_x_next(mp);
17930   }
17931 }
17932
17933 @ Here is a comparatively simple routine that is used to scan the
17934 \&{suffix} parameters of a macro.
17935
17936 @<Declare the basic parsing subroutines@>=
17937 void mp_scan_suffix (MP mp) {
17938   pointer h,t; /* head and tail of the list being built */
17939   pointer p; /* temporary register */
17940   h=mp_get_avail(mp); t=h;
17941   while (1) { 
17942     if ( mp->cur_cmd==left_bracket ) {
17943       @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>;
17944     }
17945     if ( mp->cur_cmd==numeric_token ) {
17946       p=mp_new_num_tok(mp, mp->cur_mod);
17947     } else if ((mp->cur_cmd==tag_token)||(mp->cur_cmd==internal_quantity) ) {
17948        p=mp_get_avail(mp); info(p)=mp->cur_sym;
17949     } else {
17950       break;
17951     }
17952     link(t)=p; t=p; mp_get_x_next(mp);
17953   }
17954   mp->cur_exp=link(h); free_avail(h); mp->cur_type=mp_token_list;
17955 }
17956
17957 @ @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>=
17958
17959   mp_get_x_next(mp); mp_scan_expression(mp);
17960   if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17961   if ( mp->cur_cmd!=right_bracket ) {
17962      mp_missing_err(mp, "]");
17963 @.Missing `]'@>
17964     help3("I've seen a `[' and a subscript value, in a suffix,")
17965       ("so a right bracket should have come next.")
17966       ("I shall pretend that one was there.");
17967     mp_back_error(mp);
17968   }
17969   mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp;
17970 }
17971
17972 @* \[38] Parsing secondary and higher expressions.
17973 After the intricacies of |scan_primary|\kern-1pt,
17974 the |scan_secondary| routine is
17975 refreshingly simple. It's not trivial, but the operations are relatively
17976 straightforward; the main difficulty is, again, that expressions and data
17977 structures might change drastically every time we call |get_x_next|, so a
17978 cautious approach is mandatory. For example, a macro defined by
17979 \&{primarydef} might have disappeared by the time its second argument has
17980 been scanned; we solve this by increasing the reference count of its token
17981 list, so that the macro can be called even after it has been clobbered.
17982
17983 @<Declare the basic parsing subroutines@>=
17984 void mp_scan_secondary (MP mp) {
17985   pointer p; /* for list manipulation */
17986   halfword c,d; /* operation codes or modifiers */
17987   pointer mac_name; /* token defined with \&{primarydef} */
17988 RESTART:
17989   if ((mp->cur_cmd<min_primary_command)||
17990       (mp->cur_cmd>max_primary_command) )
17991     mp_bad_exp(mp, "A secondary");
17992 @.A secondary expression...@>
17993   mp_scan_primary(mp);
17994 CONTINUE: 
17995   if ( mp->cur_cmd<=max_secondary_command )
17996     if ( mp->cur_cmd>=min_secondary_command ) {
17997       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17998       if ( d==secondary_primary_macro ) { 
17999         mac_name=mp->cur_sym; add_mac_ref(c);
18000      }
18001      mp_get_x_next(mp); mp_scan_primary(mp);
18002      if ( d!=secondary_primary_macro ) {
18003        mp_do_binary(mp, p,c);
18004      } else  { 
18005        mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
18006        decr(ref_count(c)); mp_get_x_next(mp); 
18007        goto RESTART;
18008     }
18009     goto CONTINUE;
18010   }
18011 }
18012
18013 @ The following procedure calls a macro that has two parameters,
18014 |p| and |cur_exp|.
18015
18016 @c void mp_binary_mac (MP mp,pointer p, pointer c, pointer n) {
18017   pointer q,r; /* nodes in the parameter list */
18018   q=mp_get_avail(mp); r=mp_get_avail(mp); link(q)=r;
18019   info(q)=p; info(r)=mp_stash_cur_exp(mp);
18020   mp_macro_call(mp, c,q,n);
18021 }
18022
18023 @ The next procedure, |scan_tertiary|, is pretty much the same deal.
18024
18025 @<Declare the basic parsing subroutines@>=
18026 void mp_scan_tertiary (MP mp) {
18027   pointer p; /* for list manipulation */
18028   halfword c,d; /* operation codes or modifiers */
18029   pointer mac_name; /* token defined with \&{secondarydef} */
18030 RESTART:
18031   if ((mp->cur_cmd<min_primary_command)||
18032       (mp->cur_cmd>max_primary_command) )
18033     mp_bad_exp(mp, "A tertiary");
18034 @.A tertiary expression...@>
18035   mp_scan_secondary(mp);
18036 CONTINUE: 
18037   if ( mp->cur_cmd<=max_tertiary_command ) {
18038     if ( mp->cur_cmd>=min_tertiary_command ) {
18039       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
18040       if ( d==tertiary_secondary_macro ) { 
18041         mac_name=mp->cur_sym; add_mac_ref(c);
18042       };
18043       mp_get_x_next(mp); mp_scan_secondary(mp);
18044       if ( d!=tertiary_secondary_macro ) {
18045         mp_do_binary(mp, p,c);
18046       } else { 
18047         mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
18048         decr(ref_count(c)); mp_get_x_next(mp); 
18049         goto RESTART;
18050       }
18051       goto CONTINUE;
18052     }
18053   }
18054 }
18055
18056 @ Finally we reach the deepest level in our quartet of parsing routines.
18057 This one is much like the others; but it has an extra complication from
18058 paths, which materialize here.
18059
18060 @d continue_path 25 /* a label inside of |scan_expression| */
18061 @d finish_path 26 /* another */
18062
18063 @<Declare the basic parsing subroutines@>=
18064 void mp_scan_expression (MP mp) {
18065   pointer p,q,r,pp,qq; /* for list manipulation */
18066   halfword c,d; /* operation codes or modifiers */
18067   int my_var_flag; /* initial value of |var_flag| */
18068   pointer mac_name; /* token defined with \&{tertiarydef} */
18069   boolean cycle_hit; /* did a path expression just end with `\&{cycle}'? */
18070   scaled x,y; /* explicit coordinates or tension at a path join */
18071   int t; /* knot type following a path join */
18072   t=0; y=0; x=0;
18073   my_var_flag=mp->var_flag; mac_name=null;
18074 RESTART:
18075   if ((mp->cur_cmd<min_primary_command)||
18076       (mp->cur_cmd>max_primary_command) )
18077     mp_bad_exp(mp, "An");
18078 @.An expression...@>
18079   mp_scan_tertiary(mp);
18080 CONTINUE: 
18081   if ( mp->cur_cmd<=max_expression_command )
18082     if ( mp->cur_cmd>=min_expression_command ) {
18083       if ( (mp->cur_cmd!=equals)||(my_var_flag!=assignment) ) {
18084         p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
18085         if ( d==expression_tertiary_macro ) {
18086           mac_name=mp->cur_sym; add_mac_ref(c);
18087         }
18088         if ( (d<ampersand)||((d==ampersand)&&
18089              ((type(p)==mp_pair_type)||(type(p)==mp_path_type))) ) {
18090           @<Scan a path construction operation;
18091             but |return| if |p| has the wrong type@>;
18092         } else { 
18093           mp_get_x_next(mp); mp_scan_tertiary(mp);
18094           if ( d!=expression_tertiary_macro ) {
18095             mp_do_binary(mp, p,c);
18096           } else  { 
18097             mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
18098             decr(ref_count(c)); mp_get_x_next(mp); 
18099             goto RESTART;
18100           }
18101         }
18102         goto CONTINUE;
18103      }
18104   }
18105 }
18106
18107 @ The reader should review the data structure conventions for paths before
18108 hoping to understand the next part of this code.
18109
18110 @<Scan a path construction operation...@>=
18111
18112   cycle_hit=false;
18113   @<Convert the left operand, |p|, into a partial path ending at~|q|;
18114     but |return| if |p| doesn't have a suitable type@>;
18115 CONTINUE_PATH: 
18116   @<Determine the path join parameters;
18117     but |goto finish_path| if there's only a direction specifier@>;
18118   if ( mp->cur_cmd==cycle ) {
18119     @<Get ready to close a cycle@>;
18120   } else { 
18121     mp_scan_tertiary(mp);
18122     @<Convert the right operand, |cur_exp|,
18123       into a partial path from |pp| to~|qq|@>;
18124   }
18125   @<Join the partial paths and reset |p| and |q| to the head and tail
18126     of the result@>;
18127   if ( mp->cur_cmd>=min_expression_command )
18128     if ( mp->cur_cmd<=ampersand ) if ( ! cycle_hit ) goto CONTINUE_PATH;
18129 FINISH_PATH:
18130   @<Choose control points for the path and put the result into |cur_exp|@>;
18131 }
18132
18133 @ @<Convert the left operand, |p|, into a partial path ending at~|q|...@>=
18134
18135   mp_unstash_cur_exp(mp, p);
18136   if ( mp->cur_type==mp_pair_type ) p=mp_new_knot(mp);
18137   else if ( mp->cur_type==mp_path_type ) p=mp->cur_exp;
18138   else return;
18139   q=p;
18140   while ( link(q)!=p ) q=link(q);
18141   if ( left_type(p)!=mp_endpoint ) { /* open up a cycle */
18142     r=mp_copy_knot(mp, p); link(q)=r; q=r;
18143   }
18144   left_type(p)=mp_open; right_type(q)=mp_open;
18145 }
18146
18147 @ A pair of numeric values is changed into a knot node for a one-point path
18148 when \MP\ discovers that the pair is part of a path.
18149
18150 @c@<Declare the procedure called |known_pair|@>;
18151 pointer mp_new_knot (MP mp) { /* convert a pair to a knot with two endpoints */
18152   pointer q; /* the new node */
18153   q=mp_get_node(mp, knot_node_size); left_type(q)=mp_endpoint;
18154   right_type(q)=mp_endpoint; originator(q)=mp_metapost_user; link(q)=q;
18155   mp_known_pair(mp); x_coord(q)=mp->cur_x; y_coord(q)=mp->cur_y;
18156   return q;
18157 }
18158
18159 @ The |known_pair| subroutine sets |cur_x| and |cur_y| to the components
18160 of the current expression, assuming that the current expression is a
18161 pair of known numerics. Unknown components are zeroed, and the
18162 current expression is flushed.
18163
18164 @<Declare the procedure called |known_pair|@>=
18165 void mp_known_pair (MP mp) {
18166   pointer p; /* the pair node */
18167   if ( mp->cur_type!=mp_pair_type ) {
18168     exp_err("Undefined coordinates have been replaced by (0,0)");
18169 @.Undefined coordinates...@>
18170     help5("I need x and y numbers for this part of the path.")
18171       ("The value I found (see above) was no good;")
18172       ("so I'll try to keep going by using zero instead.")
18173       ("(Chapter 27 of The METAFONTbook explains that")
18174 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18175       ("you might want to type `I ??" "?' now.)");
18176     mp_put_get_flush_error(mp, 0); mp->cur_x=0; mp->cur_y=0;
18177   } else { 
18178     p=value(mp->cur_exp);
18179      @<Make sure that both |x| and |y| parts of |p| are known;
18180        copy them into |cur_x| and |cur_y|@>;
18181     mp_flush_cur_exp(mp, 0);
18182   }
18183 }
18184
18185 @ @<Make sure that both |x| and |y| parts of |p| are known...@>=
18186 if ( type(x_part_loc(p))==mp_known ) {
18187   mp->cur_x=value(x_part_loc(p));
18188 } else { 
18189   mp_disp_err(mp, x_part_loc(p),
18190     "Undefined x coordinate has been replaced by 0");
18191 @.Undefined coordinates...@>
18192   help5("I need a `known' x value for this part of the path.")
18193     ("The value I found (see above) was no good;")
18194     ("so I'll try to keep going by using zero instead.")
18195     ("(Chapter 27 of The METAFONTbook explains that")
18196 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18197     ("you might want to type `I ??" "?' now.)");
18198   mp_put_get_error(mp); mp_recycle_value(mp, x_part_loc(p)); mp->cur_x=0;
18199 }
18200 if ( type(y_part_loc(p))==mp_known ) {
18201   mp->cur_y=value(y_part_loc(p));
18202 } else { 
18203   mp_disp_err(mp, y_part_loc(p),
18204     "Undefined y coordinate has been replaced by 0");
18205   help5("I need a `known' y value for this part of the path.")
18206     ("The value I found (see above) was no good;")
18207     ("so I'll try to keep going by using zero instead.")
18208     ("(Chapter 27 of The METAFONTbook explains that")
18209     ("you might want to type `I ??" "?' now.)");
18210   mp_put_get_error(mp); mp_recycle_value(mp, y_part_loc(p)); mp->cur_y=0;
18211 }
18212
18213 @ At this point |cur_cmd| is either |ampersand|, |left_brace|, or |path_join|.
18214
18215 @<Determine the path join parameters...@>=
18216 if ( mp->cur_cmd==left_brace ) {
18217   @<Put the pre-join direction information into node |q|@>;
18218 }
18219 d=mp->cur_cmd;
18220 if ( d==path_join ) {
18221   @<Determine the tension and/or control points@>;
18222 } else if ( d!=ampersand ) {
18223   goto FINISH_PATH;
18224 }
18225 mp_get_x_next(mp);
18226 if ( mp->cur_cmd==left_brace ) {
18227   @<Put the post-join direction information into |x| and |t|@>;
18228 } else if ( right_type(q)!=mp_explicit ) {
18229   t=mp_open; x=0;
18230 }
18231
18232 @ The |scan_direction| subroutine looks at the directional information
18233 that is enclosed in braces, and also scans ahead to the following character.
18234 A type code is returned, either |open| (if the direction was $(0,0)$),
18235 or |curl| (if the direction was a curl of known value |cur_exp|), or
18236 |given| (if the direction is given by the |angle| value that now
18237 appears in |cur_exp|).
18238
18239 There's nothing difficult about this subroutine, but the program is rather
18240 lengthy because a variety of potential errors need to be nipped in the bud.
18241
18242 @c small_number mp_scan_direction (MP mp) {
18243   int t; /* the type of information found */
18244   scaled x; /* an |x| coordinate */
18245   mp_get_x_next(mp);
18246   if ( mp->cur_cmd==curl_command ) {
18247      @<Scan a curl specification@>;
18248   } else {
18249     @<Scan a given direction@>;
18250   }
18251   if ( mp->cur_cmd!=right_brace ) {
18252     mp_missing_err(mp, "}");
18253 @.Missing `\char`\}'@>
18254     help3("I've scanned a direction spec for part of a path,")
18255       ("so a right brace should have come next.")
18256       ("I shall pretend that one was there.");
18257     mp_back_error(mp);
18258   }
18259   mp_get_x_next(mp); 
18260   return t;
18261 }
18262
18263 @ @<Scan a curl specification@>=
18264 { mp_get_x_next(mp); mp_scan_expression(mp);
18265 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<0) ){ 
18266   exp_err("Improper curl has been replaced by 1");
18267 @.Improper curl@>
18268   help1("A curl must be a known, nonnegative number.");
18269   mp_put_get_flush_error(mp, unity);
18270 }
18271 t=mp_curl;
18272 }
18273
18274 @ @<Scan a given direction@>=
18275 { mp_scan_expression(mp);
18276   if ( mp->cur_type>mp_pair_type ) {
18277     @<Get given directions separated by commas@>;
18278   } else {
18279     mp_known_pair(mp);
18280   }
18281   if ( (mp->cur_x==0)&&(mp->cur_y==0) )  t=mp_open;
18282   else  { t=mp_given; mp->cur_exp=mp_n_arg(mp, mp->cur_x,mp->cur_y);}
18283 }
18284
18285 @ @<Get given directions separated by commas@>=
18286
18287   if ( mp->cur_type!=mp_known ) {
18288     exp_err("Undefined x coordinate has been replaced by 0");
18289 @.Undefined coordinates...@>
18290     help5("I need a `known' x value for this part of the path.")
18291       ("The value I found (see above) was no good;")
18292       ("so I'll try to keep going by using zero instead.")
18293       ("(Chapter 27 of The METAFONTbook explains that")
18294 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18295       ("you might want to type `I ??" "?' now.)");
18296     mp_put_get_flush_error(mp, 0);
18297   }
18298   x=mp->cur_exp;
18299   if ( mp->cur_cmd!=comma ) {
18300     mp_missing_err(mp, ",");
18301 @.Missing `,'@>
18302     help2("I've got the x coordinate of a path direction;")
18303       ("will look for the y coordinate next.");
18304     mp_back_error(mp);
18305   }
18306   mp_get_x_next(mp); mp_scan_expression(mp);
18307   if ( mp->cur_type!=mp_known ) {
18308      exp_err("Undefined y coordinate has been replaced by 0");
18309     help5("I need a `known' y value for this part of the path.")
18310       ("The value I found (see above) was no good;")
18311       ("so I'll try to keep going by using zero instead.")
18312       ("(Chapter 27 of The METAFONTbook explains that")
18313       ("you might want to type `I ??" "?' now.)");
18314     mp_put_get_flush_error(mp, 0);
18315   }
18316   mp->cur_y=mp->cur_exp; mp->cur_x=x;
18317 }
18318
18319 @ At this point |right_type(q)| is usually |open|, but it may have been
18320 set to some other value by a previous splicing operation. We must maintain
18321 the value of |right_type(q)| in unusual cases such as
18322 `\.{..z1\{z2\}\&\{z3\}z1\{0,0\}..}'.
18323
18324 @<Put the pre-join...@>=
18325
18326   t=mp_scan_direction(mp);
18327   if ( t!=mp_open ) {
18328     right_type(q)=t; right_given(q)=mp->cur_exp;
18329     if ( left_type(q)==mp_open ) {
18330       left_type(q)=t; left_given(q)=mp->cur_exp;
18331     } /* note that |left_given(q)=left_curl(q)| */
18332   }
18333 }
18334
18335 @ Since |left_tension| and |left_y| share the same position in knot nodes,
18336 and since |left_given| is similarly equivalent to |left_x|, we use
18337 |x| and |y| to hold the given direction and tension information when
18338 there are no explicit control points.
18339
18340 @<Put the post-join...@>=
18341
18342   t=mp_scan_direction(mp);
18343   if ( right_type(q)!=mp_explicit ) x=mp->cur_exp;
18344   else t=mp_explicit; /* the direction information is superfluous */
18345 }
18346
18347 @ @<Determine the tension and/or...@>=
18348
18349   mp_get_x_next(mp);
18350   if ( mp->cur_cmd==tension ) {
18351     @<Set explicit tensions@>;
18352   } else if ( mp->cur_cmd==controls ) {
18353     @<Set explicit control points@>;
18354   } else  { 
18355     right_tension(q)=unity; y=unity; mp_back_input(mp); /* default tension */
18356     goto DONE;
18357   };
18358   if ( mp->cur_cmd!=path_join ) {
18359      mp_missing_err(mp, "..");
18360 @.Missing `..'@>
18361     help1("A path join command should end with two dots.");
18362     mp_back_error(mp);
18363   }
18364 DONE:
18365   ;
18366 }
18367
18368 @ @<Set explicit tensions@>=
18369
18370   mp_get_x_next(mp); y=mp->cur_cmd;
18371   if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18372   mp_scan_primary(mp);
18373   @<Make sure that the current expression is a valid tension setting@>;
18374   if ( y==at_least ) negate(mp->cur_exp);
18375   right_tension(q)=mp->cur_exp;
18376   if ( mp->cur_cmd==and_command ) {
18377     mp_get_x_next(mp); y=mp->cur_cmd;
18378     if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18379     mp_scan_primary(mp);
18380     @<Make sure that the current expression is a valid tension setting@>;
18381     if ( y==at_least ) negate(mp->cur_exp);
18382   }
18383   y=mp->cur_exp;
18384 }
18385
18386 @ @d min_tension three_quarter_unit
18387
18388 @<Make sure that the current expression is a valid tension setting@>=
18389 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<min_tension) ) {
18390   exp_err("Improper tension has been set to 1");
18391 @.Improper tension@>
18392   help1("The expression above should have been a number >=3/4.");
18393   mp_put_get_flush_error(mp, unity);
18394 }
18395
18396 @ @<Set explicit control points@>=
18397
18398   right_type(q)=mp_explicit; t=mp_explicit; mp_get_x_next(mp); mp_scan_primary(mp);
18399   mp_known_pair(mp); right_x(q)=mp->cur_x; right_y(q)=mp->cur_y;
18400   if ( mp->cur_cmd!=and_command ) {
18401     x=right_x(q); y=right_y(q);
18402   } else { 
18403     mp_get_x_next(mp); mp_scan_primary(mp);
18404     mp_known_pair(mp); x=mp->cur_x; y=mp->cur_y;
18405   }
18406 }
18407
18408 @ @<Convert the right operand, |cur_exp|, into a partial path...@>=
18409
18410   if ( mp->cur_type!=mp_path_type ) pp=mp_new_knot(mp);
18411   else pp=mp->cur_exp;
18412   qq=pp;
18413   while ( link(qq)!=pp ) qq=link(qq);
18414   if ( left_type(pp)!=mp_endpoint ) { /* open up a cycle */
18415     r=mp_copy_knot(mp, pp); link(qq)=r; qq=r;
18416   }
18417   left_type(pp)=mp_open; right_type(qq)=mp_open;
18418 }
18419
18420 @ If a person tries to define an entire path by saying `\.{(x,y)\&cycle}',
18421 we silently change the specification to `\.{(x,y)..cycle}', since a cycle
18422 shouldn't have length zero.
18423
18424 @<Get ready to close a cycle@>=
18425
18426   cycle_hit=true; mp_get_x_next(mp); pp=p; qq=p;
18427   if ( d==ampersand ) if ( p==q ) {
18428     d=path_join; right_tension(q)=unity; y=unity;
18429   }
18430 }
18431
18432 @ @<Join the partial paths and reset |p| and |q|...@>=
18433
18434 if ( d==ampersand ) {
18435   if ( (x_coord(q)!=x_coord(pp))||(y_coord(q)!=y_coord(pp)) ) {
18436     print_err("Paths don't touch; `&' will be changed to `..'");
18437 @.Paths don't touch@>
18438     help3("When you join paths `p&q', the ending point of p")
18439       ("must be exactly equal to the starting point of q.")
18440       ("So I'm going to pretend that you said `p..q' instead.");
18441     mp_put_get_error(mp); d=path_join; right_tension(q)=unity; y=unity;
18442   }
18443 }
18444 @<Plug an opening in |right_type(pp)|, if possible@>;
18445 if ( d==ampersand ) {
18446   @<Splice independent paths together@>;
18447 } else  { 
18448   @<Plug an opening in |right_type(q)|, if possible@>;
18449   link(q)=pp; left_y(pp)=y;
18450   if ( t!=mp_open ) { left_x(pp)=x; left_type(pp)=t;  };
18451 }
18452 q=qq;
18453 }
18454
18455 @ @<Plug an opening in |right_type(q)|...@>=
18456 if ( right_type(q)==mp_open ) {
18457   if ( (left_type(q)==mp_curl)||(left_type(q)==mp_given) ) {
18458     right_type(q)=left_type(q); right_given(q)=left_given(q);
18459   }
18460 }
18461
18462 @ @<Plug an opening in |right_type(pp)|...@>=
18463 if ( right_type(pp)==mp_open ) {
18464   if ( (t==mp_curl)||(t==mp_given) ) {
18465     right_type(pp)=t; right_given(pp)=x;
18466   }
18467 }
18468
18469 @ @<Splice independent paths together@>=
18470
18471   if ( left_type(q)==mp_open ) if ( right_type(q)==mp_open ) {
18472     left_type(q)=mp_curl; left_curl(q)=unity;
18473   }
18474   if ( right_type(pp)==mp_open ) if ( t==mp_open ) {
18475     right_type(pp)=mp_curl; right_curl(pp)=unity;
18476   }
18477   right_type(q)=right_type(pp); link(q)=link(pp);
18478   right_x(q)=right_x(pp); right_y(q)=right_y(pp);
18479   mp_free_node(mp, pp,knot_node_size);
18480   if ( qq==pp ) qq=q;
18481 }
18482
18483 @ @<Choose control points for the path...@>=
18484 if ( cycle_hit ) { 
18485   if ( d==ampersand ) p=q;
18486 } else  { 
18487   left_type(p)=mp_endpoint;
18488   if ( right_type(p)==mp_open ) { 
18489     right_type(p)=mp_curl; right_curl(p)=unity;
18490   }
18491   right_type(q)=mp_endpoint;
18492   if ( left_type(q)==mp_open ) { 
18493     left_type(q)=mp_curl; left_curl(q)=unity;
18494   }
18495   link(q)=p;
18496 }
18497 mp_make_choices(mp, p);
18498 mp->cur_type=mp_path_type; mp->cur_exp=p
18499
18500 @ Finally, we sometimes need to scan an expression whose value is
18501 supposed to be either |true_code| or |false_code|.
18502
18503 @<Declare the basic parsing subroutines@>=
18504 void mp_get_boolean (MP mp) { 
18505   mp_get_x_next(mp); mp_scan_expression(mp);
18506   if ( mp->cur_type!=mp_boolean_type ) {
18507     exp_err("Undefined condition will be treated as `false'");
18508 @.Undefined condition...@>
18509     help2("The expression shown above should have had a definite")
18510       ("true-or-false value. I'm changing it to `false'.");
18511     mp_put_get_flush_error(mp, false_code); mp->cur_type=mp_boolean_type;
18512   }
18513 }
18514
18515 @* \[39] Doing the operations.
18516 The purpose of parsing is primarily to permit people to avoid piles of
18517 parentheses. But the real work is done after the structure of an expression
18518 has been recognized; that's when new expressions are generated. We
18519 turn now to the guts of \MP, which handles individual operators that
18520 have come through the parsing mechanism.
18521
18522 We'll start with the easy ones that take no operands, then work our way
18523 up to operators with one and ultimately two arguments. In other words,
18524 we will write the three procedures |do_nullary|, |do_unary|, and |do_binary|
18525 that are invoked periodically by the expression scanners.
18526
18527 First let's make sure that all of the primitive operators are in the
18528 hash table. Although |scan_primary| and its relatives made use of the
18529 \\{cmd} code for these operators, the \\{do} routines base everything
18530 on the \\{mod} code. For example, |do_binary| doesn't care whether the
18531 operation it performs is a |primary_binary| or |secondary_binary|, etc.
18532
18533 @<Put each...@>=
18534 mp_primitive(mp, "true",nullary,true_code);
18535 @:true_}{\&{true} primitive@>
18536 mp_primitive(mp, "false",nullary,false_code);
18537 @:false_}{\&{false} primitive@>
18538 mp_primitive(mp, "nullpicture",nullary,null_picture_code);
18539 @:null_picture_}{\&{nullpicture} primitive@>
18540 mp_primitive(mp, "nullpen",nullary,null_pen_code);
18541 @:null_pen_}{\&{nullpen} primitive@>
18542 mp_primitive(mp, "jobname",nullary,job_name_op);
18543 @:job_name_}{\&{jobname} primitive@>
18544 mp_primitive(mp, "readstring",nullary,read_string_op);
18545 @:read_string_}{\&{readstring} primitive@>
18546 mp_primitive(mp, "pencircle",nullary,pen_circle);
18547 @:pen_circle_}{\&{pencircle} primitive@>
18548 mp_primitive(mp, "normaldeviate",nullary,normal_deviate);
18549 @:normal_deviate_}{\&{normaldeviate} primitive@>
18550 mp_primitive(mp, "readfrom",unary,read_from_op);
18551 @:read_from_}{\&{readfrom} primitive@>
18552 mp_primitive(mp, "closefrom",unary,close_from_op);
18553 @:close_from_}{\&{closefrom} primitive@>
18554 mp_primitive(mp, "odd",unary,odd_op);
18555 @:odd_}{\&{odd} primitive@>
18556 mp_primitive(mp, "known",unary,known_op);
18557 @:known_}{\&{known} primitive@>
18558 mp_primitive(mp, "unknown",unary,unknown_op);
18559 @:unknown_}{\&{unknown} primitive@>
18560 mp_primitive(mp, "not",unary,not_op);
18561 @:not_}{\&{not} primitive@>
18562 mp_primitive(mp, "decimal",unary,decimal);
18563 @:decimal_}{\&{decimal} primitive@>
18564 mp_primitive(mp, "reverse",unary,reverse);
18565 @:reverse_}{\&{reverse} primitive@>
18566 mp_primitive(mp, "makepath",unary,make_path_op);
18567 @:make_path_}{\&{makepath} primitive@>
18568 mp_primitive(mp, "makepen",unary,make_pen_op);
18569 @:make_pen_}{\&{makepen} primitive@>
18570 mp_primitive(mp, "oct",unary,oct_op);
18571 @:oct_}{\&{oct} primitive@>
18572 mp_primitive(mp, "hex",unary,hex_op);
18573 @:hex_}{\&{hex} primitive@>
18574 mp_primitive(mp, "ASCII",unary,ASCII_op);
18575 @:ASCII_}{\&{ASCII} primitive@>
18576 mp_primitive(mp, "char",unary,char_op);
18577 @:char_}{\&{char} primitive@>
18578 mp_primitive(mp, "length",unary,length_op);
18579 @:length_}{\&{length} primitive@>
18580 mp_primitive(mp, "turningnumber",unary,turning_op);
18581 @:turning_number_}{\&{turningnumber} primitive@>
18582 mp_primitive(mp, "xpart",unary,x_part);
18583 @:x_part_}{\&{xpart} primitive@>
18584 mp_primitive(mp, "ypart",unary,y_part);
18585 @:y_part_}{\&{ypart} primitive@>
18586 mp_primitive(mp, "xxpart",unary,xx_part);
18587 @:xx_part_}{\&{xxpart} primitive@>
18588 mp_primitive(mp, "xypart",unary,xy_part);
18589 @:xy_part_}{\&{xypart} primitive@>
18590 mp_primitive(mp, "yxpart",unary,yx_part);
18591 @:yx_part_}{\&{yxpart} primitive@>
18592 mp_primitive(mp, "yypart",unary,yy_part);
18593 @:yy_part_}{\&{yypart} primitive@>
18594 mp_primitive(mp, "redpart",unary,red_part);
18595 @:red_part_}{\&{redpart} primitive@>
18596 mp_primitive(mp, "greenpart",unary,green_part);
18597 @:green_part_}{\&{greenpart} primitive@>
18598 mp_primitive(mp, "bluepart",unary,blue_part);
18599 @:blue_part_}{\&{bluepart} primitive@>
18600 mp_primitive(mp, "cyanpart",unary,cyan_part);
18601 @:cyan_part_}{\&{cyanpart} primitive@>
18602 mp_primitive(mp, "magentapart",unary,magenta_part);
18603 @:magenta_part_}{\&{magentapart} primitive@>
18604 mp_primitive(mp, "yellowpart",unary,yellow_part);
18605 @:yellow_part_}{\&{yellowpart} primitive@>
18606 mp_primitive(mp, "blackpart",unary,black_part);
18607 @:black_part_}{\&{blackpart} primitive@>
18608 mp_primitive(mp, "greypart",unary,grey_part);
18609 @:grey_part_}{\&{greypart} primitive@>
18610 mp_primitive(mp, "colormodel",unary,color_model_part);
18611 @:color_model_part_}{\&{colormodel} primitive@>
18612 mp_primitive(mp, "fontpart",unary,font_part);
18613 @:font_part_}{\&{fontpart} primitive@>
18614 mp_primitive(mp, "textpart",unary,text_part);
18615 @:text_part_}{\&{textpart} primitive@>
18616 mp_primitive(mp, "pathpart",unary,path_part);
18617 @:path_part_}{\&{pathpart} primitive@>
18618 mp_primitive(mp, "penpart",unary,pen_part);
18619 @:pen_part_}{\&{penpart} primitive@>
18620 mp_primitive(mp, "dashpart",unary,dash_part);
18621 @:dash_part_}{\&{dashpart} primitive@>
18622 mp_primitive(mp, "sqrt",unary,sqrt_op);
18623 @:sqrt_}{\&{sqrt} primitive@>
18624 mp_primitive(mp, "mexp",unary,m_exp_op);
18625 @:m_exp_}{\&{mexp} primitive@>
18626 mp_primitive(mp, "mlog",unary,m_log_op);
18627 @:m_log_}{\&{mlog} primitive@>
18628 mp_primitive(mp, "sind",unary,sin_d_op);
18629 @:sin_d_}{\&{sind} primitive@>
18630 mp_primitive(mp, "cosd",unary,cos_d_op);
18631 @:cos_d_}{\&{cosd} primitive@>
18632 mp_primitive(mp, "floor",unary,floor_op);
18633 @:floor_}{\&{floor} primitive@>
18634 mp_primitive(mp, "uniformdeviate",unary,uniform_deviate);
18635 @:uniform_deviate_}{\&{uniformdeviate} primitive@>
18636 mp_primitive(mp, "charexists",unary,char_exists_op);
18637 @:char_exists_}{\&{charexists} primitive@>
18638 mp_primitive(mp, "fontsize",unary,font_size);
18639 @:font_size_}{\&{fontsize} primitive@>
18640 mp_primitive(mp, "llcorner",unary,ll_corner_op);
18641 @:ll_corner_}{\&{llcorner} primitive@>
18642 mp_primitive(mp, "lrcorner",unary,lr_corner_op);
18643 @:lr_corner_}{\&{lrcorner} primitive@>
18644 mp_primitive(mp, "ulcorner",unary,ul_corner_op);
18645 @:ul_corner_}{\&{ulcorner} primitive@>
18646 mp_primitive(mp, "urcorner",unary,ur_corner_op);
18647 @:ur_corner_}{\&{urcorner} primitive@>
18648 mp_primitive(mp, "arclength",unary,arc_length);
18649 @:arc_length_}{\&{arclength} primitive@>
18650 mp_primitive(mp, "angle",unary,angle_op);
18651 @:angle_}{\&{angle} primitive@>
18652 mp_primitive(mp, "cycle",cycle,cycle_op);
18653 @:cycle_}{\&{cycle} primitive@>
18654 mp_primitive(mp, "stroked",unary,stroked_op);
18655 @:stroked_}{\&{stroked} primitive@>
18656 mp_primitive(mp, "filled",unary,filled_op);
18657 @:filled_}{\&{filled} primitive@>
18658 mp_primitive(mp, "textual",unary,textual_op);
18659 @:textual_}{\&{textual} primitive@>
18660 mp_primitive(mp, "clipped",unary,clipped_op);
18661 @:clipped_}{\&{clipped} primitive@>
18662 mp_primitive(mp, "bounded",unary,bounded_op);
18663 @:bounded_}{\&{bounded} primitive@>
18664 mp_primitive(mp, "+",plus_or_minus,plus);
18665 @:+ }{\.{+} primitive@>
18666 mp_primitive(mp, "-",plus_or_minus,minus);
18667 @:- }{\.{-} primitive@>
18668 mp_primitive(mp, "*",secondary_binary,times);
18669 @:* }{\.{*} primitive@>
18670 mp_primitive(mp, "/",slash,over); mp->eqtb[frozen_slash]=mp->eqtb[mp->cur_sym];
18671 @:/ }{\.{/} primitive@>
18672 mp_primitive(mp, "++",tertiary_binary,pythag_add);
18673 @:++_}{\.{++} primitive@>
18674 mp_primitive(mp, "+-+",tertiary_binary,pythag_sub);
18675 @:+-+_}{\.{+-+} primitive@>
18676 mp_primitive(mp, "or",tertiary_binary,or_op);
18677 @:or_}{\&{or} primitive@>
18678 mp_primitive(mp, "and",and_command,and_op);
18679 @:and_}{\&{and} primitive@>
18680 mp_primitive(mp, "<",expression_binary,less_than);
18681 @:< }{\.{<} primitive@>
18682 mp_primitive(mp, "<=",expression_binary,less_or_equal);
18683 @:<=_}{\.{<=} primitive@>
18684 mp_primitive(mp, ">",expression_binary,greater_than);
18685 @:> }{\.{>} primitive@>
18686 mp_primitive(mp, ">=",expression_binary,greater_or_equal);
18687 @:>=_}{\.{>=} primitive@>
18688 mp_primitive(mp, "=",equals,equal_to);
18689 @:= }{\.{=} primitive@>
18690 mp_primitive(mp, "<>",expression_binary,unequal_to);
18691 @:<>_}{\.{<>} primitive@>
18692 mp_primitive(mp, "substring",primary_binary,substring_of);
18693 @:substring_}{\&{substring} primitive@>
18694 mp_primitive(mp, "subpath",primary_binary,subpath_of);
18695 @:subpath_}{\&{subpath} primitive@>
18696 mp_primitive(mp, "directiontime",primary_binary,direction_time_of);
18697 @:direction_time_}{\&{directiontime} primitive@>
18698 mp_primitive(mp, "point",primary_binary,point_of);
18699 @:point_}{\&{point} primitive@>
18700 mp_primitive(mp, "precontrol",primary_binary,precontrol_of);
18701 @:precontrol_}{\&{precontrol} primitive@>
18702 mp_primitive(mp, "postcontrol",primary_binary,postcontrol_of);
18703 @:postcontrol_}{\&{postcontrol} primitive@>
18704 mp_primitive(mp, "penoffset",primary_binary,pen_offset_of);
18705 @:pen_offset_}{\&{penoffset} primitive@>
18706 mp_primitive(mp, "arctime",primary_binary,arc_time_of);
18707 @:arc_time_of_}{\&{arctime} primitive@>
18708 mp_primitive(mp, "mpversion",nullary,mp_version);
18709 @:mp_verison_}{\&{mpversion} primitive@>
18710 mp_primitive(mp, "&",ampersand,concatenate);
18711 @:!!!}{\.{\&} primitive@>
18712 mp_primitive(mp, "rotated",secondary_binary,rotated_by);
18713 @:rotated_}{\&{rotated} primitive@>
18714 mp_primitive(mp, "slanted",secondary_binary,slanted_by);
18715 @:slanted_}{\&{slanted} primitive@>
18716 mp_primitive(mp, "scaled",secondary_binary,scaled_by);
18717 @:scaled_}{\&{scaled} primitive@>
18718 mp_primitive(mp, "shifted",secondary_binary,shifted_by);
18719 @:shifted_}{\&{shifted} primitive@>
18720 mp_primitive(mp, "transformed",secondary_binary,transformed_by);
18721 @:transformed_}{\&{transformed} primitive@>
18722 mp_primitive(mp, "xscaled",secondary_binary,x_scaled);
18723 @:x_scaled_}{\&{xscaled} primitive@>
18724 mp_primitive(mp, "yscaled",secondary_binary,y_scaled);
18725 @:y_scaled_}{\&{yscaled} primitive@>
18726 mp_primitive(mp, "zscaled",secondary_binary,z_scaled);
18727 @:z_scaled_}{\&{zscaled} primitive@>
18728 mp_primitive(mp, "infont",secondary_binary,in_font);
18729 @:in_font_}{\&{infont} primitive@>
18730 mp_primitive(mp, "intersectiontimes",tertiary_binary,intersect);
18731 @:intersection_times_}{\&{intersectiontimes} primitive@>
18732 mp_primitive(mp, "envelope",primary_binary,envelope_of);
18733 @:envelope_}{\&{envelope} primitive@>
18734
18735 @ @<Cases of |print_cmd...@>=
18736 case nullary:
18737 case unary:
18738 case primary_binary:
18739 case secondary_binary:
18740 case tertiary_binary:
18741 case expression_binary:
18742 case cycle:
18743 case plus_or_minus:
18744 case slash:
18745 case ampersand:
18746 case equals:
18747 case and_command:
18748   mp_print_op(mp, m);
18749   break;
18750
18751 @ OK, let's look at the simplest \\{do} procedure first.
18752
18753 @c @<Declare nullary action procedure@>;
18754 void mp_do_nullary (MP mp,quarterword c) { 
18755   check_arith;
18756   if ( mp->internal[mp_tracing_commands]>two )
18757     mp_show_cmd_mod(mp, nullary,c);
18758   switch (c) {
18759   case true_code: case false_code: 
18760     mp->cur_type=mp_boolean_type; mp->cur_exp=c;
18761     break;
18762   case null_picture_code: 
18763     mp->cur_type=mp_picture_type;
18764     mp->cur_exp=mp_get_node(mp, edge_header_size); 
18765     mp_init_edges(mp, mp->cur_exp);
18766     break;
18767   case null_pen_code: 
18768     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, 0);
18769     break;
18770   case normal_deviate: 
18771     mp->cur_type=mp_known; mp->cur_exp=mp_norm_rand(mp);
18772     break;
18773   case pen_circle: 
18774     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, unity);
18775     break;
18776   case job_name_op:  
18777     if ( mp->job_name==NULL ) mp_open_log_file(mp);
18778     mp->cur_type=mp_string_type; mp->cur_exp=rts(mp->job_name);
18779     break;
18780   case mp_version: 
18781     mp->cur_type=mp_string_type; 
18782     mp->cur_exp=intern(metapost_version) ;
18783     break;
18784   case read_string_op:
18785     @<Read a string from the terminal@>;
18786     break;
18787   } /* there are no other cases */
18788   check_arith;
18789 }
18790
18791 @ @<Read a string...@>=
18792
18793   if ( mp->interaction<=mp_nonstop_mode )
18794     mp_fatal_error(mp, "*** (cannot readstring in nonstop modes)");
18795   mp_begin_file_reading(mp); name=is_read;
18796   limit=start; prompt_input("");
18797   mp_finish_read(mp);
18798 }
18799
18800 @ @<Declare nullary action procedure@>=
18801 void mp_finish_read (MP mp) { /* copy |buffer| line to |cur_exp| */
18802   size_t k;
18803   str_room((int)mp->last-start);
18804   for (k=start;k<=mp->last-1;k++) {
18805    append_char(mp->buffer[k]);
18806   }
18807   mp_end_file_reading(mp); mp->cur_type=mp_string_type; 
18808   mp->cur_exp=mp_make_string(mp);
18809 }
18810
18811 @ Things get a bit more interesting when there's an operand. The
18812 operand to |do_unary| appears in |cur_type| and |cur_exp|.
18813
18814 @c @<Declare unary action procedures@>;
18815 void mp_do_unary (MP mp,quarterword c) {
18816   pointer p,q,r; /* for list manipulation */
18817   integer x; /* a temporary register */
18818   check_arith;
18819   if ( mp->internal[mp_tracing_commands]>two )
18820     @<Trace the current unary operation@>;
18821   switch (c) {
18822   case plus:
18823     if ( mp->cur_type<mp_color_type ) mp_bad_unary(mp, plus);
18824     break;
18825   case minus:
18826     @<Negate the current expression@>;
18827     break;
18828   @<Additional cases of unary operators@>;
18829   } /* there are no other cases */
18830   check_arith;
18831 };
18832
18833 @ The |nice_pair| function returns |true| if both components of a pair
18834 are known.
18835
18836 @<Declare unary action procedures@>=
18837 boolean mp_nice_pair (MP mp,integer p, quarterword t) { 
18838   if ( t==mp_pair_type ) {
18839     p=value(p);
18840     if ( type(x_part_loc(p))==mp_known )
18841       if ( type(y_part_loc(p))==mp_known )
18842         return true;
18843   }
18844   return false;
18845 }
18846
18847 @ The |nice_color_or_pair| function is analogous except that it also accepts
18848 fully known colors.
18849
18850 @<Declare unary action procedures@>=
18851 boolean mp_nice_color_or_pair (MP mp,integer p, quarterword t) {
18852   pointer q,r; /* for scanning the big node */
18853   if ( (t!=mp_pair_type)&&(t!=mp_color_type)&&(t!=mp_cmykcolor_type) ) {
18854     return false;
18855   } else { 
18856     q=value(p);
18857     r=q+mp->big_node_size[type(p)];
18858     do {  
18859       r=r-2;
18860       if ( type(r)!=mp_known )
18861         return false;
18862     } while (r!=q);
18863     return true;
18864   }
18865 }
18866
18867 @ @<Declare unary action...@>=
18868 void mp_print_known_or_unknown_type (MP mp,small_number t, integer v) { 
18869   mp_print_char(mp, '(');
18870   if ( t>mp_known ) mp_print(mp, "unknown numeric");
18871   else { if ( (t==mp_pair_type)||(t==mp_color_type)||(t==mp_cmykcolor_type) )
18872     if ( ! mp_nice_color_or_pair(mp, v,t) ) mp_print(mp, "unknown ");
18873     mp_print_type(mp, t);
18874   }
18875   mp_print_char(mp, ')');
18876 }
18877
18878 @ @<Declare unary action...@>=
18879 void mp_bad_unary (MP mp,quarterword c) { 
18880   exp_err("Not implemented: "); mp_print_op(mp, c);
18881 @.Not implemented...@>
18882   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
18883   help3("I'm afraid I don't know how to apply that operation to that")
18884     ("particular type. Continue, and I'll simply return the")
18885     ("argument (shown above) as the result of the operation.");
18886   mp_put_get_error(mp);
18887 }
18888
18889 @ @<Trace the current unary operation@>=
18890
18891   mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); 
18892   mp_print_op(mp, c); mp_print_char(mp, '(');
18893   mp_print_exp(mp, null,0); /* show the operand, but not verbosely */
18894   mp_print(mp, ")}"); mp_end_diagnostic(mp, false);
18895 }
18896
18897 @ Negation is easy except when the current expression
18898 is of type |independent|, or when it is a pair with one or more
18899 |independent| components.
18900
18901 It is tempting to argue that the negative of an independent variable
18902 is an independent variable, hence we don't have to do anything when
18903 negating it. The fallacy is that other dependent variables pointing
18904 to the current expression must change the sign of their
18905 coefficients if we make no change to the current expression.
18906
18907 Instead, we work around the problem by copying the current expression
18908 and recycling it afterwards (cf.~the |stash_in| routine).
18909
18910 @<Negate the current expression@>=
18911 switch (mp->cur_type) {
18912 case mp_color_type:
18913 case mp_cmykcolor_type:
18914 case mp_pair_type:
18915 case mp_independent: 
18916   q=mp->cur_exp; mp_make_exp_copy(mp, q);
18917   if ( mp->cur_type==mp_dependent ) {
18918     mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18919   } else if ( mp->cur_type<=mp_pair_type ) { /* |mp_color_type| or |mp_pair_type| */
18920     p=value(mp->cur_exp);
18921     r=p+mp->big_node_size[mp->cur_type];
18922     do {  
18923       r=r-2;
18924       if ( type(r)==mp_known ) negate(value(r));
18925       else mp_negate_dep_list(mp, dep_list(r));
18926     } while (r!=p);
18927   } /* if |cur_type=mp_known| then |cur_exp=0| */
18928   mp_recycle_value(mp, q); mp_free_node(mp, q,value_node_size);
18929   break;
18930 case mp_dependent:
18931 case mp_proto_dependent:
18932   mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18933   break;
18934 case mp_known:
18935   negate(mp->cur_exp);
18936   break;
18937 default:
18938   mp_bad_unary(mp, minus);
18939   break;
18940 }
18941
18942 @ @<Declare unary action...@>=
18943 void mp_negate_dep_list (MP mp,pointer p) { 
18944   while (1) { 
18945     negate(value(p));
18946     if ( info(p)==null ) return;
18947     p=link(p);
18948   }
18949 }
18950
18951 @ @<Additional cases of unary operators@>=
18952 case not_op: 
18953   if ( mp->cur_type!=mp_boolean_type ) mp_bad_unary(mp, not_op);
18954   else mp->cur_exp=true_code+false_code-mp->cur_exp;
18955   break;
18956
18957 @ @d three_sixty_units 23592960 /* that's |360*unity| */
18958 @d boolean_reset(A) if ( (A) ) mp->cur_exp=true_code; else mp->cur_exp=false_code
18959
18960 @<Additional cases of unary operators@>=
18961 case sqrt_op:
18962 case m_exp_op:
18963 case m_log_op:
18964 case sin_d_op:
18965 case cos_d_op:
18966 case floor_op:
18967 case  uniform_deviate:
18968 case odd_op:
18969 case char_exists_op:
18970   if ( mp->cur_type!=mp_known ) {
18971     mp_bad_unary(mp, c);
18972   } else {
18973     switch (c) {
18974     case sqrt_op:mp->cur_exp=mp_square_rt(mp, mp->cur_exp);break;
18975     case m_exp_op:mp->cur_exp=mp_m_exp(mp, mp->cur_exp);break;
18976     case m_log_op:mp->cur_exp=mp_m_log(mp, mp->cur_exp);break;
18977     case sin_d_op:
18978     case cos_d_op:
18979       mp_n_sin_cos(mp, (mp->cur_exp % three_sixty_units)*16);
18980       if ( c==sin_d_op ) mp->cur_exp=mp_round_fraction(mp, mp->n_sin);
18981       else mp->cur_exp=mp_round_fraction(mp, mp->n_cos);
18982       break;
18983     case floor_op:mp->cur_exp=mp_floor_scaled(mp, mp->cur_exp);break;
18984     case uniform_deviate:mp->cur_exp=mp_unif_rand(mp, mp->cur_exp);break;
18985     case odd_op: 
18986       boolean_reset(odd(mp_round_unscaled(mp, mp->cur_exp)));
18987       mp->cur_type=mp_boolean_type;
18988       break;
18989     case char_exists_op:
18990       @<Determine if a character has been shipped out@>;
18991       break;
18992     } /* there are no other cases */
18993   }
18994   break;
18995
18996 @ @<Additional cases of unary operators@>=
18997 case angle_op:
18998   if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) ) {
18999     p=value(mp->cur_exp);
19000     x=mp_n_arg(mp, value(x_part_loc(p)),value(y_part_loc(p)));
19001     if ( x>=0 ) mp_flush_cur_exp(mp, (x+8)/ 16);
19002     else mp_flush_cur_exp(mp, -((-x+8)/ 16));
19003   } else {
19004     mp_bad_unary(mp, angle_op);
19005   }
19006   break;
19007
19008 @ If the current expression is a pair, but the context wants it to
19009 be a path, we call |pair_to_path|.
19010
19011 @<Declare unary action...@>=
19012 void mp_pair_to_path (MP mp) { 
19013   mp->cur_exp=mp_new_knot(mp); 
19014   mp->cur_type=mp_path_type;
19015 };
19016
19017 @ @<Additional cases of unary operators@>=
19018 case x_part:
19019 case y_part:
19020   if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_transform_type) )
19021     mp_take_part(mp, c);
19022   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19023   else mp_bad_unary(mp, c);
19024   break;
19025 case xx_part:
19026 case xy_part:
19027 case yx_part:
19028 case yy_part: 
19029   if ( mp->cur_type==mp_transform_type ) mp_take_part(mp, c);
19030   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19031   else mp_bad_unary(mp, c);
19032   break;
19033 case red_part:
19034 case green_part:
19035 case blue_part: 
19036   if ( mp->cur_type==mp_color_type ) mp_take_part(mp, c);
19037   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19038   else mp_bad_unary(mp, c);
19039   break;
19040 case cyan_part:
19041 case magenta_part:
19042 case yellow_part:
19043 case black_part: 
19044   if ( mp->cur_type==mp_cmykcolor_type) mp_take_part(mp, c); 
19045   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19046   else mp_bad_unary(mp, c);
19047   break;
19048 case grey_part: 
19049   if ( mp->cur_type==mp_known ) mp->cur_exp=value(c);
19050   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19051   else mp_bad_unary(mp, c);
19052   break;
19053 case color_model_part: 
19054   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19055   else mp_bad_unary(mp, c);
19056   break;
19057
19058 @ In the following procedure, |cur_exp| points to a capsule, which points to
19059 a big node. We want to delete all but one part of the big node.
19060
19061 @<Declare unary action...@>=
19062 void mp_take_part (MP mp,quarterword c) {
19063   pointer p; /* the big node */
19064   p=value(mp->cur_exp); value(temp_val)=p; type(temp_val)=mp->cur_type;
19065   link(p)=temp_val; mp_free_node(mp, mp->cur_exp,value_node_size);
19066   mp_make_exp_copy(mp, p+mp->sector_offset[c+mp_x_part_sector-x_part]);
19067   mp_recycle_value(mp, temp_val);
19068 }
19069
19070 @ @<Initialize table entries...@>=
19071 name_type(temp_val)=mp_capsule;
19072
19073 @ @<Additional cases of unary operators@>=
19074 case font_part:
19075 case text_part:
19076 case path_part:
19077 case pen_part:
19078 case dash_part:
19079   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19080   else mp_bad_unary(mp, c);
19081   break;
19082
19083 @ @<Declarations@>=
19084 void mp_scale_edges (MP mp);
19085
19086 @ @<Declare unary action...@>=
19087 void mp_take_pict_part (MP mp,quarterword c) {
19088   pointer p; /* first graphical object in |cur_exp| */
19089   p=link(dummy_loc(mp->cur_exp));
19090   if ( p!=null ) {
19091     switch (c) {
19092     case x_part: case y_part: case xx_part:
19093     case xy_part: case yx_part: case yy_part:
19094       if ( type(p)==mp_text_code ) mp_flush_cur_exp(mp, text_trans_part(p+c));
19095       else goto NOT_FOUND;
19096       break;
19097     case red_part: case green_part: case blue_part:
19098       if ( has_color(p) ) mp_flush_cur_exp(mp, obj_color_part(p+c));
19099       else goto NOT_FOUND;
19100       break;
19101     case cyan_part: case magenta_part: case yellow_part:
19102     case black_part:
19103       if ( has_color(p) ) {
19104         if ( color_model(p)==mp_uninitialized_model )
19105           mp_flush_cur_exp(mp, unity);
19106         else
19107           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-cyan_part)));
19108       } else goto NOT_FOUND;
19109       break;
19110     case grey_part:
19111       if ( has_color(p) )
19112           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-grey_part)));
19113       else goto NOT_FOUND;
19114       break;
19115     case color_model_part:
19116       if ( has_color(p) ) {
19117         if ( color_model(p)==mp_uninitialized_model )
19118           mp_flush_cur_exp(mp, mp->internal[mp_default_color_model]);
19119         else
19120           mp_flush_cur_exp(mp, color_model(p)*unity);
19121       } else goto NOT_FOUND;
19122       break;
19123     @<Handle other cases in |take_pict_part| or |goto not_found|@>;
19124     } /* all cases have been enumerated */
19125     return;
19126   };
19127 NOT_FOUND:
19128   @<Convert the current expression to a null value appropriate
19129     for |c|@>;
19130 }
19131
19132 @ @<Handle other cases in |take_pict_part| or |goto not_found|@>=
19133 case text_part: 
19134   if ( type(p)!=mp_text_code ) goto NOT_FOUND;
19135   else { 
19136     mp_flush_cur_exp(mp, text_p(p));
19137     add_str_ref(mp->cur_exp);
19138     mp->cur_type=mp_string_type;
19139     };
19140   break;
19141 case font_part: 
19142   if ( type(p)!=mp_text_code ) goto NOT_FOUND;
19143   else { 
19144     mp_flush_cur_exp(mp, rts(mp->font_name[font_n(p)])); 
19145     add_str_ref(mp->cur_exp);
19146     mp->cur_type=mp_string_type;
19147   };
19148   break;
19149 case path_part:
19150   if ( type(p)==mp_text_code ) goto NOT_FOUND;
19151   else if ( is_stop(p) ) mp_confusion(mp, "pict");
19152 @:this can't happen pict}{\quad pict@>
19153   else { 
19154     mp_flush_cur_exp(mp, mp_copy_path(mp, path_p(p)));
19155     mp->cur_type=mp_path_type;
19156   }
19157   break;
19158 case pen_part: 
19159   if ( ! has_pen(p) ) goto NOT_FOUND;
19160   else {
19161     if ( pen_p(p)==null ) goto NOT_FOUND;
19162     else { mp_flush_cur_exp(mp, copy_pen(pen_p(p)));
19163       mp->cur_type=mp_pen_type;
19164     };
19165   }
19166   break;
19167 case dash_part: 
19168   if ( type(p)!=mp_stroked_code ) goto NOT_FOUND;
19169   else { if ( dash_p(p)==null ) goto NOT_FOUND;
19170     else { add_edge_ref(dash_p(p));
19171     mp->se_sf=dash_scale(p);
19172     mp->se_pic=dash_p(p);
19173     mp_scale_edges(mp);
19174     mp_flush_cur_exp(mp, mp->se_pic);
19175     mp->cur_type=mp_picture_type;
19176     };
19177   }
19178   break;
19179
19180 @ Since |scale_edges| had to be declared |forward|, it had to be declared as a
19181 parameterless procedure even though it really takes two arguments and updates
19182 one of them.  Hence the following globals are needed.
19183
19184 @<Global...@>=
19185 pointer se_pic;  /* edge header used and updated by |scale_edges| */
19186 scaled se_sf;  /* the scale factor argument to |scale_edges| */
19187
19188 @ @<Convert the current expression to a null value appropriate...@>=
19189 switch (c) {
19190 case text_part: case font_part: 
19191   mp_flush_cur_exp(mp, rts(""));
19192   mp->cur_type=mp_string_type;
19193   break;
19194 case path_part: 
19195   mp_flush_cur_exp(mp, mp_get_node(mp, knot_node_size));
19196   left_type(mp->cur_exp)=mp_endpoint;
19197   right_type(mp->cur_exp)=mp_endpoint;
19198   link(mp->cur_exp)=mp->cur_exp;
19199   x_coord(mp->cur_exp)=0;
19200   y_coord(mp->cur_exp)=0;
19201   originator(mp->cur_exp)=mp_metapost_user;
19202   mp->cur_type=mp_path_type;
19203   break;
19204 case pen_part: 
19205   mp_flush_cur_exp(mp, mp_get_pen_circle(mp, 0));
19206   mp->cur_type=mp_pen_type;
19207   break;
19208 case dash_part: 
19209   mp_flush_cur_exp(mp, mp_get_node(mp, edge_header_size));
19210   mp_init_edges(mp, mp->cur_exp);
19211   mp->cur_type=mp_picture_type;
19212   break;
19213 default: 
19214    mp_flush_cur_exp(mp, 0);
19215   break;
19216 }
19217
19218 @ @<Additional cases of unary...@>=
19219 case char_op: 
19220   if ( mp->cur_type!=mp_known ) { 
19221     mp_bad_unary(mp, char_op);
19222   } else { 
19223     mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256; 
19224     mp->cur_type=mp_string_type;
19225     if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
19226   }
19227   break;
19228 case decimal: 
19229   if ( mp->cur_type!=mp_known ) {
19230      mp_bad_unary(mp, decimal);
19231   } else { 
19232     mp->old_setting=mp->selector; mp->selector=new_string;
19233     mp_print_scaled(mp, mp->cur_exp); mp->cur_exp=mp_make_string(mp);
19234     mp->selector=mp->old_setting; mp->cur_type=mp_string_type;
19235   }
19236   break;
19237 case oct_op:
19238 case hex_op:
19239 case ASCII_op: 
19240   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19241   else mp_str_to_num(mp, c);
19242   break;
19243 case font_size: 
19244   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, font_size);
19245   else @<Find the design size of the font whose name is |cur_exp|@>;
19246   break;
19247
19248 @ @<Declare unary action...@>=
19249 void mp_str_to_num (MP mp,quarterword c) { /* converts a string to a number */
19250   integer n; /* accumulator */
19251   ASCII_code m; /* current character */
19252   pool_pointer k; /* index into |str_pool| */
19253   int b; /* radix of conversion */
19254   boolean bad_char; /* did the string contain an invalid digit? */
19255   if ( c==ASCII_op ) {
19256     if ( length(mp->cur_exp)==0 ) n=-1;
19257     else n=mp->str_pool[mp->str_start[mp->cur_exp]];
19258   } else { 
19259     if ( c==oct_op ) b=8; else b=16;
19260     n=0; bad_char=false;
19261     for (k=mp->str_start[mp->cur_exp];k<=str_stop(mp->cur_exp)-1;k++) {
19262       m=mp->str_pool[k];
19263       if ( (m>='0')&&(m<='9') ) m=m-'0';
19264       else if ( (m>='A')&&(m<='F') ) m=m-'A'+10;
19265       else if ( (m>='a')&&(m<='f') ) m=m-'a'+10;
19266       else  { bad_char=true; m=0; };
19267       if ( m>=b ) { bad_char=true; m=0; };
19268       if ( n<32768 / b ) n=n*b+m; else n=32767;
19269     }
19270     @<Give error messages if |bad_char| or |n>=4096|@>;
19271   }
19272   mp_flush_cur_exp(mp, n*unity);
19273 }
19274
19275 @ @<Give error messages if |bad_char|...@>=
19276 if ( bad_char ) { 
19277   exp_err("String contains illegal digits");
19278 @.String contains illegal digits@>
19279   if ( c==oct_op ) {
19280     help1("I zeroed out characters that weren't in the range 0..7.");
19281   } else  {
19282     help1("I zeroed out characters that weren't hex digits.");
19283   }
19284   mp_put_get_error(mp);
19285 }
19286 if ( (n>4095) ) {
19287   if ( mp->internal[mp_warning_check]>0 ) {
19288     print_err("Number too large ("); 
19289     mp_print_int(mp, n); mp_print_char(mp, ')');
19290 @.Number too large@>
19291     help2("I have trouble with numbers greater than 4095; watch out.")
19292       ("(Set warningcheck:=0 to suppress this message.)");
19293     mp_put_get_error(mp);
19294   }
19295 }
19296
19297 @ The length operation is somewhat unusual in that it applies to a variety
19298 of different types of operands.
19299
19300 @<Additional cases of unary...@>=
19301 case length_op: 
19302   switch (mp->cur_type) {
19303   case mp_string_type: mp_flush_cur_exp(mp, length(mp->cur_exp)*unity); break;
19304   case mp_path_type: mp_flush_cur_exp(mp, mp_path_length(mp)); break;
19305   case mp_known: mp->cur_exp=abs(mp->cur_exp); break;
19306   case mp_picture_type: mp_flush_cur_exp(mp, mp_pict_length(mp)); break;
19307   default: 
19308     if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) )
19309       mp_flush_cur_exp(mp, mp_pyth_add(mp, 
19310         value(x_part_loc(value(mp->cur_exp))),
19311         value(y_part_loc(value(mp->cur_exp)))));
19312     else mp_bad_unary(mp, c);
19313     break;
19314   }
19315   break;
19316
19317 @ @<Declare unary action...@>=
19318 scaled mp_path_length (MP mp) { /* computes the length of the current path */
19319   scaled n; /* the path length so far */
19320   pointer p; /* traverser */
19321   p=mp->cur_exp;
19322   if ( left_type(p)==mp_endpoint ) n=-unity; else n=0;
19323   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
19324   return n;
19325 }
19326
19327 @ @<Declare unary action...@>=
19328 scaled mp_pict_length (MP mp) { 
19329   /* counts interior components in picture |cur_exp| */
19330   scaled n; /* the count so far */
19331   pointer p; /* traverser */
19332   n=0;
19333   p=link(dummy_loc(mp->cur_exp));
19334   if ( p!=null ) {
19335     if ( is_start_or_stop(p) )
19336       if ( mp_skip_1component(mp, p)==null ) p=link(p);
19337     while ( p!=null )  { 
19338       skip_component(p) return n; 
19339       n=n+unity;   
19340     }
19341   }
19342   return n;
19343 }
19344
19345 @ Implement |turningnumber|
19346
19347 @<Additional cases of unary...@>=
19348 case turning_op:
19349   if ( mp->cur_type==mp_pair_type ) mp_flush_cur_exp(mp, 0);
19350   else if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, turning_op);
19351   else if ( left_type(mp->cur_exp)==mp_endpoint )
19352      mp_flush_cur_exp(mp, 0); /* not a cyclic path */
19353   else
19354     mp_flush_cur_exp(mp, mp_turn_cycles_wrapper(mp, mp->cur_exp));
19355   break;
19356
19357 @ The function |an_angle| returns the value of the |angle| primitive, or $0$ if the
19358 argument is |origin|.
19359
19360 @<Declare unary action...@>=
19361 angle mp_an_angle (MP mp,scaled xpar, scaled ypar) {
19362   if ( (! ((xpar==0) && (ypar==0))) )
19363     return mp_n_arg(mp, xpar,ypar);
19364   return 0;
19365 }
19366
19367
19368 @ The actual turning number is (for the moment) computed in a C function
19369 that receives eight integers corresponding to the four controlling points,
19370 and returns a single angle.  Besides those, we have to account for discrete
19371 moves at the actual points.
19372
19373 @d floor(a) (a>=0 ? a : -(int)(-a))
19374 @d bezier_error (720<<20)+1
19375 @d sign(v) ((v)>0 ? 1 : ((v)<0 ? -1 : 0 ))
19376 @d print_roots(a) 
19377 @d out ((double)(xo>>20))
19378 @d mid ((double)(xm>>20))
19379 @d in  ((double)(xi>>20))
19380 @d divisor (256*256)
19381 @d double2angle(a) (int)floor(a*256.0*256.0*16.0)
19382
19383 @<Declare unary action...@>=
19384 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19385             integer CX,integer CY,integer DX,integer DY);
19386
19387 @ @c 
19388 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19389             integer CX,integer CY,integer DX,integer DY) {
19390   double a, b, c;
19391   integer deltax,deltay;
19392   double ax,ay,bx,by,cx,cy,dx,dy;
19393   angle xi = 0, xo = 0, xm = 0;
19394   double res = 0;
19395   ax=AX/divisor;  ay=AY/divisor;
19396   bx=BX/divisor;  by=BY/divisor;
19397   cx=CX/divisor;  cy=CY/divisor;
19398   dx=DX/divisor;  dy=DY/divisor;
19399
19400   deltax = (BX-AX); deltay = (BY-AY);
19401   if (deltax==0 && deltay == 0) { deltax=(CX-AX); deltay=(CY-AY); }
19402   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19403   xi = mp_an_angle(mp,deltax,deltay);
19404
19405   deltax = (CX-BX); deltay = (CY-BY);
19406   xm = mp_an_angle(mp,deltax,deltay);
19407
19408   deltax = (DX-CX); deltay = (DY-CY);
19409   if (deltax==0 && deltay == 0) { deltax=(DX-BX); deltay=(DY-BY); }
19410   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19411   xo = mp_an_angle(mp,deltax,deltay);
19412
19413   a = (bx-ax)*(cy-by) - (cx-bx)*(by-ay); /* a = (bp-ap)x(cp-bp); */
19414   b = (bx-ax)*(dy-cy) - (by-ay)*(dx-cx);; /* b = (bp-ap)x(dp-cp);*/
19415   c = (cx-bx)*(dy-cy) - (dx-cx)*(cy-by); /* c = (cp-bp)x(dp-cp);*/
19416
19417   if ((a==0)&&(c==0)) {
19418     res = (b==0 ?  0 :  (out-in)); 
19419     print_roots("no roots (a)");
19420   } else if ((a==0)||(c==0)) {
19421     if ((sign(b) == sign(a)) || (sign(b) == sign(c))) {
19422       res = out-in; /* ? */
19423       if (res<-180.0) 
19424         res += 360.0;
19425       else if (res>180.0)
19426         res -= 360.0;
19427       print_roots("no roots (b)");
19428     } else {
19429       res = out-in; /* ? */
19430       print_roots("one root (a)");
19431     }
19432   } else if ((sign(a)*sign(c))<0) {
19433     res = out-in; /* ? */
19434       if (res<-180.0) 
19435         res += 360.0;
19436       else if (res>180.0)
19437         res -= 360.0;
19438     print_roots("one root (b)");
19439   } else {
19440     if (sign(a) == sign(b)) {
19441       res = out-in; /* ? */
19442       if (res<-180.0) 
19443         res += 360.0;
19444       else if (res>180.0)
19445         res -= 360.0;
19446       print_roots("no roots (d)");
19447     } else {
19448       if ((b*b) == (4*a*c)) {
19449         res = bezier_error;
19450         print_roots("double root"); /* cusp */
19451       } else if ((b*b) < (4*a*c)) {
19452         res = out-in; /* ? */
19453         if (res<=0.0 &&res>-180.0) 
19454           res += 360.0;
19455         else if (res>=0.0 && res<180.0)
19456           res -= 360.0;
19457         print_roots("no roots (e)");
19458       } else {
19459         res = out-in;
19460         if (res<-180.0) 
19461           res += 360.0;
19462         else if (res>180.0)
19463           res -= 360.0;
19464         print_roots("two roots"); /* two inflections */
19465       }
19466     }
19467   }
19468   return double2angle(res);
19469 }
19470
19471 @
19472 @d p_nextnext link(link(p))
19473 @d p_next link(p)
19474 @d seven_twenty_deg 05500000000 /* $720\cdot2^{20}$, represents $720^\circ$ */
19475
19476 @<Declare unary action...@>=
19477 scaled mp_new_turn_cycles (MP mp,pointer c) {
19478   angle res,ang; /*  the angles of intermediate results  */
19479   scaled turns;  /*  the turn counter  */
19480   pointer p;     /*  for running around the path  */
19481   integer xp,yp;   /*  coordinates of next point  */
19482   integer x,y;   /*  helper coordinates  */
19483   angle in_angle,out_angle;     /*  helper angles */
19484   int old_setting; /* saved |selector| setting */
19485   res=0;
19486   turns= 0;
19487   p=c;
19488   old_setting = mp->selector; mp->selector=term_only;
19489   if ( mp->internal[mp_tracing_commands]>unity ) {
19490     mp_begin_diagnostic(mp);
19491     mp_print_nl(mp, "");
19492     mp_end_diagnostic(mp, false);
19493   }
19494   do { 
19495     xp = x_coord(p_next); yp = y_coord(p_next);
19496     ang  = mp_bezier_slope(mp,x_coord(p), y_coord(p), right_x(p), right_y(p),
19497              left_x(p_next), left_y(p_next), xp, yp);
19498     if ( ang>seven_twenty_deg ) {
19499       print_err("Strange path");
19500       mp_error(mp);
19501       mp->selector=old_setting;
19502       return 0;
19503     }
19504     res  = res + ang;
19505     if ( res > one_eighty_deg ) {
19506       res = res - three_sixty_deg;
19507       turns = turns + unity;
19508     }
19509     if ( res <= -one_eighty_deg ) {
19510       res = res + three_sixty_deg;
19511       turns = turns - unity;
19512     }
19513     /*  incoming angle at next point  */
19514     x = left_x(p_next);  y = left_y(p_next);
19515     if ( (xp==x)&&(yp==y) ) { x = right_x(p);  y = right_y(p);  };
19516     if ( (xp==x)&&(yp==y) ) { x = x_coord(p);  y = y_coord(p);  };
19517     in_angle = mp_an_angle(mp, xp - x, yp - y);
19518     /*  outgoing angle at next point  */
19519     x = right_x(p_next);  y = right_y(p_next);
19520     if ( (xp==x)&&(yp==y) ) { x = left_x(p_nextnext);  y = left_y(p_nextnext);  };
19521     if ( (xp==x)&&(yp==y) ) { x = x_coord(p_nextnext); y = y_coord(p_nextnext); };
19522     out_angle = mp_an_angle(mp, x - xp, y- yp);
19523     ang  = (out_angle - in_angle);
19524     reduce_angle(ang);
19525     if ( ang!=0 ) {
19526       res  = res + ang;
19527       if ( res >= one_eighty_deg ) {
19528         res = res - three_sixty_deg;
19529         turns = turns + unity;
19530       };
19531       if ( res <= -one_eighty_deg ) {
19532         res = res + three_sixty_deg;
19533         turns = turns - unity;
19534       };
19535     };
19536     p = link(p);
19537   } while (p!=c);
19538   mp->selector=old_setting;
19539   return turns;
19540 }
19541
19542
19543 @ This code is based on Bogus\l{}av Jackowski's
19544 |emergency_turningnumber| macro, with some minor changes by Taco
19545 Hoekwater. The macro code looked more like this:
19546 {\obeylines
19547 vardef turning\_number primary p =
19548 ~~save res, ang, turns;
19549 ~~res := 0;
19550 ~~if length p <= 2:
19551 ~~~~if Angle ((point 0 of p) - (postcontrol 0 of p)) >= 0:  1  else: -1 fi
19552 ~~else:
19553 ~~~~for t = 0 upto length p-1 :
19554 ~~~~~~angc := Angle ((point t+1 of p)  - (point t of p))
19555 ~~~~~~~~- Angle ((point t of p) - (point t-1 of p));
19556 ~~~~~~if angc > 180: angc := angc - 360; fi;
19557 ~~~~~~if angc < -180: angc := angc + 360; fi;
19558 ~~~~~~res  := res + angc;
19559 ~~~~endfor;
19560 ~~res/360
19561 ~~fi
19562 enddef;}
19563 The general idea is to calculate only the sum of the angles of
19564 straight lines between the points, of a path, not worrying about cusps
19565 or self-intersections in the segments at all. If the segment is not
19566 well-behaved, the result is not necesarily correct. But the old code
19567 was not always correct either, and worse, it sometimes failed for
19568 well-behaved paths as well. All known bugs that were triggered by the
19569 original code no longer occur with this code, and it runs roughly 3
19570 times as fast because the algorithm is much simpler.
19571
19572 @ It is possible to overflow the return value of the |turn_cycles|
19573 function when the path is sufficiently long and winding, but I am not
19574 going to bother testing for that. In any case, it would only return
19575 the looped result value, which is not a big problem.
19576
19577 The macro code for the repeat loop was a bit nicer to look
19578 at than the pascal code, because it could use |point -1 of p|. In
19579 pascal, the fastest way to loop around the path is not to look
19580 backward once, but forward twice. These defines help hide the trick.
19581
19582 @d p_to link(link(p))
19583 @d p_here link(p)
19584 @d p_from p
19585
19586 @<Declare unary action...@>=
19587 scaled mp_turn_cycles (MP mp,pointer c) {
19588   angle res,ang; /*  the angles of intermediate results  */
19589   scaled turns;  /*  the turn counter  */
19590   pointer p;     /*  for running around the path  */
19591   res=0;  turns= 0; p=c;
19592   do { 
19593     ang  = mp_an_angle (mp, x_coord(p_to) - x_coord(p_here), 
19594                             y_coord(p_to) - y_coord(p_here))
19595         - mp_an_angle (mp, x_coord(p_here) - x_coord(p_from), 
19596                            y_coord(p_here) - y_coord(p_from));
19597     reduce_angle(ang);
19598     res  = res + ang;
19599     if ( res >= three_sixty_deg )  {
19600       res = res - three_sixty_deg;
19601       turns = turns + unity;
19602     };
19603     if ( res <= -three_sixty_deg ) {
19604       res = res + three_sixty_deg;
19605       turns = turns - unity;
19606     };
19607     p = link(p);
19608   } while (p!=c);
19609   return turns;
19610 }
19611
19612 @ @<Declare unary action...@>=
19613 scaled mp_turn_cycles_wrapper (MP mp,pointer c) {
19614   scaled nval,oval;
19615   scaled saved_t_o; /* tracing\_online saved  */
19616   if ( (link(c)==c)||(link(link(c))==c) ) {
19617     if ( mp_an_angle (mp, x_coord(c) - right_x(c),  y_coord(c) - right_y(c)) > 0 )
19618       return unity;
19619     else
19620       return -unity;
19621   } else {
19622     nval = mp_new_turn_cycles(mp, c);
19623     oval = mp_turn_cycles(mp, c);
19624     if ( nval!=oval ) {
19625       saved_t_o=mp->internal[mp_tracing_online];
19626       mp->internal[mp_tracing_online]=unity;
19627       mp_begin_diagnostic(mp);
19628       mp_print_nl (mp, "Warning: the turningnumber algorithms do not agree."
19629                        " The current computed value is ");
19630       mp_print_scaled(mp, nval);
19631       mp_print(mp, ", but the 'connect-the-dots' algorithm returned ");
19632       mp_print_scaled(mp, oval);
19633       mp_end_diagnostic(mp, false);
19634       mp->internal[mp_tracing_online]=saved_t_o;
19635     }
19636     return nval;
19637   }
19638 }
19639
19640 @ @<Declare unary action...@>=
19641 scaled mp_count_turns (MP mp,pointer c) {
19642   pointer p; /* a knot in envelope spec |c| */
19643   integer t; /* total pen offset changes counted */
19644   t=0; p=c;
19645   do {  
19646     t=t+info(p)-zero_off;
19647     p=link(p);
19648   } while (p!=c);
19649   return ((t / 3)*unity);
19650 }
19651
19652 @ @d type_range(A,B) { 
19653   if ( (mp->cur_type>=(A)) && (mp->cur_type<=(B)) ) 
19654     mp_flush_cur_exp(mp, true_code);
19655   else mp_flush_cur_exp(mp, false_code);
19656   mp->cur_type=mp_boolean_type;
19657   }
19658 @d type_test(A) { 
19659   if ( mp->cur_type==(A) ) mp_flush_cur_exp(mp, true_code);
19660   else mp_flush_cur_exp(mp, false_code);
19661   mp->cur_type=mp_boolean_type;
19662   }
19663
19664 @<Additional cases of unary operators@>=
19665 case mp_boolean_type: 
19666   type_range(mp_boolean_type,mp_unknown_boolean); break;
19667 case mp_string_type: 
19668   type_range(mp_string_type,mp_unknown_string); break;
19669 case mp_pen_type: 
19670   type_range(mp_pen_type,mp_unknown_pen); break;
19671 case mp_path_type: 
19672   type_range(mp_path_type,mp_unknown_path); break;
19673 case mp_picture_type: 
19674   type_range(mp_picture_type,mp_unknown_picture); break;
19675 case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
19676 case mp_pair_type: 
19677   type_test(c); break;
19678 case mp_numeric_type: 
19679   type_range(mp_known,mp_independent); break;
19680 case known_op: case unknown_op: 
19681   mp_test_known(mp, c); break;
19682
19683 @ @<Declare unary action procedures@>=
19684 void mp_test_known (MP mp,quarterword c) {
19685   int b; /* is the current expression known? */
19686   pointer p,q; /* locations in a big node */
19687   b=false_code;
19688   switch (mp->cur_type) {
19689   case mp_vacuous: case mp_boolean_type: case mp_string_type:
19690   case mp_pen_type: case mp_path_type: case mp_picture_type:
19691   case mp_known: 
19692     b=true_code;
19693     break;
19694   case mp_transform_type:
19695   case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: 
19696     p=value(mp->cur_exp);
19697     q=p+mp->big_node_size[mp->cur_type];
19698     do {  
19699       q=q-2;
19700       if ( type(q)!=mp_known ) 
19701        goto DONE;
19702     } while (q!=p);
19703     b=true_code;
19704   DONE:  
19705     break;
19706   default: 
19707     break;
19708   }
19709   if ( c==known_op ) mp_flush_cur_exp(mp, b);
19710   else mp_flush_cur_exp(mp, true_code+false_code-b);
19711   mp->cur_type=mp_boolean_type;
19712 }
19713
19714 @ @<Additional cases of unary operators@>=
19715 case cycle_op: 
19716   if ( mp->cur_type!=mp_path_type ) mp_flush_cur_exp(mp, false_code);
19717   else if ( left_type(mp->cur_exp)!=mp_endpoint ) mp_flush_cur_exp(mp, true_code);
19718   else mp_flush_cur_exp(mp, false_code);
19719   mp->cur_type=mp_boolean_type;
19720   break;
19721
19722 @ @<Additional cases of unary operators@>=
19723 case arc_length: 
19724   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19725   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, arc_length);
19726   else mp_flush_cur_exp(mp, mp_get_arc_length(mp, mp->cur_exp));
19727   break;
19728
19729 @ Here we use the fact that |c-filled_op+fill_code| is the desired graphical
19730 object |type|.
19731 @^data structure assumptions@>
19732
19733 @<Additional cases of unary operators@>=
19734 case filled_op:
19735 case stroked_op:
19736 case textual_op:
19737 case clipped_op:
19738 case bounded_op:
19739   if ( mp->cur_type!=mp_picture_type ) mp_flush_cur_exp(mp, false_code);
19740   else if ( link(dummy_loc(mp->cur_exp))==null ) mp_flush_cur_exp(mp, false_code);
19741   else if ( type(link(dummy_loc(mp->cur_exp)))==c+mp_fill_code-filled_op )
19742     mp_flush_cur_exp(mp, true_code);
19743   else mp_flush_cur_exp(mp, false_code);
19744   mp->cur_type=mp_boolean_type;
19745   break;
19746
19747 @ @<Additional cases of unary operators@>=
19748 case make_pen_op: 
19749   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19750   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, make_pen_op);
19751   else { 
19752     mp->cur_type=mp_pen_type;
19753     mp->cur_exp=mp_make_pen(mp, mp->cur_exp,true);
19754   };
19755   break;
19756 case make_path_op: 
19757   if ( mp->cur_type!=mp_pen_type ) mp_bad_unary(mp, make_path_op);
19758   else  { 
19759     mp->cur_type=mp_path_type;
19760     mp_make_path(mp, mp->cur_exp);
19761   };
19762   break;
19763 case reverse: 
19764   if ( mp->cur_type==mp_path_type ) {
19765     p=mp_htap_ypoc(mp, mp->cur_exp);
19766     if ( right_type(p)==mp_endpoint ) p=link(p);
19767     mp_toss_knot_list(mp, mp->cur_exp); mp->cur_exp=p;
19768   } else if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19769   else mp_bad_unary(mp, reverse);
19770   break;
19771
19772 @ The |pair_value| routine changes the current expression to a
19773 given ordered pair of values.
19774
19775 @<Declare unary action procedures@>=
19776 void mp_pair_value (MP mp,scaled x, scaled y) {
19777   pointer p; /* a pair node */
19778   p=mp_get_node(mp, value_node_size); 
19779   mp_flush_cur_exp(mp, p); mp->cur_type=mp_pair_type;
19780   type(p)=mp_pair_type; name_type(p)=mp_capsule; mp_init_big_node(mp, p);
19781   p=value(p);
19782   type(x_part_loc(p))=mp_known; value(x_part_loc(p))=x;
19783   type(y_part_loc(p))=mp_known; value(y_part_loc(p))=y;
19784 }
19785
19786 @ @<Additional cases of unary operators@>=
19787 case ll_corner_op: 
19788   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ll_corner_op);
19789   else mp_pair_value(mp, minx,miny);
19790   break;
19791 case lr_corner_op: 
19792   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, lr_corner_op);
19793   else mp_pair_value(mp, maxx,miny);
19794   break;
19795 case ul_corner_op: 
19796   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ul_corner_op);
19797   else mp_pair_value(mp, minx,maxy);
19798   break;
19799 case ur_corner_op: 
19800   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ur_corner_op);
19801   else mp_pair_value(mp, maxx,maxy);
19802   break;
19803
19804 @ Here is a function that sets |minx|, |maxx|, |miny|, |maxy| to the bounding
19805 box of the current expression.  The boolean result is |false| if the expression
19806 has the wrong type.
19807
19808 @<Declare unary action procedures@>=
19809 boolean mp_get_cur_bbox (MP mp) { 
19810   switch (mp->cur_type) {
19811   case mp_picture_type: 
19812     mp_set_bbox(mp, mp->cur_exp,true);
19813     if ( minx_val(mp->cur_exp)>maxx_val(mp->cur_exp) ) {
19814       minx=0; maxx=0; miny=0; maxy=0;
19815     } else { 
19816       minx=minx_val(mp->cur_exp);
19817       maxx=maxx_val(mp->cur_exp);
19818       miny=miny_val(mp->cur_exp);
19819       maxy=maxy_val(mp->cur_exp);
19820     }
19821     break;
19822   case mp_path_type: 
19823     mp_path_bbox(mp, mp->cur_exp);
19824     break;
19825   case mp_pen_type: 
19826     mp_pen_bbox(mp, mp->cur_exp);
19827     break;
19828   default: 
19829     return false;
19830   }
19831   return true;
19832 }
19833
19834 @ @<Additional cases of unary operators@>=
19835 case read_from_op:
19836 case close_from_op: 
19837   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19838   else mp_do_read_or_close(mp,c);
19839   break;
19840
19841 @ Here is a routine that interprets |cur_exp| as a file name and tries to read
19842 a line from the file or to close the file.
19843
19844 @<Declare unary action procedures@>=
19845 void mp_do_read_or_close (MP mp,quarterword c) {
19846   readf_index n,n0; /* indices for searching |rd_fname| */
19847   @<Find the |n| where |rd_fname[n]=cur_exp|; if |cur_exp| must be inserted,
19848     call |start_read_input| and |goto found| or |not_found|@>;
19849   mp_begin_file_reading(mp);
19850   name=is_read;
19851   if ( mp_input_ln(mp, mp->rd_file[n] ) ) 
19852     goto FOUND;
19853   mp_end_file_reading(mp);
19854 NOT_FOUND:
19855   @<Record the end of file and set |cur_exp| to a dummy value@>;
19856   return;
19857 CLOSE_FILE:
19858   mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous; 
19859   return;
19860 FOUND:
19861   mp_flush_cur_exp(mp, 0);
19862   mp_finish_read(mp);
19863 }
19864
19865 @ Free slots in the |rd_file| and |rd_fname| arrays are marked with NULL's in
19866 |rd_fname|.
19867
19868 @<Find the |n| where |rd_fname[n]=cur_exp|...@>=
19869 {   
19870   char *fn;
19871   n=mp->read_files;
19872   n0=mp->read_files;
19873   fn = str(mp->cur_exp);
19874   while (mp_xstrcmp(fn,mp->rd_fname[n])!=0) { 
19875     if ( n>0 ) {
19876       decr(n);
19877     } else if ( c==close_from_op ) {
19878       goto CLOSE_FILE;
19879     } else {
19880       if ( n0==mp->read_files ) {
19881         if ( mp->read_files<mp->max_read_files ) {
19882           incr(mp->read_files);
19883         } else {
19884           void **rd_file;
19885           char **rd_fname;
19886               readf_index l,k;
19887           l = mp->max_read_files + (mp->max_read_files>>2);
19888           rd_file = xmalloc((l+1), sizeof(void *));
19889           rd_fname = xmalloc((l+1), sizeof(char *));
19890               for (k=0;k<=l;k++) {
19891             if (k<=mp->max_read_files) {
19892                   rd_file[k]=mp->rd_file[k]; 
19893               rd_fname[k]=mp->rd_fname[k];
19894             } else {
19895               rd_file[k]=0; 
19896               rd_fname[k]=NULL;
19897             }
19898           }
19899               xfree(mp->rd_file); xfree(mp->rd_fname);
19900           mp->max_read_files = l;
19901           mp->rd_file = rd_file;
19902           mp->rd_fname = rd_fname;
19903         }
19904       }
19905       n=n0;
19906       if ( mp_start_read_input(mp,fn,n) ) 
19907         goto FOUND;
19908       else 
19909         goto NOT_FOUND;
19910     }
19911     if ( mp->rd_fname[n]==NULL ) { n0=n; }
19912   } 
19913   if ( c==close_from_op ) { 
19914     (mp->close_file)(mp->rd_file[n]); 
19915     goto NOT_FOUND; 
19916   }
19917 }
19918
19919 @ @<Record the end of file and set |cur_exp| to a dummy value@>=
19920 xfree(mp->rd_fname[n]);
19921 mp->rd_fname[n]=NULL;
19922 if ( n==mp->read_files-1 ) mp->read_files=n;
19923 if ( c==close_from_op ) 
19924   goto CLOSE_FILE;
19925 mp_flush_cur_exp(mp, mp->eof_line);
19926 mp->cur_type=mp_string_type
19927
19928 @ The string denoting end-of-file is a one-byte string at position zero, by definition
19929
19930 @<Glob...@>=
19931 str_number eof_line;
19932
19933 @ @<Set init...@>=
19934 mp->eof_line=0;
19935
19936 @ Finally, we have the operations that combine a capsule~|p|
19937 with the current expression.
19938
19939 @c @<Declare binary action procedures@>;
19940 void mp_do_binary (MP mp,pointer p, quarterword c) {
19941   pointer q,r,rr; /* for list manipulation */
19942   pointer old_p,old_exp; /* capsules to recycle */
19943   integer v; /* for numeric manipulation */
19944   check_arith;
19945   if ( mp->internal[mp_tracing_commands]>two ) {
19946     @<Trace the current binary operation@>;
19947   }
19948   @<Sidestep |independent| cases in capsule |p|@>;
19949   @<Sidestep |independent| cases in the current expression@>;
19950   switch (c) {
19951   case plus: case minus:
19952     @<Add or subtract the current expression from |p|@>;
19953     break;
19954   @<Additional cases of binary operators@>;
19955   }; /* there are no other cases */
19956   mp_recycle_value(mp, p); 
19957   mp_free_node(mp, p,value_node_size); /* |return| to avoid this */
19958   check_arith; 
19959   @<Recycle any sidestepped |independent| capsules@>;
19960 }
19961
19962 @ @<Declare binary action...@>=
19963 void mp_bad_binary (MP mp,pointer p, quarterword c) { 
19964   mp_disp_err(mp, p,"");
19965   exp_err("Not implemented: ");
19966 @.Not implemented...@>
19967   if ( c>=min_of ) mp_print_op(mp, c);
19968   mp_print_known_or_unknown_type(mp, type(p),p);
19969   if ( c>=min_of ) mp_print(mp, "of"); else mp_print_op(mp, c);
19970   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
19971   help3("I'm afraid I don't know how to apply that operation to that")
19972        ("combination of types. Continue, and I'll return the second")
19973       ("argument (see above) as the result of the operation.");
19974   mp_put_get_error(mp);
19975 }
19976 void mp_bad_envelope_pen (MP mp) {
19977   mp_disp_err(mp, null,"");
19978   exp_err("Not implemented: envelope(elliptical pen)of(path)");
19979 @.Not implemented...@>
19980   help3("I'm afraid I don't know how to apply that operation to that")
19981        ("combination of types. Continue, and I'll return the second")
19982       ("argument (see above) as the result of the operation.");
19983   mp_put_get_error(mp);
19984 }
19985
19986 @ @<Trace the current binary operation@>=
19987
19988   mp_begin_diagnostic(mp); mp_print_nl(mp, "{(");
19989   mp_print_exp(mp,p,0); /* show the operand, but not verbosely */
19990   mp_print_char(mp,')'); mp_print_op(mp,c); mp_print_char(mp,'(');
19991   mp_print_exp(mp,null,0); mp_print(mp,")}"); 
19992   mp_end_diagnostic(mp, false);
19993 }
19994
19995 @ Several of the binary operations are potentially complicated by the
19996 fact that |independent| values can sneak into capsules. For example,
19997 we've seen an instance of this difficulty in the unary operation
19998 of negation. In order to reduce the number of cases that need to be
19999 handled, we first change the two operands (if necessary)
20000 to rid them of |independent| components. The original operands are
20001 put into capsules called |old_p| and |old_exp|, which will be
20002 recycled after the binary operation has been safely carried out.
20003
20004 @<Recycle any sidestepped |independent| capsules@>=
20005 if ( old_p!=null ) { 
20006   mp_recycle_value(mp, old_p); mp_free_node(mp, old_p,value_node_size);
20007 }
20008 if ( old_exp!=null ) {
20009   mp_recycle_value(mp, old_exp); mp_free_node(mp, old_exp,value_node_size);
20010 }
20011
20012 @ A big node is considered to be ``tarnished'' if it contains at least one
20013 independent component. We will define a simple function called `|tarnished|'
20014 that returns |null| if and only if its argument is not tarnished.
20015
20016 @<Sidestep |independent| cases in capsule |p|@>=
20017 switch (type(p)) {
20018 case mp_transform_type:
20019 case mp_color_type:
20020 case mp_cmykcolor_type:
20021 case mp_pair_type: 
20022   old_p=mp_tarnished(mp, p);
20023   break;
20024 case mp_independent: old_p=mp_void; break;
20025 default: old_p=null; break;
20026 };
20027 if ( old_p!=null ) {
20028   q=mp_stash_cur_exp(mp); old_p=p; mp_make_exp_copy(mp, old_p);
20029   p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
20030 }
20031
20032 @ @<Sidestep |independent| cases in the current expression@>=
20033 switch (mp->cur_type) {
20034 case mp_transform_type:
20035 case mp_color_type:
20036 case mp_cmykcolor_type:
20037 case mp_pair_type: 
20038   old_exp=mp_tarnished(mp, mp->cur_exp);
20039   break;
20040 case mp_independent:old_exp=mp_void; break;
20041 default: old_exp=null; break;
20042 };
20043 if ( old_exp!=null ) {
20044   old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20045 }
20046
20047 @ @<Declare binary action...@>=
20048 pointer mp_tarnished (MP mp,pointer p) {
20049   pointer q; /* beginning of the big node */
20050   pointer r; /* current position in the big node */
20051   q=value(p); r=q+mp->big_node_size[type(p)];
20052   do {  
20053    r=r-2;
20054    if ( type(r)==mp_independent ) return mp_void; 
20055   } while (r!=q);
20056   return null;
20057 }
20058
20059 @ @<Add or subtract the current expression from |p|@>=
20060 if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
20061   mp_bad_binary(mp, p,c);
20062 } else  {
20063   if ((mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
20064     mp_add_or_subtract(mp, p,null,c);
20065   } else {
20066     if ( mp->cur_type!=type(p) )  {
20067       mp_bad_binary(mp, p,c);
20068     } else { 
20069       q=value(p); r=value(mp->cur_exp);
20070       rr=r+mp->big_node_size[mp->cur_type];
20071       while ( r<rr ) { 
20072         mp_add_or_subtract(mp, q,r,c);
20073         q=q+2; r=r+2;
20074       }
20075     }
20076   }
20077 }
20078
20079 @ The first argument to |add_or_subtract| is the location of a value node
20080 in a capsule or pair node that will soon be recycled. The second argument
20081 is either a location within a pair or transform node of |cur_exp|,
20082 or it is null (which means that |cur_exp| itself should be the second
20083 argument).  The third argument is either |plus| or |minus|.
20084
20085 The sum or difference of the numeric quantities will replace the second
20086 operand.  Arithmetic overflow may go undetected; users aren't supposed to
20087 be monkeying around with really big values.
20088
20089 @<Declare binary action...@>=
20090 @<Declare the procedure called |dep_finish|@>;
20091 void mp_add_or_subtract (MP mp,pointer p, pointer q, quarterword c) {
20092   small_number s,t; /* operand types */
20093   pointer r; /* list traverser */
20094   integer v; /* second operand value */
20095   if ( q==null ) { 
20096     t=mp->cur_type;
20097     if ( t<mp_dependent ) v=mp->cur_exp; else v=dep_list(mp->cur_exp);
20098   } else { 
20099     t=type(q);
20100     if ( t<mp_dependent ) v=value(q); else v=dep_list(q);
20101   }
20102   if ( t==mp_known ) {
20103     if ( c==minus ) negate(v);
20104     if ( type(p)==mp_known ) {
20105       v=mp_slow_add(mp, value(p),v);
20106       if ( q==null ) mp->cur_exp=v; else value(q)=v;
20107       return;
20108     }
20109     @<Add a known value to the constant term of |dep_list(p)|@>;
20110   } else  { 
20111     if ( c==minus ) mp_negate_dep_list(mp, v);
20112     @<Add operand |p| to the dependency list |v|@>;
20113   }
20114 }
20115
20116 @ @<Add a known value to the constant term of |dep_list(p)|@>=
20117 r=dep_list(p);
20118 while ( info(r)!=null ) r=link(r);
20119 value(r)=mp_slow_add(mp, value(r),v);
20120 if ( q==null ) {
20121   q=mp_get_node(mp, value_node_size); mp->cur_exp=q; mp->cur_type=type(p);
20122   name_type(q)=mp_capsule;
20123 }
20124 dep_list(q)=dep_list(p); type(q)=type(p);
20125 prev_dep(q)=prev_dep(p); link(prev_dep(p))=q;
20126 type(p)=mp_known; /* this will keep the recycler from collecting non-garbage */
20127
20128 @ We prefer |dependent| lists to |mp_proto_dependent| ones, because it is
20129 nice to retain the extra accuracy of |fraction| coefficients.
20130 But we have to handle both kinds, and mixtures too.
20131
20132 @<Add operand |p| to the dependency list |v|@>=
20133 if ( type(p)==mp_known ) {
20134   @<Add the known |value(p)| to the constant term of |v|@>;
20135 } else { 
20136   s=type(p); r=dep_list(p);
20137   if ( t==mp_dependent ) {
20138     if ( s==mp_dependent ) {
20139       if ( mp_max_coef(mp, r)+mp_max_coef(mp, v)<coef_bound )
20140         v=mp_p_plus_q(mp, v,r,mp_dependent); goto DONE;
20141       } /* |fix_needed| will necessarily be false */
20142       t=mp_proto_dependent; 
20143       v=mp_p_over_v(mp, v,unity,mp_dependent,mp_proto_dependent);
20144     }
20145     if ( s==mp_proto_dependent ) v=mp_p_plus_q(mp, v,r,mp_proto_dependent);
20146     else v=mp_p_plus_fq(mp, v,unity,r,mp_proto_dependent,mp_dependent);
20147  DONE:  
20148     @<Output the answer, |v| (which might have become |known|)@>;
20149   }
20150
20151 @ @<Add the known |value(p)| to the constant term of |v|@>=
20152
20153   while ( info(v)!=null ) v=link(v);
20154   value(v)=mp_slow_add(mp, value(p),value(v));
20155 }
20156
20157 @ @<Output the answer, |v| (which might have become |known|)@>=
20158 if ( q!=null ) mp_dep_finish(mp, v,q,t);
20159 else  { mp->cur_type=t; mp_dep_finish(mp, v,null,t); }
20160
20161 @ Here's the current situation: The dependency list |v| of type |t|
20162 should either be put into the current expression (if |q=null|) or
20163 into location |q| within a pair node (otherwise). The destination (|cur_exp|
20164 or |q|) formerly held a dependency list with the same
20165 final pointer as the list |v|.
20166
20167 @<Declare the procedure called |dep_finish|@>=
20168 void mp_dep_finish (MP mp, pointer v, pointer q, small_number t) {
20169   pointer p; /* the destination */
20170   scaled vv; /* the value, if it is |known| */
20171   if ( q==null ) p=mp->cur_exp; else p=q;
20172   dep_list(p)=v; type(p)=t;
20173   if ( info(v)==null ) { 
20174     vv=value(v);
20175     if ( q==null ) { 
20176       mp_flush_cur_exp(mp, vv);
20177     } else  { 
20178       mp_recycle_value(mp, p); type(q)=mp_known; value(q)=vv; 
20179     }
20180   } else if ( q==null ) {
20181     mp->cur_type=t;
20182   }
20183   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20184 }
20185
20186 @ Let's turn now to the six basic relations of comparison.
20187
20188 @<Additional cases of binary operators@>=
20189 case less_than: case less_or_equal: case greater_than:
20190 case greater_or_equal: case equal_to: case unequal_to:
20191   check_arith; /* at this point |arith_error| should be |false|? */
20192   if ( (mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
20193     mp_add_or_subtract(mp, p,null,minus); /* |cur_exp:=(p)-cur_exp| */
20194   } else if ( mp->cur_type!=type(p) ) {
20195     mp_bad_binary(mp, p,c); goto DONE; 
20196   } else if ( mp->cur_type==mp_string_type ) {
20197     mp_flush_cur_exp(mp, mp_str_vs_str(mp, value(p),mp->cur_exp));
20198   } else if ((mp->cur_type==mp_unknown_string)||
20199            (mp->cur_type==mp_unknown_boolean) ) {
20200     @<Check if unknowns have been equated@>;
20201   } else if ( (mp->cur_type<=mp_pair_type)&&(mp->cur_type>=mp_transform_type)) {
20202     @<Reduce comparison of big nodes to comparison of scalars@>;
20203   } else if ( mp->cur_type==mp_boolean_type ) {
20204     mp_flush_cur_exp(mp, mp->cur_exp-value(p));
20205   } else { 
20206     mp_bad_binary(mp, p,c); goto DONE;
20207   }
20208   @<Compare the current expression with zero@>;
20209 DONE:  
20210   mp->arith_error=false; /* ignore overflow in comparisons */
20211   break;
20212
20213 @ @<Compare the current expression with zero@>=
20214 if ( mp->cur_type!=mp_known ) {
20215   if ( mp->cur_type<mp_known ) {
20216     mp_disp_err(mp, p,"");
20217     help1("The quantities shown above have not been equated.")
20218   } else  {
20219     help2("Oh dear. I can\'t decide if the expression above is positive,")
20220      ("negative, or zero. So this comparison test won't be `true'.");
20221   }
20222   exp_err("Unknown relation will be considered false");
20223 @.Unknown relation...@>
20224   mp_put_get_flush_error(mp, false_code);
20225 } else {
20226   switch (c) {
20227   case less_than: boolean_reset(mp->cur_exp<0); break;
20228   case less_or_equal: boolean_reset(mp->cur_exp<=0); break;
20229   case greater_than: boolean_reset(mp->cur_exp>0); break;
20230   case greater_or_equal: boolean_reset(mp->cur_exp>=0); break;
20231   case equal_to: boolean_reset(mp->cur_exp==0); break;
20232   case unequal_to: boolean_reset(mp->cur_exp!=0); break;
20233   }; /* there are no other cases */
20234 }
20235 mp->cur_type=mp_boolean_type
20236
20237 @ When two unknown strings are in the same ring, we know that they are
20238 equal. Otherwise, we don't know whether they are equal or not, so we
20239 make no change.
20240
20241 @<Check if unknowns have been equated@>=
20242
20243   q=value(mp->cur_exp);
20244   while ( (q!=mp->cur_exp)&&(q!=p) ) q=value(q);
20245   if ( q==p ) mp_flush_cur_exp(mp, 0);
20246 }
20247
20248 @ @<Reduce comparison of big nodes to comparison of scalars@>=
20249
20250   q=value(p); r=value(mp->cur_exp);
20251   rr=r+mp->big_node_size[mp->cur_type]-2;
20252   while (1) { mp_add_or_subtract(mp, q,r,minus);
20253     if ( type(r)!=mp_known ) break;
20254     if ( value(r)!=0 ) break;
20255     if ( r==rr ) break;
20256     q=q+2; r=r+2;
20257   }
20258   mp_take_part(mp, name_type(r)+x_part-mp_x_part_sector);
20259 }
20260
20261 @ Here we use the sneaky fact that |and_op-false_code=or_op-true_code|.
20262
20263 @<Additional cases of binary operators@>=
20264 case and_op:
20265 case or_op: 
20266   if ( (type(p)!=mp_boolean_type)||(mp->cur_type!=mp_boolean_type) )
20267     mp_bad_binary(mp, p,c);
20268   else if ( value(p)==c+false_code-and_op ) mp->cur_exp=value(p);
20269   break;
20270
20271 @ @<Additional cases of binary operators@>=
20272 case times: 
20273   if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
20274    mp_bad_binary(mp, p,times);
20275   } else if ( (mp->cur_type==mp_known)||(type(p)==mp_known) ) {
20276     @<Multiply when at least one operand is known@>;
20277   } else if ( (mp_nice_color_or_pair(mp, p,type(p))&&(mp->cur_type>mp_pair_type))
20278       ||(mp_nice_color_or_pair(mp, mp->cur_exp,mp->cur_type)&&
20279           (type(p)>mp_pair_type)) ) {
20280     mp_hard_times(mp, p); return;
20281   } else {
20282     mp_bad_binary(mp, p,times);
20283   }
20284   break;
20285
20286 @ @<Multiply when at least one operand is known@>=
20287
20288   if ( type(p)==mp_known ) {
20289     v=value(p); mp_free_node(mp, p,value_node_size); 
20290   } else {
20291     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20292   }
20293   if ( mp->cur_type==mp_known ) {
20294     mp->cur_exp=mp_take_scaled(mp, mp->cur_exp,v);
20295   } else if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_color_type)||
20296               (mp->cur_type==mp_cmykcolor_type) ) {
20297     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20298     do {  
20299        p=p-2; mp_dep_mult(mp, p,v,true);
20300     } while (p!=value(mp->cur_exp));
20301   } else {
20302     mp_dep_mult(mp, null,v,true);
20303   }
20304   return;
20305 }
20306
20307 @ @<Declare binary action...@>=
20308 void mp_dep_mult (MP mp,pointer p, integer v, boolean v_is_scaled) {
20309   pointer q; /* the dependency list being multiplied by |v| */
20310   small_number s,t; /* its type, before and after */
20311   if ( p==null ) {
20312     q=mp->cur_exp;
20313   } else if ( type(p)!=mp_known ) {
20314     q=p;
20315   } else { 
20316     if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
20317     else value(p)=mp_take_fraction(mp, value(p),v);
20318     return;
20319   };
20320   t=type(q); q=dep_list(q); s=t;
20321   if ( t==mp_dependent ) if ( v_is_scaled )
20322     if (mp_ab_vs_cd(mp, mp_max_coef(mp,q),abs(v),coef_bound-1,unity)>=0 ) 
20323       t=mp_proto_dependent;
20324   q=mp_p_times_v(mp, q,v,s,t,v_is_scaled); 
20325   mp_dep_finish(mp, q,p,t);
20326 }
20327
20328 @ Here is a routine that is similar to |times|; but it is invoked only
20329 internally, when |v| is a |fraction| whose magnitude is at most~1,
20330 and when |cur_type>=mp_color_type|.
20331
20332 @c void mp_frac_mult (MP mp,scaled n, scaled d) {
20333   /* multiplies |cur_exp| by |n/d| */
20334   pointer p; /* a pair node */
20335   pointer old_exp; /* a capsule to recycle */
20336   fraction v; /* |n/d| */
20337   if ( mp->internal[mp_tracing_commands]>two ) {
20338     @<Trace the fraction multiplication@>;
20339   }
20340   switch (mp->cur_type) {
20341   case mp_transform_type:
20342   case mp_color_type:
20343   case mp_cmykcolor_type:
20344   case mp_pair_type:
20345    old_exp=mp_tarnished(mp, mp->cur_exp);
20346    break;
20347   case mp_independent: old_exp=mp_void; break;
20348   default: old_exp=null; break;
20349   }
20350   if ( old_exp!=null ) { 
20351      old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20352   }
20353   v=mp_make_fraction(mp, n,d);
20354   if ( mp->cur_type==mp_known ) {
20355     mp->cur_exp=mp_take_fraction(mp, mp->cur_exp,v);
20356   } else if ( mp->cur_type<=mp_pair_type ) { 
20357     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20358     do {  
20359       p=p-2;
20360       mp_dep_mult(mp, p,v,false);
20361     } while (p!=value(mp->cur_exp));
20362   } else {
20363     mp_dep_mult(mp, null,v,false);
20364   }
20365   if ( old_exp!=null ) {
20366     mp_recycle_value(mp, old_exp); 
20367     mp_free_node(mp, old_exp,value_node_size);
20368   }
20369 }
20370
20371 @ @<Trace the fraction multiplication@>=
20372
20373   mp_begin_diagnostic(mp); 
20374   mp_print_nl(mp, "{("); mp_print_scaled(mp,n); mp_print_char(mp,'/');
20375   mp_print_scaled(mp,d); mp_print(mp,")*("); mp_print_exp(mp,null,0); 
20376   mp_print(mp,")}");
20377   mp_end_diagnostic(mp, false);
20378 }
20379
20380 @ The |hard_times| routine multiplies a nice color or pair by a dependency list.
20381
20382 @<Declare binary action procedures@>=
20383 void mp_hard_times (MP mp,pointer p) {
20384   pointer q; /* a copy of the dependent variable |p| */
20385   pointer r; /* a component of the big node for the nice color or pair */
20386   scaled v; /* the known value for |r| */
20387   if ( type(p)<=mp_pair_type ) { 
20388      q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); p=q;
20389   }; /* now |cur_type=mp_pair_type| or |cur_type=mp_color_type| */
20390   r=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20391   while (1) { 
20392     r=r-2;
20393     v=value(r);
20394     type(r)=type(p);
20395     if ( r==value(mp->cur_exp) ) 
20396       break;
20397     mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(p)));
20398     mp_dep_mult(mp, r,v,true);
20399   }
20400   mp->mem[value_loc(r)]=mp->mem[value_loc(p)];
20401   link(prev_dep(p))=r;
20402   mp_free_node(mp, p,value_node_size);
20403   mp_dep_mult(mp, r,v,true);
20404 }
20405
20406 @ @<Additional cases of binary operators@>=
20407 case over: 
20408   if ( (mp->cur_type!=mp_known)||(type(p)<mp_color_type) ) {
20409     mp_bad_binary(mp, p,over);
20410   } else { 
20411     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20412     if ( v==0 ) {
20413       @<Squeal about division by zero@>;
20414     } else { 
20415       if ( mp->cur_type==mp_known ) {
20416         mp->cur_exp=mp_make_scaled(mp, mp->cur_exp,v);
20417       } else if ( mp->cur_type<=mp_pair_type ) { 
20418         p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20419         do {  
20420           p=p-2;  mp_dep_div(mp, p,v);
20421         } while (p!=value(mp->cur_exp));
20422       } else {
20423         mp_dep_div(mp, null,v);
20424       }
20425     }
20426     return;
20427   }
20428   break;
20429
20430 @ @<Declare binary action...@>=
20431 void mp_dep_div (MP mp,pointer p, scaled v) {
20432   pointer q; /* the dependency list being divided by |v| */
20433   small_number s,t; /* its type, before and after */
20434   if ( p==null ) q=mp->cur_exp;
20435   else if ( type(p)!=mp_known ) q=p;
20436   else { value(p)=mp_make_scaled(mp, value(p),v); return; };
20437   t=type(q); q=dep_list(q); s=t;
20438   if ( t==mp_dependent )
20439     if ( mp_ab_vs_cd(mp, mp_max_coef(mp,q),unity,coef_bound-1,abs(v))>=0 ) 
20440       t=mp_proto_dependent;
20441   q=mp_p_over_v(mp, q,v,s,t); 
20442   mp_dep_finish(mp, q,p,t);
20443 }
20444
20445 @ @<Squeal about division by zero@>=
20446
20447   exp_err("Division by zero");
20448 @.Division by zero@>
20449   help2("You're trying to divide the quantity shown above the error")
20450     ("message by zero. I'm going to divide it by one instead.");
20451   mp_put_get_error(mp);
20452 }
20453
20454 @ @<Additional cases of binary operators@>=
20455 case pythag_add:
20456 case pythag_sub: 
20457    if ( (mp->cur_type==mp_known)&&(type(p)==mp_known) ) {
20458      if ( c==pythag_add ) mp->cur_exp=mp_pyth_add(mp, value(p),mp->cur_exp);
20459      else mp->cur_exp=mp_pyth_sub(mp, value(p),mp->cur_exp);
20460    } else mp_bad_binary(mp, p,c);
20461    break;
20462
20463 @ The next few sections of the program deal with affine transformations
20464 of coordinate data.
20465
20466 @<Additional cases of binary operators@>=
20467 case rotated_by: case slanted_by:
20468 case scaled_by: case shifted_by: case transformed_by:
20469 case x_scaled: case y_scaled: case z_scaled:
20470   if ( type(p)==mp_path_type ) { 
20471     path_trans(c,p); return;
20472   } else if ( type(p)==mp_pen_type ) { 
20473     pen_trans(c,p);
20474     mp->cur_exp=mp_convex_hull(mp, mp->cur_exp); 
20475       /* rounding error could destroy convexity */
20476     return;
20477   } else if ( (type(p)==mp_pair_type)||(type(p)==mp_transform_type) ) {
20478     mp_big_trans(mp, p,c);
20479   } else if ( type(p)==mp_picture_type ) {
20480     mp_do_edges_trans(mp, p,c); return;
20481   } else {
20482     mp_bad_binary(mp, p,c);
20483   }
20484   break;
20485
20486 @ Let |c| be one of the eight transform operators. The procedure call
20487 |set_up_trans(c)| first changes |cur_exp| to a transform that corresponds to
20488 |c| and the original value of |cur_exp|. (In particular, |cur_exp| doesn't
20489 change at all if |c=transformed_by|.)
20490
20491 Then, if all components of the resulting transform are |known|, they are
20492 moved to the global variables |txx|, |txy|, |tyx|, |tyy|, |tx|, |ty|;
20493 and |cur_exp| is changed to the known value zero.
20494
20495 @<Declare binary action...@>=
20496 void mp_set_up_trans (MP mp,quarterword c) {
20497   pointer p,q,r; /* list manipulation registers */
20498   if ( (c!=transformed_by)||(mp->cur_type!=mp_transform_type) ) {
20499     @<Put the current transform into |cur_exp|@>;
20500   }
20501   @<If the current transform is entirely known, stash it in global variables;
20502     otherwise |return|@>;
20503 }
20504
20505 @ @<Glob...@>=
20506 scaled txx;
20507 scaled txy;
20508 scaled tyx;
20509 scaled tyy;
20510 scaled tx;
20511 scaled ty; /* current transform coefficients */
20512
20513 @ @<Put the current transform...@>=
20514
20515   p=mp_stash_cur_exp(mp); 
20516   mp->cur_exp=mp_id_transform(mp); 
20517   mp->cur_type=mp_transform_type;
20518   q=value(mp->cur_exp);
20519   switch (c) {
20520   @<For each of the eight cases, change the relevant fields of |cur_exp|
20521     and |goto done|;
20522     but do nothing if capsule |p| doesn't have the appropriate type@>;
20523   }; /* there are no other cases */
20524   mp_disp_err(mp, p,"Improper transformation argument");
20525 @.Improper transformation argument@>
20526   help3("The expression shown above has the wrong type,")
20527        ("so I can\'t transform anything using it.")
20528        ("Proceed, and I'll omit the transformation.");
20529   mp_put_get_error(mp);
20530 DONE: 
20531   mp_recycle_value(mp, p); 
20532   mp_free_node(mp, p,value_node_size);
20533 }
20534
20535 @ @<If the current transform is entirely known, ...@>=
20536 q=value(mp->cur_exp); r=q+transform_node_size;
20537 do {  
20538   r=r-2;
20539   if ( type(r)!=mp_known ) return;
20540 } while (r!=q);
20541 mp->txx=value(xx_part_loc(q));
20542 mp->txy=value(xy_part_loc(q));
20543 mp->tyx=value(yx_part_loc(q));
20544 mp->tyy=value(yy_part_loc(q));
20545 mp->tx=value(x_part_loc(q));
20546 mp->ty=value(y_part_loc(q));
20547 mp_flush_cur_exp(mp, 0)
20548
20549 @ @<For each of the eight cases...@>=
20550 case rotated_by:
20551   if ( type(p)==mp_known )
20552     @<Install sines and cosines, then |goto done|@>;
20553   break;
20554 case slanted_by:
20555   if ( type(p)>mp_pair_type ) { 
20556    mp_install(mp, xy_part_loc(q),p); goto DONE;
20557   };
20558   break;
20559 case scaled_by:
20560   if ( type(p)>mp_pair_type ) { 
20561     mp_install(mp, xx_part_loc(q),p); mp_install(mp, yy_part_loc(q),p); 
20562     goto DONE;
20563   };
20564   break;
20565 case shifted_by:
20566   if ( type(p)==mp_pair_type ) {
20567     r=value(p); mp_install(mp, x_part_loc(q),x_part_loc(r));
20568     mp_install(mp, y_part_loc(q),y_part_loc(r)); goto DONE;
20569   };
20570   break;
20571 case x_scaled:
20572   if ( type(p)>mp_pair_type ) {
20573     mp_install(mp, xx_part_loc(q),p); goto DONE;
20574   };
20575   break;
20576 case y_scaled:
20577   if ( type(p)>mp_pair_type ) {
20578     mp_install(mp, yy_part_loc(q),p); goto DONE;
20579   };
20580   break;
20581 case z_scaled:
20582   if ( type(p)==mp_pair_type )
20583     @<Install a complex multiplier, then |goto done|@>;
20584   break;
20585 case transformed_by:
20586   break;
20587   
20588
20589 @ @<Install sines and cosines, then |goto done|@>=
20590 { mp_n_sin_cos(mp, (value(p) % three_sixty_units)*16);
20591   value(xx_part_loc(q))=mp_round_fraction(mp, mp->n_cos);
20592   value(yx_part_loc(q))=mp_round_fraction(mp, mp->n_sin);
20593   value(xy_part_loc(q))=-value(yx_part_loc(q));
20594   value(yy_part_loc(q))=value(xx_part_loc(q));
20595   goto DONE;
20596 }
20597
20598 @ @<Install a complex multiplier, then |goto done|@>=
20599
20600   r=value(p);
20601   mp_install(mp, xx_part_loc(q),x_part_loc(r));
20602   mp_install(mp, yy_part_loc(q),x_part_loc(r));
20603   mp_install(mp, yx_part_loc(q),y_part_loc(r));
20604   if ( type(y_part_loc(r))==mp_known ) negate(value(y_part_loc(r)));
20605   else mp_negate_dep_list(mp, dep_list(y_part_loc(r)));
20606   mp_install(mp, xy_part_loc(q),y_part_loc(r));
20607   goto DONE;
20608 }
20609
20610 @ Procedure |set_up_known_trans| is like |set_up_trans|, but it
20611 insists that the transformation be entirely known.
20612
20613 @<Declare binary action...@>=
20614 void mp_set_up_known_trans (MP mp,quarterword c) { 
20615   mp_set_up_trans(mp, c);
20616   if ( mp->cur_type!=mp_known ) {
20617     exp_err("Transform components aren't all known");
20618 @.Transform components...@>
20619     help3("I'm unable to apply a partially specified transformation")
20620       ("except to a fully known pair or transform.")
20621       ("Proceed, and I'll omit the transformation.");
20622     mp_put_get_flush_error(mp, 0);
20623     mp->txx=unity; mp->txy=0; mp->tyx=0; mp->tyy=unity; 
20624     mp->tx=0; mp->ty=0;
20625   }
20626 }
20627
20628 @ Here's a procedure that applies the transform |txx..ty| to a pair of
20629 coordinates in locations |p| and~|q|.
20630
20631 @<Declare binary action...@>= 
20632 void mp_trans (MP mp,pointer p, pointer q) {
20633   scaled v; /* the new |x| value */
20634   v=mp_take_scaled(mp, mp->mem[p].sc,mp->txx)+
20635   mp_take_scaled(mp, mp->mem[q].sc,mp->txy)+mp->tx;
20636   mp->mem[q].sc=mp_take_scaled(mp, mp->mem[p].sc,mp->tyx)+
20637   mp_take_scaled(mp, mp->mem[q].sc,mp->tyy)+mp->ty;
20638   mp->mem[p].sc=v;
20639 }
20640
20641 @ The simplest transformation procedure applies a transform to all
20642 coordinates of a path.  The |path_trans(c)(p)| macro applies
20643 a transformation defined by |cur_exp| and the transform operator |c|
20644 to the path~|p|.
20645
20646 @d path_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20647                      mp_unstash_cur_exp(mp, (B)); 
20648                      mp_do_path_trans(mp, mp->cur_exp); }
20649
20650 @<Declare binary action...@>=
20651 void mp_do_path_trans (MP mp,pointer p) {
20652   pointer q; /* list traverser */
20653   q=p;
20654   do { 
20655     if ( left_type(q)!=mp_endpoint ) 
20656       mp_trans(mp, q+3,q+4); /* that's |left_x| and |left_y| */
20657     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20658     if ( right_type(q)!=mp_endpoint ) 
20659       mp_trans(mp, q+5,q+6); /* that's |right_x| and |right_y| */
20660 @^data structure assumptions@>
20661     q=link(q);
20662   } while (q!=p);
20663 }
20664
20665 @ Transforming a pen is very similar, except that there are no |left_type|
20666 and |right_type| fields.
20667
20668 @d pen_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20669                     mp_unstash_cur_exp(mp, (B)); 
20670                     mp_do_pen_trans(mp, mp->cur_exp); }
20671
20672 @<Declare binary action...@>=
20673 void mp_do_pen_trans (MP mp,pointer p) {
20674   pointer q; /* list traverser */
20675   if ( pen_is_elliptical(p) ) {
20676     mp_trans(mp, p+3,p+4); /* that's |left_x| and |left_y| */
20677     mp_trans(mp, p+5,p+6); /* that's |right_x| and |right_y| */
20678   };
20679   q=p;
20680   do { 
20681     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20682 @^data structure assumptions@>
20683     q=link(q);
20684   } while (q!=p);
20685 }
20686
20687 @ The next transformation procedure applies to edge structures. It will do
20688 any transformation, but the results may be substandard if the picture contains
20689 text that uses downloaded bitmap fonts.  The binary action procedure is
20690 |do_edges_trans|, but we also need a function that just scales a picture.
20691 That routine is |scale_edges|.  Both it and the underlying routine |edges_trans|
20692 should be thought of as procedures that update an edge structure |h|, except
20693 that they have to return a (possibly new) structure because of the need to call
20694 |private_edges|.
20695
20696 @<Declare binary action...@>=
20697 pointer mp_edges_trans (MP mp, pointer h) {
20698   pointer q; /* the object being transformed */
20699   pointer r,s; /* for list manipulation */
20700   scaled sx,sy; /* saved transformation parameters */
20701   scaled sqdet; /* square root of determinant for |dash_scale| */
20702   integer sgndet; /* sign of the determinant */
20703   scaled v; /* a temporary value */
20704   h=mp_private_edges(mp, h);
20705   sqdet=mp_sqrt_det(mp, mp->txx,mp->txy,mp->tyx,mp->tyy);
20706   sgndet=mp_ab_vs_cd(mp, mp->txx,mp->tyy,mp->txy,mp->tyx);
20707   if ( dash_list(h)!=null_dash ) {
20708     @<Try to transform the dash list of |h|@>;
20709   }
20710   @<Make the bounding box of |h| unknown if it can't be updated properly
20711     without scanning the whole structure@>;  
20712   q=link(dummy_loc(h));
20713   while ( q!=null ) { 
20714     @<Transform graphical object |q|@>;
20715     q=link(q);
20716   }
20717   return h;
20718 }
20719 void mp_do_edges_trans (MP mp,pointer p, quarterword c) { 
20720   mp_set_up_known_trans(mp, c);
20721   value(p)=mp_edges_trans(mp, value(p));
20722   mp_unstash_cur_exp(mp, p);
20723 }
20724 void mp_scale_edges (MP mp) { 
20725   mp->txx=mp->se_sf; mp->tyy=mp->se_sf;
20726   mp->txy=0; mp->tyx=0; mp->tx=0; mp->ty=0;
20727   mp->se_pic=mp_edges_trans(mp, mp->se_pic);
20728 }
20729
20730 @ @<Try to transform the dash list of |h|@>=
20731 if ( (mp->txy!=0)||(mp->tyx!=0)||
20732      (mp->ty!=0)||(abs(mp->txx)!=abs(mp->tyy))) {
20733   mp_flush_dash_list(mp, h);
20734 } else { 
20735   if ( mp->txx<0 ) { @<Reverse the dash list of |h|@>; } 
20736   @<Scale the dash list by |txx| and shift it by |tx|@>;
20737   dash_y(h)=mp_take_scaled(mp, dash_y(h),abs(mp->tyy));
20738 }
20739
20740 @ @<Reverse the dash list of |h|@>=
20741
20742   r=dash_list(h);
20743   dash_list(h)=null_dash;
20744   while ( r!=null_dash ) {
20745     s=r; r=link(r);
20746     v=start_x(s); start_x(s)=stop_x(s); stop_x(s)=v;
20747     link(s)=dash_list(h);
20748     dash_list(h)=s;
20749   }
20750 }
20751
20752 @ @<Scale the dash list by |txx| and shift it by |tx|@>=
20753 r=dash_list(h);
20754 while ( r!=null_dash ) {
20755   start_x(r)=mp_take_scaled(mp, start_x(r),mp->txx)+mp->tx;
20756   stop_x(r)=mp_take_scaled(mp, stop_x(r),mp->txx)+mp->tx;
20757   r=link(r);
20758 }
20759
20760 @ @<Make the bounding box of |h| unknown if it can't be updated properly...@>=
20761 if ( (mp->txx==0)&&(mp->tyy==0) ) {
20762   @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>;
20763 } else if ( (mp->txy!=0)||(mp->tyx!=0) ) {
20764   mp_init_bbox(mp, h);
20765   goto DONE1;
20766 }
20767 if ( minx_val(h)<=maxx_val(h) ) {
20768   @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift by
20769    |(tx,ty)|@>;
20770 }
20771 DONE1:
20772
20773
20774
20775 @ @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>=
20776
20777   v=minx_val(h); minx_val(h)=miny_val(h); miny_val(h)=v;
20778   v=maxx_val(h); maxx_val(h)=maxy_val(h); maxy_val(h)=v;
20779 }
20780
20781 @ The sum ``|txx+txy|'' is whichever of |txx| or |txy| is nonzero.  The other
20782 sum is similar.
20783
20784 @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift...@>=
20785
20786   minx_val(h)=mp_take_scaled(mp, minx_val(h),mp->txx+mp->txy)+mp->tx;
20787   maxx_val(h)=mp_take_scaled(mp, maxx_val(h),mp->txx+mp->txy)+mp->tx;
20788   miny_val(h)=mp_take_scaled(mp, miny_val(h),mp->tyx+mp->tyy)+mp->ty;
20789   maxy_val(h)=mp_take_scaled(mp, maxy_val(h),mp->tyx+mp->tyy)+mp->ty;
20790   if ( mp->txx+mp->txy<0 ) {
20791     v=minx_val(h); minx_val(h)=maxx_val(h); maxx_val(h)=v;
20792   }
20793   if ( mp->tyx+mp->tyy<0 ) {
20794     v=miny_val(h); miny_val(h)=maxy_val(h); maxy_val(h)=v;
20795   }
20796 }
20797
20798 @ Now we ready for the main task of transforming the graphical objects in edge
20799 structure~|h|.
20800
20801 @<Transform graphical object |q|@>=
20802 switch (type(q)) {
20803 case mp_fill_code: case mp_stroked_code: 
20804   mp_do_path_trans(mp, path_p(q));
20805   @<Transform |pen_p(q)|, making sure polygonal pens stay counter-clockwise@>;
20806   break;
20807 case mp_start_clip_code: case mp_start_bounds_code: 
20808   mp_do_path_trans(mp, path_p(q));
20809   break;
20810 case mp_text_code: 
20811   r=text_tx_loc(q);
20812   @<Transform the compact transformation starting at |r|@>;
20813   break;
20814 case mp_stop_clip_code: case mp_stop_bounds_code: 
20815   break;
20816 } /* there are no other cases */
20817
20818 @ Note that the shift parameters |(tx,ty)| apply only to the path being stroked.
20819 The |dash_scale| has to be adjusted  to scale the dash lengths in |dash_p(q)|
20820 since the \ps\ output procedures will try to compensate for the transformation
20821 we are applying to |pen_p(q)|.  Since this compensation is based on the square
20822 root of the determinant, |sqdet| is the appropriate factor.
20823
20824 @<Transform |pen_p(q)|, making sure...@>=
20825 if ( pen_p(q)!=null ) {
20826   sx=mp->tx; sy=mp->ty;
20827   mp->tx=0; mp->ty=0;
20828   mp_do_pen_trans(mp, pen_p(q));
20829   if ( ((type(q)==mp_stroked_code)&&(dash_p(q)!=null)) )
20830     dash_scale(q)=mp_take_scaled(mp, dash_scale(q),sqdet);
20831   if ( ! pen_is_elliptical(pen_p(q)) )
20832     if ( sgndet<0 )
20833       pen_p(q)=mp_make_pen(mp, mp_copy_path(mp, pen_p(q)),true); 
20834          /* this unreverses the pen */
20835   mp->tx=sx; mp->ty=sy;
20836 }
20837
20838 @ This uses the fact that transformations are stored in the order
20839 |(tx,ty,txx,txy,tyx,tyy)|.
20840 @^data structure assumptions@>
20841
20842 @<Transform the compact transformation starting at |r|@>=
20843 mp_trans(mp, r,r+1);
20844 sx=mp->tx; sy=mp->ty;
20845 mp->tx=0; mp->ty=0;
20846 mp_trans(mp, r+2,r+4);
20847 mp_trans(mp, r+3,r+5);
20848 mp->tx=sx; mp->ty=sy
20849
20850 @ The hard cases of transformation occur when big nodes are involved,
20851 and when some of their components are unknown.
20852
20853 @<Declare binary action...@>=
20854 @<Declare subroutines needed by |big_trans|@>;
20855 void mp_big_trans (MP mp,pointer p, quarterword c) {
20856   pointer q,r,pp,qq; /* list manipulation registers */
20857   small_number s; /* size of a big node */
20858   s=mp->big_node_size[type(p)]; q=value(p); r=q+s;
20859   do {  
20860     r=r-2;
20861     if ( type(r)!=mp_known ) {
20862       @<Transform an unknown big node and |return|@>;
20863     }
20864   } while (r!=q);
20865   @<Transform a known big node@>;
20866 }; /* node |p| will now be recycled by |do_binary| */
20867
20868 @ @<Transform an unknown big node and |return|@>=
20869
20870   mp_set_up_known_trans(mp, c); mp_make_exp_copy(mp, p); 
20871   r=value(mp->cur_exp);
20872   if ( mp->cur_type==mp_transform_type ) {
20873     mp_bilin1(mp, yy_part_loc(r),mp->tyy,xy_part_loc(q),mp->tyx,0);
20874     mp_bilin1(mp, yx_part_loc(r),mp->tyy,xx_part_loc(q),mp->tyx,0);
20875     mp_bilin1(mp, xy_part_loc(r),mp->txx,yy_part_loc(q),mp->txy,0);
20876     mp_bilin1(mp, xx_part_loc(r),mp->txx,yx_part_loc(q),mp->txy,0);
20877   }
20878   mp_bilin1(mp, y_part_loc(r),mp->tyy,x_part_loc(q),mp->tyx,mp->ty);
20879   mp_bilin1(mp, x_part_loc(r),mp->txx,y_part_loc(q),mp->txy,mp->tx);
20880   return;
20881 }
20882
20883 @ Let |p| point to a two-word value field inside a big node of |cur_exp|,
20884 and let |q| point to a another value field. The |bilin1| procedure
20885 replaces |p| by $p\cdot t+q\cdot u+\delta$.
20886
20887 @<Declare subroutines needed by |big_trans|@>=
20888 void mp_bilin1 (MP mp, pointer p, scaled t, pointer q, 
20889                 scaled u, scaled delta) {
20890   pointer r; /* list traverser */
20891   if ( t!=unity ) mp_dep_mult(mp, p,t,true);
20892   if ( u!=0 ) {
20893     if ( type(q)==mp_known ) {
20894       delta+=mp_take_scaled(mp, value(q),u);
20895     } else { 
20896       @<Ensure that |type(p)=mp_proto_dependent|@>;
20897       dep_list(p)=mp_p_plus_fq(mp, dep_list(p),u,dep_list(q),
20898                                mp_proto_dependent,type(q));
20899     }
20900   }
20901   if ( type(p)==mp_known ) {
20902     value(p)+=delta;
20903   } else {
20904     r=dep_list(p);
20905     while ( info(r)!=null ) r=link(r);
20906     delta+=value(r);
20907     if ( r!=dep_list(p) ) value(r)=delta;
20908     else { mp_recycle_value(mp, p); type(p)=mp_known; value(p)=delta; };
20909   }
20910   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20911 }
20912
20913 @ @<Ensure that |type(p)=mp_proto_dependent|@>=
20914 if ( type(p)!=mp_proto_dependent ) {
20915   if ( type(p)==mp_known ) 
20916     mp_new_dep(mp, p,mp_const_dependency(mp, value(p)));
20917   else 
20918     dep_list(p)=mp_p_times_v(mp, dep_list(p),unity,mp_dependent,
20919                              mp_proto_dependent,true);
20920   type(p)=mp_proto_dependent;
20921 }
20922
20923 @ @<Transform a known big node@>=
20924 mp_set_up_trans(mp, c);
20925 if ( mp->cur_type==mp_known ) {
20926   @<Transform known by known@>;
20927 } else { 
20928   pp=mp_stash_cur_exp(mp); qq=value(pp);
20929   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20930   if ( mp->cur_type==mp_transform_type ) {
20931     mp_bilin2(mp, yy_part_loc(r),yy_part_loc(qq),
20932       value(xy_part_loc(q)),yx_part_loc(qq),null);
20933     mp_bilin2(mp, yx_part_loc(r),yy_part_loc(qq),
20934       value(xx_part_loc(q)),yx_part_loc(qq),null);
20935     mp_bilin2(mp, xy_part_loc(r),xx_part_loc(qq),
20936       value(yy_part_loc(q)),xy_part_loc(qq),null);
20937     mp_bilin2(mp, xx_part_loc(r),xx_part_loc(qq),
20938       value(yx_part_loc(q)),xy_part_loc(qq),null);
20939   };
20940   mp_bilin2(mp, y_part_loc(r),yy_part_loc(qq),
20941     value(x_part_loc(q)),yx_part_loc(qq),y_part_loc(qq));
20942   mp_bilin2(mp, x_part_loc(r),xx_part_loc(qq),
20943     value(y_part_loc(q)),xy_part_loc(qq),x_part_loc(qq));
20944   mp_recycle_value(mp, pp); mp_free_node(mp, pp,value_node_size);
20945 }
20946
20947 @ Let |p| be a |mp_proto_dependent| value whose dependency list ends
20948 at |dep_final|. The following procedure adds |v| times another
20949 numeric quantity to~|p|.
20950
20951 @<Declare subroutines needed by |big_trans|@>=
20952 void mp_add_mult_dep (MP mp,pointer p, scaled v, pointer r) { 
20953   if ( type(r)==mp_known ) {
20954     value(mp->dep_final)+=mp_take_scaled(mp, value(r),v);
20955   } else  { 
20956     dep_list(p)=mp_p_plus_fq(mp, dep_list(p),v,dep_list(r),
20957                                                          mp_proto_dependent,type(r));
20958     if ( mp->fix_needed ) mp_fix_dependencies(mp);
20959   }
20960 }
20961
20962 @ The |bilin2| procedure is something like |bilin1|, but with known
20963 and unknown quantities reversed. Parameter |p| points to a value field
20964 within the big node for |cur_exp|; and |type(p)=mp_known|. Parameters
20965 |t| and~|u| point to value fields elsewhere; so does parameter~|q|,
20966 unless it is |null| (which stands for zero). Location~|p| will be
20967 replaced by $p\cdot t+v\cdot u+q$.
20968
20969 @<Declare subroutines needed by |big_trans|@>=
20970 void mp_bilin2 (MP mp,pointer p, pointer t, scaled v, 
20971                 pointer u, pointer q) {
20972   scaled vv; /* temporary storage for |value(p)| */
20973   vv=value(p); type(p)=mp_proto_dependent;
20974   mp_new_dep(mp, p,mp_const_dependency(mp, 0)); /* this sets |dep_final| */
20975   if ( vv!=0 ) 
20976     mp_add_mult_dep(mp, p,vv,t); /* |dep_final| doesn't change */
20977   if ( v!=0 ) mp_add_mult_dep(mp, p,v,u);
20978   if ( q!=null ) mp_add_mult_dep(mp, p,unity,q);
20979   if ( dep_list(p)==mp->dep_final ) {
20980     vv=value(mp->dep_final); mp_recycle_value(mp, p);
20981     type(p)=mp_known; value(p)=vv;
20982   }
20983 }
20984
20985 @ @<Transform known by known@>=
20986
20987   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20988   if ( mp->cur_type==mp_transform_type ) {
20989     mp_bilin3(mp, yy_part_loc(r),mp->tyy,value(xy_part_loc(q)),mp->tyx,0);
20990     mp_bilin3(mp, yx_part_loc(r),mp->tyy,value(xx_part_loc(q)),mp->tyx,0);
20991     mp_bilin3(mp, xy_part_loc(r),mp->txx,value(yy_part_loc(q)),mp->txy,0);
20992     mp_bilin3(mp, xx_part_loc(r),mp->txx,value(yx_part_loc(q)),mp->txy,0);
20993   }
20994   mp_bilin3(mp, y_part_loc(r),mp->tyy,value(x_part_loc(q)),mp->tyx,mp->ty);
20995   mp_bilin3(mp, x_part_loc(r),mp->txx,value(y_part_loc(q)),mp->txy,mp->tx);
20996 }
20997
20998 @ Finally, in |bilin3| everything is |known|.
20999
21000 @<Declare subroutines needed by |big_trans|@>=
21001 void mp_bilin3 (MP mp,pointer p, scaled t, 
21002                scaled v, scaled u, scaled delta) { 
21003   if ( t!=unity )
21004     delta+=mp_take_scaled(mp, value(p),t);
21005   else 
21006     delta+=value(p);
21007   if ( u!=0 ) value(p)=delta+mp_take_scaled(mp, v,u);
21008   else value(p)=delta;
21009 }
21010
21011 @ @<Additional cases of binary operators@>=
21012 case concatenate: 
21013   if ( (mp->cur_type==mp_string_type)&&(type(p)==mp_string_type) ) mp_cat(mp, p);
21014   else mp_bad_binary(mp, p,concatenate);
21015   break;
21016 case substring_of: 
21017   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_string_type) )
21018     mp_chop_string(mp, value(p));
21019   else mp_bad_binary(mp, p,substring_of);
21020   break;
21021 case subpath_of: 
21022   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21023   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_path_type) )
21024     mp_chop_path(mp, value(p));
21025   else mp_bad_binary(mp, p,subpath_of);
21026   break;
21027
21028 @ @<Declare binary action...@>=
21029 void mp_cat (MP mp,pointer p) {
21030   str_number a,b; /* the strings being concatenated */
21031   pool_pointer k; /* index into |str_pool| */
21032   a=value(p); b=mp->cur_exp; str_room(length(a)+length(b));
21033   for (k=mp->str_start[a];k<=str_stop(a)-1;k++) {
21034     append_char(mp->str_pool[k]);
21035   }
21036   for (k=mp->str_start[b];k<=str_stop(b)-1;k++) {
21037     append_char(mp->str_pool[k]);
21038   }
21039   mp->cur_exp=mp_make_string(mp); delete_str_ref(b);
21040 }
21041
21042 @ @<Declare binary action...@>=
21043 void mp_chop_string (MP mp,pointer p) {
21044   integer a, b; /* start and stop points */
21045   integer l; /* length of the original string */
21046   integer k; /* runs from |a| to |b| */
21047   str_number s; /* the original string */
21048   boolean reversed; /* was |a>b|? */
21049   a=mp_round_unscaled(mp, value(x_part_loc(p)));
21050   b=mp_round_unscaled(mp, value(y_part_loc(p)));
21051   if ( a<=b ) reversed=false;
21052   else  { reversed=true; k=a; a=b; b=k; };
21053   s=mp->cur_exp; l=length(s);
21054   if ( a<0 ) { 
21055     a=0;
21056     if ( b<0 ) b=0;
21057   }
21058   if ( b>l ) { 
21059     b=l;
21060     if ( a>l ) a=l;
21061   }
21062   str_room(b-a);
21063   if ( reversed ) {
21064     for (k=mp->str_start[s]+b-1;k>=mp->str_start[s]+a;k--)  {
21065       append_char(mp->str_pool[k]);
21066     }
21067   } else  {
21068     for (k=mp->str_start[s]+a;k<=mp->str_start[s]+b-1;k++)  {
21069       append_char(mp->str_pool[k]);
21070     }
21071   }
21072   mp->cur_exp=mp_make_string(mp); delete_str_ref(s);
21073 }
21074
21075 @ @<Declare binary action...@>=
21076 void mp_chop_path (MP mp,pointer p) {
21077   pointer q; /* a knot in the original path */
21078   pointer pp,qq,rr,ss; /* link variables for copies of path nodes */
21079   scaled a,b,k,l; /* indices for chopping */
21080   boolean reversed; /* was |a>b|? */
21081   l=mp_path_length(mp); a=value(x_part_loc(p)); b=value(y_part_loc(p));
21082   if ( a<=b ) reversed=false;
21083   else  { reversed=true; k=a; a=b; b=k; };
21084   @<Dispense with the cases |a<0| and/or |b>l|@>;
21085   q=mp->cur_exp;
21086   while ( a>=unity ) {
21087     q=link(q); a=a-unity; b=b-unity;
21088   }
21089   if ( b==a ) {
21090     @<Construct a path from |pp| to |qq| of length zero@>; 
21091   } else { 
21092     @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>; 
21093   }
21094   left_type(pp)=mp_endpoint; right_type(qq)=mp_endpoint; link(qq)=pp;
21095   mp_toss_knot_list(mp, mp->cur_exp);
21096   if ( reversed ) {
21097     mp->cur_exp=link(mp_htap_ypoc(mp, pp)); mp_toss_knot_list(mp, pp);
21098   } else {
21099     mp->cur_exp=pp;
21100   }
21101 }
21102
21103 @ @<Dispense with the cases |a<0| and/or |b>l|@>=
21104 if ( a<0 ) {
21105   if ( left_type(mp->cur_exp)==mp_endpoint ) {
21106     a=0; if ( b<0 ) b=0;
21107   } else  {
21108     do {  a=a+l; b=b+l; } while (a<0); /* a cycle always has length |l>0| */
21109   }
21110 }
21111 if ( b>l ) {
21112   if ( left_type(mp->cur_exp)==mp_endpoint ) {
21113     b=l; if ( a>l ) a=l;
21114   } else {
21115     while ( a>=l ) { 
21116       a=a-l; b=b-l;
21117     }
21118   }
21119 }
21120
21121 @ @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>=
21122
21123   pp=mp_copy_knot(mp, q); qq=pp;
21124   do {  
21125     q=link(q); rr=qq; qq=mp_copy_knot(mp, q); link(rr)=qq; b=b-unity;
21126   } while (b>0);
21127   if ( a>0 ) {
21128     ss=pp; pp=link(pp);
21129     mp_split_cubic(mp, ss,a*010000); pp=link(ss);
21130     mp_free_node(mp, ss,knot_node_size);
21131     if ( rr==ss ) {
21132       b=mp_make_scaled(mp, b,unity-a); rr=pp;
21133     }
21134   }
21135   if ( b<0 ) {
21136     mp_split_cubic(mp, rr,(b+unity)*010000);
21137     mp_free_node(mp, qq,knot_node_size);
21138     qq=link(rr);
21139   }
21140 }
21141
21142 @ @<Construct a path from |pp| to |qq| of length zero@>=
21143
21144   if ( a>0 ) { mp_split_cubic(mp, q,a*010000); q=link(q); };
21145   pp=mp_copy_knot(mp, q); qq=pp;
21146 }
21147
21148 @ @<Additional cases of binary operators@>=
21149 case point_of: case precontrol_of: case postcontrol_of: 
21150   if ( mp->cur_type==mp_pair_type )
21151      mp_pair_to_path(mp);
21152   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
21153     mp_find_point(mp, value(p),c);
21154   else 
21155     mp_bad_binary(mp, p,c);
21156   break;
21157 case pen_offset_of: 
21158   if ( (mp->cur_type==mp_pen_type)&& mp_nice_pair(mp, p,type(p)) )
21159     mp_set_up_offset(mp, value(p));
21160   else 
21161     mp_bad_binary(mp, p,pen_offset_of);
21162   break;
21163 case direction_time_of: 
21164   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21165   if ( (mp->cur_type==mp_path_type)&& mp_nice_pair(mp, p,type(p)) )
21166     mp_set_up_direction_time(mp, value(p));
21167   else 
21168     mp_bad_binary(mp, p,direction_time_of);
21169   break;
21170 case envelope_of:
21171   if ( (type(p) != mp_pen_type) || (mp->cur_type != mp_path_type) )
21172     mp_bad_binary(mp, p,envelope_of);
21173   else
21174     mp_set_up_envelope(mp, p);
21175   break;
21176
21177 @ @<Declare binary action...@>=
21178 void mp_set_up_offset (MP mp,pointer p) { 
21179   mp_find_offset(mp, value(x_part_loc(p)),value(y_part_loc(p)),mp->cur_exp);
21180   mp_pair_value(mp, mp->cur_x,mp->cur_y);
21181 }
21182 void mp_set_up_direction_time (MP mp,pointer p) { 
21183   mp_flush_cur_exp(mp, mp_find_direction_time(mp, value(x_part_loc(p)),
21184   value(y_part_loc(p)),mp->cur_exp));
21185 }
21186 void mp_set_up_envelope (MP mp,pointer p) {
21187   pointer q = mp_copy_path(mp, mp->cur_exp); /* the original path */
21188   /* TODO: accept elliptical pens for straight paths */
21189   if (pen_is_elliptical(value(p))) {
21190     mp_bad_envelope_pen(mp);
21191     mp->cur_exp = q;
21192     mp->cur_type = mp_path_type;
21193     return;
21194   }
21195   small_number ljoin, lcap;
21196   scaled miterlim;
21197   if ( mp->internal[mp_linejoin]>unity ) ljoin=2;
21198   else if ( mp->internal[mp_linejoin]>0 ) ljoin=1;
21199   else ljoin=0;
21200   if ( mp->internal[mp_linecap]>unity ) lcap=2;
21201   else if ( mp->internal[mp_linecap]>0 ) lcap=1;
21202   else lcap=0;
21203   if ( mp->internal[mp_miterlimit]<unity )
21204     miterlim=unity;
21205   else
21206     miterlim=mp->internal[mp_miterlimit];
21207   mp->cur_exp = mp_make_envelope(mp, q, value(p), ljoin,lcap,miterlim);
21208   mp->cur_type = mp_path_type;
21209 }
21210
21211 @ @<Declare binary action...@>=
21212 void mp_find_point (MP mp,scaled v, quarterword c) {
21213   pointer p; /* the path */
21214   scaled n; /* its length */
21215   p=mp->cur_exp;
21216   if ( left_type(p)==mp_endpoint ) n=-unity; else n=0;
21217   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
21218   if ( n==0 ) { 
21219     v=0; 
21220   } else if ( v<0 ) {
21221     if ( left_type(p)==mp_endpoint ) v=0;
21222     else v=n-1-((-v-1) % n);
21223   } else if ( v>n ) {
21224     if ( left_type(p)==mp_endpoint ) v=n;
21225     else v=v % n;
21226   }
21227   p=mp->cur_exp;
21228   while ( v>=unity ) { p=link(p); v=v-unity;  };
21229   if ( v!=0 ) {
21230      @<Insert a fractional node by splitting the cubic@>;
21231   }
21232   @<Set the current expression to the desired path coordinates@>;
21233 }
21234
21235 @ @<Insert a fractional node...@>=
21236 { mp_split_cubic(mp, p,v*010000); p=link(p); }
21237
21238 @ @<Set the current expression to the desired path coordinates...@>=
21239 switch (c) {
21240 case point_of: 
21241   mp_pair_value(mp, x_coord(p),y_coord(p));
21242   break;
21243 case precontrol_of: 
21244   if ( left_type(p)==mp_endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
21245   else mp_pair_value(mp, left_x(p),left_y(p));
21246   break;
21247 case postcontrol_of: 
21248   if ( right_type(p)==mp_endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
21249   else mp_pair_value(mp, right_x(p),right_y(p));
21250   break;
21251 } /* there are no other cases */
21252
21253 @ @<Additional cases of binary operators@>=
21254 case arc_time_of: 
21255   if ( mp->cur_type==mp_pair_type )
21256      mp_pair_to_path(mp);
21257   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
21258     mp_flush_cur_exp(mp, mp_get_arc_time(mp, mp->cur_exp,value(p)));
21259   else 
21260     mp_bad_binary(mp, p,c);
21261   break;
21262
21263 @ @<Additional cases of bin...@>=
21264 case intersect: 
21265   if ( type(p)==mp_pair_type ) {
21266     q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p);
21267     mp_pair_to_path(mp); p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
21268   };
21269   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21270   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_path_type) ) {
21271     mp_path_intersection(mp, value(p),mp->cur_exp);
21272     mp_pair_value(mp, mp->cur_t,mp->cur_tt);
21273   } else {
21274     mp_bad_binary(mp, p,intersect);
21275   }
21276   break;
21277
21278 @ @<Additional cases of bin...@>=
21279 case in_font:
21280   if ( (mp->cur_type!=mp_string_type)||(type(p)!=mp_string_type)) 
21281     mp_bad_binary(mp, p,in_font);
21282   else { mp_do_infont(mp, p); return; }
21283   break;
21284
21285 @ Function |new_text_node| owns the reference count for its second argument
21286 (the text string) but not its first (the font name).
21287
21288 @<Declare binary action...@>=
21289 void mp_do_infont (MP mp,pointer p) {
21290   pointer q;
21291   q=mp_get_node(mp, edge_header_size);
21292   mp_init_edges(mp, q);
21293   link(obj_tail(q))=mp_new_text_node(mp, str(mp->cur_exp),value(p));
21294   obj_tail(q)=link(obj_tail(q));
21295   mp_free_node(mp, p,value_node_size);
21296   mp_flush_cur_exp(mp, q);
21297   mp->cur_type=mp_picture_type;
21298 }
21299
21300 @* \[40] Statements and commands.
21301 The chief executive of \MP\ is the |do_statement| routine, which
21302 contains the master switch that causes all the various pieces of \MP\
21303 to do their things, in the right order.
21304
21305 In a sense, this is the grand climax of the program: It applies all the
21306 tools that we have worked so hard to construct. In another sense, this is
21307 the messiest part of the program: It necessarily refers to other pieces
21308 of code all over the place, so that a person can't fully understand what is
21309 going on without paging back and forth to be reminded of conventions that
21310 are defined elsewhere. We are now at the hub of the web.
21311
21312 The structure of |do_statement| itself is quite simple.  The first token
21313 of the statement is fetched using |get_x_next|.  If it can be the first
21314 token of an expression, we look for an equation, an assignment, or a
21315 title. Otherwise we use a \&{case} construction to branch at high speed to
21316 the appropriate routine for various and sundry other types of commands,
21317 each of which has an ``action procedure'' that does the necessary work.
21318
21319 The program uses the fact that
21320 $$\hbox{|min_primary_command=max_statement_command=type_name|}$$
21321 to interpret a statement that starts with, e.g., `\&{string}',
21322 as a type declaration rather than a boolean expression.
21323
21324 @c void mp_do_statement (MP mp) { /* governs \MP's activities */
21325   mp->cur_type=mp_vacuous; mp_get_x_next(mp);
21326   if ( mp->cur_cmd>max_primary_command ) {
21327     @<Worry about bad statement@>;
21328   } else if ( mp->cur_cmd>max_statement_command ) {
21329     @<Do an equation, assignment, title, or
21330      `$\langle\,$expression$\,\rangle\,$\&{endgroup}'@>;
21331   } else {
21332     @<Do a statement that doesn't begin with an expression@>;
21333   }
21334   if ( mp->cur_cmd<semicolon )
21335     @<Flush unparsable junk that was found after the statement@>;
21336   mp->error_count=0;
21337 }
21338
21339 @ @<Declarations@>=
21340 @<Declare action procedures for use by |do_statement|@>;
21341
21342 @ The only command codes |>max_primary_command| that can be present
21343 at the beginning of a statement are |semicolon| and higher; these
21344 occur when the statement is null.
21345
21346 @<Worry about bad statement@>=
21347
21348   if ( mp->cur_cmd<semicolon ) {
21349     print_err("A statement can't begin with `");
21350 @.A statement can't begin with x@>
21351     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); mp_print_char(mp, '\'');
21352     help5("I was looking for the beginning of a new statement.")
21353       ("If you just proceed without changing anything, I'll ignore")
21354       ("everything up to the next `;'. Please insert a semicolon")
21355       ("now in front of anything that you don't want me to delete.")
21356       ("(See Chapter 27 of The METAFONTbook for an example.)");
21357 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21358     mp_back_error(mp); mp_get_x_next(mp);
21359   }
21360 }
21361
21362 @ The help message printed here says that everything is flushed up to
21363 a semicolon, but actually the commands |end_group| and |stop| will
21364 also terminate a statement.
21365
21366 @<Flush unparsable junk that was found after the statement@>=
21367
21368   print_err("Extra tokens will be flushed");
21369 @.Extra tokens will be flushed@>
21370   help6("I've just read as much of that statement as I could fathom,")
21371        ("so a semicolon should have been next. It's very puzzling...")
21372        ("but I'll try to get myself back together, by ignoring")
21373        ("everything up to the next `;'. Please insert a semicolon")
21374        ("now in front of anything that you don't want me to delete.")
21375        ("(See Chapter 27 of The METAFONTbook for an example.)");
21376 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21377   mp_back_error(mp); mp->scanner_status=flushing;
21378   do {  
21379     get_t_next;
21380     @<Decrease the string reference count...@>;
21381   } while (! end_of_statement); /* |cur_cmd=semicolon|, |end_group|, or |stop| */
21382   mp->scanner_status=normal;
21383 }
21384
21385 @ If |do_statement| ends with |cur_cmd=end_group|, we should have
21386 |cur_type=mp_vacuous| unless the statement was simply an expression;
21387 in the latter case, |cur_type| and |cur_exp| should represent that
21388 expression.
21389
21390 @<Do a statement that doesn't...@>=
21391
21392   if ( mp->internal[mp_tracing_commands]>0 ) 
21393     show_cur_cmd_mod;
21394   switch (mp->cur_cmd ) {
21395   case type_name:mp_do_type_declaration(mp); break;
21396   case macro_def:
21397     if ( mp->cur_mod>var_def ) mp_make_op_def(mp);
21398     else if ( mp->cur_mod>end_def ) mp_scan_def(mp);
21399      break;
21400   @<Cases of |do_statement| that invoke particular commands@>;
21401   } /* there are no other cases */
21402   mp->cur_type=mp_vacuous;
21403 }
21404
21405 @ The most important statements begin with expressions.
21406
21407 @<Do an equation, assignment, title, or...@>=
21408
21409   mp->var_flag=assignment; mp_scan_expression(mp);
21410   if ( mp->cur_cmd<end_group ) {
21411     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21412     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21413     else if ( mp->cur_type==mp_string_type ) {@<Do a title@> ; }
21414     else if ( mp->cur_type!=mp_vacuous ){ 
21415       exp_err("Isolated expression");
21416 @.Isolated expression@>
21417       help3("I couldn't find an `=' or `:=' after the")
21418         ("expression that is shown above this error message,")
21419         ("so I guess I'll just ignore it and carry on.");
21420       mp_put_get_error(mp);
21421     }
21422     mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous;
21423   }
21424 }
21425
21426 @ @<Do a title@>=
21427
21428   if ( mp->internal[mp_tracing_titles]>0 ) {
21429     mp_print_nl(mp, "");  mp_print_str(mp, mp->cur_exp); update_terminal;
21430   }
21431 }
21432
21433 @ Equations and assignments are performed by the pair of mutually recursive
21434 @^recursion@>
21435 routines |do_equation| and |do_assignment|. These routines are called when
21436 |cur_cmd=equals| and when |cur_cmd=assignment|, respectively; the left-hand
21437 side is in |cur_type| and |cur_exp|, while the right-hand side is yet
21438 to be scanned. After the routines are finished, |cur_type| and |cur_exp|
21439 will be equal to the right-hand side (which will normally be equal
21440 to the left-hand side).
21441
21442 @<Declare action procedures for use by |do_statement|@>=
21443 @<Declare the procedure called |try_eq|@>;
21444 @<Declare the procedure called |make_eq|@>;
21445 void mp_do_equation (MP mp) ;
21446
21447 @ @c
21448 void mp_do_equation (MP mp) {
21449   pointer lhs; /* capsule for the left-hand side */
21450   pointer p; /* temporary register */
21451   lhs=mp_stash_cur_exp(mp); mp_get_x_next(mp); 
21452   mp->var_flag=assignment; mp_scan_expression(mp);
21453   if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21454   else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21455   if ( mp->internal[mp_tracing_commands]>two ) 
21456     @<Trace the current equation@>;
21457   if ( mp->cur_type==mp_unknown_path ) if ( type(lhs)==mp_pair_type ) {
21458     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, lhs); lhs=p;
21459   }; /* in this case |make_eq| will change the pair to a path */
21460   mp_make_eq(mp, lhs); /* equate |lhs| to |(cur_type,cur_exp)| */
21461 }
21462
21463 @ And |do_assignment| is similar to |do_expression|:
21464
21465 @<Declarations@>=
21466 void mp_do_assignment (MP mp);
21467
21468 @ @<Declare action procedures for use by |do_statement|@>=
21469 void mp_do_assignment (MP mp) ;
21470
21471 @ @c
21472 void mp_do_assignment (MP mp) {
21473   pointer lhs; /* token list for the left-hand side */
21474   pointer p; /* where the left-hand value is stored */
21475   pointer q; /* temporary capsule for the right-hand value */
21476   if ( mp->cur_type!=mp_token_list ) { 
21477     exp_err("Improper `:=' will be changed to `='");
21478 @.Improper `:='@>
21479     help2("I didn't find a variable name at the left of the `:=',")
21480       ("so I'm going to pretend that you said `=' instead.");
21481     mp_error(mp); mp_do_equation(mp);
21482   } else { 
21483     lhs=mp->cur_exp; mp->cur_type=mp_vacuous;
21484     mp_get_x_next(mp); mp->var_flag=assignment; mp_scan_expression(mp);
21485     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21486     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21487     if ( mp->internal[mp_tracing_commands]>two ) 
21488       @<Trace the current assignment@>;
21489     if ( info(lhs)>hash_end ) {
21490       @<Assign the current expression to an internal variable@>;
21491     } else  {
21492       @<Assign the current expression to the variable |lhs|@>;
21493     }
21494     mp_flush_node_list(mp, lhs);
21495   }
21496 }
21497
21498 @ @<Trace the current equation@>=
21499
21500   mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp,lhs,0);
21501   mp_print(mp,")=("); mp_print_exp(mp,null,0); 
21502   mp_print(mp,")}"); mp_end_diagnostic(mp, false);
21503 }
21504
21505 @ @<Trace the current assignment@>=
21506
21507   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
21508   if ( info(lhs)>hash_end ) 
21509      mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21510   else 
21511      mp_show_token_list(mp, lhs,null,1000,0);
21512   mp_print(mp, ":="); mp_print_exp(mp, null,0); 
21513   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
21514 }
21515
21516 @ @<Assign the current expression to an internal variable@>=
21517 if ( mp->cur_type==mp_known )  {
21518   mp->internal[info(lhs)-(hash_end)]=mp->cur_exp;
21519 } else { 
21520   exp_err("Internal quantity `");
21521 @.Internal quantity...@>
21522   mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21523   mp_print(mp, "' must receive a known value");
21524   help2("I can\'t set an internal quantity to anything but a known")
21525     ("numeric value, so I'll have to ignore this assignment.");
21526   mp_put_get_error(mp);
21527 }
21528
21529 @ @<Assign the current expression to the variable |lhs|@>=
21530
21531   p=mp_find_variable(mp, lhs);
21532   if ( p!=null ) {
21533     q=mp_stash_cur_exp(mp); mp->cur_type=mp_und_type(mp, p); 
21534     mp_recycle_value(mp, p);
21535     type(p)=mp->cur_type; value(p)=null; mp_make_exp_copy(mp, p);
21536     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); mp_make_eq(mp, p);
21537   } else  { 
21538     mp_obliterated(mp, lhs); mp_put_get_error(mp);
21539   }
21540 }
21541
21542
21543 @ And now we get to the nitty-gritty. The |make_eq| procedure is given
21544 a pointer to a capsule that is to be equated to the current expression.
21545
21546 @<Declare the procedure called |make_eq|@>=
21547 void mp_make_eq (MP mp,pointer lhs) ;
21548
21549
21550
21551 @c void mp_make_eq (MP mp,pointer lhs) {
21552   small_number t; /* type of the left-hand side */
21553   pointer p,q; /* pointers inside of big nodes */
21554   integer v=0; /* value of the left-hand side */
21555 RESTART: 
21556   t=type(lhs);
21557   if ( t<=mp_pair_type ) v=value(lhs);
21558   switch (t) {
21559   @<For each type |t|, make an equation and |goto done| unless |cur_type|
21560     is incompatible with~|t|@>;
21561   } /* all cases have been listed */
21562   @<Announce that the equation cannot be performed@>;
21563 DONE:
21564   check_arith; mp_recycle_value(mp, lhs); 
21565   mp_free_node(mp, lhs,value_node_size);
21566 }
21567
21568 @ @<Announce that the equation cannot be performed@>=
21569 mp_disp_err(mp, lhs,""); 
21570 exp_err("Equation cannot be performed (");
21571 @.Equation cannot be performed@>
21572 if ( type(lhs)<=mp_pair_type ) mp_print_type(mp, type(lhs));
21573 else mp_print(mp, "numeric");
21574 mp_print_char(mp, '=');
21575 if ( mp->cur_type<=mp_pair_type ) mp_print_type(mp, mp->cur_type);
21576 else mp_print(mp, "numeric");
21577 mp_print_char(mp, ')');
21578 help2("I'm sorry, but I don't know how to make such things equal.")
21579      ("(See the two expressions just above the error message.)");
21580 mp_put_get_error(mp)
21581
21582 @ @<For each type |t|, make an equation and |goto done| unless...@>=
21583 case mp_boolean_type: case mp_string_type: case mp_pen_type:
21584 case mp_path_type: case mp_picture_type:
21585   if ( mp->cur_type==t+unknown_tag ) { 
21586     mp_nonlinear_eq(mp, v,mp->cur_exp,false); goto DONE;
21587   } else if ( mp->cur_type==t ) {
21588     @<Report redundant or inconsistent equation and |goto done|@>;
21589   }
21590   break;
21591 case unknown_types:
21592   if ( mp->cur_type==t-unknown_tag ) { 
21593     mp_nonlinear_eq(mp, mp->cur_exp,lhs,true); goto DONE;
21594   } else if ( mp->cur_type==t ) { 
21595     mp_ring_merge(mp, lhs,mp->cur_exp); goto DONE;
21596   } else if ( mp->cur_type==mp_pair_type ) {
21597     if ( t==mp_unknown_path ) { 
21598      mp_pair_to_path(mp); goto RESTART;
21599     };
21600   }
21601   break;
21602 case mp_transform_type: case mp_color_type:
21603 case mp_cmykcolor_type: case mp_pair_type:
21604   if ( mp->cur_type==t ) {
21605     @<Do multiple equations and |goto done|@>;
21606   }
21607   break;
21608 case mp_known: case mp_dependent:
21609 case mp_proto_dependent: case mp_independent:
21610   if ( mp->cur_type>=mp_known ) { 
21611     mp_try_eq(mp, lhs,null); goto DONE;
21612   };
21613   break;
21614 case mp_vacuous:
21615   break;
21616
21617 @ @<Report redundant or inconsistent equation and |goto done|@>=
21618
21619   if ( mp->cur_type<=mp_string_type ) {
21620     if ( mp->cur_type==mp_string_type ) {
21621       if ( mp_str_vs_str(mp, v,mp->cur_exp)!=0 ) {
21622         goto NOT_FOUND;
21623       }
21624     } else if ( v!=mp->cur_exp ) {
21625       goto NOT_FOUND;
21626     }
21627     @<Exclaim about a redundant equation@>; goto DONE;
21628   }
21629   print_err("Redundant or inconsistent equation");
21630 @.Redundant or inconsistent equation@>
21631   help2("An equation between already-known quantities can't help.")
21632        ("But don't worry; continue and I'll just ignore it.");
21633   mp_put_get_error(mp); goto DONE;
21634 NOT_FOUND: 
21635   print_err("Inconsistent equation");
21636 @.Inconsistent equation@>
21637   help2("The equation I just read contradicts what was said before.")
21638        ("But don't worry; continue and I'll just ignore it.");
21639   mp_put_get_error(mp); goto DONE;
21640 }
21641
21642 @ @<Do multiple equations and |goto done|@>=
21643
21644   p=v+mp->big_node_size[t]; 
21645   q=value(mp->cur_exp)+mp->big_node_size[t];
21646   do {  
21647     p=p-2; q=q-2; mp_try_eq(mp, p,q);
21648   } while (p!=v);
21649   goto DONE;
21650 }
21651
21652 @ The first argument to |try_eq| is the location of a value node
21653 in a capsule that will soon be recycled. The second argument is
21654 either a location within a pair or transform node pointed to by
21655 |cur_exp|, or it is |null| (which means that |cur_exp| itself
21656 serves as the second argument). The idea is to leave |cur_exp| unchanged,
21657 but to equate the two operands.
21658
21659 @<Declare the procedure called |try_eq|@>=
21660 void mp_try_eq (MP mp,pointer l, pointer r) ;
21661
21662
21663 @c void mp_try_eq (MP mp,pointer l, pointer r) {
21664   pointer p; /* dependency list for right operand minus left operand */
21665   int t; /* the type of list |p| */
21666   pointer q; /* the constant term of |p| is here */
21667   pointer pp; /* dependency list for right operand */
21668   int tt; /* the type of list |pp| */
21669   boolean copied; /* have we copied a list that ought to be recycled? */
21670   @<Remove the left operand from its container, negate it, and
21671     put it into dependency list~|p| with constant term~|q|@>;
21672   @<Add the right operand to list |p|@>;
21673   if ( info(p)==null ) {
21674     @<Deal with redundant or inconsistent equation@>;
21675   } else { 
21676     mp_linear_eq(mp, p,t);
21677     if ( r==null ) if ( mp->cur_type!=mp_known ) {
21678       if ( type(mp->cur_exp)==mp_known ) {
21679         pp=mp->cur_exp; mp->cur_exp=value(mp->cur_exp); mp->cur_type=mp_known;
21680         mp_free_node(mp, pp,value_node_size);
21681       }
21682     }
21683   }
21684 }
21685
21686 @ @<Remove the left operand from its container, negate it, and...@>=
21687 t=type(l);
21688 if ( t==mp_known ) { 
21689   t=mp_dependent; p=mp_const_dependency(mp, -value(l)); q=p;
21690 } else if ( t==mp_independent ) {
21691   t=mp_dependent; p=mp_single_dependency(mp, l); negate(value(p));
21692   q=mp->dep_final;
21693 } else { 
21694   p=dep_list(l); q=p;
21695   while (1) { 
21696     negate(value(q));
21697     if ( info(q)==null ) break;
21698     q=link(q);
21699   }
21700   link(prev_dep(l))=link(q); prev_dep(link(q))=prev_dep(l);
21701   type(l)=mp_known;
21702 }
21703
21704 @ @<Deal with redundant or inconsistent equation@>=
21705
21706   if ( abs(value(p))>64 ) { /* off by .001 or more */
21707     print_err("Inconsistent equation");
21708 @.Inconsistent equation@>
21709     mp_print(mp, " (off by "); mp_print_scaled(mp, value(p)); 
21710     mp_print_char(mp, ')');
21711     help2("The equation I just read contradicts what was said before.")
21712       ("But don't worry; continue and I'll just ignore it.");
21713     mp_put_get_error(mp);
21714   } else if ( r==null ) {
21715     @<Exclaim about a redundant equation@>;
21716   }
21717   mp_free_node(mp, p,dep_node_size);
21718 }
21719
21720 @ @<Add the right operand to list |p|@>=
21721 if ( r==null ) {
21722   if ( mp->cur_type==mp_known ) {
21723     value(q)=value(q)+mp->cur_exp; goto DONE1;
21724   } else { 
21725     tt=mp->cur_type;
21726     if ( tt==mp_independent ) pp=mp_single_dependency(mp, mp->cur_exp);
21727     else pp=dep_list(mp->cur_exp);
21728   } 
21729 } else {
21730   if ( type(r)==mp_known ) {
21731     value(q)=value(q)+value(r); goto DONE1;
21732   } else { 
21733     tt=type(r);
21734     if ( tt==mp_independent ) pp=mp_single_dependency(mp, r);
21735     else pp=dep_list(r);
21736   }
21737 }
21738 if ( tt!=mp_independent ) copied=false;
21739 else  { copied=true; tt=mp_dependent; };
21740 @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>;
21741 if ( copied ) mp_flush_node_list(mp, pp);
21742 DONE1:
21743
21744 @ @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>=
21745 mp->watch_coefs=false;
21746 if ( t==tt ) {
21747   p=mp_p_plus_q(mp, p,pp,t);
21748 } else if ( t==mp_proto_dependent ) {
21749   p=mp_p_plus_fq(mp, p,unity,pp,mp_proto_dependent,mp_dependent);
21750 } else { 
21751   q=p;
21752   while ( info(q)!=null ) {
21753     value(q)=mp_round_fraction(mp, value(q)); q=link(q);
21754   }
21755   t=mp_proto_dependent; p=mp_p_plus_q(mp, p,pp,t);
21756 }
21757 mp->watch_coefs=true;
21758
21759 @ Our next goal is to process type declarations. For this purpose it's
21760 convenient to have a procedure that scans a $\langle\,$declared
21761 variable$\,\rangle$ and returns the corresponding token list. After the
21762 following procedure has acted, the token after the declared variable
21763 will have been scanned, so it will appear in |cur_cmd|, |cur_mod|,
21764 and~|cur_sym|.
21765
21766 @<Declare the function called |scan_declared_variable|@>=
21767 pointer mp_scan_declared_variable (MP mp) {
21768   pointer x; /* hash address of the variable's root */
21769   pointer h,t; /* head and tail of the token list to be returned */
21770   pointer l; /* hash address of left bracket */
21771   mp_get_symbol(mp); x=mp->cur_sym;
21772   if ( mp->cur_cmd!=tag_token ) mp_clear_symbol(mp, x,false);
21773   h=mp_get_avail(mp); info(h)=x; t=h;
21774   while (1) { 
21775     mp_get_x_next(mp);
21776     if ( mp->cur_sym==0 ) break;
21777     if ( mp->cur_cmd!=tag_token ) if ( mp->cur_cmd!=internal_quantity)  {
21778       if ( mp->cur_cmd==left_bracket ) {
21779         @<Descend past a collective subscript@>;
21780       } else {
21781         break;
21782       }
21783     }
21784     link(t)=mp_get_avail(mp); t=link(t); info(t)=mp->cur_sym;
21785   }
21786   if ( eq_type(x)!=tag_token ) mp_clear_symbol(mp, x,false);
21787   if ( equiv(x)==null ) mp_new_root(mp, x);
21788   return h;
21789 }
21790
21791 @ If the subscript isn't collective, we don't accept it as part of the
21792 declared variable.
21793
21794 @<Descend past a collective subscript@>=
21795
21796   l=mp->cur_sym; mp_get_x_next(mp);
21797   if ( mp->cur_cmd!=right_bracket ) {
21798     mp_back_input(mp); mp->cur_sym=l; mp->cur_cmd=left_bracket; break;
21799   } else {
21800     mp->cur_sym=collective_subscript;
21801   }
21802 }
21803
21804 @ Type declarations are introduced by the following primitive operations.
21805
21806 @<Put each...@>=
21807 mp_primitive(mp, "numeric",type_name,mp_numeric_type);
21808 @:numeric_}{\&{numeric} primitive@>
21809 mp_primitive(mp, "string",type_name,mp_string_type);
21810 @:string_}{\&{string} primitive@>
21811 mp_primitive(mp, "boolean",type_name,mp_boolean_type);
21812 @:boolean_}{\&{boolean} primitive@>
21813 mp_primitive(mp, "path",type_name,mp_path_type);
21814 @:path_}{\&{path} primitive@>
21815 mp_primitive(mp, "pen",type_name,mp_pen_type);
21816 @:pen_}{\&{pen} primitive@>
21817 mp_primitive(mp, "picture",type_name,mp_picture_type);
21818 @:picture_}{\&{picture} primitive@>
21819 mp_primitive(mp, "transform",type_name,mp_transform_type);
21820 @:transform_}{\&{transform} primitive@>
21821 mp_primitive(mp, "color",type_name,mp_color_type);
21822 @:color_}{\&{color} primitive@>
21823 mp_primitive(mp, "rgbcolor",type_name,mp_color_type);
21824 @:color_}{\&{rgbcolor} primitive@>
21825 mp_primitive(mp, "cmykcolor",type_name,mp_cmykcolor_type);
21826 @:color_}{\&{cmykcolor} primitive@>
21827 mp_primitive(mp, "pair",type_name,mp_pair_type);
21828 @:pair_}{\&{pair} primitive@>
21829
21830 @ @<Cases of |print_cmd...@>=
21831 case type_name: mp_print_type(mp, m); break;
21832
21833 @ Now we are ready to handle type declarations, assuming that a
21834 |type_name| has just been scanned.
21835
21836 @<Declare action procedures for use by |do_statement|@>=
21837 void mp_do_type_declaration (MP mp) ;
21838
21839 @ @c
21840 void mp_do_type_declaration (MP mp) {
21841   small_number t; /* the type being declared */
21842   pointer p; /* token list for a declared variable */
21843   pointer q; /* value node for the variable */
21844   if ( mp->cur_mod>=mp_transform_type ) 
21845     t=mp->cur_mod;
21846   else 
21847     t=mp->cur_mod+unknown_tag;
21848   do {  
21849     p=mp_scan_declared_variable(mp);
21850     mp_flush_variable(mp, equiv(info(p)),link(p),false);
21851     q=mp_find_variable(mp, p);
21852     if ( q!=null ) { 
21853       type(q)=t; value(q)=null; 
21854     } else  { 
21855       print_err("Declared variable conflicts with previous vardef");
21856 @.Declared variable conflicts...@>
21857       help2("You can't use, e.g., `numeric foo[]' after `vardef foo'.")
21858            ("Proceed, and I'll ignore the illegal redeclaration.");
21859       mp_put_get_error(mp);
21860     }
21861     mp_flush_list(mp, p);
21862     if ( mp->cur_cmd<comma ) {
21863       @<Flush spurious symbols after the declared variable@>;
21864     }
21865   } while (! end_of_statement);
21866 }
21867
21868 @ @<Flush spurious symbols after the declared variable@>=
21869
21870   print_err("Illegal suffix of declared variable will be flushed");
21871 @.Illegal suffix...flushed@>
21872   help5("Variables in declarations must consist entirely of")
21873     ("names and collective subscripts, e.g., `x[]a'.")
21874     ("Are you trying to use a reserved word in a variable name?")
21875     ("I'm going to discard the junk I found here,")
21876     ("up to the next comma or the end of the declaration.");
21877   if ( mp->cur_cmd==numeric_token )
21878     mp->help_line[2]="Explicit subscripts like `x15a' aren't permitted.";
21879   mp_put_get_error(mp); mp->scanner_status=flushing;
21880   do {  
21881     get_t_next;
21882     @<Decrease the string reference count...@>;
21883   } while (mp->cur_cmd<comma); /* either |end_of_statement| or |cur_cmd=comma| */
21884   mp->scanner_status=normal;
21885 }
21886
21887 @ \MP's |main_control| procedure just calls |do_statement| repeatedly
21888 until coming to the end of the user's program.
21889 Each execution of |do_statement| concludes with
21890 |cur_cmd=semicolon|, |end_group|, or |stop|.
21891
21892 @c void mp_main_control (MP mp) { 
21893   do {  
21894     mp_do_statement(mp);
21895     if ( mp->cur_cmd==end_group ) {
21896       print_err("Extra `endgroup'");
21897 @.Extra `endgroup'@>
21898       help2("I'm not currently working on a `begingroup',")
21899         ("so I had better not try to end anything.");
21900       mp_flush_error(mp, 0);
21901     }
21902   } while (mp->cur_cmd!=stop);
21903 }
21904 int mp_run (MP mp) {
21905   @<Install and test the non-local jump buffer@>;
21906   mp_main_control(mp); /* come to life */
21907   mp_final_cleanup(mp); /* prepare for death */
21908   mp_close_files_and_terminate(mp);
21909   return mp->history;
21910 }
21911 char * mp_mplib_version (MP mp) {
21912   assert(mp);
21913   return mplib_version;
21914 }
21915 char * mp_metapost_version (MP mp) {
21916   assert(mp);
21917   return metapost_version;
21918 }
21919
21920 @ @<Exported function headers@>=
21921 int mp_run (MP mp);
21922 char * mp_mplib_version (MP mp);
21923 char * mp_metapost_version (MP mp);
21924
21925 @ @<Put each...@>=
21926 mp_primitive(mp, "end",stop,0);
21927 @:end_}{\&{end} primitive@>
21928 mp_primitive(mp, "dump",stop,1);
21929 @:dump_}{\&{dump} primitive@>
21930
21931 @ @<Cases of |print_cmd...@>=
21932 case stop:
21933   if ( m==0 ) mp_print(mp, "end");
21934   else mp_print(mp, "dump");
21935   break;
21936
21937 @* \[41] Commands.
21938 Let's turn now to statements that are classified as ``commands'' because
21939 of their imperative nature. We'll begin with simple ones, so that it
21940 will be clear how to hook command processing into the |do_statement| routine;
21941 then we'll tackle the tougher commands.
21942
21943 Here's one of the simplest:
21944
21945 @<Cases of |do_statement|...@>=
21946 case random_seed: mp_do_random_seed(mp);  break;
21947
21948 @ @<Declare action procedures for use by |do_statement|@>=
21949 void mp_do_random_seed (MP mp) ;
21950
21951 @ @c void mp_do_random_seed (MP mp) { 
21952   mp_get_x_next(mp);
21953   if ( mp->cur_cmd!=assignment ) {
21954     mp_missing_err(mp, ":=");
21955 @.Missing `:='@>
21956     help1("Always say `randomseed:=<numeric expression>'.");
21957     mp_back_error(mp);
21958   };
21959   mp_get_x_next(mp); mp_scan_expression(mp);
21960   if ( mp->cur_type!=mp_known ) {
21961     exp_err("Unknown value will be ignored");
21962 @.Unknown value...ignored@>
21963     help2("Your expression was too random for me to handle,")
21964       ("so I won't change the random seed just now.");
21965     mp_put_get_flush_error(mp, 0);
21966   } else {
21967    @<Initialize the random seed to |cur_exp|@>;
21968   }
21969 }
21970
21971 @ @<Initialize the random seed to |cur_exp|@>=
21972
21973   mp_init_randoms(mp, mp->cur_exp);
21974   if ( mp->selector>=log_only && mp->selector<write_file) {
21975     mp->old_setting=mp->selector; mp->selector=log_only;
21976     mp_print_nl(mp, "{randomseed:="); 
21977     mp_print_scaled(mp, mp->cur_exp); 
21978     mp_print_char(mp, '}');
21979     mp_print_nl(mp, ""); mp->selector=mp->old_setting;
21980   }
21981 }
21982
21983 @ And here's another simple one (somewhat different in flavor):
21984
21985 @<Cases of |do_statement|...@>=
21986 case mode_command: 
21987   mp_print_ln(mp); mp->interaction=mp->cur_mod;
21988   @<Initialize the print |selector| based on |interaction|@>;
21989   if ( mp->log_opened ) mp->selector=mp->selector+2;
21990   mp_get_x_next(mp);
21991   break;
21992
21993 @ @<Put each...@>=
21994 mp_primitive(mp, "batchmode",mode_command,mp_batch_mode);
21995 @:mp_batch_mode_}{\&{batchmode} primitive@>
21996 mp_primitive(mp, "nonstopmode",mode_command,mp_nonstop_mode);
21997 @:mp_nonstop_mode_}{\&{nonstopmode} primitive@>
21998 mp_primitive(mp, "scrollmode",mode_command,mp_scroll_mode);
21999 @:mp_scroll_mode_}{\&{scrollmode} primitive@>
22000 mp_primitive(mp, "errorstopmode",mode_command,mp_error_stop_mode);
22001 @:mp_error_stop_mode_}{\&{errorstopmode} primitive@>
22002
22003 @ @<Cases of |print_cmd_mod|...@>=
22004 case mode_command: 
22005   switch (m) {
22006   case mp_batch_mode: mp_print(mp, "batchmode"); break;
22007   case mp_nonstop_mode: mp_print(mp, "nonstopmode"); break;
22008   case mp_scroll_mode: mp_print(mp, "scrollmode"); break;
22009   default: mp_print(mp, "errorstopmode"); break;
22010   }
22011   break;
22012
22013 @ The `\&{inner}' and `\&{outer}' commands are only slightly harder.
22014
22015 @<Cases of |do_statement|...@>=
22016 case protection_command: mp_do_protection(mp); break;
22017
22018 @ @<Put each...@>=
22019 mp_primitive(mp, "inner",protection_command,0);
22020 @:inner_}{\&{inner} primitive@>
22021 mp_primitive(mp, "outer",protection_command,1);
22022 @:outer_}{\&{outer} primitive@>
22023
22024 @ @<Cases of |print_cmd...@>=
22025 case protection_command: 
22026   if ( m==0 ) mp_print(mp, "inner");
22027   else mp_print(mp, "outer");
22028   break;
22029
22030 @ @<Declare action procedures for use by |do_statement|@>=
22031 void mp_do_protection (MP mp) ;
22032
22033 @ @c void mp_do_protection (MP mp) {
22034   int m; /* 0 to unprotect, 1 to protect */
22035   halfword t; /* the |eq_type| before we change it */
22036   m=mp->cur_mod;
22037   do {  
22038     mp_get_symbol(mp); t=eq_type(mp->cur_sym);
22039     if ( m==0 ) { 
22040       if ( t>=outer_tag ) 
22041         eq_type(mp->cur_sym)=t-outer_tag;
22042     } else if ( t<outer_tag ) {
22043       eq_type(mp->cur_sym)=t+outer_tag;
22044     }
22045     mp_get_x_next(mp);
22046   } while (mp->cur_cmd==comma);
22047 }
22048
22049 @ \MP\ never defines the tokens `\.(' and `\.)' to be primitives, but
22050 plain \MP\ begins with the declaration `\&{delimiters} \.{()}'. Such a
22051 declaration assigns the command code |left_delimiter| to `\.{(}' and
22052 |right_delimiter| to `\.{)}'; the |equiv| of each delimiter is the
22053 hash address of its mate.
22054
22055 @<Cases of |do_statement|...@>=
22056 case delimiters: mp_def_delims(mp); break;
22057
22058 @ @<Declare action procedures for use by |do_statement|@>=
22059 void mp_def_delims (MP mp) ;
22060
22061 @ @c void mp_def_delims (MP mp) {
22062   pointer l_delim,r_delim; /* the new delimiter pair */
22063   mp_get_clear_symbol(mp); l_delim=mp->cur_sym;
22064   mp_get_clear_symbol(mp); r_delim=mp->cur_sym;
22065   eq_type(l_delim)=left_delimiter; equiv(l_delim)=r_delim;
22066   eq_type(r_delim)=right_delimiter; equiv(r_delim)=l_delim;
22067   mp_get_x_next(mp);
22068 }
22069
22070 @ Here is a procedure that is called when \MP\ has reached a point
22071 where some right delimiter is mandatory.
22072
22073 @<Declare the procedure called |check_delimiter|@>=
22074 void mp_check_delimiter (MP mp,pointer l_delim, pointer r_delim) {
22075   if ( mp->cur_cmd==right_delimiter ) 
22076     if ( mp->cur_mod==l_delim ) 
22077       return;
22078   if ( mp->cur_sym!=r_delim ) {
22079      mp_missing_err(mp, str(text(r_delim)));
22080 @.Missing `)'@>
22081     help2("I found no right delimiter to match a left one. So I've")
22082       ("put one in, behind the scenes; this may fix the problem.");
22083     mp_back_error(mp);
22084   } else { 
22085     print_err("The token `"); mp_print_text(r_delim);
22086 @.The token...delimiter@>
22087     mp_print(mp, "' is no longer a right delimiter");
22088     help3("Strange: This token has lost its former meaning!")
22089       ("I'll read it as a right delimiter this time;")
22090       ("but watch out, I'll probably miss it later.");
22091     mp_error(mp);
22092   }
22093 }
22094
22095 @ The next four commands save or change the values associated with tokens.
22096
22097 @<Cases of |do_statement|...@>=
22098 case save_command: 
22099   do {  
22100     mp_get_symbol(mp); mp_save_variable(mp, mp->cur_sym); mp_get_x_next(mp);
22101   } while (mp->cur_cmd==comma);
22102   break;
22103 case interim_command: mp_do_interim(mp); break;
22104 case let_command: mp_do_let(mp); break;
22105 case new_internal: mp_do_new_internal(mp); break;
22106
22107 @ @<Declare action procedures for use by |do_statement|@>=
22108 void mp_do_statement (MP mp);
22109 void mp_do_interim (MP mp);
22110
22111 @ @c void mp_do_interim (MP mp) { 
22112   mp_get_x_next(mp);
22113   if ( mp->cur_cmd!=internal_quantity ) {
22114      print_err("The token `");
22115 @.The token...quantity@>
22116     if ( mp->cur_sym==0 ) mp_print(mp, "(%CAPSULE)");
22117     else mp_print_text(mp->cur_sym);
22118     mp_print(mp, "' isn't an internal quantity");
22119     help1("Something like `tracingonline' should follow `interim'.");
22120     mp_back_error(mp);
22121   } else { 
22122     mp_save_internal(mp, mp->cur_mod); mp_back_input(mp);
22123   }
22124   mp_do_statement(mp);
22125 }
22126
22127 @ The following procedure is careful not to undefine the left-hand symbol
22128 too soon, lest commands like `{\tt let x=x}' have a surprising effect.
22129
22130 @<Declare action procedures for use by |do_statement|@>=
22131 void mp_do_let (MP mp) ;
22132
22133 @ @c void mp_do_let (MP mp) {
22134   pointer l; /* hash location of the left-hand symbol */
22135   mp_get_symbol(mp); l=mp->cur_sym; mp_get_x_next(mp);
22136   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
22137      mp_missing_err(mp, "=");
22138 @.Missing `='@>
22139     help3("You should have said `let symbol = something'.")
22140       ("But don't worry; I'll pretend that an equals sign")
22141       ("was present. The next token I read will be `something'.");
22142     mp_back_error(mp);
22143   }
22144   mp_get_symbol(mp);
22145   switch (mp->cur_cmd) {
22146   case defined_macro: case secondary_primary_macro:
22147   case tertiary_secondary_macro: case expression_tertiary_macro: 
22148     add_mac_ref(mp->cur_mod);
22149     break;
22150   default: 
22151     break;
22152   }
22153   mp_clear_symbol(mp, l,false); eq_type(l)=mp->cur_cmd;
22154   if ( mp->cur_cmd==tag_token ) equiv(l)=null;
22155   else equiv(l)=mp->cur_mod;
22156   mp_get_x_next(mp);
22157 }
22158
22159 @ @<Declarations@>=
22160 void mp_grow_internals (MP mp, int l);
22161 void mp_do_new_internal (MP mp) ;
22162
22163 @ @c
22164 void mp_grow_internals (MP mp, int l) {
22165   scaled *internal;
22166   char * *int_name; 
22167   int k;
22168   if ( hash_end+l>max_halfword ) {
22169     mp_confusion(mp, "out of memory space"); /* can't be reached */
22170   }
22171   int_name = xmalloc ((l+1),sizeof(char *));
22172   internal = xmalloc ((l+1),sizeof(scaled));
22173   for (k=0;k<=l; k++ ) { 
22174     if (k<=mp->max_internal) {
22175       internal[k]=mp->internal[k]; 
22176       int_name[k]=mp->int_name[k]; 
22177     } else {
22178       internal[k]=0; 
22179       int_name[k]=NULL; 
22180     }
22181   }
22182   xfree(mp->internal); xfree(mp->int_name);
22183   mp->int_name = int_name;
22184   mp->internal = internal;
22185   mp->max_internal = l;
22186 }
22187
22188
22189 void mp_do_new_internal (MP mp) { 
22190   do {  
22191     if ( mp->int_ptr==mp->max_internal ) {
22192       mp_grow_internals(mp, (mp->max_internal + (mp->max_internal>>2)));
22193     }
22194     mp_get_clear_symbol(mp); incr(mp->int_ptr);
22195     eq_type(mp->cur_sym)=internal_quantity; 
22196     equiv(mp->cur_sym)=mp->int_ptr;
22197     if(mp->int_name[mp->int_ptr]!=NULL)
22198       xfree(mp->int_name[mp->int_ptr]);
22199     mp->int_name[mp->int_ptr]=str(text(mp->cur_sym)); 
22200     mp->internal[mp->int_ptr]=0;
22201     mp_get_x_next(mp);
22202   } while (mp->cur_cmd==comma);
22203 }
22204
22205 @ @<Dealloc variables@>=
22206 for (k=0;k<=mp->max_internal;k++) {
22207    xfree(mp->int_name[k]);
22208 }
22209 xfree(mp->internal); 
22210 xfree(mp->int_name); 
22211
22212
22213 @ The various `\&{show}' commands are distinguished by modifier fields
22214 in the usual way.
22215
22216 @d show_token_code 0 /* show the meaning of a single token */
22217 @d show_stats_code 1 /* show current memory and string usage */
22218 @d show_code 2 /* show a list of expressions */
22219 @d show_var_code 3 /* show a variable and its descendents */
22220 @d show_dependencies_code 4 /* show dependent variables in terms of independents */
22221
22222 @<Put each...@>=
22223 mp_primitive(mp, "showtoken",show_command,show_token_code);
22224 @:show_token_}{\&{showtoken} primitive@>
22225 mp_primitive(mp, "showstats",show_command,show_stats_code);
22226 @:show_stats_}{\&{showstats} primitive@>
22227 mp_primitive(mp, "show",show_command,show_code);
22228 @:show_}{\&{show} primitive@>
22229 mp_primitive(mp, "showvariable",show_command,show_var_code);
22230 @:show_var_}{\&{showvariable} primitive@>
22231 mp_primitive(mp, "showdependencies",show_command,show_dependencies_code);
22232 @:show_dependencies_}{\&{showdependencies} primitive@>
22233
22234 @ @<Cases of |print_cmd...@>=
22235 case show_command: 
22236   switch (m) {
22237   case show_token_code:mp_print(mp, "showtoken"); break;
22238   case show_stats_code:mp_print(mp, "showstats"); break;
22239   case show_code:mp_print(mp, "show"); break;
22240   case show_var_code:mp_print(mp, "showvariable"); break;
22241   default: mp_print(mp, "showdependencies"); break;
22242   }
22243   break;
22244
22245 @ @<Cases of |do_statement|...@>=
22246 case show_command:mp_do_show_whatever(mp); break;
22247
22248 @ The value of |cur_mod| controls the |verbosity| in the |print_exp| routine:
22249 if it's |show_code|, complicated structures are abbreviated, otherwise
22250 they aren't.
22251
22252 @<Declare action procedures for use by |do_statement|@>=
22253 void mp_do_show (MP mp) ;
22254
22255 @ @c void mp_do_show (MP mp) { 
22256   do {  
22257     mp_get_x_next(mp); mp_scan_expression(mp);
22258     mp_print_nl(mp, ">> ");
22259 @.>>@>
22260     mp_print_exp(mp, null,2); mp_flush_cur_exp(mp, 0);
22261   } while (mp->cur_cmd==comma);
22262 }
22263
22264 @ @<Declare action procedures for use by |do_statement|@>=
22265 void mp_disp_token (MP mp) ;
22266
22267 @ @c void mp_disp_token (MP mp) { 
22268   mp_print_nl(mp, "> ");
22269 @.>\relax@>
22270   if ( mp->cur_sym==0 ) {
22271     @<Show a numeric or string or capsule token@>;
22272   } else { 
22273     mp_print_text(mp->cur_sym); mp_print_char(mp, '=');
22274     if ( eq_type(mp->cur_sym)>=outer_tag ) mp_print(mp, "(outer) ");
22275     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod);
22276     if ( mp->cur_cmd==defined_macro ) {
22277       mp_print_ln(mp); mp_show_macro(mp, mp->cur_mod,null,100000);
22278     } /* this avoids recursion between |show_macro| and |print_cmd_mod| */
22279 @^recursion@>
22280   }
22281 }
22282
22283 @ @<Show a numeric or string or capsule token@>=
22284
22285   if ( mp->cur_cmd==numeric_token ) {
22286     mp_print_scaled(mp, mp->cur_mod);
22287   } else if ( mp->cur_cmd==capsule_token ) {
22288     mp->g_pointer=mp->cur_mod; mp_print_capsule(mp);
22289   } else  { 
22290     mp_print_char(mp, '"'); 
22291     mp_print_str(mp, mp->cur_mod); mp_print_char(mp, '"');
22292     delete_str_ref(mp->cur_mod);
22293   }
22294 }
22295
22296 @ The following cases of |print_cmd_mod| might arise in connection
22297 with |disp_token|, although they don't correspond to any
22298 primitive tokens.
22299
22300 @<Cases of |print_cmd_...@>=
22301 case left_delimiter:
22302 case right_delimiter: 
22303   if ( c==left_delimiter ) mp_print(mp, "left");
22304   else mp_print(mp, "right");
22305   mp_print(mp, " delimiter that matches "); 
22306   mp_print_text(m);
22307   break;
22308 case tag_token:
22309   if ( m==null ) mp_print(mp, "tag");
22310    else mp_print(mp, "variable");
22311    break;
22312 case defined_macro: 
22313    mp_print(mp, "macro:");
22314    break;
22315 case secondary_primary_macro:
22316 case tertiary_secondary_macro:
22317 case expression_tertiary_macro:
22318   mp_print_cmd_mod(mp, macro_def,c); 
22319   mp_print(mp, "'d macro:");
22320   mp_print_ln(mp); mp_show_token_list(mp, link(link(m)),null,1000,0);
22321   break;
22322 case repeat_loop:
22323   mp_print(mp, "[repeat the loop]");
22324   break;
22325 case internal_quantity:
22326   mp_print(mp, mp->int_name[m]);
22327   break;
22328
22329 @ @<Declare action procedures for use by |do_statement|@>=
22330 void mp_do_show_token (MP mp) ;
22331
22332 @ @c void mp_do_show_token (MP mp) { 
22333   do {  
22334     get_t_next; mp_disp_token(mp);
22335     mp_get_x_next(mp);
22336   } while (mp->cur_cmd==comma);
22337 }
22338
22339 @ @<Declare action procedures for use by |do_statement|@>=
22340 void mp_do_show_stats (MP mp) ;
22341
22342 @ @c void mp_do_show_stats (MP mp) { 
22343   mp_print_nl(mp, "Memory usage ");
22344 @.Memory usage...@>
22345   mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used);
22346   if ( false )
22347     mp_print(mp, "unknown");
22348   mp_print(mp, " ("); mp_print_int(mp, mp->hi_mem_min-mp->lo_mem_max-1);
22349   mp_print(mp, " still untouched)"); mp_print_ln(mp);
22350   mp_print_nl(mp, "String usage ");
22351   mp_print_int(mp, mp->strs_in_use-mp->init_str_use);
22352   mp_print_char(mp, '&'); mp_print_int(mp, mp->pool_in_use-mp->init_pool_ptr);
22353   if ( false )
22354     mp_print(mp, "unknown");
22355   mp_print(mp, " (");
22356   mp_print_int(mp, mp->max_strings-1-mp->strs_used_up); mp_print_char(mp, '&');
22357   mp_print_int(mp, mp->pool_size-mp->pool_ptr); 
22358   mp_print(mp, " now untouched)"); mp_print_ln(mp);
22359   mp_get_x_next(mp);
22360 }
22361
22362 @ Here's a recursive procedure that gives an abbreviated account
22363 of a variable, for use by |do_show_var|.
22364
22365 @<Declare action procedures for use by |do_statement|@>=
22366 void mp_disp_var (MP mp,pointer p) ;
22367
22368 @ @c void mp_disp_var (MP mp,pointer p) {
22369   pointer q; /* traverses attributes and subscripts */
22370   int n; /* amount of macro text to show */
22371   if ( type(p)==mp_structured )  {
22372     @<Descend the structure@>;
22373   } else if ( type(p)>=mp_unsuffixed_macro ) {
22374     @<Display a variable macro@>;
22375   } else if ( type(p)!=undefined ){ 
22376     mp_print_nl(mp, ""); mp_print_variable_name(mp, p); 
22377     mp_print_char(mp, '=');
22378     mp_print_exp(mp, p,0);
22379   }
22380 }
22381
22382 @ @<Descend the structure@>=
22383
22384   q=attr_head(p);
22385   do {  mp_disp_var(mp, q); q=link(q); } while (q!=end_attr);
22386   q=subscr_head(p);
22387   while ( name_type(q)==mp_subscr ) { 
22388     mp_disp_var(mp, q); q=link(q);
22389   }
22390 }
22391
22392 @ @<Display a variable macro@>=
22393
22394   mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22395   if ( type(p)>mp_unsuffixed_macro ) 
22396     mp_print(mp, "@@#"); /* |suffixed_macro| */
22397   mp_print(mp, "=macro:");
22398   if ( (int)mp->file_offset>=mp->max_print_line-20 ) n=5;
22399   else n=mp->max_print_line-mp->file_offset-15;
22400   mp_show_macro(mp, value(p),null,n);
22401 }
22402
22403 @ @<Declare action procedures for use by |do_statement|@>=
22404 void mp_do_show_var (MP mp) ;
22405
22406 @ @c void mp_do_show_var (MP mp) { 
22407   do {  
22408     get_t_next;
22409     if ( mp->cur_sym>0 ) if ( mp->cur_sym<=hash_end )
22410       if ( mp->cur_cmd==tag_token ) if ( mp->cur_mod!=null ) {
22411       mp_disp_var(mp, mp->cur_mod); goto DONE;
22412     }
22413    mp_disp_token(mp);
22414   DONE:
22415    mp_get_x_next(mp);
22416   } while (mp->cur_cmd==comma);
22417 }
22418
22419 @ @<Declare action procedures for use by |do_statement|@>=
22420 void mp_do_show_dependencies (MP mp) ;
22421
22422 @ @c void mp_do_show_dependencies (MP mp) {
22423   pointer p; /* link that runs through all dependencies */
22424   p=link(dep_head);
22425   while ( p!=dep_head ) {
22426     if ( mp_interesting(mp, p) ) {
22427       mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22428       if ( type(p)==mp_dependent ) mp_print_char(mp, '=');
22429       else mp_print(mp, " = "); /* extra spaces imply proto-dependency */
22430       mp_print_dependency(mp, dep_list(p),type(p));
22431     }
22432     p=dep_list(p);
22433     while ( info(p)!=null ) p=link(p);
22434     p=link(p);
22435   }
22436   mp_get_x_next(mp);
22437 }
22438
22439 @ Finally we are ready for the procedure that governs all of the
22440 show commands.
22441
22442 @<Declare action procedures for use by |do_statement|@>=
22443 void mp_do_show_whatever (MP mp) ;
22444
22445 @ @c void mp_do_show_whatever (MP mp) { 
22446   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
22447   switch (mp->cur_mod) {
22448   case show_token_code:mp_do_show_token(mp); break;
22449   case show_stats_code:mp_do_show_stats(mp); break;
22450   case show_code:mp_do_show(mp); break;
22451   case show_var_code:mp_do_show_var(mp); break;
22452   case show_dependencies_code:mp_do_show_dependencies(mp); break;
22453   } /* there are no other cases */
22454   if ( mp->internal[mp_showstopping]>0 ){ 
22455     print_err("OK");
22456 @.OK@>
22457     if ( mp->interaction<mp_error_stop_mode ) { 
22458       help0; decr(mp->error_count);
22459     } else {
22460       help1("This isn't an error message; I'm just showing something.");
22461     }
22462     if ( mp->cur_cmd==semicolon ) mp_error(mp);
22463      else mp_put_get_error(mp);
22464   }
22465 }
22466
22467 @ The `\&{addto}' command needs the following additional primitives:
22468
22469 @d double_path_code 0 /* command modifier for `\&{doublepath}' */
22470 @d contour_code 1 /* command modifier for `\&{contour}' */
22471 @d also_code 2 /* command modifier for `\&{also}' */
22472
22473 @ Pre and postscripts need two new identifiers:
22474
22475 @d with_pre_script 11
22476 @d with_post_script 13
22477
22478 @<Put each...@>=
22479 mp_primitive(mp, "doublepath",thing_to_add,double_path_code);
22480 @:double_path_}{\&{doublepath} primitive@>
22481 mp_primitive(mp, "contour",thing_to_add,contour_code);
22482 @:contour_}{\&{contour} primitive@>
22483 mp_primitive(mp, "also",thing_to_add,also_code);
22484 @:also_}{\&{also} primitive@>
22485 mp_primitive(mp, "withpen",with_option,mp_pen_type);
22486 @:with_pen_}{\&{withpen} primitive@>
22487 mp_primitive(mp, "dashed",with_option,mp_picture_type);
22488 @:dashed_}{\&{dashed} primitive@>
22489 mp_primitive(mp, "withprescript",with_option,with_pre_script);
22490 @:with_pre_script_}{\&{withprescript} primitive@>
22491 mp_primitive(mp, "withpostscript",with_option,with_post_script);
22492 @:with_post_script_}{\&{withpostscript} primitive@>
22493 mp_primitive(mp, "withoutcolor",with_option,mp_no_model);
22494 @:with_color_}{\&{withoutcolor} primitive@>
22495 mp_primitive(mp, "withgreyscale",with_option,mp_grey_model);
22496 @:with_color_}{\&{withgreyscale} primitive@>
22497 mp_primitive(mp, "withcolor",with_option,mp_uninitialized_model);
22498 @:with_color_}{\&{withcolor} primitive@>
22499 /*  \&{withrgbcolor} is an alias for \&{withcolor} */
22500 mp_primitive(mp, "withrgbcolor",with_option,mp_rgb_model);
22501 @:with_color_}{\&{withrgbcolor} primitive@>
22502 mp_primitive(mp, "withcmykcolor",with_option,mp_cmyk_model);
22503 @:with_color_}{\&{withcmykcolor} primitive@>
22504
22505 @ @<Cases of |print_cmd...@>=
22506 case thing_to_add:
22507   if ( m==contour_code ) mp_print(mp, "contour");
22508   else if ( m==double_path_code ) mp_print(mp, "doublepath");
22509   else mp_print(mp, "also");
22510   break;
22511 case with_option:
22512   if ( m==mp_pen_type ) mp_print(mp, "withpen");
22513   else if ( m==with_pre_script ) mp_print(mp, "withprescript");
22514   else if ( m==with_post_script ) mp_print(mp, "withpostscript");
22515   else if ( m==mp_no_model ) mp_print(mp, "withoutcolor");
22516   else if ( m==mp_rgb_model ) mp_print(mp, "withrgbcolor");
22517   else if ( m==mp_uninitialized_model ) mp_print(mp, "withcolor");
22518   else if ( m==mp_cmyk_model ) mp_print(mp, "withcmykcolor");
22519   else if ( m==mp_grey_model ) mp_print(mp, "withgreyscale");
22520   else mp_print(mp, "dashed");
22521   break;
22522
22523 @ The |scan_with_list| procedure parses a $\langle$with list$\rangle$ and
22524 updates the list of graphical objects starting at |p|.  Each $\langle$with
22525 clause$\rangle$ updates all graphical objects whose |type| is compatible.
22526 Other objects are ignored.
22527
22528 @<Declare action procedures for use by |do_statement|@>=
22529 void mp_scan_with_list (MP mp,pointer p) ;
22530
22531 @ @c void mp_scan_with_list (MP mp,pointer p) {
22532   small_number t; /* |cur_mod| of the |with_option| (should match |cur_type|) */
22533   pointer q; /* for list manipulation */
22534   int old_setting; /* saved |selector| setting */
22535   pointer k; /* for finding the near-last item in a list  */
22536   str_number s; /* for string cleanup after combining  */
22537   pointer cp,pp,dp,ap,bp;
22538     /* objects being updated; |void| initially; |null| to suppress update */
22539   cp=mp_void; pp=mp_void; dp=mp_void; ap=mp_void; bp=mp_void;
22540   k=0;
22541   while ( mp->cur_cmd==with_option ){ 
22542     t=mp->cur_mod;
22543     mp_get_x_next(mp);
22544     if ( t!=mp_no_model ) mp_scan_expression(mp);
22545     if (((t==with_pre_script)&&(mp->cur_type!=mp_string_type))||
22546      ((t==with_post_script)&&(mp->cur_type!=mp_string_type))||
22547      ((t==mp_uninitialized_model)&&
22548         ((mp->cur_type!=mp_cmykcolor_type)&&(mp->cur_type!=mp_color_type)
22549           &&(mp->cur_type!=mp_known)&&(mp->cur_type!=mp_boolean_type)))||
22550      ((t==mp_cmyk_model)&&(mp->cur_type!=mp_cmykcolor_type))||
22551      ((t==mp_rgb_model)&&(mp->cur_type!=mp_color_type))||
22552      ((t==mp_grey_model)&&(mp->cur_type!=mp_known))||
22553      ((t==mp_pen_type)&&(mp->cur_type!=t))||
22554      ((t==mp_picture_type)&&(mp->cur_type!=t)) ) {
22555       @<Complain about improper type@>;
22556     } else if ( t==mp_uninitialized_model ) {
22557       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22558       if ( cp!=null )
22559         @<Transfer a color from the current expression to object~|cp|@>;
22560       mp_flush_cur_exp(mp, 0);
22561     } else if ( t==mp_rgb_model ) {
22562       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22563       if ( cp!=null )
22564         @<Transfer a rgbcolor from the current expression to object~|cp|@>;
22565       mp_flush_cur_exp(mp, 0);
22566     } else if ( t==mp_cmyk_model ) {
22567       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22568       if ( cp!=null )
22569         @<Transfer a cmykcolor from the current expression to object~|cp|@>;
22570       mp_flush_cur_exp(mp, 0);
22571     } else if ( t==mp_grey_model ) {
22572       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22573       if ( cp!=null )
22574         @<Transfer a greyscale from the current expression to object~|cp|@>;
22575       mp_flush_cur_exp(mp, 0);
22576     } else if ( t==mp_no_model ) {
22577       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
22578       if ( cp!=null )
22579         @<Transfer a noncolor from the current expression to object~|cp|@>;
22580     } else if ( t==mp_pen_type ) {
22581       if ( pp==mp_void ) @<Make |pp| an object in list~|p| that needs a pen@>;
22582       if ( pp!=null ) {
22583         if ( pen_p(pp)!=null ) mp_toss_knot_list(mp, pen_p(pp));
22584         pen_p(pp)=mp->cur_exp; mp->cur_type=mp_vacuous;
22585       }
22586     } else if ( t==with_pre_script ) {
22587       if ( ap==mp_void )
22588         ap=p;
22589       while ( (ap!=null)&&(! has_color(ap)) )
22590          ap=link(ap);
22591       if ( ap!=null ) {
22592         if ( pre_script(ap)!=null ) { /*  build a new,combined string  */
22593           s=pre_script(ap);
22594           old_setting=mp->selector;
22595               mp->selector=new_string;
22596           str_room(length(pre_script(ap))+length(mp->cur_exp)+2);
22597               mp_print_str(mp, mp->cur_exp);
22598           append_char(13);  /* a forced \ps\ newline  */
22599           mp_print_str(mp, pre_script(ap));
22600           pre_script(ap)=mp_make_string(mp);
22601           delete_str_ref(s);
22602           mp->selector=old_setting;
22603         } else {
22604           pre_script(ap)=mp->cur_exp;
22605         }
22606         mp->cur_type=mp_vacuous;
22607       }
22608     } else if ( t==with_post_script ) {
22609       if ( bp==mp_void )
22610         k=p; 
22611       bp=k;
22612       while ( link(k)!=null ) {
22613         k=link(k);
22614         if ( has_color(k) ) bp=k;
22615       }
22616       if ( bp!=null ) {
22617          if ( post_script(bp)!=null ) {
22618            s=post_script(bp);
22619            old_setting=mp->selector;
22620                mp->selector=new_string;
22621            str_room(length(post_script(bp))+length(mp->cur_exp)+2);
22622            mp_print_str(mp, post_script(bp));
22623            append_char(13); /* a forced \ps\ newline  */
22624            mp_print_str(mp, mp->cur_exp);
22625            post_script(bp)=mp_make_string(mp);
22626            delete_str_ref(s);
22627            mp->selector=old_setting;
22628          } else {
22629            post_script(bp)=mp->cur_exp;
22630          }
22631          mp->cur_type=mp_vacuous;
22632        }
22633     } else { 
22634       if ( dp==mp_void ) {
22635         @<Make |dp| a stroked node in list~|p|@>;
22636       }
22637       if ( dp!=null ) {
22638         if ( dash_p(dp)!=null ) delete_edge_ref(dash_p(dp));
22639         dash_p(dp)=mp_make_dashes(mp, mp->cur_exp);
22640         dash_scale(dp)=unity;
22641         mp->cur_type=mp_vacuous;
22642       }
22643     }
22644   }
22645   @<Copy the information from objects |cp|, |pp|, and |dp| into the rest
22646     of the list@>;
22647 };
22648
22649 @ @<Complain about improper type@>=
22650 { exp_err("Improper type");
22651 @.Improper type@>
22652 help2("Next time say `withpen <known pen expression>';")
22653   ("I'll ignore the bad `with' clause and look for another.");
22654 if ( t==with_pre_script )
22655   mp->help_line[1]="Next time say `withprescript <known string expression>';";
22656 else if ( t==with_post_script )
22657   mp->help_line[1]="Next time say `withpostscript <known string expression>';";
22658 else if ( t==mp_picture_type )
22659   mp->help_line[1]="Next time say `dashed <known picture expression>';";
22660 else if ( t==mp_uninitialized_model )
22661   mp->help_line[1]="Next time say `withcolor <known color expression>';";
22662 else if ( t==mp_rgb_model )
22663   mp->help_line[1]="Next time say `withrgbcolor <known color expression>';";
22664 else if ( t==mp_cmyk_model )
22665   mp->help_line[1]="Next time say `withcmykcolor <known cmykcolor expression>';";
22666 else if ( t==mp_grey_model )
22667   mp->help_line[1]="Next time say `withgreyscale <known numeric expression>';";;
22668 mp_put_get_flush_error(mp, 0);
22669 }
22670
22671 @ Forcing the color to be between |0| and |unity| here guarantees that no
22672 picture will ever contain a color outside the legal range for \ps\ graphics.
22673
22674 @<Transfer a color from the current expression to object~|cp|@>=
22675 { if ( mp->cur_type==mp_color_type )
22676    @<Transfer a rgbcolor from the current expression to object~|cp|@>
22677 else if ( mp->cur_type==mp_cmykcolor_type )
22678    @<Transfer a cmykcolor from the current expression to object~|cp|@>
22679 else if ( mp->cur_type==mp_known )
22680    @<Transfer a greyscale from the current expression to object~|cp|@>
22681 else if ( mp->cur_exp==false_code )
22682    @<Transfer a noncolor from the current expression to object~|cp|@>;
22683 }
22684
22685 @ @<Transfer a rgbcolor from the current expression to object~|cp|@>=
22686 { q=value(mp->cur_exp);
22687 cyan_val(cp)=0;
22688 magenta_val(cp)=0;
22689 yellow_val(cp)=0;
22690 black_val(cp)=0;
22691 red_val(cp)=value(red_part_loc(q));
22692 green_val(cp)=value(green_part_loc(q));
22693 blue_val(cp)=value(blue_part_loc(q));
22694 color_model(cp)=mp_rgb_model;
22695 if ( red_val(cp)<0 ) red_val(cp)=0;
22696 if ( green_val(cp)<0 ) green_val(cp)=0;
22697 if ( blue_val(cp)<0 ) blue_val(cp)=0;
22698 if ( red_val(cp)>unity ) red_val(cp)=unity;
22699 if ( green_val(cp)>unity ) green_val(cp)=unity;
22700 if ( blue_val(cp)>unity ) blue_val(cp)=unity;
22701 }
22702
22703 @ @<Transfer a cmykcolor from the current expression to object~|cp|@>=
22704 { q=value(mp->cur_exp);
22705 cyan_val(cp)=value(cyan_part_loc(q));
22706 magenta_val(cp)=value(magenta_part_loc(q));
22707 yellow_val(cp)=value(yellow_part_loc(q));
22708 black_val(cp)=value(black_part_loc(q));
22709 color_model(cp)=mp_cmyk_model;
22710 if ( cyan_val(cp)<0 ) cyan_val(cp)=0;
22711 if ( magenta_val(cp)<0 ) magenta_val(cp)=0;
22712 if ( yellow_val(cp)<0 ) yellow_val(cp)=0;
22713 if ( black_val(cp)<0 ) black_val(cp)=0;
22714 if ( cyan_val(cp)>unity ) cyan_val(cp)=unity;
22715 if ( magenta_val(cp)>unity ) magenta_val(cp)=unity;
22716 if ( yellow_val(cp)>unity ) yellow_val(cp)=unity;
22717 if ( black_val(cp)>unity ) black_val(cp)=unity;
22718 }
22719
22720 @ @<Transfer a greyscale from the current expression to object~|cp|@>=
22721 { q=mp->cur_exp;
22722 cyan_val(cp)=0;
22723 magenta_val(cp)=0;
22724 yellow_val(cp)=0;
22725 black_val(cp)=0;
22726 grey_val(cp)=q;
22727 color_model(cp)=mp_grey_model;
22728 if ( grey_val(cp)<0 ) grey_val(cp)=0;
22729 if ( grey_val(cp)>unity ) grey_val(cp)=unity;
22730 }
22731
22732 @ @<Transfer a noncolor from the current expression to object~|cp|@>=
22733 {
22734 cyan_val(cp)=0;
22735 magenta_val(cp)=0;
22736 yellow_val(cp)=0;
22737 black_val(cp)=0;
22738 grey_val(cp)=0;
22739 color_model(cp)=mp_no_model;
22740 }
22741
22742 @ @<Make |cp| a colored object in object list~|p|@>=
22743 { cp=p;
22744   while ( cp!=null ){ 
22745     if ( has_color(cp) ) break;
22746     cp=link(cp);
22747   }
22748 }
22749
22750 @ @<Make |pp| an object in list~|p| that needs a pen@>=
22751 { pp=p;
22752   while ( pp!=null ) {
22753     if ( has_pen(pp) ) break;
22754     pp=link(pp);
22755   }
22756 }
22757
22758 @ @<Make |dp| a stroked node in list~|p|@>=
22759 { dp=p;
22760   while ( dp!=null ) {
22761     if ( type(dp)==mp_stroked_code ) break;
22762     dp=link(dp);
22763   }
22764 }
22765
22766 @ @<Copy the information from objects |cp|, |pp|, and |dp| into...@>=
22767 @<Copy |cp|'s color into the colored objects linked to~|cp|@>;
22768 if ( pp>mp_void ) {
22769   @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>;
22770 }
22771 if ( dp>mp_void ) {
22772   @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>;
22773 }
22774
22775
22776 @ @<Copy |cp|'s color into the colored objects linked to~|cp|@>=
22777 { q=link(cp);
22778   while ( q!=null ) { 
22779     if ( has_color(q) ) {
22780       red_val(q)=red_val(cp);
22781       green_val(q)=green_val(cp);
22782       blue_val(q)=blue_val(cp);
22783       black_val(q)=black_val(cp);
22784       color_model(q)=color_model(cp);
22785     }
22786     q=link(q);
22787   }
22788 }
22789
22790 @ @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>=
22791 { q=link(pp);
22792   while ( q!=null ) {
22793     if ( has_pen(q) ) {
22794       if ( pen_p(q)!=null ) mp_toss_knot_list(mp, pen_p(q));
22795       pen_p(q)=copy_pen(pen_p(pp));
22796     }
22797     q=link(q);
22798   }
22799 }
22800
22801 @ @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>=
22802 { q=link(dp);
22803   while ( q!=null ) {
22804     if ( type(q)==mp_stroked_code ) {
22805       if ( dash_p(q)!=null ) delete_edge_ref(dash_p(q));
22806       dash_p(q)=dash_p(dp);
22807       dash_scale(q)=unity;
22808       if ( dash_p(q)!=null ) add_edge_ref(dash_p(q));
22809     }
22810     q=link(q);
22811   }
22812 }
22813
22814 @ One of the things we need to do when we've parsed an \&{addto} or
22815 similar command is find the header of a supposed \&{picture} variable, given
22816 a token list for that variable.  Since the edge structure is about to be
22817 updated, we use |private_edges| to make sure that this is possible.
22818
22819 @<Declare action procedures for use by |do_statement|@>=
22820 pointer mp_find_edges_var (MP mp, pointer t) ;
22821
22822 @ @c pointer mp_find_edges_var (MP mp, pointer t) {
22823   pointer p;
22824   pointer cur_edges; /* the return value */
22825   p=mp_find_variable(mp, t); cur_edges=null;
22826   if ( p==null ) { 
22827     mp_obliterated(mp, t); mp_put_get_error(mp);
22828   } else if ( type(p)!=mp_picture_type )  { 
22829     print_err("Variable "); mp_show_token_list(mp, t,null,1000,0);
22830 @.Variable x is the wrong type@>
22831     mp_print(mp, " is the wrong type ("); 
22832     mp_print_type(mp, type(p)); mp_print_char(mp, ')');
22833     help2("I was looking for a \"known\" picture variable.")
22834          ("So I'll not change anything just now."); 
22835     mp_put_get_error(mp);
22836   } else { 
22837     value(p)=mp_private_edges(mp, value(p));
22838     cur_edges=value(p);
22839   }
22840   mp_flush_node_list(mp, t);
22841   return cur_edges;
22842 };
22843
22844 @ @<Cases of |do_statement|...@>=
22845 case add_to_command: mp_do_add_to(mp); break;
22846 case bounds_command:mp_do_bounds(mp); break;
22847
22848 @ @<Put each...@>=
22849 mp_primitive(mp, "clip",bounds_command,mp_start_clip_code);
22850 @:clip_}{\&{clip} primitive@>
22851 mp_primitive(mp, "setbounds",bounds_command,mp_start_bounds_code);
22852 @:set_bounds_}{\&{setbounds} primitive@>
22853
22854 @ @<Cases of |print_cmd...@>=
22855 case bounds_command: 
22856   if ( m==mp_start_clip_code ) mp_print(mp, "clip");
22857   else mp_print(mp, "setbounds");
22858   break;
22859
22860 @ The following function parses the beginning of an \&{addto} or \&{clip}
22861 command: it expects a variable name followed by a token with |cur_cmd=sep|
22862 and then an expression.  The function returns the token list for the variable
22863 and stores the command modifier for the separator token in the global variable
22864 |last_add_type|.  We must be careful because this variable might get overwritten
22865 any time we call |get_x_next|.
22866
22867 @<Glob...@>=
22868 quarterword last_add_type;
22869   /* command modifier that identifies the last \&{addto} command */
22870
22871 @ @<Declare action procedures for use by |do_statement|@>=
22872 pointer mp_start_draw_cmd (MP mp,quarterword sep) ;
22873
22874 @ @c pointer mp_start_draw_cmd (MP mp,quarterword sep) {
22875   pointer lhv; /* variable to add to left */
22876   quarterword add_type=0; /* value to be returned in |last_add_type| */
22877   lhv=null;
22878   mp_get_x_next(mp); mp->var_flag=sep; mp_scan_primary(mp);
22879   if ( mp->cur_type!=mp_token_list ) {
22880     @<Abandon edges command because there's no variable@>;
22881   } else  { 
22882     lhv=mp->cur_exp; add_type=mp->cur_mod;
22883     mp->cur_type=mp_vacuous; mp_get_x_next(mp); mp_scan_expression(mp);
22884   }
22885   mp->last_add_type=add_type;
22886   return lhv;
22887 }
22888
22889 @ @<Abandon edges command because there's no variable@>=
22890 { exp_err("Not a suitable variable");
22891 @.Not a suitable variable@>
22892   help4("At this point I needed to see the name of a picture variable.")
22893     ("(Or perhaps you have indeed presented me with one; I might")
22894     ("have missed it, if it wasn't followed by the proper token.)")
22895     ("So I'll not change anything just now.");
22896   mp_put_get_flush_error(mp, 0);
22897 }
22898
22899 @ Here is an example of how to use |start_draw_cmd|.
22900
22901 @<Declare action procedures for use by |do_statement|@>=
22902 void mp_do_bounds (MP mp) ;
22903
22904 @ @c void mp_do_bounds (MP mp) {
22905   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22906   pointer p; /* for list manipulation */
22907   integer m; /* initial value of |cur_mod| */
22908   m=mp->cur_mod;
22909   lhv=mp_start_draw_cmd(mp, to_token);
22910   if ( lhv!=null ) {
22911     lhe=mp_find_edges_var(mp, lhv);
22912     if ( lhe==null ) {
22913       mp_flush_cur_exp(mp, 0);
22914     } else if ( mp->cur_type!=mp_path_type ) {
22915       exp_err("Improper `clip'");
22916 @.Improper `addto'@>
22917       help2("This expression should have specified a known path.")
22918         ("So I'll not change anything just now."); 
22919       mp_put_get_flush_error(mp, 0);
22920     } else if ( left_type(mp->cur_exp)==mp_endpoint ) {
22921       @<Complain about a non-cycle@>;
22922     } else {
22923       @<Make |cur_exp| into a \&{setbounds} or clipping path and add it to |lhe|@>;
22924     }
22925   }
22926 }
22927
22928 @ @<Complain about a non-cycle@>=
22929 { print_err("Not a cycle");
22930 @.Not a cycle@>
22931   help2("That contour should have ended with `..cycle' or `&cycle'.")
22932     ("So I'll not change anything just now."); mp_put_get_error(mp);
22933 }
22934
22935 @ @<Make |cur_exp| into a \&{setbounds} or clipping path and add...@>=
22936 { p=mp_new_bounds_node(mp, mp->cur_exp,m);
22937   link(p)=link(dummy_loc(lhe));
22938   link(dummy_loc(lhe))=p;
22939   if ( obj_tail(lhe)==dummy_loc(lhe) ) obj_tail(lhe)=p;
22940   p=mp_get_node(mp, mp->gr_object_size[stop_type(m)]);
22941   type(p)=stop_type(m);
22942   link(obj_tail(lhe))=p;
22943   obj_tail(lhe)=p;
22944   mp_init_bbox(mp, lhe);
22945 }
22946
22947 @ The |do_add_to| procedure is a little like |do_clip| but there are a lot more
22948 cases to deal with.
22949
22950 @<Declare action procedures for use by |do_statement|@>=
22951 void mp_do_add_to (MP mp) ;
22952
22953 @ @c void mp_do_add_to (MP mp) {
22954   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22955   pointer p; /* the graphical object or list for |scan_with_list| to update */
22956   pointer e; /* an edge structure to be merged */
22957   quarterword add_type; /* |also_code|, |contour_code|, or |double_path_code| */
22958   lhv=mp_start_draw_cmd(mp, thing_to_add); add_type=mp->last_add_type;
22959   if ( lhv!=null ) {
22960     if ( add_type==also_code ) {
22961       @<Make sure the current expression is a suitable picture and set |e| and |p|
22962        appropriately@>;
22963     } else {
22964       @<Create a graphical object |p| based on |add_type| and the current
22965         expression@>;
22966     }
22967     mp_scan_with_list(mp, p);
22968     @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>;
22969   }
22970 }
22971
22972 @ Setting |p:=null| causes the $\langle$with list$\rangle$ to be ignored;
22973 setting |e:=null| prevents anything from being added to |lhe|.
22974
22975 @ @<Make sure the current expression is a suitable picture and set |e|...@>=
22976
22977   p=null; e=null;
22978   if ( mp->cur_type!=mp_picture_type ) {
22979     exp_err("Improper `addto'");
22980 @.Improper `addto'@>
22981     help2("This expression should have specified a known picture.")
22982       ("So I'll not change anything just now."); mp_put_get_flush_error(mp, 0);
22983   } else { 
22984     e=mp_private_edges(mp, mp->cur_exp); mp->cur_type=mp_vacuous;
22985     p=link(dummy_loc(e));
22986   }
22987 }
22988
22989 @ In this case |add_type<>also_code| so setting |p:=null| suppresses future
22990 attempts to add to the edge structure.
22991
22992 @<Create a graphical object |p| based on |add_type| and the current...@>=
22993 { e=null; p=null;
22994   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
22995   if ( mp->cur_type!=mp_path_type ) {
22996     exp_err("Improper `addto'");
22997 @.Improper `addto'@>
22998     help2("This expression should have specified a known path.")
22999       ("So I'll not change anything just now."); 
23000     mp_put_get_flush_error(mp, 0);
23001   } else if ( add_type==contour_code ) {
23002     if ( left_type(mp->cur_exp)==mp_endpoint ) {
23003       @<Complain about a non-cycle@>;
23004     } else { 
23005       p=mp_new_fill_node(mp, mp->cur_exp);
23006       mp->cur_type=mp_vacuous;
23007     }
23008   } else { 
23009     p=mp_new_stroked_node(mp, mp->cur_exp);
23010     mp->cur_type=mp_vacuous;
23011   }
23012 }
23013
23014 @ @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>=
23015 lhe=mp_find_edges_var(mp, lhv);
23016 if ( lhe==null ) {
23017   if ( (e==null)&&(p!=null) ) e=mp_toss_gr_object(mp, p);
23018   if ( e!=null ) delete_edge_ref(e);
23019 } else if ( add_type==also_code ) {
23020   if ( e!=null ) {
23021     @<Merge |e| into |lhe| and delete |e|@>;
23022   } else { 
23023     do_nothing;
23024   }
23025 } else if ( p!=null ) {
23026   link(obj_tail(lhe))=p;
23027   obj_tail(lhe)=p;
23028   if ( add_type==double_path_code )
23029     if ( pen_p(p)==null ) 
23030       pen_p(p)=mp_get_pen_circle(mp, 0);
23031 }
23032
23033 @ @<Merge |e| into |lhe| and delete |e|@>=
23034 { if ( link(dummy_loc(e))!=null ) {
23035     link(obj_tail(lhe))=link(dummy_loc(e));
23036     obj_tail(lhe)=obj_tail(e);
23037     obj_tail(e)=dummy_loc(e);
23038     link(dummy_loc(e))=null;
23039     mp_flush_dash_list(mp, lhe);
23040   }
23041   mp_toss_edges(mp, e);
23042 }
23043
23044 @ @<Cases of |do_statement|...@>=
23045 case ship_out_command: mp_do_ship_out(mp); break;
23046
23047 @ @<Declare action procedures for use by |do_statement|@>=
23048 @<Declare the function called |tfm_check|@>;
23049 @<Declare the \ps\ output procedures@>;
23050 void mp_do_ship_out (MP mp) ;
23051
23052 @ @c void mp_do_ship_out (MP mp) {
23053   integer c; /* the character code */
23054   mp_get_x_next(mp); mp_scan_expression(mp);
23055   if ( mp->cur_type!=mp_picture_type ) {
23056     @<Complain that it's not a known picture@>;
23057   } else { 
23058     c=mp_round_unscaled(mp, mp->internal[mp_char_code]) % 256;
23059     if ( c<0 ) c=c+256;
23060     @<Store the width information for character code~|c|@>;
23061     mp_ship_out(mp, mp->cur_exp);
23062     mp_flush_cur_exp(mp, 0);
23063   }
23064 }
23065
23066 @ @<Complain that it's not a known picture@>=
23067
23068   exp_err("Not a known picture");
23069   help1("I can only output known pictures.");
23070   mp_put_get_flush_error(mp, 0);
23071 }
23072
23073 @ The \&{everyjob} command simply assigns a nonzero value to the global variable
23074 |start_sym|.
23075
23076 @<Cases of |do_statement|...@>=
23077 case every_job_command: 
23078   mp_get_symbol(mp); mp->start_sym=mp->cur_sym; mp_get_x_next(mp);
23079   break;
23080
23081 @ @<Glob...@>=
23082 halfword start_sym; /* a symbolic token to insert at beginning of job */
23083
23084 @ @<Set init...@>=
23085 mp->start_sym=0;
23086
23087 @ Finally, we have only the ``message'' commands remaining.
23088
23089 @d message_code 0
23090 @d err_message_code 1
23091 @d err_help_code 2
23092 @d filename_template_code 3
23093 @d print_with_leading_zeroes(A)  g = mp->pool_ptr;
23094               mp_print_int(mp, (A)); g = mp->pool_ptr-g;
23095               if ( f>g ) {
23096                 mp->pool_ptr = mp->pool_ptr - g;
23097                 while ( f>g ) {
23098                   mp_print_char(mp, '0');
23099                   decr(f);
23100                   };
23101                 mp_print_int(mp, (A));
23102               };
23103               f = 0
23104
23105 @<Put each...@>=
23106 mp_primitive(mp, "message",message_command,message_code);
23107 @:message_}{\&{message} primitive@>
23108 mp_primitive(mp, "errmessage",message_command,err_message_code);
23109 @:err_message_}{\&{errmessage} primitive@>
23110 mp_primitive(mp, "errhelp",message_command,err_help_code);
23111 @:err_help_}{\&{errhelp} primitive@>
23112 mp_primitive(mp, "filenametemplate",message_command,filename_template_code);
23113 @:filename_template_}{\&{filenametemplate} primitive@>
23114
23115 @ @<Cases of |print_cmd...@>=
23116 case message_command: 
23117   if ( m<err_message_code ) mp_print(mp, "message");
23118   else if ( m==err_message_code ) mp_print(mp, "errmessage");
23119   else if ( m==filename_template_code ) mp_print(mp, "filenametemplate");
23120   else mp_print(mp, "errhelp");
23121   break;
23122
23123 @ @<Cases of |do_statement|...@>=
23124 case message_command: mp_do_message(mp); break;
23125
23126 @ @<Declare action procedures for use by |do_statement|@>=
23127 @<Declare a procedure called |no_string_err|@>;
23128 void mp_do_message (MP mp) ;
23129
23130
23131 @c void mp_do_message (MP mp) {
23132   int m; /* the type of message */
23133   m=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
23134   if ( mp->cur_type!=mp_string_type )
23135     mp_no_string_err(mp, "A message should be a known string expression.");
23136   else {
23137     switch (m) {
23138     case message_code: 
23139       mp_print_nl(mp, ""); mp_print_str(mp, mp->cur_exp);
23140       break;
23141     case err_message_code:
23142       @<Print string |cur_exp| as an error message@>;
23143       break;
23144     case err_help_code:
23145       @<Save string |cur_exp| as the |err_help|@>;
23146       break;
23147     case filename_template_code:
23148       @<Save the filename template@>;
23149       break;
23150     } /* there are no other cases */
23151   }
23152   mp_flush_cur_exp(mp, 0);
23153 }
23154
23155 @ @<Declare a procedure called |no_string_err|@>=
23156 void mp_no_string_err (MP mp,char *s) { 
23157    exp_err("Not a string");
23158 @.Not a string@>
23159   help1(s);
23160   mp_put_get_error(mp);
23161 }
23162
23163 @ The global variable |err_help| is zero when the user has most recently
23164 given an empty help string, or if none has ever been given.
23165
23166 @<Save string |cur_exp| as the |err_help|@>=
23167
23168   if ( mp->err_help!=0 ) delete_str_ref(mp->err_help);
23169   if ( length(mp->cur_exp)==0 ) mp->err_help=0;
23170   else  { mp->err_help=mp->cur_exp; add_str_ref(mp->err_help); }
23171 }
23172
23173 @ If \&{errmessage} occurs often in |mp_scroll_mode|, without user-defined
23174 \&{errhelp}, we don't want to give a long help message each time. So we
23175 give a verbose explanation only once.
23176
23177 @<Glob...@>=
23178 boolean long_help_seen; /* has the long \.{\\errmessage} help been used? */
23179
23180 @ @<Set init...@>=mp->long_help_seen=false;
23181
23182 @ @<Print string |cur_exp| as an error message@>=
23183
23184   print_err(""); mp_print_str(mp, mp->cur_exp);
23185   if ( mp->err_help!=0 ) {
23186     mp->use_err_help=true;
23187   } else if ( mp->long_help_seen ) { 
23188     help1("(That was another `errmessage'.)") ; 
23189   } else  { 
23190    if ( mp->interaction<mp_error_stop_mode ) mp->long_help_seen=true;
23191     help4("This error message was generated by an `errmessage'")
23192      ("command, so I can\'t give any explicit help.")
23193      ("Pretend that you're Miss Marple: Examine all clues,")
23194 @^Marple, Jane@>
23195      ("and deduce the truth by inspired guesses.");
23196   }
23197   mp_put_get_error(mp); mp->use_err_help=false;
23198 }
23199
23200 @ @<Cases of |do_statement|...@>=
23201 case write_command: mp_do_write(mp); break;
23202
23203 @ @<Declare action procedures for use by |do_statement|@>=
23204 void mp_do_write (MP mp) ;
23205
23206 @ @c void mp_do_write (MP mp) {
23207   str_number t; /* the line of text to be written */
23208   write_index n,n0; /* for searching |wr_fname| and |wr_file| arrays */
23209   int old_setting; /* for saving |selector| during output */
23210   mp_get_x_next(mp);
23211   mp_scan_expression(mp);
23212   if ( mp->cur_type!=mp_string_type ) {
23213     mp_no_string_err(mp, "The text to be written should be a known string expression");
23214   } else if ( mp->cur_cmd!=to_token ) { 
23215     print_err("Missing `to' clause");
23216     help1("A write command should end with `to <filename>'");
23217     mp_put_get_error(mp);
23218   } else { 
23219     t=mp->cur_exp; mp->cur_type=mp_vacuous;
23220     mp_get_x_next(mp);
23221     mp_scan_expression(mp);
23222     if ( mp->cur_type!=mp_string_type )
23223       mp_no_string_err(mp, "I can\'t write to that file name.  It isn't a known string");
23224     else {
23225       @<Write |t| to the file named by |cur_exp|@>;
23226     }
23227     delete_str_ref(t);
23228   }
23229   mp_flush_cur_exp(mp, 0);
23230 }
23231
23232 @ @<Write |t| to the file named by |cur_exp|@>=
23233
23234   @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if
23235     |cur_exp| must be inserted@>;
23236   if ( mp_str_vs_str(mp, t,mp->eof_line)==0 ) {
23237     @<Record the end of file on |wr_file[n]|@>;
23238   } else { 
23239     old_setting=mp->selector;
23240     mp->selector=n+write_file;
23241     mp_print_str(mp, t); mp_print_ln(mp);
23242     mp->selector = old_setting;
23243   }
23244 }
23245
23246 @ @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if...@>=
23247 {
23248   char *fn = str(mp->cur_exp);
23249   n=mp->write_files;
23250   n0=mp->write_files;
23251   while (mp_xstrcmp(fn,mp->wr_fname[n])!=0) { 
23252     if ( n==0 ) { /* bottom reached */
23253           if ( n0==mp->write_files ) {
23254         if ( mp->write_files<mp->max_write_files ) {
23255           incr(mp->write_files);
23256         } else {
23257           void **wr_file;
23258           char **wr_fname;
23259               write_index l,k;
23260           l = mp->max_write_files + (mp->max_write_files>>2);
23261           wr_file = xmalloc((l+1),sizeof(void *));
23262           wr_fname = xmalloc((l+1),sizeof(char *));
23263               for (k=0;k<=l;k++) {
23264             if (k<=mp->max_write_files) {
23265                   wr_file[k]=mp->wr_file[k]; 
23266               wr_fname[k]=mp->wr_fname[k];
23267             } else {
23268                   wr_file[k]=0; 
23269               wr_fname[k]=NULL;
23270             }
23271           }
23272               xfree(mp->wr_file); xfree(mp->wr_fname);
23273           mp->max_write_files = l;
23274           mp->wr_file = wr_file;
23275           mp->wr_fname = wr_fname;
23276         }
23277       }
23278       n=n0;
23279       mp_open_write_file(mp, fn ,n);
23280     } else { 
23281       decr(n);
23282           if ( mp->wr_fname[n]==NULL )  n0=n; 
23283     }
23284   }
23285 }
23286
23287 @ @<Record the end of file on |wr_file[n]|@>=
23288 { (mp->close_file)(mp->wr_file[n]);
23289   xfree(mp->wr_fname[n]);
23290   mp->wr_fname[n]=NULL;
23291   if ( n==mp->write_files-1 ) mp->write_files=n;
23292 }
23293
23294
23295 @* \[42] Writing font metric data.
23296 \TeX\ gets its knowledge about fonts from font metric files, also called
23297 \.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
23298 but other programs know about them too. One of \MP's duties is to
23299 write \.{TFM} files so that the user's fonts can readily be
23300 applied to typesetting.
23301 @:TFM files}{\.{TFM} files@>
23302 @^font metric files@>
23303
23304 The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
23305 Since the number of bytes is always a multiple of~4, we could
23306 also regard the file as a sequence of 32-bit words, but \MP\ uses the
23307 byte interpretation. The format of \.{TFM} files was designed by
23308 Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
23309 @^Ramshaw, Lyle Harold@>
23310 of information in a compact but useful form.
23311
23312 @<Glob...@>=
23313 void * tfm_file; /* the font metric output goes here */
23314 char * metric_file_name; /* full name of the font metric file */
23315
23316 @ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
23317 integers that give the lengths of the various subsequent portions
23318 of the file. These twelve integers are, in order:
23319 $$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
23320 |lf|&length of the entire file, in words;\cr
23321 |lh|&length of the header data, in words;\cr
23322 |bc|&smallest character code in the font;\cr
23323 |ec|&largest character code in the font;\cr
23324 |nw|&number of words in the width table;\cr
23325 |nh|&number of words in the height table;\cr
23326 |nd|&number of words in the depth table;\cr
23327 |ni|&number of words in the italic correction table;\cr
23328 |nl|&number of words in the lig/kern table;\cr
23329 |nk|&number of words in the kern table;\cr
23330 |ne|&number of words in the extensible character table;\cr
23331 |np|&number of font parameter words.\cr}}$$
23332 They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
23333 |ne<=256|, and
23334 $$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
23335 Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
23336 and as few as 0 characters (if |bc=ec+1|).
23337
23338 Incidentally, when two or more 8-bit bytes are combined to form an integer of
23339 16 or more bits, the most significant bytes appear first in the file.
23340 This is called BigEndian order.
23341 @^BigEndian order@>
23342
23343 @ The rest of the \.{TFM} file may be regarded as a sequence of ten data
23344 arrays.
23345
23346 The most important data type used here is a |fix_word|, which is
23347 a 32-bit representation of a binary fraction. A |fix_word| is a signed
23348 quantity, with the two's complement of the entire word used to represent
23349 negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
23350 binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
23351 the smallest is $-2048$. We will see below, however, that all but two of
23352 the |fix_word| values must lie between $-16$ and $+16$.
23353
23354 @ The first data array is a block of header information, which contains
23355 general facts about the font. The header must contain at least two words,
23356 |header[0]| and |header[1]|, whose meaning is explained below.  Additional
23357 header information of use to other software routines might also be
23358 included, and \MP\ will generate it if the \.{headerbyte} command occurs.
23359 For example, 16 more words of header information are in use at the Xerox
23360 Palo Alto Research Center; the first ten specify the character coding
23361 scheme used (e.g., `\.{XEROX TEXT}' or `\.{TEX MATHSY}'), the next five
23362 give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
23363 last gives the ``face byte.''
23364
23365 \yskip\hang|header[0]| is a 32-bit check sum that \MP\ will copy into
23366 the \.{GF} output file. This helps ensure consistency between files,
23367 since \TeX\ records the check sums from the \.{TFM}'s it reads, and these
23368 should match the check sums on actual fonts that are used.  The actual
23369 relation between this check sum and the rest of the \.{TFM} file is not
23370 important; the check sum is simply an identification number with the
23371 property that incompatible fonts almost always have distinct check sums.
23372 @^check sum@>
23373
23374 \yskip\hang|header[1]| is a |fix_word| containing the design size of the
23375 font, in units of \TeX\ points. This number must be at least 1.0; it is
23376 fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
23377 font, i.e., a font that was designed to look best at a 10-point size,
23378 whatever that really means. When a \TeX\ user asks for a font `\.{at}
23379 $\delta$ \.{pt}', the effect is to override the design size and replace it
23380 by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in
23381 the font image by a factor of $\delta$ divided by the design size.  {\sl
23382 All other dimensions in the\/ \.{TFM} file are |fix_word|\kern-1pt\
23383 numbers in design-size units.} Thus, for example, the value of |param[6]|,
23384 which defines the \.{em} unit, is often the |fix_word| value $2^{20}=1.0$,
23385 since many fonts have a design size equal to one em.  The other dimensions
23386 must be less than 16 design-size units in absolute value; thus,
23387 |header[1]| and |param[1]| are the only |fix_word| entries in the whole
23388 \.{TFM} file whose first byte might be something besides 0 or 255.
23389
23390 @ Next comes the |char_info| array, which contains one |char_info_word|
23391 per character. Each word in this part of the file contains six fields
23392 packed into four bytes as follows.
23393
23394 \yskip\hang first byte: |width_index| (8 bits)\par
23395 \hang second byte: |height_index| (4 bits) times 16, plus |depth_index|
23396   (4~bits)\par
23397 \hang third byte: |italic_index| (6 bits) times 4, plus |tag|
23398   (2~bits)\par
23399 \hang fourth byte: |remainder| (8 bits)\par
23400 \yskip\noindent
23401 The actual width of a character is \\{width}|[width_index]|, in design-size
23402 units; this is a device for compressing information, since many characters
23403 have the same width. Since it is quite common for many characters
23404 to have the same height, depth, or italic correction, the \.{TFM} format
23405 imposes a limit of 16 different heights, 16 different depths, and
23406 64 different italic corrections.
23407
23408 Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
23409 \\{italic}[0]=0$ should always hold, so that an index of zero implies a
23410 value of zero.  The |width_index| should never be zero unless the
23411 character does not exist in the font, since a character is valid if and
23412 only if it lies between |bc| and |ec| and has a nonzero |width_index|.
23413
23414 @ The |tag| field in a |char_info_word| has four values that explain how to
23415 interpret the |remainder| field.
23416
23417 \yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
23418 \hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
23419 program starting at location |remainder| in the |lig_kern| array.\par
23420 \hang|tag=2| (|list_tag|) means that this character is part of a chain of
23421 characters of ascending sizes, and not the largest in the chain.  The
23422 |remainder| field gives the character code of the next larger character.\par
23423 \hang|tag=3| (|ext_tag|) means that this character code represents an
23424 extensible character, i.e., a character that is built up of smaller pieces
23425 so that it can be made arbitrarily large. The pieces are specified in
23426 |exten[remainder]|.\par
23427 \yskip\noindent
23428 Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
23429 unless they are used in special circumstances in math formulas. For example,
23430 \TeX's \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
23431 operation looks for both |list_tag| and |ext_tag|.
23432
23433 @d no_tag 0 /* vanilla character */
23434 @d lig_tag 1 /* character has a ligature/kerning program */
23435 @d list_tag 2 /* character has a successor in a charlist */
23436 @d ext_tag 3 /* character is extensible */
23437
23438 @ The |lig_kern| array contains instructions in a simple programming language
23439 that explains what to do for special letter pairs. Each word in this array is a
23440 |lig_kern_command| of four bytes.
23441
23442 \yskip\hang first byte: |skip_byte|, indicates that this is the final program
23443   step if the byte is 128 or more, otherwise the next step is obtained by
23444   skipping this number of intervening steps.\par
23445 \hang second byte: |next_char|, ``if |next_char| follows the current character,
23446   then perform the operation and stop, otherwise continue.''\par
23447 \hang third byte: |op_byte|, indicates a ligature step if less than~128,
23448   a kern step otherwise.\par
23449 \hang fourth byte: |remainder|.\par
23450 \yskip\noindent
23451 In a kern step, an
23452 additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
23453 between the current character and |next_char|. This amount is
23454 often negative, so that the characters are brought closer together
23455 by kerning; but it might be positive.
23456
23457 There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
23458 $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
23459 |remainder| is inserted between the current character and |next_char|;
23460 then the current character is deleted if $b=0$, and |next_char| is
23461 deleted if $c=0$; then we pass over $a$~characters to reach the next
23462 current character (which may have a ligature/kerning program of its own).
23463
23464 If the very first instruction of the |lig_kern| array has |skip_byte=255|,
23465 the |next_char| byte is the so-called right boundary character of this font;
23466 the value of |next_char| need not lie between |bc| and~|ec|.
23467 If the very last instruction of the |lig_kern| array has |skip_byte=255|,
23468 there is a special ligature/kerning program for a left boundary character,
23469 beginning at location |256*op_byte+remainder|.
23470 The interpretation is that \TeX\ puts implicit boundary characters
23471 before and after each consecutive string of characters from the same font.
23472 These implicit characters do not appear in the output, but they can affect
23473 ligatures and kerning.
23474
23475 If the very first instruction of a character's |lig_kern| program has
23476 |skip_byte>128|, the program actually begins in location
23477 |256*op_byte+remainder|. This feature allows access to large |lig_kern|
23478 arrays, because the first instruction must otherwise
23479 appear in a location |<=255|.
23480
23481 Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
23482 the condition
23483 $$\hbox{|256*op_byte+remainder<nl|.}$$
23484 If such an instruction is encountered during
23485 normal program execution, it denotes an unconditional halt; no ligature
23486 command is performed.
23487
23488 @d stop_flag (128)
23489   /* value indicating `\.{STOP}' in a lig/kern program */
23490 @d kern_flag (128) /* op code for a kern step */
23491 @d skip_byte(A) mp->lig_kern[(A)].b0
23492 @d next_char(A) mp->lig_kern[(A)].b1
23493 @d op_byte(A) mp->lig_kern[(A)].b2
23494 @d rem_byte(A) mp->lig_kern[(A)].b3
23495
23496 @ Extensible characters are specified by an |extensible_recipe|, which
23497 consists of four bytes called |top|, |mid|, |bot|, and |rep| (in this
23498 order). These bytes are the character codes of individual pieces used to
23499 build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
23500 present in the built-up result. For example, an extensible vertical line is
23501 like an extensible bracket, except that the top and bottom pieces are missing.
23502
23503 Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
23504 if the piece isn't present. Then the extensible characters have the form
23505 $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
23506 in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
23507 The width of the extensible character is the width of $R$; and the
23508 height-plus-depth is the sum of the individual height-plus-depths of the
23509 components used, since the pieces are butted together in a vertical list.
23510
23511 @d ext_top(A) mp->exten[(A)].b0 /* |top| piece in a recipe */
23512 @d ext_mid(A) mp->exten[(A)].b1 /* |mid| piece in a recipe */
23513 @d ext_bot(A) mp->exten[(A)].b2 /* |bot| piece in a recipe */
23514 @d ext_rep(A) mp->exten[(A)].b3 /* |rep| piece in a recipe */
23515
23516 @ The final portion of a \.{TFM} file is the |param| array, which is another
23517 sequence of |fix_word| values.
23518
23519 \yskip\hang|param[1]=slant| is the amount of italic slant, which is used
23520 to help position accents. For example, |slant=.25| means that when you go
23521 up one unit, you also go .25 units to the right. The |slant| is a pure
23522 number; it is the only |fix_word| other than the design size itself that is
23523 not scaled by the design size.
23524
23525 \hang|param[2]=space| is the normal spacing between words in text.
23526 Note that character 040 in the font need not have anything to do with
23527 blank spaces.
23528
23529 \hang|param[3]=space_stretch| is the amount of glue stretching between words.
23530
23531 \hang|param[4]=space_shrink| is the amount of glue shrinking between words.
23532
23533 \hang|param[5]=x_height| is the size of one ex in the font; it is also
23534 the height of letters for which accents don't have to be raised or lowered.
23535
23536 \hang|param[6]=quad| is the size of one em in the font.
23537
23538 \hang|param[7]=extra_space| is the amount added to |param[2]| at the
23539 ends of sentences.
23540
23541 \yskip\noindent
23542 If fewer than seven parameters are present, \TeX\ sets the missing parameters
23543 to zero.
23544
23545 @d slant_code 1
23546 @d space_code 2
23547 @d space_stretch_code 3
23548 @d space_shrink_code 4
23549 @d x_height_code 5
23550 @d quad_code 6
23551 @d extra_space_code 7
23552
23553 @ So that is what \.{TFM} files hold. One of \MP's duties is to output such
23554 information, and it does this all at once at the end of a job.
23555 In order to prepare for such frenetic activity, it squirrels away the
23556 necessary facts in various arrays as information becomes available.
23557
23558 Character dimensions (\&{charwd}, \&{charht}, \&{chardp}, and \&{charic})
23559 are stored respectively in |tfm_width|, |tfm_height|, |tfm_depth|, and
23560 |tfm_ital_corr|. Other information about a character (e.g., about
23561 its ligatures or successors) is accessible via the |char_tag| and
23562 |char_remainder| arrays. Other information about the font as a whole
23563 is kept in additional arrays called |header_byte|, |lig_kern|,
23564 |kern|, |exten|, and |param|.
23565
23566 @d max_tfm_int 32510
23567 @d undefined_label max_tfm_int /* an undefined local label */
23568
23569 @<Glob...@>=
23570 #define TFM_ITEMS 257
23571 eight_bits bc;
23572 eight_bits ec; /* smallest and largest character codes shipped out */
23573 scaled tfm_width[TFM_ITEMS]; /* \&{charwd} values */
23574 scaled tfm_height[TFM_ITEMS]; /* \&{charht} values */
23575 scaled tfm_depth[TFM_ITEMS]; /* \&{chardp} values */
23576 scaled tfm_ital_corr[TFM_ITEMS]; /* \&{charic} values */
23577 boolean char_exists[TFM_ITEMS]; /* has this code been shipped out? */
23578 int char_tag[TFM_ITEMS]; /* |remainder| category */
23579 int char_remainder[TFM_ITEMS]; /* the |remainder| byte */
23580 char *header_byte; /* bytes of the \.{TFM} header */
23581 int header_last; /* last initialized \.{TFM} header byte */
23582 int header_size; /* size of the \.{TFM} header */
23583 four_quarters *lig_kern; /* the ligature/kern table */
23584 short nl; /* the number of ligature/kern steps so far */
23585 scaled *kern; /* distinct kerning amounts */
23586 short nk; /* the number of distinct kerns so far */
23587 four_quarters exten[TFM_ITEMS]; /* extensible character recipes */
23588 short ne; /* the number of extensible characters so far */
23589 scaled *param; /* \&{fontinfo} parameters */
23590 short np; /* the largest \&{fontinfo} parameter specified so far */
23591 short nw;short nh;short nd;short ni; /* sizes of \.{TFM} subtables */
23592 short skip_table[TFM_ITEMS]; /* local label status */
23593 boolean lk_started; /* has there been a lig/kern step in this command yet? */
23594 integer bchar; /* right boundary character */
23595 short bch_label; /* left boundary starting location */
23596 short ll;short lll; /* registers used for lig/kern processing */
23597 short label_loc[257]; /* lig/kern starting addresses */
23598 eight_bits label_char[257]; /* characters for |label_loc| */
23599 short label_ptr; /* highest position occupied in |label_loc| */
23600
23601 @ @<Allocate or initialize ...@>=
23602 mp->header_last = 0; mp->header_size = 128; /* just for init */
23603 mp->header_byte = xmalloc(mp->header_size, sizeof(char));
23604 mp->lig_kern = NULL; /* allocated when needed */
23605 mp->kern = NULL; /* allocated when needed */ 
23606 mp->param = NULL; /* allocated when needed */
23607
23608 @ @<Dealloc variables@>=
23609 xfree(mp->header_byte);
23610 xfree(mp->lig_kern);
23611 xfree(mp->kern);
23612 xfree(mp->param);
23613
23614 @ @<Set init...@>=
23615 for (k=0;k<= 255;k++ ) {
23616   mp->tfm_width[k]=0; mp->tfm_height[k]=0; mp->tfm_depth[k]=0; mp->tfm_ital_corr[k]=0;
23617   mp->char_exists[k]=false; mp->char_tag[k]=no_tag; mp->char_remainder[k]=0;
23618   mp->skip_table[k]=undefined_label;
23619 };
23620 memset(mp->header_byte,0,mp->header_size);
23621 mp->bc=255; mp->ec=0; mp->nl=0; mp->nk=0; mp->ne=0; mp->np=0;
23622 mp->internal[mp_boundary_char]=-unity;
23623 mp->bch_label=undefined_label;
23624 mp->label_loc[0]=-1; mp->label_ptr=0;
23625
23626 @ @<Declarations@>=
23627 scaled mp_tfm_check (MP mp,small_number m) ;
23628
23629 @ @<Declare the function called |tfm_check|@>=
23630 scaled mp_tfm_check (MP mp,small_number m) {
23631   if ( abs(mp->internal[m])>=fraction_half ) {
23632     print_err("Enormous "); mp_print(mp, mp->int_name[m]);
23633 @.Enormous charwd...@>
23634 @.Enormous chardp...@>
23635 @.Enormous charht...@>
23636 @.Enormous charic...@>
23637 @.Enormous designsize...@>
23638     mp_print(mp, " has been reduced");
23639     help1("Font metric dimensions must be less than 2048pt.");
23640     mp_put_get_error(mp);
23641     if ( mp->internal[m]>0 ) return (fraction_half-1);
23642     else return (1-fraction_half);
23643   } else {
23644     return mp->internal[m];
23645   }
23646 }
23647
23648 @ @<Store the width information for character code~|c|@>=
23649 if ( c<mp->bc ) mp->bc=c;
23650 if ( c>mp->ec ) mp->ec=c;
23651 mp->char_exists[c]=true;
23652 mp->tfm_width[c]=mp_tfm_check(mp, mp_char_wd);
23653 mp->tfm_height[c]=mp_tfm_check(mp, mp_char_ht);
23654 mp->tfm_depth[c]=mp_tfm_check(mp, mp_char_dp);
23655 mp->tfm_ital_corr[c]=mp_tfm_check(mp, mp_char_ic)
23656
23657 @ Now let's consider \MP's special \.{TFM}-oriented commands.
23658
23659 @<Cases of |do_statement|...@>=
23660 case tfm_command: mp_do_tfm_command(mp); break;
23661
23662 @ @d char_list_code 0
23663 @d lig_table_code 1
23664 @d extensible_code 2
23665 @d header_byte_code 3
23666 @d font_dimen_code 4
23667
23668 @<Put each...@>=
23669 mp_primitive(mp, "charlist",tfm_command,char_list_code);
23670 @:char_list_}{\&{charlist} primitive@>
23671 mp_primitive(mp, "ligtable",tfm_command,lig_table_code);
23672 @:lig_table_}{\&{ligtable} primitive@>
23673 mp_primitive(mp, "extensible",tfm_command,extensible_code);
23674 @:extensible_}{\&{extensible} primitive@>
23675 mp_primitive(mp, "headerbyte",tfm_command,header_byte_code);
23676 @:header_byte_}{\&{headerbyte} primitive@>
23677 mp_primitive(mp, "fontdimen",tfm_command,font_dimen_code);
23678 @:font_dimen_}{\&{fontdimen} primitive@>
23679
23680 @ @<Cases of |print_cmd...@>=
23681 case tfm_command: 
23682   switch (m) {
23683   case char_list_code:mp_print(mp, "charlist"); break;
23684   case lig_table_code:mp_print(mp, "ligtable"); break;
23685   case extensible_code:mp_print(mp, "extensible"); break;
23686   case header_byte_code:mp_print(mp, "headerbyte"); break;
23687   default: mp_print(mp, "fontdimen"); break;
23688   }
23689   break;
23690
23691 @ @<Declare action procedures for use by |do_statement|@>=
23692 eight_bits mp_get_code (MP mp) ;
23693
23694 @ @c eight_bits mp_get_code (MP mp) { /* scans a character code value */
23695   integer c; /* the code value found */
23696   mp_get_x_next(mp); mp_scan_expression(mp);
23697   if ( mp->cur_type==mp_known ) { 
23698     c=mp_round_unscaled(mp, mp->cur_exp);
23699     if ( c>=0 ) if ( c<256 ) return c;
23700   } else if ( mp->cur_type==mp_string_type ) {
23701     if ( length(mp->cur_exp)==1 )  { 
23702       c=mp->str_pool[mp->str_start[mp->cur_exp]];
23703       return c;
23704     }
23705   }
23706   exp_err("Invalid code has been replaced by 0");
23707 @.Invalid code...@>
23708   help2("I was looking for a number between 0 and 255, or for a")
23709        ("string of length 1. Didn't find it; will use 0 instead.");
23710   mp_put_get_flush_error(mp, 0); c=0;
23711   return c;
23712 };
23713
23714 @ @<Declare action procedures for use by |do_statement|@>=
23715 void mp_set_tag (MP mp,halfword c, small_number t, halfword r) ;
23716
23717 @ @c void mp_set_tag (MP mp,halfword c, small_number t, halfword r) { 
23718   if ( mp->char_tag[c]==no_tag ) {
23719     mp->char_tag[c]=t; mp->char_remainder[c]=r;
23720     if ( t==lig_tag ){ 
23721       incr(mp->label_ptr); mp->label_loc[mp->label_ptr]=r; 
23722       mp->label_char[mp->label_ptr]=c;
23723     }
23724   } else {
23725     @<Complain about a character tag conflict@>;
23726   }
23727 }
23728
23729 @ @<Complain about a character tag conflict@>=
23730
23731   print_err("Character ");
23732   if ( (c>' ')&&(c<127) ) mp_print_char(mp,c);
23733   else if ( c==256 ) mp_print(mp, "||");
23734   else  { mp_print(mp, "code "); mp_print_int(mp, c); };
23735   mp_print(mp, " is already ");
23736 @.Character c is already...@>
23737   switch (mp->char_tag[c]) {
23738   case lig_tag: mp_print(mp, "in a ligtable"); break;
23739   case list_tag: mp_print(mp, "in a charlist"); break;
23740   case ext_tag: mp_print(mp, "extensible"); break;
23741   } /* there are no other cases */
23742   help2("It's not legal to label a character more than once.")
23743     ("So I'll not change anything just now.");
23744   mp_put_get_error(mp); 
23745 }
23746
23747 @ @<Declare action procedures for use by |do_statement|@>=
23748 void mp_do_tfm_command (MP mp) ;
23749
23750 @ @c void mp_do_tfm_command (MP mp) {
23751   int c,cc; /* character codes */
23752   int k; /* index into the |kern| array */
23753   int j; /* index into |header_byte| or |param| */
23754   switch (mp->cur_mod) {
23755   case char_list_code: 
23756     c=mp_get_code(mp);
23757      /* we will store a list of character successors */
23758     while ( mp->cur_cmd==colon )   { 
23759       cc=mp_get_code(mp); mp_set_tag(mp, c,list_tag,cc); c=cc;
23760     };
23761     break;
23762   case lig_table_code: 
23763     if (mp->lig_kern==NULL) 
23764        mp->lig_kern = xmalloc((max_tfm_int+1),sizeof(four_quarters));
23765     if (mp->kern==NULL) 
23766        mp->kern = xmalloc((max_tfm_int+1),sizeof(scaled));
23767     @<Store a list of ligature/kern steps@>;
23768     break;
23769   case extensible_code: 
23770     @<Define an extensible recipe@>;
23771     break;
23772   case header_byte_code: 
23773   case font_dimen_code: 
23774     c=mp->cur_mod; mp_get_x_next(mp);
23775     mp_scan_expression(mp);
23776     if ( (mp->cur_type!=mp_known)||(mp->cur_exp<half_unit) ) {
23777       exp_err("Improper location");
23778 @.Improper location@>
23779       help2("I was looking for a known, positive number.")
23780        ("For safety's sake I'll ignore the present command.");
23781       mp_put_get_error(mp);
23782     } else  { 
23783       j=mp_round_unscaled(mp, mp->cur_exp);
23784       if ( mp->cur_cmd!=colon ) {
23785         mp_missing_err(mp, ":");
23786 @.Missing `:'@>
23787         help1("A colon should follow a headerbyte or fontinfo location.");
23788         mp_back_error(mp);
23789       }
23790       if ( c==header_byte_code ) { 
23791         @<Store a list of header bytes@>;
23792       } else {     
23793         if (mp->param==NULL) 
23794           mp->param = xmalloc((max_tfm_int+1),sizeof(scaled));
23795         @<Store a list of font dimensions@>;
23796       }
23797     }
23798     break;
23799   } /* there are no other cases */
23800 };
23801
23802 @ @<Store a list of ligature/kern steps@>=
23803
23804   mp->lk_started=false;
23805 CONTINUE: 
23806   mp_get_x_next(mp);
23807   if ((mp->cur_cmd==skip_to)&& mp->lk_started )
23808     @<Process a |skip_to| command and |goto done|@>;
23809   if ( mp->cur_cmd==bchar_label ) { c=256; mp->cur_cmd=colon; }
23810   else { mp_back_input(mp); c=mp_get_code(mp); };
23811   if ((mp->cur_cmd==colon)||(mp->cur_cmd==double_colon)) {
23812     @<Record a label in a lig/kern subprogram and |goto continue|@>;
23813   }
23814   if ( mp->cur_cmd==lig_kern_token ) { 
23815     @<Compile a ligature/kern command@>; 
23816   } else  { 
23817     print_err("Illegal ligtable step");
23818 @.Illegal ligtable step@>
23819     help1("I was looking for `=:' or `kern' here.");
23820     mp_back_error(mp); next_char(mp->nl)=qi(0); 
23821     op_byte(mp->nl)=qi(0); rem_byte(mp->nl)=qi(0);
23822     skip_byte(mp->nl)=stop_flag+1; /* this specifies an unconditional stop */
23823   }
23824   if ( mp->nl==max_tfm_int) mp_fatal_error(mp, "ligtable too large");
23825   incr(mp->nl);
23826   if ( mp->cur_cmd==comma ) goto CONTINUE;
23827   if ( skip_byte(mp->nl-1)<stop_flag ) skip_byte(mp->nl-1)=stop_flag;
23828 }
23829 DONE:
23830
23831 @ @<Put each...@>=
23832 mp_primitive(mp, "=:",lig_kern_token,0);
23833 @:=:_}{\.{=:} primitive@>
23834 mp_primitive(mp, "=:|",lig_kern_token,1);
23835 @:=:/_}{\.{=:\char'174} primitive@>
23836 mp_primitive(mp, "=:|>",lig_kern_token,5);
23837 @:=:/>_}{\.{=:\char'174>} primitive@>
23838 mp_primitive(mp, "|=:",lig_kern_token,2);
23839 @:=:/_}{\.{\char'174=:} primitive@>
23840 mp_primitive(mp, "|=:>",lig_kern_token,6);
23841 @:=:/>_}{\.{\char'174=:>} primitive@>
23842 mp_primitive(mp, "|=:|",lig_kern_token,3);
23843 @:=:/_}{\.{\char'174=:\char'174} primitive@>
23844 mp_primitive(mp, "|=:|>",lig_kern_token,7);
23845 @:=:/>_}{\.{\char'174=:\char'174>} primitive@>
23846 mp_primitive(mp, "|=:|>>",lig_kern_token,11);
23847 @:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
23848 mp_primitive(mp, "kern",lig_kern_token,128);
23849 @:kern_}{\&{kern} primitive@>
23850
23851 @ @<Cases of |print_cmd...@>=
23852 case lig_kern_token: 
23853   switch (m) {
23854   case 0:mp_print(mp, "=:"); break;
23855   case 1:mp_print(mp, "=:|"); break;
23856   case 2:mp_print(mp, "|=:"); break;
23857   case 3:mp_print(mp, "|=:|"); break;
23858   case 5:mp_print(mp, "=:|>"); break;
23859   case 6:mp_print(mp, "|=:>"); break;
23860   case 7:mp_print(mp, "|=:|>"); break;
23861   case 11:mp_print(mp, "|=:|>>"); break;
23862   default: mp_print(mp, "kern"); break;
23863   }
23864   break;
23865
23866 @ Local labels are implemented by maintaining the |skip_table| array,
23867 where |skip_table[c]| is either |undefined_label| or the address of the
23868 most recent lig/kern instruction that skips to local label~|c|. In the
23869 latter case, the |skip_byte| in that instruction will (temporarily)
23870 be zero if there were no prior skips to this label, or it will be the
23871 distance to the prior skip.
23872
23873 We may need to cancel skips that span more than 127 lig/kern steps.
23874
23875 @d cancel_skips(A) mp->ll=(A);
23876   do {  
23877     mp->lll=qo(skip_byte(mp->ll)); 
23878     skip_byte(mp->ll)=stop_flag; mp->ll=mp->ll-mp->lll;
23879   } while (mp->lll!=0)
23880 @d skip_error(A) { print_err("Too far to skip");
23881 @.Too far to skip@>
23882   help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
23883   mp_error(mp); cancel_skips((A));
23884   }
23885
23886 @<Process a |skip_to| command and |goto done|@>=
23887
23888   c=mp_get_code(mp);
23889   if ( mp->nl-mp->skip_table[c]>128 ) { /* |skip_table[c]<<nl<=undefined_label| */
23890     skip_error(mp->skip_table[c]); mp->skip_table[c]=undefined_label;
23891   }
23892   if ( mp->skip_table[c]==undefined_label ) skip_byte(mp->nl-1)=qi(0);
23893   else skip_byte(mp->nl-1)=qi(mp->nl-mp->skip_table[c]-1);
23894   mp->skip_table[c]=mp->nl-1; goto DONE;
23895 }
23896
23897 @ @<Record a label in a lig/kern subprogram and |goto continue|@>=
23898
23899   if ( mp->cur_cmd==colon ) {
23900     if ( c==256 ) mp->bch_label=mp->nl;
23901     else mp_set_tag(mp, c,lig_tag,mp->nl);
23902   } else if ( mp->skip_table[c]<undefined_label ) {
23903     mp->ll=mp->skip_table[c]; mp->skip_table[c]=undefined_label;
23904     do {  
23905       mp->lll=qo(skip_byte(mp->ll));
23906       if ( mp->nl-mp->ll>128 ) {
23907         skip_error(mp->ll); goto CONTINUE;
23908       }
23909       skip_byte(mp->ll)=qi(mp->nl-mp->ll-1); mp->ll=mp->ll-mp->lll;
23910     } while (mp->lll!=0);
23911   }
23912   goto CONTINUE;
23913 }
23914
23915 @ @<Compile a ligature/kern...@>=
23916
23917   next_char(mp->nl)=qi(c); skip_byte(mp->nl)=qi(0);
23918   if ( mp->cur_mod<128 ) { /* ligature op */
23919     op_byte(mp->nl)=qi(mp->cur_mod); rem_byte(mp->nl)=qi(mp_get_code(mp));
23920   } else { 
23921     mp_get_x_next(mp); mp_scan_expression(mp);
23922     if ( mp->cur_type!=mp_known ) {
23923       exp_err("Improper kern");
23924 @.Improper kern@>
23925       help2("The amount of kern should be a known numeric value.")
23926         ("I'm zeroing this one. Proceed, with fingers crossed.");
23927       mp_put_get_flush_error(mp, 0);
23928     }
23929     mp->kern[mp->nk]=mp->cur_exp;
23930     k=0; 
23931     while ( mp->kern[k]!=mp->cur_exp ) incr(k);
23932     if ( k==mp->nk ) {
23933       if ( mp->nk==max_tfm_int ) mp_fatal_error(mp, "too many TFM kerns");
23934       incr(mp->nk);
23935     }
23936     op_byte(mp->nl)=kern_flag+(k / 256);
23937     rem_byte(mp->nl)=qi((k % 256));
23938   }
23939   mp->lk_started=true;
23940 }
23941
23942 @ @d missing_extensible_punctuation(A) 
23943   { mp_missing_err(mp, (A));
23944 @.Missing `\char`\#'@>
23945   help1("I'm processing `extensible c: t,m,b,r'."); mp_back_error(mp);
23946   }
23947
23948 @<Define an extensible recipe@>=
23949
23950   if ( mp->ne==256 ) mp_fatal_error(mp, "too many extensible recipies");
23951   c=mp_get_code(mp); mp_set_tag(mp, c,ext_tag,mp->ne);
23952   if ( mp->cur_cmd!=colon ) missing_extensible_punctuation(":");
23953   ext_top(mp->ne)=qi(mp_get_code(mp));
23954   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23955   ext_mid(mp->ne)=qi(mp_get_code(mp));
23956   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23957   ext_bot(mp->ne)=qi(mp_get_code(mp));
23958   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23959   ext_rep(mp->ne)=qi(mp_get_code(mp));
23960   incr(mp->ne);
23961 }
23962
23963 @ The header could contain ASCII zeroes, so can't use |strdup|.
23964
23965 @<Store a list of header bytes@>=
23966 do {  
23967   if ( j>=mp->header_size ) {
23968     int l = mp->header_size + (mp->header_size >> 2);
23969     char *t = xmalloc(l,sizeof(char));
23970     memset(t,0,l); 
23971     memcpy(t,mp->header_byte,mp->header_size);
23972     xfree (mp->header_byte);
23973     mp->header_byte = t;
23974     mp->header_size = l;
23975   }
23976   mp->header_byte[j]=mp_get_code(mp); 
23977   incr(j); incr(mp->header_last);
23978 } while (mp->cur_cmd==comma)
23979
23980 @ @<Store a list of font dimensions@>=
23981 do {  
23982   if ( j>max_tfm_int ) mp_fatal_error(mp, "too many fontdimens");
23983   while ( j>mp->np ) { incr(mp->np); mp->param[mp->np]=0; };
23984   mp_get_x_next(mp); mp_scan_expression(mp);
23985   if ( mp->cur_type!=mp_known ){ 
23986     exp_err("Improper font parameter");
23987 @.Improper font parameter@>
23988     help1("I'm zeroing this one. Proceed, with fingers crossed.");
23989     mp_put_get_flush_error(mp, 0);
23990   }
23991   mp->param[j]=mp->cur_exp; incr(j);
23992 } while (mp->cur_cmd==comma)
23993
23994 @ OK: We've stored all the data that is needed for the \.{TFM} file.
23995 All that remains is to output it in the correct format.
23996
23997 An interesting problem needs to be solved in this connection, because
23998 the \.{TFM} format allows at most 256~widths, 16~heights, 16~depths,
23999 and 64~italic corrections. If the data has more distinct values than
24000 this, we want to meet the necessary restrictions by perturbing the
24001 given values as little as possible.
24002
24003 \MP\ solves this problem in two steps. First the values of a given
24004 kind (widths, heights, depths, or italic corrections) are sorted;
24005 then the list of sorted values is perturbed, if necessary.
24006
24007 The sorting operation is facilitated by having a special node of
24008 essentially infinite |value| at the end of the current list.
24009
24010 @<Initialize table entries...@>=
24011 value(inf_val)=fraction_four;
24012
24013 @ Straight linear insertion is good enough for sorting, since the lists
24014 are usually not terribly long. As we work on the data, the current list
24015 will start at |link(temp_head)| and end at |inf_val|; the nodes in this
24016 list will be in increasing order of their |value| fields.
24017
24018 Given such a list, the |sort_in| function takes a value and returns a pointer
24019 to where that value can be found in the list. The value is inserted in
24020 the proper place, if necessary.
24021
24022 At the time we need to do these operations, most of \MP's work has been
24023 completed, so we will have plenty of memory to play with. The value nodes
24024 that are allocated for sorting will never be returned to free storage.
24025
24026 @d clear_the_list link(temp_head)=inf_val
24027
24028 @c pointer mp_sort_in (MP mp,scaled v) {
24029   pointer p,q,r; /* list manipulation registers */
24030   p=temp_head;
24031   while (1) { 
24032     q=link(p);
24033     if ( v<=value(q) ) break;
24034     p=q;
24035   }
24036   if ( v<value(q) ) {
24037     r=mp_get_node(mp, value_node_size); value(r)=v; link(r)=q; link(p)=r;
24038   }
24039   return link(p);
24040 }
24041
24042 @ Now we come to the interesting part, where we reduce the list if necessary
24043 until it has the required size. The |min_cover| routine is basic to this
24044 process; it computes the minimum number~|m| such that the values of the
24045 current sorted list can be covered by |m|~intervals of width~|d|. It
24046 also sets the global value |perturbation| to the smallest value $d'>d$
24047 such that the covering found by this algorithm would be different.
24048
24049 In particular, |min_cover(0)| returns the number of distinct values in the
24050 current list and sets |perturbation| to the minimum distance between
24051 adjacent values.
24052
24053 @c integer mp_min_cover (MP mp,scaled d) {
24054   pointer p; /* runs through the current list */
24055   scaled l; /* the least element covered by the current interval */
24056   integer m; /* lower bound on the size of the minimum cover */
24057   m=0; p=link(temp_head); mp->perturbation=el_gordo;
24058   while ( p!=inf_val ){ 
24059     incr(m); l=value(p);
24060     do {  p=link(p); } while (value(p)<=l+d);
24061     if ( value(p)-l<mp->perturbation ) 
24062       mp->perturbation=value(p)-l;
24063   }
24064   return m;
24065 }
24066
24067 @ @<Glob...@>=
24068 scaled perturbation; /* quantity related to \.{TFM} rounding */
24069 integer excess; /* the list is this much too long */
24070
24071 @ The smallest |d| such that a given list can be covered with |m| intervals
24072 is determined by the |threshold| routine, which is sort of an inverse
24073 to |min_cover|. The idea is to increase the interval size rapidly until
24074 finding the range, then to go sequentially until the exact borderline has
24075 been discovered.
24076
24077 @c scaled mp_threshold (MP mp,integer m) {
24078   scaled d; /* lower bound on the smallest interval size */
24079   mp->excess=mp_min_cover(mp, 0)-m;
24080   if ( mp->excess<=0 ) {
24081     return 0;
24082   } else  { 
24083     do {  
24084       d=mp->perturbation;
24085     } while (mp_min_cover(mp, d+d)>m);
24086     while ( mp_min_cover(mp, d)>m ) 
24087       d=mp->perturbation;
24088     return d;
24089   }
24090 }
24091
24092 @ The |skimp| procedure reduces the current list to at most |m| entries,
24093 by changing values if necessary. It also sets |info(p):=k| if |value(p)|
24094 is the |k|th distinct value on the resulting list, and it sets
24095 |perturbation| to the maximum amount by which a |value| field has
24096 been changed. The size of the resulting list is returned as the
24097 value of |skimp|.
24098
24099 @c integer mp_skimp (MP mp,integer m) {
24100   scaled d; /* the size of intervals being coalesced */
24101   pointer p,q,r; /* list manipulation registers */
24102   scaled l; /* the least value in the current interval */
24103   scaled v; /* a compromise value */
24104   d=mp_threshold(mp, m); mp->perturbation=0;
24105   q=temp_head; m=0; p=link(temp_head);
24106   while ( p!=inf_val ) {
24107     incr(m); l=value(p); info(p)=m;
24108     if ( value(link(p))<=l+d ) {
24109       @<Replace an interval of values by its midpoint@>;
24110     }
24111     q=p; p=link(p);
24112   }
24113   return m;
24114 }
24115
24116 @ @<Replace an interval...@>=
24117
24118   do {  
24119     p=link(p); info(p)=m;
24120     decr(mp->excess); if ( mp->excess==0 ) d=0;
24121   } while (value(link(p))<=l+d);
24122   v=l+halfp(value(p)-l);
24123   if ( value(p)-v>mp->perturbation ) 
24124     mp->perturbation=value(p)-v;
24125   r=q;
24126   do {  
24127     r=link(r); value(r)=v;
24128   } while (r!=p);
24129   link(q)=p; /* remove duplicate values from the current list */
24130 }
24131
24132 @ A warning message is issued whenever something is perturbed by
24133 more than 1/16\thinspace pt.
24134
24135 @c void mp_tfm_warning (MP mp,small_number m) { 
24136   mp_print_nl(mp, "(some "); 
24137   mp_print(mp, mp->int_name[m]);
24138 @.some charwds...@>
24139 @.some chardps...@>
24140 @.some charhts...@>
24141 @.some charics...@>
24142   mp_print(mp, " values had to be adjusted by as much as ");
24143   mp_print_scaled(mp, mp->perturbation); mp_print(mp, "pt)");
24144 }
24145
24146 @ Here's an example of how we use these routines.
24147 The width data needs to be perturbed only if there are 256 distinct
24148 widths, but \MP\ must check for this case even though it is
24149 highly unusual.
24150
24151 An integer variable |k| will be defined when we use this code.
24152 The |dimen_head| array will contain pointers to the sorted
24153 lists of dimensions.
24154
24155 @<Massage the \.{TFM} widths@>=
24156 clear_the_list;
24157 for (k=mp->bc;k<=mp->ec;k++)  {
24158   if ( mp->char_exists[k] )
24159     mp->tfm_width[k]=mp_sort_in(mp, mp->tfm_width[k]);
24160 }
24161 mp->nw=mp_skimp(mp, 255)+1; mp->dimen_head[1]=link(temp_head);
24162 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_wd)
24163
24164 @ @<Glob...@>=
24165 pointer dimen_head[5]; /* lists of \.{TFM} dimensions */
24166
24167 @ Heights, depths, and italic corrections are different from widths
24168 not only because their list length is more severely restricted, but
24169 also because zero values do not need to be put into the lists.
24170
24171 @<Massage the \.{TFM} heights, depths, and italic corrections@>=
24172 clear_the_list;
24173 for (k=mp->bc;k<=mp->ec;k++) {
24174   if ( mp->char_exists[k] ) {
24175     if ( mp->tfm_height[k]==0 ) mp->tfm_height[k]=zero_val;
24176     else mp->tfm_height[k]=mp_sort_in(mp, mp->tfm_height[k]);
24177   }
24178 }
24179 mp->nh=mp_skimp(mp, 15)+1; mp->dimen_head[2]=link(temp_head);
24180 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_ht);
24181 clear_the_list;
24182 for (k=mp->bc;k<=mp->ec;k++) {
24183   if ( mp->char_exists[k] ) {
24184     if ( mp->tfm_depth[k]==0 ) mp->tfm_depth[k]=zero_val;
24185     else mp->tfm_depth[k]=mp_sort_in(mp, mp->tfm_depth[k]);
24186   }
24187 }
24188 mp->nd=mp_skimp(mp, 15)+1; mp->dimen_head[3]=link(temp_head);
24189 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_dp);
24190 clear_the_list;
24191 for (k=mp->bc;k<=mp->ec;k++) {
24192   if ( mp->char_exists[k] ) {
24193     if ( mp->tfm_ital_corr[k]==0 ) mp->tfm_ital_corr[k]=zero_val;
24194     else mp->tfm_ital_corr[k]=mp_sort_in(mp, mp->tfm_ital_corr[k]);
24195   }
24196 }
24197 mp->ni=mp_skimp(mp, 63)+1; mp->dimen_head[4]=link(temp_head);
24198 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_ic)
24199
24200 @ @<Initialize table entries...@>=
24201 value(zero_val)=0; info(zero_val)=0;
24202
24203 @ Bytes 5--8 of the header are set to the design size, unless the user has
24204 some crazy reason for specifying them differently.
24205
24206 Error messages are not allowed at the time this procedure is called,
24207 so a warning is printed instead.
24208
24209 The value of |max_tfm_dimen| is calculated so that
24210 $$\hbox{|make_scaled(16*max_tfm_dimen,internal[mp_design_size])|}
24211  < \\{three\_bytes}.$$
24212
24213 @d three_bytes 0100000000 /* $2^{24}$ */
24214
24215 @c 
24216 void mp_fix_design_size (MP mp) {
24217   scaled d; /* the design size */
24218   d=mp->internal[mp_design_size];
24219   if ( (d<unity)||(d>=fraction_half) ) {
24220     if ( d!=0 )
24221       mp_print_nl(mp, "(illegal design size has been changed to 128pt)");
24222 @.illegal design size...@>
24223     d=040000000; mp->internal[mp_design_size]=d;
24224   }
24225   if ( mp->header_byte[4]<0 ) if ( mp->header_byte[5]<0 )
24226     if ( mp->header_byte[6]<0 ) if ( mp->header_byte[7]<0 ) {
24227      mp->header_byte[4]=d / 04000000;
24228      mp->header_byte[5]=(d / 4096) % 256;
24229      mp->header_byte[6]=(d / 16) % 256;
24230      mp->header_byte[7]=(d % 16)*16;
24231   };
24232   mp->max_tfm_dimen=16*mp->internal[mp_design_size]-mp->internal[mp_design_size] / 010000000;
24233   if ( mp->max_tfm_dimen>=fraction_half ) mp->max_tfm_dimen=fraction_half-1;
24234 }
24235
24236 @ The |dimen_out| procedure computes a |fix_word| relative to the
24237 design size. If the data was out of range, it is corrected and the
24238 global variable |tfm_changed| is increased by~one.
24239
24240 @c integer mp_dimen_out (MP mp,scaled x) { 
24241   if ( abs(x)>mp->max_tfm_dimen ) {
24242     incr(mp->tfm_changed);
24243     if ( x>0 ) x=three_bytes-1; else x=1-three_bytes;
24244   } else {
24245     x=mp_make_scaled(mp, x*16,mp->internal[mp_design_size]);
24246   }
24247   return x;
24248 }
24249
24250 @ @<Glob...@>=
24251 scaled max_tfm_dimen; /* bound on widths, heights, kerns, etc. */
24252 integer tfm_changed; /* the number of data entries that were out of bounds */
24253
24254 @ If the user has not specified any of the first four header bytes,
24255 the |fix_check_sum| procedure replaces them by a ``check sum'' computed
24256 from the |tfm_width| data relative to the design size.
24257 @^check sum@>
24258
24259 @c void mp_fix_check_sum (MP mp) {
24260   eight_bits k; /* runs through character codes */
24261   eight_bits B1,B2,B3,B4; /* bytes of the check sum */
24262   integer x;  /* hash value used in check sum computation */
24263   if ( mp->header_byte[0]==0 && mp->header_byte[1]==0 &&
24264        mp->header_byte[2]==0 && mp->header_byte[3]==0 ) {
24265     @<Compute a check sum in |(b1,b2,b3,b4)|@>;
24266     mp->header_byte[0]=B1; mp->header_byte[1]=B2;
24267     mp->header_byte[2]=B3; mp->header_byte[3]=B4; 
24268     return;
24269   }
24270 }
24271
24272 @ @<Compute a check sum in |(b1,b2,b3,b4)|@>=
24273 B1=mp->bc; B2=mp->ec; B3=mp->bc; B4=mp->ec; mp->tfm_changed=0;
24274 for (k=mp->bc;k<=mp->ec;k++) { 
24275   if ( mp->char_exists[k] ) {
24276     x=mp_dimen_out(mp, value(mp->tfm_width[k]))+(k+4)*020000000; /* this is positive */
24277     B1=(B1+B1+x) % 255;
24278     B2=(B2+B2+x) % 253;
24279     B3=(B3+B3+x) % 251;
24280     B4=(B4+B4+x) % 247;
24281   }
24282 }
24283
24284 @ Finally we're ready to actually write the \.{TFM} information.
24285 Here are some utility routines for this purpose.
24286
24287 @d tfm_out(A) do { /* output one byte to |tfm_file| */
24288   unsigned char s=(A); 
24289   (mp->write_binary_file)(mp->tfm_file,(void *)&s,1); 
24290   } while (0)
24291
24292 @c void mp_tfm_two (MP mp,integer x) { /* output two bytes to |tfm_file| */
24293   tfm_out(x / 256); tfm_out(x % 256);
24294 }
24295 void mp_tfm_four (MP mp,integer x) { /* output four bytes to |tfm_file| */
24296   if ( x>=0 ) tfm_out(x / three_bytes);
24297   else { 
24298     x=x+010000000000; /* use two's complement for negative values */
24299     x=x+010000000000;
24300     tfm_out((x / three_bytes) + 128);
24301   };
24302   x=x % three_bytes; tfm_out(x / unity);
24303   x=x % unity; tfm_out(x / 0400);
24304   tfm_out(x % 0400);
24305 }
24306 void mp_tfm_qqqq (MP mp,four_quarters x) { /* output four quarterwords to |tfm_file| */
24307   tfm_out(qo(x.b0)); tfm_out(qo(x.b1)); 
24308   tfm_out(qo(x.b2)); tfm_out(qo(x.b3));
24309 }
24310
24311 @ @<Finish the \.{TFM} file@>=
24312 if ( mp->job_name==NULL ) mp_open_log_file(mp);
24313 mp_pack_job_name(mp, ".tfm");
24314 while ( ! mp_b_open_out(mp, &mp->tfm_file, mp_filetype_metrics) )
24315   mp_prompt_file_name(mp, "file name for font metrics",".tfm");
24316 mp->metric_file_name=xstrdup(mp->name_of_file);
24317 @<Output the subfile sizes and header bytes@>;
24318 @<Output the character information bytes, then
24319   output the dimensions themselves@>;
24320 @<Output the ligature/kern program@>;
24321 @<Output the extensible character recipes and the font metric parameters@>;
24322   if ( mp->internal[mp_tracing_stats]>0 )
24323   @<Log the subfile sizes of the \.{TFM} file@>;
24324 mp_print_nl(mp, "Font metrics written on "); 
24325 mp_print(mp, mp->metric_file_name); mp_print_char(mp, '.');
24326 @.Font metrics written...@>
24327 (mp->close_file)(mp->tfm_file)
24328
24329 @ Integer variables |lh|, |k|, and |lk_offset| will be defined when we use
24330 this code.
24331
24332 @<Output the subfile sizes and header bytes@>=
24333 k=mp->header_last;
24334 LH=(k+3) / 4; /* this is the number of header words */
24335 if ( mp->bc>mp->ec ) mp->bc=1; /* if there are no characters, |ec=0| and |bc=1| */
24336 @<Compute the ligature/kern program offset and implant the
24337   left boundary label@>;
24338 mp_tfm_two(mp,6+LH+(mp->ec-mp->bc+1)+mp->nw+mp->nh+mp->nd+mp->ni+mp->nl
24339      +lk_offset+mp->nk+mp->ne+mp->np);
24340   /* this is the total number of file words that will be output */
24341 mp_tfm_two(mp, LH); mp_tfm_two(mp, mp->bc); mp_tfm_two(mp, mp->ec); 
24342 mp_tfm_two(mp, mp->nw); mp_tfm_two(mp, mp->nh);
24343 mp_tfm_two(mp, mp->nd); mp_tfm_two(mp, mp->ni); mp_tfm_two(mp, mp->nl+lk_offset); 
24344 mp_tfm_two(mp, mp->nk); mp_tfm_two(mp, mp->ne);
24345 mp_tfm_two(mp, mp->np);
24346 for (k=0;k< 4*LH;k++)   { 
24347   tfm_out(mp->header_byte[k]);
24348 }
24349
24350 @ @<Output the character information bytes...@>=
24351 for (k=mp->bc;k<=mp->ec;k++) {
24352   if ( ! mp->char_exists[k] ) {
24353     mp_tfm_four(mp, 0);
24354   } else { 
24355     tfm_out(info(mp->tfm_width[k])); /* the width index */
24356     tfm_out((info(mp->tfm_height[k]))*16+info(mp->tfm_depth[k]));
24357     tfm_out((info(mp->tfm_ital_corr[k]))*4+mp->char_tag[k]);
24358     tfm_out(mp->char_remainder[k]);
24359   };
24360 }
24361 mp->tfm_changed=0;
24362 for (k=1;k<=4;k++) { 
24363   mp_tfm_four(mp, 0); p=mp->dimen_head[k];
24364   while ( p!=inf_val ) {
24365     mp_tfm_four(mp, mp_dimen_out(mp, value(p))); p=link(p);
24366   }
24367 }
24368
24369
24370 @ We need to output special instructions at the beginning of the
24371 |lig_kern| array in order to specify the right boundary character
24372 and/or to handle starting addresses that exceed 255. The |label_loc|
24373 and |label_char| arrays have been set up to record all the
24374 starting addresses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
24375 \le|label_loc|[|label_ptr]|$.
24376
24377 @<Compute the ligature/kern program offset...@>=
24378 mp->bchar=mp_round_unscaled(mp, mp->internal[mp_boundary_char]);
24379 if ((mp->bchar<0)||(mp->bchar>255))
24380   { mp->bchar=-1; mp->lk_started=false; lk_offset=0; }
24381 else { mp->lk_started=true; lk_offset=1; };
24382 @<Find the minimum |lk_offset| and adjust all remainders@>;
24383 if ( mp->bch_label<undefined_label )
24384   { skip_byte(mp->nl)=qi(255); next_char(mp->nl)=qi(0);
24385   op_byte(mp->nl)=qi(((mp->bch_label+lk_offset)/ 256));
24386   rem_byte(mp->nl)=qi(((mp->bch_label+lk_offset)% 256));
24387   incr(mp->nl); /* possibly |nl=lig_table_size+1| */
24388   }
24389
24390 @ @<Find the minimum |lk_offset|...@>=
24391 k=mp->label_ptr; /* pointer to the largest unallocated label */
24392 if ( mp->label_loc[k]+lk_offset>255 ) {
24393   lk_offset=0; mp->lk_started=false; /* location 0 can do double duty */
24394   do {  
24395     mp->char_remainder[mp->label_char[k]]=lk_offset;
24396     while ( mp->label_loc[k-1]==mp->label_loc[k] ) {
24397        decr(k); mp->char_remainder[mp->label_char[k]]=lk_offset;
24398     }
24399     incr(lk_offset); decr(k);
24400   } while (! (lk_offset+mp->label_loc[k]<256));
24401     /* N.B.: |lk_offset=256| satisfies this when |k=0| */
24402 };
24403 if ( lk_offset>0 ) {
24404   while ( k>0 ) {
24405     mp->char_remainder[mp->label_char[k]]
24406      =mp->char_remainder[mp->label_char[k]]+lk_offset;
24407     decr(k);
24408   }
24409 }
24410
24411 @ @<Output the ligature/kern program@>=
24412 for (k=0;k<= 255;k++ ) {
24413   if ( mp->skip_table[k]<undefined_label ) {
24414      mp_print_nl(mp, "(local label "); mp_print_int(mp, k); mp_print(mp, ":: was missing)");
24415 @.local label l:: was missing@>
24416     cancel_skips(mp->skip_table[k]);
24417   }
24418 }
24419 if ( mp->lk_started ) { /* |lk_offset=1| for the special |bchar| */
24420   tfm_out(255); tfm_out(mp->bchar); mp_tfm_two(mp, 0);
24421 } else {
24422   for (k=1;k<=lk_offset;k++) {/* output the redirection specs */
24423     mp->ll=mp->label_loc[mp->label_ptr];
24424     if ( mp->bchar<0 ) { tfm_out(254); tfm_out(0);   }
24425     else { tfm_out(255); tfm_out(mp->bchar);   };
24426     mp_tfm_two(mp, mp->ll+lk_offset);
24427     do {  
24428       decr(mp->label_ptr);
24429     } while (! (mp->label_loc[mp->label_ptr]<mp->ll));
24430   }
24431 }
24432 for (k=0;k<=mp->nl-1;k++) mp_tfm_qqqq(mp, mp->lig_kern[k]);
24433 for (k=0;k<=mp->nk-1;k++) mp_tfm_four(mp, mp_dimen_out(mp, mp->kern[k]))
24434
24435 @ @<Output the extensible character recipes...@>=
24436 for (k=0;k<=mp->ne-1;k++) 
24437   mp_tfm_qqqq(mp, mp->exten[k]);
24438 for (k=1;k<=mp->np;k++) {
24439   if ( k==1 ) {
24440     if ( abs(mp->param[1])<fraction_half ) {
24441       mp_tfm_four(mp, mp->param[1]*16);
24442     } else  { 
24443       incr(mp->tfm_changed);
24444       if ( mp->param[1]>0 ) mp_tfm_four(mp, el_gordo);
24445       else mp_tfm_four(mp, -el_gordo);
24446     }
24447   } else {
24448     mp_tfm_four(mp, mp_dimen_out(mp, mp->param[k]));
24449   }
24450 }
24451 if ( mp->tfm_changed>0 )  { 
24452   if ( mp->tfm_changed==1 ) mp_print_nl(mp, "(a font metric dimension");
24453 @.a font metric dimension...@>
24454   else  { 
24455     mp_print_nl(mp, "("); mp_print_int(mp, mp->tfm_changed);
24456 @.font metric dimensions...@>
24457     mp_print(mp, " font metric dimensions");
24458   }
24459   mp_print(mp, " had to be decreased)");
24460 }
24461
24462 @ @<Log the subfile sizes of the \.{TFM} file@>=
24463
24464   char s[200];
24465   wlog_ln(" ");
24466   if ( mp->bch_label<undefined_label ) decr(mp->nl);
24467   snprintf(s,128,"(You used %iw,%ih,%id,%ii,%il,%ik,%ie,%ip metric file positions)",
24468                  mp->nw, mp->nh, mp->nd, mp->ni, mp->nl, mp->nk, mp->ne,mp->np);
24469   wlog_ln(s);
24470 }
24471
24472 @* \[43] Reading font metric data.
24473
24474 \MP\ isn't a typesetting program but it does need to find the bounding box
24475 of a sequence of typeset characters.  Thus it needs to read \.{TFM} files as
24476 well as write them.
24477
24478 @<Glob...@>=
24479 void * tfm_infile;
24480
24481 @ All the width, height, and depth information is stored in an array called
24482 |font_info|.  This array is allocated sequentially and each font is stored
24483 as a series of |char_info| words followed by the width, height, and depth
24484 tables.  Since |font_name| entries are permanent, their |str_ref| values are
24485 set to |max_str_ref|.
24486
24487 @<Types...@>=
24488 typedef unsigned int font_number; /* |0..font_max| */
24489
24490 @ The |font_info| array is indexed via a group directory arrays.
24491 For example, the |char_info| data for character~|c| in font~|f| will be
24492 in |font_info[char_base[f]+c].qqqq|.
24493
24494 @<Glob...@>=
24495 font_number font_max; /* maximum font number for included text fonts */
24496 size_t      font_mem_size; /* number of words for \.{TFM} information for text fonts */
24497 memory_word *font_info; /* height, width, and depth data */
24498 char        **font_enc_name; /* encoding names, if any */
24499 boolean     *font_ps_name_fixed; /* are the postscript names fixed already?  */
24500 int         next_fmem; /* next unused entry in |font_info| */
24501 font_number last_fnum; /* last font number used so far */
24502 scaled      *font_dsize;  /* 16 times the ``design'' size in \ps\ points */
24503 char        **font_name;  /* name as specified in the \&{infont} command */
24504 char        **font_ps_name;  /* PostScript name for use when |internal[mp_prologues]>0| */
24505 font_number last_ps_fnum; /* last valid |font_ps_name| index */
24506 eight_bits  *font_bc;
24507 eight_bits  *font_ec;  /* first and last character code */
24508 int         *char_base;  /* base address for |char_info| */
24509 int         *width_base; /* index for zeroth character width */
24510 int         *height_base; /* index for zeroth character height */
24511 int         *depth_base; /* index for zeroth character depth */
24512 pointer     *font_sizes;
24513
24514 @ @<Allocate or initialize ...@>=
24515 mp->font_mem_size = 10000; 
24516 mp->font_info = xmalloc ((mp->font_mem_size+1),sizeof(memory_word));
24517 memset (mp->font_info,0,sizeof(memory_word)*(mp->font_mem_size+1));
24518 mp->font_enc_name = NULL;
24519 mp->font_ps_name_fixed = NULL;
24520 mp->font_dsize = NULL;
24521 mp->font_name = NULL;
24522 mp->font_ps_name = NULL;
24523 mp->font_bc = NULL;
24524 mp->font_ec = NULL;
24525 mp->last_fnum = null_font;
24526 mp->char_base = NULL;
24527 mp->width_base = NULL;
24528 mp->height_base = NULL;
24529 mp->depth_base = NULL;
24530 mp->font_sizes = null;
24531
24532 @ @<Dealloc variables@>=
24533 xfree(mp->font_info);
24534 xfree(mp->font_enc_name);
24535 xfree(mp->font_ps_name_fixed);
24536 xfree(mp->font_dsize);
24537 xfree(mp->font_name);
24538 xfree(mp->font_ps_name);
24539 xfree(mp->font_bc);
24540 xfree(mp->font_ec);
24541 xfree(mp->char_base);
24542 xfree(mp->width_base);
24543 xfree(mp->height_base);
24544 xfree(mp->depth_base);
24545 xfree(mp->font_sizes);
24546
24547
24548 @c 
24549 void mp_reallocate_fonts (MP mp, font_number l) {
24550   font_number f;
24551   XREALLOC(mp->font_enc_name,      l, char *);
24552   XREALLOC(mp->font_ps_name_fixed, l, boolean);
24553   XREALLOC(mp->font_dsize,         l, scaled);
24554   XREALLOC(mp->font_name,          l, char *);
24555   XREALLOC(mp->font_ps_name,       l, char *);
24556   XREALLOC(mp->font_bc,            l, eight_bits);
24557   XREALLOC(mp->font_ec,            l, eight_bits);
24558   XREALLOC(mp->char_base,          l, int);
24559   XREALLOC(mp->width_base,         l, int);
24560   XREALLOC(mp->height_base,        l, int);
24561   XREALLOC(mp->depth_base,         l, int);
24562   XREALLOC(mp->font_sizes,         l, pointer);
24563   for (f=(mp->last_fnum+1);f<=l;f++) {
24564     mp->font_enc_name[f]=NULL;
24565     mp->font_ps_name_fixed[f] = false;
24566     mp->font_name[f]=NULL;
24567     mp->font_ps_name[f]=NULL;
24568     mp->font_sizes[f]=null;
24569   }
24570   mp->font_max = l;
24571 }
24572
24573 @ @<Declare |mp_reallocate| functions@>=
24574 void mp_reallocate_fonts (MP mp, font_number l);
24575
24576
24577 @ A |null_font| containing no characters is useful for error recovery.  Its
24578 |font_name| entry starts out empty but is reset each time an erroneous font is
24579 found.  This helps to cut down on the number of duplicate error messages without
24580 wasting a lot of space.
24581
24582 @d null_font 0 /* the |font_number| for an empty font */
24583
24584 @<Set initial...@>=
24585 mp->font_dsize[null_font]=0;
24586 mp->font_bc[null_font]=1;
24587 mp->font_ec[null_font]=0;
24588 mp->char_base[null_font]=0;
24589 mp->width_base[null_font]=0;
24590 mp->height_base[null_font]=0;
24591 mp->depth_base[null_font]=0;
24592 mp->next_fmem=0;
24593 mp->last_fnum=null_font;
24594 mp->last_ps_fnum=null_font;
24595 mp->font_name[null_font]="nullfont";
24596 mp->font_ps_name[null_font]="";
24597
24598 @ Each |char_info| word is of type |four_quarters|.  The |b0| field contains
24599 the |width index|; the |b1| field contains the height
24600 index; the |b2| fields contains the depth index, and the |b3| field used only
24601 for temporary storage. (It is used to keep track of which characters occur in
24602 an edge structure that is being shipped out.)
24603 The corresponding words in the width, height, and depth tables are stored as
24604 |scaled| values in units of \ps\ points.
24605
24606 With the macros below, the |char_info| word for character~|c| in font~|f| is
24607 |char_info(f)(c)| and the width is
24608 $$\hbox{|char_width(f)(char_info(f)(c)).sc|.}$$
24609
24610 @d char_info_end(A) (A)].qqqq
24611 @d char_info(A) mp->font_info[mp->char_base[(A)]+char_info_end
24612 @d char_width_end(A) (A).b0].sc
24613 @d char_width(A) mp->font_info[mp->width_base[(A)]+char_width_end
24614 @d char_height_end(A) (A).b1].sc
24615 @d char_height(A) mp->font_info[mp->height_base[(A)]+char_height_end
24616 @d char_depth_end(A) (A).b2].sc
24617 @d char_depth(A) mp->font_info[mp->depth_base[(A)]+char_depth_end
24618 @d ichar_exists(A) ((A).b0>0)
24619
24620 @ The |font_ps_name| for a built-in font should be what PostScript expects.
24621 A preliminary name is obtained here from the \.{TFM} name as given in the
24622 |fname| argument.  This gets updated later from an external table if necessary.
24623
24624 @<Declare text measuring subroutines@>=
24625 @<Declare subroutines for parsing file names@>;
24626 font_number mp_read_font_info (MP mp, char*fname) {
24627   boolean file_opened; /* has |tfm_infile| been opened? */
24628   font_number n; /* the number to return */
24629   halfword lf,tfm_lh,bc,ec,nw,nh,nd; /* subfile size parameters */
24630   size_t whd_size; /* words needed for heights, widths, and depths */
24631   int i,ii; /* |font_info| indices */
24632   int jj; /* counts bytes to be ignored */
24633   scaled z; /* used to compute the design size */
24634   fraction d;
24635   /* height, width, or depth as a fraction of design size times $2^{-8}$ */
24636   eight_bits h_and_d; /* height and depth indices being unpacked */
24637   unsigned char tfbyte; /* a byte read from the file */
24638   n=null_font;
24639   @<Open |tfm_infile| for input@>;
24640   @<Read data from |tfm_infile|; if there is no room, say so and |goto done|;
24641     otherwise |goto bad_tfm| or |goto done| as appropriate@>;
24642 BAD_TFM:
24643   @<Complain that the \.{TFM} file is bad@>;
24644 DONE:
24645   if ( file_opened ) (mp->close_file)(mp->tfm_infile);
24646   if ( n!=null_font ) { 
24647     mp->font_ps_name[n]=fname;
24648     mp->font_name[n]=fname;
24649   }
24650   return n;
24651 }
24652
24653 @ \MP\ doesn't bother to check the entire \.{TFM} file for errors or explain
24654 precisely what is wrong if it does find a problem.  Programs called \.{TFtoPL}
24655 @.TFtoPL@> @.PLtoTF@>
24656 and \.{PLtoTF} can be used to debug \.{TFM} files.
24657
24658 @<Complain that the \.{TFM} file is bad@>=
24659 print_err("Font ");
24660 mp_print(mp, fname);
24661 if ( file_opened ) mp_print(mp, " not usable: TFM file is bad");
24662 else mp_print(mp, " not usable: TFM file not found");
24663 help3("I wasn't able to read the size data for this font so this")
24664   ("`infont' operation won't produce anything. If the font name")
24665   ("is right, you might ask an expert to make a TFM file");
24666 if ( file_opened )
24667   mp->help_line[0]="is right, try asking an expert to fix the TFM file";
24668 mp_error(mp)
24669
24670 @ @<Read data from |tfm_infile|; if there is no room, say so...@>=
24671 @<Read the \.{TFM} size fields@>;
24672 @<Use the size fields to allocate space in |font_info|@>;
24673 @<Read the \.{TFM} header@>;
24674 @<Read the character data and the width, height, and depth tables and
24675   |goto done|@>
24676
24677 @ A bad \.{TFM} file can be shorter than it claims to be.  The code given here
24678 might try to read past the end of the file if this happens.  Changes will be
24679 needed if it causes a system error to refer to |tfm_infile^| or call
24680 |get_tfm_infile| when |eof(tfm_infile)| is true.  For example, the definition
24681 @^system dependencies@>
24682 of |tfget| could be changed to
24683 ``|begin get(tfm_infile); if eof(tfm_infile) then goto bad_tfm; end|.''
24684
24685 @d tfget do { 
24686   size_t wanted=1; 
24687   void *tfbyte_ptr = &tfbyte;
24688   (mp->read_binary_file)(mp->tfm_infile,&tfbyte_ptr,&wanted); 
24689   if (wanted==0) goto BAD_TFM; 
24690 } while (0)
24691 @d read_two(A) { (A)=tfbyte;
24692   if ( (A)>127 ) goto BAD_TFM;
24693   tfget; (A)=(A)*0400+tfbyte;
24694 }
24695 @d tf_ignore(A) { for (jj=(A);jj>=1;jj--) tfget; }
24696
24697 @<Read the \.{TFM} size fields@>=
24698 tfget; read_two(lf);
24699 tfget; read_two(tfm_lh);
24700 tfget; read_two(bc);
24701 tfget; read_two(ec);
24702 if ( (bc>1+ec)||(ec>255) ) goto BAD_TFM;
24703 tfget; read_two(nw);
24704 tfget; read_two(nh);
24705 tfget; read_two(nd);
24706 whd_size=(ec+1-bc)+nw+nh+nd;
24707 if ( lf<(int)(6+tfm_lh+whd_size) ) goto BAD_TFM;
24708 tf_ignore(10)
24709
24710 @ Offsets are added to |char_base[n]| and |width_base[n]| so that is not
24711 necessary to apply the |so|  and |qo| macros when looking up the width of a
24712 character in the string pool.  In order to ensure nonnegative |char_base|
24713 values when |bc>0|, it may be necessary to reserve a few unused |font_info|
24714 elements.
24715
24716 @<Use the size fields to allocate space in |font_info|@>=
24717 if ( mp->next_fmem<bc) mp->next_fmem=bc;  /* ensure nonnegative |char_base| */
24718 if (mp->last_fnum==mp->font_max)
24719   mp_reallocate_fonts(mp,(mp->font_max+(mp->font_max>>2)));
24720 while (mp->next_fmem+whd_size>=mp->font_mem_size) {
24721   size_t l = mp->font_mem_size+(mp->font_mem_size>>2);
24722   memory_word *font_info;
24723   font_info = xmalloc ((l+1),sizeof(memory_word));
24724   memset (font_info,0,sizeof(memory_word)*(l+1));
24725   memcpy (font_info,mp->font_info,sizeof(memory_word)*(mp->font_mem_size+1));
24726   xfree(mp->font_info);
24727   mp->font_info = font_info;
24728   mp->font_mem_size = l;
24729 }
24730 incr(mp->last_fnum);
24731 n=mp->last_fnum;
24732 mp->font_bc[n]=bc;
24733 mp->font_ec[n]=ec;
24734 mp->char_base[n]=mp->next_fmem-bc;
24735 mp->width_base[n]=mp->next_fmem+ec-bc+1;
24736 mp->height_base[n]=mp->width_base[n]+nw;
24737 mp->depth_base[n]=mp->height_base[n]+nh;
24738 mp->next_fmem=mp->next_fmem+whd_size;
24739
24740
24741 @ @<Read the \.{TFM} header@>=
24742 if ( tfm_lh<2 ) goto BAD_TFM;
24743 tf_ignore(4);
24744 tfget; read_two(z);
24745 tfget; z=z*0400+tfbyte;
24746 tfget; z=z*0400+tfbyte; /* now |z| is 16 times the design size */
24747 mp->font_dsize[n]=mp_take_fraction(mp, z,267432584);
24748   /* times ${72\over72.27}2^{28}$ to convert from \TeX\ points */
24749 tf_ignore(4*(tfm_lh-2))
24750
24751 @ @<Read the character data and the width, height, and depth tables...@>=
24752 ii=mp->width_base[n];
24753 i=mp->char_base[n]+bc;
24754 while ( i<ii ) { 
24755   tfget; mp->font_info[i].qqqq.b0=qi(tfbyte);
24756   tfget; h_and_d=tfbyte;
24757   mp->font_info[i].qqqq.b1=h_and_d / 16;
24758   mp->font_info[i].qqqq.b2=h_and_d % 16;
24759   tfget; tfget;
24760   incr(i);
24761 }
24762 while ( i<mp->next_fmem ) {
24763   @<Read a four byte dimension, scale it by the design size, store it in
24764     |font_info[i]|, and increment |i|@>;
24765 }
24766 goto DONE
24767
24768 @ The raw dimension read into |d| should have magnitude at most $2^{24}$ when
24769 interpreted as an integer, and this includes a scale factor of $2^{20}$.  Thus
24770 we can multiply it by sixteen and think of it as a |fraction| that has been
24771 divided by sixteen.  This cancels the extra scale factor contained in
24772 |font_dsize[n|.
24773
24774 @<Read a four byte dimension, scale it by the design size, store it in...@>=
24775
24776 tfget; d=tfbyte;
24777 if ( d>=0200 ) d=d-0400;
24778 tfget; d=d*0400+tfbyte;
24779 tfget; d=d*0400+tfbyte;
24780 tfget; d=d*0400+tfbyte;
24781 mp->font_info[i].sc=mp_take_fraction(mp, d*16,mp->font_dsize[n]);
24782 incr(i);
24783 }
24784
24785 @ This function does no longer use the file name parser, because |fname| is
24786 a C string already.
24787 @<Open |tfm_infile| for input@>=
24788 file_opened=false;
24789 mp_ptr_scan_file(mp, fname);
24790 if ( strlen(mp->cur_area)==0 ) { xfree(mp->cur_area); mp->cur_area=xstrdup(MP_font_area);}
24791 if ( strlen(mp->cur_ext)==0 )  { xfree(mp->cur_ext); mp->cur_ext=xstrdup(".tfm"); }
24792 pack_cur_name;
24793 mp->tfm_infile = (mp->open_file)( mp->name_of_file, "rb",mp_filetype_metrics);
24794 if ( !mp->tfm_infile  ) goto BAD_TFM;
24795 file_opened=true
24796
24797 @ When we have a font name and we don't know whether it has been loaded yet,
24798 we scan the |font_name| array before calling |read_font_info|.
24799
24800 @<Declare text measuring subroutines@>=
24801 font_number mp_find_font (MP mp, char *f) {
24802   font_number n;
24803   for (n=0;n<=mp->last_fnum;n++) {
24804     if (mp_xstrcmp(f,mp->font_name[n])==0 )
24805       return n;
24806   }
24807   return mp_read_font_info(mp, f);
24808 }
24809
24810 @ One simple application of |find_font| is the implementation of the |font_size|
24811 operator that gets the design size for a given font name.
24812
24813 @<Find the design size of the font whose name is |cur_exp|@>=
24814 mp_flush_cur_exp(mp, (mp->font_dsize[mp_find_font(mp, str(mp->cur_exp))]+8) / 16)
24815
24816 @ If we discover that the font doesn't have a requested character, we omit it
24817 from the bounding box computation and expect the \ps\ interpreter to drop it.
24818 This routine issues a warning message if the user has asked for it.
24819
24820 @<Declare text measuring subroutines@>=
24821 void mp_lost_warning (MP mp,font_number f, pool_pointer k) { 
24822   if ( mp->internal[mp_tracing_lost_chars]>0 ) { 
24823     mp_begin_diagnostic(mp);
24824     if ( mp->selector==log_only ) incr(mp->selector);
24825     mp_print_nl(mp, "Missing character: There is no ");
24826 @.Missing character@>
24827     mp_print_str(mp, mp->str_pool[k]); 
24828     mp_print(mp, " in font ");
24829     mp_print(mp, mp->font_name[f]); mp_print_char(mp, '!'); 
24830     mp_end_diagnostic(mp, false);
24831   }
24832 }
24833
24834 @ The whole purpose of saving the height, width, and depth information is to be
24835 able to find the bounding box of an item of text in an edge structure.  The
24836 |set_text_box| procedure takes a text node and adds this information.
24837
24838 @<Declare text measuring subroutines@>=
24839 void mp_set_text_box (MP mp,pointer p) {
24840   font_number f; /* |font_n(p)| */
24841   ASCII_code bc,ec; /* range of valid characters for font |f| */
24842   pool_pointer k,kk; /* current character and character to stop at */
24843   four_quarters cc; /* the |char_info| for the current character */
24844   scaled h,d; /* dimensions of the current character */
24845   width_val(p)=0;
24846   height_val(p)=-el_gordo;
24847   depth_val(p)=-el_gordo;
24848   f=font_n(p);
24849   bc=mp->font_bc[f];
24850   ec=mp->font_ec[f];
24851   kk=str_stop(text_p(p));
24852   k=mp->str_start[text_p(p)];
24853   while ( k<kk ) {
24854     @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>;
24855   }
24856   @<Set the height and depth to zero if the bounding box is empty@>;
24857 }
24858
24859 @ @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>=
24860
24861   if ( (mp->str_pool[k]<bc)||(mp->str_pool[k]>ec) ) {
24862     mp_lost_warning(mp, f,k);
24863   } else { 
24864     cc=char_info(f)(mp->str_pool[k]);
24865     if ( ! ichar_exists(cc) ) {
24866       mp_lost_warning(mp, f,k);
24867     } else { 
24868       width_val(p)=width_val(p)+char_width(f)(cc);
24869       h=char_height(f)(cc);
24870       d=char_depth(f)(cc);
24871       if ( h>height_val(p) ) height_val(p)=h;
24872       if ( d>depth_val(p) ) depth_val(p)=d;
24873     }
24874   }
24875   incr(k);
24876 }
24877
24878 @ Let's hope modern compilers do comparisons correctly when the difference would
24879 overflow.
24880
24881 @<Set the height and depth to zero if the bounding box is empty@>=
24882 if ( height_val(p)<-depth_val(p) ) { 
24883   height_val(p)=0;
24884   depth_val(p)=0;
24885 }
24886
24887 @ The new primitives fontmapfile and fontmapline.
24888
24889 @<Declare action procedures for use by |do_statement|@>=
24890 void mp_do_mapfile (MP mp) ;
24891 void mp_do_mapline (MP mp) ;
24892
24893 @ @c void mp_do_mapfile (MP mp) { 
24894   mp_get_x_next(mp); mp_scan_expression(mp);
24895   if ( mp->cur_type!=mp_string_type ) {
24896     @<Complain about improper map operation@>;
24897   } else {
24898     mp_map_file(mp,mp->cur_exp);
24899   }
24900 }
24901 void mp_do_mapline (MP mp) { 
24902   mp_get_x_next(mp); mp_scan_expression(mp);
24903   if ( mp->cur_type!=mp_string_type ) {
24904      @<Complain about improper map operation@>;
24905   } else { 
24906      mp_map_line(mp,mp->cur_exp);
24907   }
24908 }
24909
24910 @ @<Complain about improper map operation@>=
24911
24912   exp_err("Unsuitable expression");
24913   help1("Only known strings can be map files or map lines.");
24914   mp_put_get_error(mp);
24915 }
24916
24917 @ To print |scaled| value to PDF output we need some subroutines to ensure
24918 accurary.
24919
24920 @d max_integer   0x7FFFFFFF /* $2^{31}-1$ */
24921
24922 @<Glob...@>=
24923 scaled one_bp; /* scaled value corresponds to 1bp */
24924 scaled one_hundred_bp; /* scaled value corresponds to 100bp */
24925 scaled one_hundred_inch; /* scaled value corresponds to 100in */
24926 integer ten_pow[10]; /* $10^0..10^9$ */
24927 integer scaled_out; /* amount of |scaled| that was taken out in |divide_scaled| */
24928
24929 @ @<Set init...@>=
24930 mp->one_bp = 65782; /* 65781.76 */
24931 mp->one_hundred_bp = 6578176;
24932 mp->one_hundred_inch = 473628672;
24933 mp->ten_pow[0] = 1;
24934 for (i = 1;i<= 9; i++ ) {
24935   mp->ten_pow[i] = 10*mp->ten_pow[i - 1];
24936 }
24937
24938 @ The following function divides |s| by |m|. |dd| is number of decimal digits.
24939
24940 @c scaled mp_divide_scaled (MP mp,scaled s, scaled m, integer  dd) {
24941   scaled q,r;
24942   integer sign,i;
24943   sign = 1;
24944   if ( s < 0 ) { sign = -sign; s = -s; }
24945   if ( m < 0 ) { sign = -sign; m = -m; }
24946   if ( m == 0 )
24947     mp_confusion(mp, "arithmetic: divided by zero");
24948   else if ( m >= (max_integer / 10) )
24949     mp_confusion(mp, "arithmetic: number too big");
24950   q = s / m;
24951   r = s % m;
24952   for (i = 1;i<=dd;i++) {
24953     q = 10*q + (10*r) / m;
24954     r = (10*r) % m;
24955   }
24956   if ( 2*r >= m ) { incr(q); r = r - m; }
24957   mp->scaled_out = sign*(s - (r / mp->ten_pow[dd]));
24958   return (sign*q);
24959 }
24960
24961 @* \[44] Shipping pictures out.
24962 The |ship_out| procedure, to be described below, is given a pointer to
24963 an edge structure. Its mission is to output a file containing the \ps\
24964 description of an edge structure.
24965
24966 @ Each time an edge structure is shipped out we write a new \ps\ output
24967 file named according to the current \&{charcode}.
24968 @:char_code_}{\&{charcode} primitive@>
24969
24970 This is the only backend function that remains in the main |mpost.w| file. 
24971 There are just too many variable accesses needed for status reporting 
24972 etcetera to make it worthwile to move the code to |psout.w|.
24973
24974 @<Internal library declarations@>=
24975 void mp_open_output_file (MP mp) ;
24976
24977 @ @c void mp_open_output_file (MP mp) {
24978   integer c; /* \&{charcode} rounded to the nearest integer */
24979   int old_setting; /* previous |selector| setting */
24980   pool_pointer i; /*  indexes into |filename_template|  */
24981   integer cc; /* a temporary integer for template building  */
24982   integer f,g=0; /* field widths */
24983   if ( mp->job_name==NULL ) mp_open_log_file(mp);
24984   c=mp_round_unscaled(mp, mp->internal[mp_char_code]);
24985   if ( mp->filename_template==0 ) {
24986     char *s; /* a file extension derived from |c| */
24987     if ( c<0 ) 
24988       s=xstrdup(".ps");
24989     else 
24990       @<Use |c| to compute the file extension |s|@>;
24991     mp_pack_job_name(mp, s);
24992     xfree(s);
24993     while ( ! mp_a_open_out(mp, (void *)&mp->ps_file, mp_filetype_postscript) )
24994       mp_prompt_file_name(mp, "file name for output",s);
24995   } else { /* initializations */
24996     str_number s, n; /* a file extension derived from |c| */
24997     old_setting=mp->selector; 
24998     mp->selector=new_string;
24999     f = 0;
25000     i = mp->str_start[mp->filename_template];
25001     n = rts(""); /* initialize */
25002     while ( i<str_stop(mp->filename_template) ) {
25003        if ( mp->str_pool[i]=='%' ) {
25004       CONTINUE:
25005         incr(i);
25006         if ( i<str_stop(mp->filename_template) ) {
25007           if ( mp->str_pool[i]=='j' ) {
25008             mp_print(mp, mp->job_name);
25009           } else if ( mp->str_pool[i]=='d' ) {
25010              cc= mp_round_unscaled(mp, mp->internal[mp_day]);
25011              print_with_leading_zeroes(cc);
25012           } else if ( mp->str_pool[i]=='m' ) {
25013              cc= mp_round_unscaled(mp, mp->internal[mp_month]);
25014              print_with_leading_zeroes(cc);
25015           } else if ( mp->str_pool[i]=='y' ) {
25016              cc= mp_round_unscaled(mp, mp->internal[mp_year]);
25017              print_with_leading_zeroes(cc);
25018           } else if ( mp->str_pool[i]=='H' ) {
25019              cc= mp_round_unscaled(mp, mp->internal[mp_time]) / 60;
25020              print_with_leading_zeroes(cc);
25021           }  else if ( mp->str_pool[i]=='M' ) {
25022              cc= mp_round_unscaled(mp, mp->internal[mp_time]) % 60;
25023              print_with_leading_zeroes(cc);
25024           } else if ( mp->str_pool[i]=='c' ) {
25025             if ( c<0 ) mp_print(mp, "ps");
25026             else print_with_leading_zeroes(c);
25027           } else if ( (mp->str_pool[i]>='0') && 
25028                       (mp->str_pool[i]<='9') ) {
25029             if ( (f<10)  )
25030               f = (f*10) + mp->str_pool[i]-'0';
25031             goto CONTINUE;
25032           } else {
25033             mp_print_str(mp, mp->str_pool[i]);
25034           }
25035         }
25036       } else {
25037         if ( mp->str_pool[i]=='.' )
25038           if (length(n)==0)
25039             n = mp_make_string(mp);
25040         mp_print_str(mp, mp->str_pool[i]);
25041       };
25042       incr(i);
25043     };
25044     s = mp_make_string(mp);
25045     mp->selector= old_setting;
25046     if (length(n)==0) {
25047        n=s;
25048        s=rts("");
25049     };
25050     mp_pack_file_name(mp, str(n),"",str(s));
25051     while ( ! mp_a_open_out(mp, (void *)&mp->ps_file, mp_filetype_postscript) )
25052       mp_prompt_file_name(mp, "file name for output",str(s));
25053     delete_str_ref(n);
25054     delete_str_ref(s);
25055   }
25056   @<Store the true output file name if appropriate@>;
25057   @<Begin the progress report for the output of picture~|c|@>;
25058 }
25059
25060 @ The file extension created here could be up to five characters long in
25061 extreme cases so it may have to be shortened on some systems.
25062 @^system dependencies@>
25063
25064 @<Use |c| to compute the file extension |s|@>=
25065
25066   s = xmalloc(7,1);
25067   snprintf(s,7,".%i",(int)c);
25068 }
25069
25070 @ The user won't want to see all the output file names so we only save the
25071 first and last ones and a count of how many there were.  For this purpose
25072 files are ordered primarily by \&{charcode} and secondarily by order of
25073 creation.
25074 @:char_code_}{\&{charcode} primitive@>
25075
25076 @<Store the true output file name if appropriate@>=
25077 if ((c<mp->first_output_code)&&(mp->first_output_code>=0)) {
25078   mp->first_output_code=c;
25079   xfree(mp->first_file_name);
25080   mp->first_file_name=xstrdup(mp->name_of_file);
25081 }
25082 if ( c>=mp->last_output_code ) {
25083   mp->last_output_code=c;
25084   xfree(mp->last_file_name);
25085   mp->last_file_name=xstrdup(mp->name_of_file);
25086 }
25087
25088 @ @<Glob...@>=
25089 char * first_file_name;
25090 char * last_file_name; /* full file names */
25091 integer first_output_code;integer last_output_code; /* rounded \&{charcode} values */
25092 @:char_code_}{\&{charcode} primitive@>
25093 integer total_shipped; /* total number of |ship_out| operations completed */
25094
25095 @ @<Set init...@>=
25096 mp->first_file_name=xstrdup("");
25097 mp->last_file_name=xstrdup("");
25098 mp->first_output_code=32768;
25099 mp->last_output_code=-32768;
25100 mp->total_shipped=0;
25101
25102 @ @<Dealloc variables@>=
25103 xfree(mp->first_file_name);
25104 xfree(mp->last_file_name);
25105
25106 @ @<Begin the progress report for the output of picture~|c|@>=
25107 if ( (int)mp->term_offset>mp->max_print_line-6 ) mp_print_ln(mp);
25108 else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
25109 mp_print_char(mp, '[');
25110 if ( c>=0 ) mp_print_int(mp, c)
25111
25112 @ @<End progress report@>=
25113 mp_print_char(mp, ']');
25114 update_terminal;
25115 incr(mp->total_shipped)
25116
25117 @ @<Explain what output files were written@>=
25118 if ( mp->total_shipped>0 ) { 
25119   mp_print_nl(mp, "");
25120   mp_print_int(mp, mp->total_shipped);
25121   mp_print(mp, " output file");
25122   if ( mp->total_shipped>1 ) mp_print_char(mp, 's');
25123   mp_print(mp, " written: ");
25124   mp_print(mp, mp->first_file_name);
25125   if ( mp->total_shipped>1 ) {
25126     if ( 31+strlen(mp->first_file_name)+
25127          strlen(mp->last_file_name)> (unsigned)mp->max_print_line) 
25128       mp_print_ln(mp);
25129     mp_print(mp, " .. ");
25130     mp_print(mp, mp->last_file_name);
25131   }
25132 }
25133
25134 @ @<Internal library declarations@>=
25135 boolean mp_has_font_size(MP mp, font_number f );
25136
25137 @ @c 
25138 boolean mp_has_font_size(MP mp, font_number f ) {
25139   return (mp->font_sizes[f]!=null);
25140 }
25141
25142 @ The \&{special} command saves up lines of text to be printed during the next
25143 |ship_out| operation.  The saved items are stored as a list of capsule tokens.
25144
25145 @<Glob...@>=
25146 pointer last_pending; /* the last token in a list of pending specials */
25147
25148 @ @<Set init...@>=
25149 mp->last_pending=spec_head;
25150
25151 @ @<Cases of |do_statement|...@>=
25152 case special_command: 
25153   if ( mp->cur_mod==0 ) mp_do_special(mp); else 
25154   if ( mp->cur_mod==1 ) mp_do_mapfile(mp); else 
25155   mp_do_mapline(mp);
25156   break;
25157
25158 @ @<Declare action procedures for use by |do_statement|@>=
25159 void mp_do_special (MP mp) ;
25160
25161 @ @c void mp_do_special (MP mp) { 
25162   mp_get_x_next(mp); mp_scan_expression(mp);
25163   if ( mp->cur_type!=mp_string_type ) {
25164     @<Complain about improper special operation@>;
25165   } else { 
25166     link(mp->last_pending)=mp_stash_cur_exp(mp);
25167     mp->last_pending=link(mp->last_pending);
25168     link(mp->last_pending)=null;
25169   }
25170 }
25171
25172 @ @<Complain about improper special operation@>=
25173
25174   exp_err("Unsuitable expression");
25175   help1("Only known strings are allowed for output as specials.");
25176   mp_put_get_error(mp);
25177 }
25178
25179 @ On the export side, we need an extra object type for special strings.
25180
25181 @<Graphical object codes@>=
25182 mp_special_code=8, 
25183
25184 @ @<Export pending specials@>=
25185 p=link(spec_head);
25186 while ( p!=null ) {
25187   hq = mp_new_graphic_object(mp,mp_special_code);
25188   gr_pre_script(hq)  = str(value(p));
25189   if (hh->body==NULL) hh->body=hq; else gr_link(hp) = hq;
25190   hp = hq;
25191   p=link(p);
25192 }
25193 mp_flush_token_list(mp, link(spec_head));
25194 link(spec_head)=null;
25195 mp->last_pending=spec_head
25196
25197 @ We are now ready for the main output procedure.  Note that the |selector|
25198 setting is saved in a global variable so that |begin_diagnostic| can access it.
25199
25200 @<Declare the \ps\ output procedures@>=
25201 void mp_ship_out (MP mp, pointer h) ;
25202
25203 @ Once again, the |gr_XXXX| macros are defined in |mppsout.h|
25204
25205 @c
25206 struct mp_edge_object *mp_gr_export(MP mp, pointer h) {
25207   pointer p; /* the current graphical object */
25208   integer t; /* a temporary value */
25209   struct mp_edge_object *hh; /* the first graphical object */
25210   struct mp_graphic_object *hp; /* the current graphical object */
25211   struct mp_graphic_object *hq; /* something |hp| points to  */
25212   mp_set_bbox(mp, h, true);
25213   hh = mp_xmalloc(mp,1,sizeof(struct mp_edge_object));
25214   hh->body = NULL;
25215   hh->_minx = minx_val(h);
25216   hh->_miny = miny_val(h);
25217   hh->_maxx = maxx_val(h);
25218   hh->_maxy = maxy_val(h);
25219   @<Export pending specials@>;
25220   p=link(dummy_loc(h));
25221   while ( p!=null ) { 
25222     hq = mp_new_graphic_object(mp,type(p));
25223     switch (type(p)) {
25224     case mp_fill_code:
25225       gr_pen_p(hq)        = mp_export_knot_list(mp,pen_p(p));
25226       if ((pen_p(p)==null) || pen_is_elliptical(pen_p(p)))  {
25227           gr_path_p(hq)       = mp_export_knot_list(mp,path_p(p));
25228       } else {
25229         pointer pc, pp;
25230         pc = mp_copy_path(mp, path_p(p));
25231         pp = mp_make_envelope(mp, pc, pen_p(p),ljoin_val(p),0,miterlim_val(p));
25232         gr_path_p(hq)       = mp_export_knot_list(mp,pp);
25233         mp_toss_knot_list(mp, pp);
25234         pc = mp_htap_ypoc(mp, path_p(p));
25235         pp = mp_make_envelope(mp, pc, pen_p(p),ljoin_val(p),0,miterlim_val(p));
25236         gr_htap_p(hq)       = mp_export_knot_list(mp,pp);
25237         mp_toss_knot_list(mp, pp);
25238       }
25239       @<Export object color@>;
25240       @<Export object scripts@>;
25241       gr_ljoin_val(hq)    = ljoin_val(p);
25242       gr_miterlim_val(hq) = miterlim_val(p);
25243       break;
25244     case mp_stroked_code:
25245       gr_pen_p(hq)        = mp_export_knot_list(mp,pen_p(p));
25246       if (pen_is_elliptical(pen_p(p)))  {
25247               gr_path_p(hq)       = mp_export_knot_list(mp,path_p(p));
25248       } else {
25249         pointer pc;
25250         pc=mp_copy_path(mp, path_p(p));
25251         t=lcap_val(p);
25252         if ( left_type(pc)!=mp_endpoint ) { 
25253           left_type(mp_insert_knot(mp, pc,x_coord(pc),y_coord(pc)))=mp_endpoint;
25254           right_type(pc)=mp_endpoint;
25255           pc=link(pc);
25256           t=1;
25257         }
25258         pc=mp_make_envelope(mp,pc,pen_p(p),ljoin_val(p),t,miterlim_val(p));
25259         gr_path_p(hq)       = mp_export_knot_list(mp,pc);
25260         mp_toss_knot_list(mp, pc);
25261       }
25262       @<Export object color@>;
25263       @<Export object scripts@>;
25264       gr_ljoin_val(hq)    = ljoin_val(p);
25265       gr_miterlim_val(hq) = miterlim_val(p);
25266       gr_lcap_val(hq)     = lcap_val(p);
25267       gr_dash_scale(hq)   = dash_scale(p);
25268       gr_dash_p(hq)       = mp_export_dashes(mp,dash_p(p));
25269       break;
25270     case mp_text_code:
25271       gr_text_p(hq)       = str(text_p(p));
25272       gr_font_n(hq)       = font_n(p);
25273       @<Export object color@>;
25274       @<Export object scripts@>;
25275       gr_width_val(hq)    = width_val(p);
25276       gr_height_val(hq)   = height_val(p);
25277       gr_depth_val(hq)    = depth_val(p);
25278       gr_tx_val(hq)       = tx_val(p);
25279       gr_ty_val(hq)       = ty_val(p);
25280       gr_txx_val(hq)      = txx_val(p);
25281       gr_txy_val(hq)      = txy_val(p);
25282       gr_tyx_val(hq)      = tyx_val(p);
25283       gr_tyy_val(hq)      = tyy_val(p);
25284       break;
25285     case mp_start_clip_code: 
25286     case mp_start_bounds_code:
25287       gr_path_p(hq) = mp_export_knot_list(mp,path_p(p));
25288       break;
25289     case mp_stop_clip_code: 
25290     case mp_stop_bounds_code:
25291       /* nothing to do here */
25292       break;
25293     } 
25294     if (hh->body==NULL) hh->body=hq; else  gr_link(hp) = hq;
25295     hp = hq;
25296     p=link(p);
25297   }
25298   return hh;
25299 }
25300
25301 @ This function is now nearly trivial.
25302
25303 @c
25304 void mp_ship_out (MP mp, pointer h) { /* output edge structure |h| */
25305   struct mp_edge_object *hh; /* the first graphical object */
25306   hh = mp_gr_export(mp,h);
25307   mp_gr_ship_out (mp, hh);
25308   mp_xfree(hh);
25309   @<End progress report@>;
25310   if ( mp->internal[mp_tracing_output]>0 ) 
25311    mp_print_edges(mp, h," (just shipped out)",true);
25312 }
25313
25314
25315 @ Once again, the |gr_XXXX| macros are defined in |mppsout.h|
25316
25317 @<Export object color@>=
25318 gr_color_model(hq)  = color_model(p);
25319 gr_cyan_val(hq)     = cyan_val(p);
25320 gr_magenta_val(hq)  = magenta_val(p);
25321 gr_yellow_val(hq)   = yellow_val(p);
25322 gr_black_val(hq)    = black_val(p);
25323 gr_red_val(hq)      = red_val(p);
25324 gr_green_val(hq)    = green_val(p);
25325 gr_blue_val(hq)     = blue_val(p);
25326 gr_grey_val(hq)     = grey_val(p)
25327
25328
25329 @ @<Export object scripts@>=
25330 if (pre_script(p)!=null)
25331   gr_pre_script(hq)   = str(pre_script(p));
25332 if (post_script(p)!=null)
25333   gr_post_script(hq)  = str(post_script(p));
25334
25335 @ Now that we've finished |ship_out|, let's look at the other commands
25336 by which a user can send things to the \.{GF} file.
25337
25338 @ @<Determine if a character has been shipped out@>=
25339
25340   mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256;
25341   if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
25342   boolean_reset(mp->char_exists[mp->cur_exp]);
25343   mp->cur_type=mp_boolean_type;
25344 }
25345
25346 @ @<Glob...@>=
25347 psout_data ps;
25348
25349 @ @<Allocate or initialize ...@>=
25350 mp_backend_initialize(mp);
25351
25352 @ @<Dealloc...@>=
25353 mp_backend_free(mp);
25354
25355
25356 @* \[45] Dumping and undumping the tables.
25357 After \.{INIMP} has seen a collection of macros, it
25358 can write all the necessary information on an auxiliary file so
25359 that production versions of \MP\ are able to initialize their
25360 memory at high speed. The present section of the program takes
25361 care of such output and input. We shall consider simultaneously
25362 the processes of storing and restoring,
25363 so that the inverse relation between them is clear.
25364 @.INIMP@>
25365
25366 The global variable |mem_ident| is a string that is printed right
25367 after the |banner| line when \MP\ is ready to start. For \.{INIMP} this
25368 string says simply `\.{(INIMP)}'; for other versions of \MP\ it says,
25369 for example, `\.{(mem=plain 90.4.14)}', showing the year,
25370 month, and day that the mem file was created. We have |mem_ident=0|
25371 before \MP's tables are loaded.
25372
25373 @<Glob...@>=
25374 char * mem_ident;
25375
25376 @ @<Set init...@>=
25377 mp->mem_ident=NULL;
25378
25379 @ @<Initialize table entries...@>=
25380 mp->mem_ident=xstrdup(" (INIMP)");
25381
25382 @ @<Declare act...@>=
25383 void mp_store_mem_file (MP mp) ;
25384
25385 @ @c void mp_store_mem_file (MP mp) {
25386   integer k;  /* all-purpose index */
25387   pointer p,q; /* all-purpose pointers */
25388   integer x; /* something to dump */
25389   four_quarters w; /* four ASCII codes */
25390   memory_word WW;
25391   @<Create the |mem_ident|, open the mem file,
25392     and inform the user that dumping has begun@>;
25393   @<Dump constants for consistency check@>;
25394   @<Dump the string pool@>;
25395   @<Dump the dynamic memory@>;
25396   @<Dump the table of equivalents and the hash table@>;
25397   @<Dump a few more things and the closing check word@>;
25398   @<Close the mem file@>;
25399 }
25400
25401 @ Corresponding to the procedure that dumps a mem file, we also have a function
25402 that reads~one~in. The function returns |false| if the dumped mem is
25403 incompatible with the present \MP\ table sizes, etc.
25404
25405 @d off_base 6666 /* go here if the mem file is unacceptable */
25406 @d too_small(A) { wake_up_terminal;
25407   wterm_ln("---! Must increase the "); wterm((A));
25408 @.Must increase the x@>
25409   goto OFF_BASE;
25410   }
25411
25412 @c 
25413 boolean mp_load_mem_file (MP mp) {
25414   integer k; /* all-purpose index */
25415   pointer p,q; /* all-purpose pointers */
25416   integer x; /* something undumped */
25417   str_number s; /* some temporary string */
25418   four_quarters w; /* four ASCII codes */
25419   memory_word WW;
25420   @<Undump constants for consistency check@>;
25421   @<Undump the string pool@>;
25422   @<Undump the dynamic memory@>;
25423   @<Undump the table of equivalents and the hash table@>;
25424   @<Undump a few more things and the closing check word@>;
25425   return true; /* it worked! */
25426 OFF_BASE: 
25427   wake_up_terminal;
25428   wterm_ln("(Fatal mem file error; I'm stymied)\n");
25429 @.Fatal mem file error@>
25430    return false;
25431 }
25432
25433 @ @<Declarations@>=
25434 boolean mp_load_mem_file (MP mp) ;
25435
25436 @ Mem files consist of |memory_word| items, and we use the following
25437 macros to dump words of different types:
25438
25439 @d dump_wd(A)   { WW=(A);       (mp->write_binary_file)(mp->mem_file,&WW,sizeof(WW)); }
25440 @d dump_int(A)  { int cint=(A); (mp->write_binary_file)(mp->mem_file,&cint,sizeof(cint)); }
25441 @d dump_hh(A)   { WW.hh=(A);    (mp->write_binary_file)(mp->mem_file,&WW,sizeof(WW)); }
25442 @d dump_qqqq(A) { WW.qqqq=(A);  (mp->write_binary_file)(mp->mem_file,&WW,sizeof(WW)); }
25443 @d dump_string(A) { dump_int(strlen(A)+1);
25444                     (mp->write_binary_file)(mp->mem_file,A,strlen(A)+1); }
25445
25446 @<Glob...@>=
25447 void * mem_file; /* for input or output of mem information */
25448
25449 @ The inverse macros are slightly more complicated, since we need to check
25450 the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
25451 read an integer value |x| that is supposed to be in the range |a<=x<=b|.
25452
25453 @d mgeti(A) do {
25454   size_t wanted = sizeof(A);
25455   void *A_ptr = &A;
25456   (mp->read_binary_file)(mp->mem_file,&A_ptr,&wanted);
25457   if (wanted!=sizeof(A)) goto OFF_BASE;
25458 } while (0)
25459
25460 @d mgetw(A) do {
25461   size_t wanted = sizeof(A);
25462   void *A_ptr = &A;
25463   (mp->read_binary_file)(mp->mem_file,&A_ptr,&wanted);
25464   if (wanted!=sizeof(A)) goto OFF_BASE;
25465 } while (0)
25466
25467 @d undump_wd(A)   { mgetw(WW); A=WW; }
25468 @d undump_int(A)  { int cint; mgeti(cint); A=cint; }
25469 @d undump_hh(A)   { mgetw(WW); A=WW.hh; }
25470 @d undump_qqqq(A) { mgetw(WW); A=WW.qqqq; }
25471 @d undump_strings(A,B,C) { 
25472    undump_int(x); if ( (x<(A)) || (x>(B)) ) goto OFF_BASE; else C=str(x); }
25473 @d undump(A,B,C) { undump_int(x); if ( (x<(A)) || (x>(int)(B)) ) goto OFF_BASE; else C=x; }
25474 @d undump_size(A,B,C,D) { undump_int(x);
25475                           if (x<(A)) goto OFF_BASE; 
25476                           if (x>(B)) { too_small((C)); } else { D=x;} }
25477 @d undump_string(A) do { 
25478   size_t wanted; 
25479   integer XX=0; 
25480   undump_int(XX);
25481   wanted = XX;
25482   A = xmalloc(XX,sizeof(char));
25483   (mp->read_binary_file)(mp->mem_file,(void **)&A,&wanted);
25484   if (wanted!=(size_t)XX) goto OFF_BASE;
25485 } while (0)
25486
25487 @ The next few sections of the program should make it clear how we use the
25488 dump/undump macros.
25489
25490 @<Dump constants for consistency check@>=
25491 dump_int(mp->mem_top);
25492 dump_int(mp->hash_size);
25493 dump_int(mp->hash_prime)
25494 dump_int(mp->param_size);
25495 dump_int(mp->max_in_open);
25496
25497 @ Sections of a \.{WEB} program that are ``commented out'' still contribute
25498 strings to the string pool; therefore \.{INIMP} and \MP\ will have
25499 the same strings. (And it is, of course, a good thing that they do.)
25500 @.WEB@>
25501 @^string pool@>
25502
25503 @<Undump constants for consistency check@>=
25504 undump_int(x); mp->mem_top = x;
25505 undump_int(x); if (mp->hash_size != x) goto OFF_BASE;
25506 undump_int(x); if (mp->hash_prime != x) goto OFF_BASE;
25507 undump_int(x); if (mp->param_size != x) goto OFF_BASE;
25508 undump_int(x); if (mp->max_in_open != x) goto OFF_BASE
25509
25510 @ We do string pool compaction to avoid dumping unused strings.
25511
25512 @d dump_four_ASCII 
25513   w.b0=qi(mp->str_pool[k]); w.b1=qi(mp->str_pool[k+1]);
25514   w.b2=qi(mp->str_pool[k+2]); w.b3=qi(mp->str_pool[k+3]);
25515   dump_qqqq(w)
25516
25517 @<Dump the string pool@>=
25518 mp_do_compaction(mp, mp->pool_size);
25519 dump_int(mp->pool_ptr);
25520 dump_int(mp->max_str_ptr);
25521 dump_int(mp->str_ptr);
25522 k=0;
25523 while ( (mp->next_str[k]==k+1) && (k<=mp->max_str_ptr) ) 
25524   incr(k);
25525 dump_int(k);
25526 while ( k<=mp->max_str_ptr ) { 
25527   dump_int(mp->next_str[k]); incr(k);
25528 }
25529 k=0;
25530 while (1)  { 
25531   dump_int(mp->str_start[k]); /* TODO: valgrind warning here */
25532   if ( k==mp->str_ptr ) {
25533     break;
25534   } else { 
25535     k=mp->next_str[k]; 
25536   }
25537 };
25538 k=0;
25539 while (k+4<mp->pool_ptr ) { 
25540   dump_four_ASCII; k=k+4; 
25541 }
25542 k=mp->pool_ptr-4; dump_four_ASCII;
25543 mp_print_ln(mp); mp_print(mp, "at most "); mp_print_int(mp, mp->max_str_ptr);
25544 mp_print(mp, " strings of total length ");
25545 mp_print_int(mp, mp->pool_ptr)
25546
25547 @ @d undump_four_ASCII 
25548   undump_qqqq(w);
25549   mp->str_pool[k]=qo(w.b0); mp->str_pool[k+1]=qo(w.b1);
25550   mp->str_pool[k+2]=qo(w.b2); mp->str_pool[k+3]=qo(w.b3)
25551
25552 @<Undump the string pool@>=
25553 undump_int(mp->pool_ptr);
25554 mp_reallocate_pool(mp, mp->pool_ptr) ;
25555 undump_int(mp->max_str_ptr);
25556 mp_reallocate_strings (mp,mp->max_str_ptr) ;
25557 undump(0,mp->max_str_ptr,mp->str_ptr);
25558 undump(0,mp->max_str_ptr+1,s);
25559 for (k=0;k<=s-1;k++) 
25560   mp->next_str[k]=k+1;
25561 for (k=s;k<=mp->max_str_ptr;k++) 
25562   undump(s+1,mp->max_str_ptr+1,mp->next_str[k]);
25563 mp->fixed_str_use=0;
25564 k=0;
25565 while (1) { 
25566   undump(0,mp->pool_ptr,mp->str_start[k]);
25567   if ( k==mp->str_ptr ) break;
25568   mp->str_ref[k]=max_str_ref;
25569   incr(mp->fixed_str_use);
25570   mp->last_fixed_str=k; k=mp->next_str[k];
25571 }
25572 k=0;
25573 while ( k+4<mp->pool_ptr ) { 
25574   undump_four_ASCII; k=k+4;
25575 }
25576 k=mp->pool_ptr-4; undump_four_ASCII;
25577 mp->init_str_use=mp->fixed_str_use; mp->init_pool_ptr=mp->pool_ptr;
25578 mp->max_pool_ptr=mp->pool_ptr;
25579 mp->strs_used_up=mp->fixed_str_use;
25580 mp->pool_in_use=mp->str_start[mp->str_ptr]; mp->strs_in_use=mp->fixed_str_use;
25581 mp->max_pl_used=mp->pool_in_use; mp->max_strs_used=mp->strs_in_use;
25582 mp->pact_count=0; mp->pact_chars=0; mp->pact_strs=0;
25583
25584 @ By sorting the list of available spaces in the variable-size portion of
25585 |mem|, we are usually able to get by without having to dump very much
25586 of the dynamic memory.
25587
25588 We recompute |var_used| and |dyn_used|, so that \.{INIMP} dumps valid
25589 information even when it has not been gathering statistics.
25590
25591 @<Dump the dynamic memory@>=
25592 mp_sort_avail(mp); mp->var_used=0;
25593 dump_int(mp->lo_mem_max); dump_int(mp->rover);
25594 p=0; q=mp->rover; x=0;
25595 do {  
25596   for (k=p;k<= q+1;k++) 
25597     dump_wd(mp->mem[k]);
25598   x=x+q+2-p; mp->var_used=mp->var_used+q-p;
25599   p=q+node_size(q); q=rlink(q);
25600 } while (q!=mp->rover);
25601 mp->var_used=mp->var_used+mp->lo_mem_max-p; 
25602 mp->dyn_used=mp->mem_end+1-mp->hi_mem_min;
25603 for (k=p;k<= mp->lo_mem_max;k++ ) 
25604   dump_wd(mp->mem[k]);
25605 x=x+mp->lo_mem_max+1-p;
25606 dump_int(mp->hi_mem_min); dump_int(mp->avail);
25607 for (k=mp->hi_mem_min;k<=mp->mem_end;k++ ) 
25608   dump_wd(mp->mem[k]);
25609 x=x+mp->mem_end+1-mp->hi_mem_min;
25610 p=mp->avail;
25611 while ( p!=null ) { 
25612   decr(mp->dyn_used); p=link(p);
25613 }
25614 dump_int(mp->var_used); dump_int(mp->dyn_used);
25615 mp_print_ln(mp); mp_print_int(mp, x);
25616 mp_print(mp, " memory locations dumped; current usage is ");
25617 mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used)
25618
25619 @ @<Undump the dynamic memory@>=
25620 undump(lo_mem_stat_max+1000,hi_mem_stat_min-1,mp->lo_mem_max);
25621 undump(lo_mem_stat_max+1,mp->lo_mem_max,mp->rover);
25622 p=0; q=mp->rover;
25623 do {  
25624   for (k=p;k<= q+1; k++) 
25625     undump_wd(mp->mem[k]);
25626   p=q+node_size(q);
25627   if ( (p>mp->lo_mem_max)||((q>=rlink(q))&&(rlink(q)!=mp->rover)) ) 
25628     goto OFF_BASE;
25629   q=rlink(q);
25630 } while (q!=mp->rover);
25631 for (k=p;k<=mp->lo_mem_max;k++ ) 
25632   undump_wd(mp->mem[k]);
25633 undump(mp->lo_mem_max+1,hi_mem_stat_min,mp->hi_mem_min);
25634 undump(null,mp->mem_top,mp->avail); mp->mem_end=mp->mem_top;
25635 for (k=mp->hi_mem_min;k<= mp->mem_end;k++) 
25636   undump_wd(mp->mem[k]);
25637 undump_int(mp->var_used); undump_int(mp->dyn_used)
25638
25639 @ A different scheme is used to compress the hash table, since its lower region
25640 is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output three
25641 words: |p|, |hash[p]|, and |eqtb[p]|. The hash table is, of course, densely
25642 packed for |p>=hash_used|, so the remaining entries are output in~a~block.
25643
25644 @<Dump the table of equivalents and the hash table@>=
25645 dump_int(mp->hash_used); 
25646 mp->st_count=frozen_inaccessible-1-mp->hash_used;
25647 for (p=1;p<=mp->hash_used;p++) {
25648   if ( text(p)!=0 ) {
25649      dump_int(p); dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]); incr(mp->st_count);
25650   }
25651 }
25652 for (p=mp->hash_used+1;p<=(int)hash_end;p++) {
25653   dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]);
25654 }
25655 dump_int(mp->st_count);
25656 mp_print_ln(mp); mp_print_int(mp, mp->st_count); mp_print(mp, " symbolic tokens")
25657
25658 @ @<Undump the table of equivalents and the hash table@>=
25659 undump(1,frozen_inaccessible,mp->hash_used); 
25660 p=0;
25661 do {  
25662   undump(p+1,mp->hash_used,p); 
25663   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
25664 } while (p!=mp->hash_used);
25665 for (p=mp->hash_used+1;p<=(int)hash_end;p++ )  { 
25666   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
25667 }
25668 undump_int(mp->st_count)
25669
25670 @ We have already printed a lot of statistics, so we set |mp_tracing_stats:=0|
25671 to prevent them appearing again.
25672
25673 @<Dump a few more things and the closing check word@>=
25674 dump_int(mp->max_internal);
25675 dump_int(mp->int_ptr);
25676 for (k=1;k<= mp->int_ptr;k++ ) { 
25677   dump_int(mp->internal[k]); 
25678   dump_string(mp->int_name[k]);
25679 }
25680 dump_int(mp->start_sym); 
25681 dump_int(mp->interaction); 
25682 dump_string(mp->mem_ident);
25683 dump_int(mp->bg_loc); dump_int(mp->eg_loc); dump_int(mp->serial_no); dump_int(69073);
25684 mp->internal[mp_tracing_stats]=0
25685
25686 @ @<Undump a few more things and the closing check word@>=
25687 undump_int(x);
25688 if (x>mp->max_internal) mp_grow_internals(mp,x);
25689 undump_int(mp->int_ptr);
25690 for (k=1;k<= mp->int_ptr;k++) { 
25691   undump_int(mp->internal[k]);
25692   undump_string(mp->int_name[k]);
25693 }
25694 undump(0,frozen_inaccessible,mp->start_sym);
25695 if (mp->interaction==mp_unspecified_mode) {
25696   undump(mp_unspecified_mode,mp_error_stop_mode,mp->interaction);
25697 } else {
25698   undump(mp_unspecified_mode,mp_error_stop_mode,x);
25699 }
25700 undump_string(mp->mem_ident);
25701 undump(1,hash_end,mp->bg_loc);
25702 undump(1,hash_end,mp->eg_loc);
25703 undump_int(mp->serial_no);
25704 undump_int(x); 
25705 if (x!=69073) goto OFF_BASE
25706
25707 @ @<Create the |mem_ident|...@>=
25708
25709   xfree(mp->mem_ident);
25710   mp->mem_ident = xmalloc(256,1);
25711   snprintf(mp->mem_ident,256," (mem=%s %i.%i.%i)", 
25712            mp->job_name,
25713            (int)(mp_round_unscaled(mp, mp->internal[mp_year]) % 100),
25714            (int)mp_round_unscaled(mp, mp->internal[mp_month]),
25715            (int)mp_round_unscaled(mp, mp->internal[mp_day]));
25716   mp_pack_job_name(mp, mem_extension);
25717   while (! mp_w_open_out(mp, &mp->mem_file) )
25718     mp_prompt_file_name(mp, "mem file name", mem_extension);
25719   mp_print_nl(mp, "Beginning to dump on file ");
25720 @.Beginning to dump...@>
25721   mp_print(mp, mp->name_of_file); 
25722   mp_print_nl(mp, mp->mem_ident);
25723 }
25724
25725 @ @<Dealloc variables@>=
25726 xfree(mp->mem_ident);
25727
25728 @ @<Close the mem file@>=
25729 (mp->close_file)(mp->mem_file)
25730
25731 @* \[46] The main program.
25732 This is it: the part of \MP\ that executes all those procedures we have
25733 written.
25734
25735 Well---almost. We haven't put the parsing subroutines into the
25736 program yet; and we'd better leave space for a few more routines that may
25737 have been forgotten.
25738
25739 @c @<Declare the basic parsing subroutines@>;
25740 @<Declare miscellaneous procedures that were declared |forward|@>;
25741 @<Last-minute procedures@>
25742
25743 @ We've noted that there are two versions of \MP. One, called \.{INIMP},
25744 @.INIMP@>
25745 has to be run first; it initializes everything from scratch, without
25746 reading a mem file, and it has the capability of dumping a mem file.
25747 The other one is called `\.{VIRMP}'; it is a ``virgin'' program that needs
25748 @.VIRMP@>
25749 to input a mem file in order to get started. \.{VIRMP} typically has
25750 a bit more memory capacity than \.{INIMP}, because it does not need the
25751 space consumed by the dumping/undumping routines and the numerous calls on
25752 |primitive|, etc.
25753
25754 The \.{VIRMP} program cannot read a mem file instantaneously, of course;
25755 the best implementations therefore allow for production versions of \MP\ that
25756 not only avoid the loading routine for \PASCAL\ object code, they also have
25757 a mem file pre-loaded. 
25758
25759 @<Glob...@>=
25760 boolean ini_version; /* are we iniMP? */
25761
25762 @ @<Option variables@>=
25763 int ini_version; /* are we iniMP? */
25764
25765 @ @<Set |ini_version|@>=
25766 mp->ini_version = (opt->ini_version ? true : false);
25767
25768 @ Here we do whatever is needed to complete \MP's job gracefully on the
25769 local operating system. The code here might come into play after a fatal
25770 error; it must therefore consist entirely of ``safe'' operations that
25771 cannot produce error messages. For example, it would be a mistake to call
25772 |str_room| or |make_string| at this time, because a call on |overflow|
25773 might lead to an infinite loop.
25774 @^system dependencies@>
25775
25776 This program doesn't bother to close the input files that may still be open.
25777
25778 @<Last-minute...@>=
25779 void mp_close_files_and_terminate (MP mp) {
25780   integer k; /* all-purpose index */
25781   integer LH; /* the length of the \.{TFM} header, in words */
25782   int lk_offset; /* extra words inserted at beginning of |lig_kern| array */
25783   pointer p; /* runs through a list of \.{TFM} dimensions */
25784   @<Close all open files in the |rd_file| and |wr_file| arrays@>;
25785   if ( mp->internal[mp_tracing_stats]>0 )
25786     @<Output statistics about this job@>;
25787   wake_up_terminal; 
25788   @<Do all the finishing work on the \.{TFM} file@>;
25789   @<Explain what output files were written@>;
25790   if ( mp->log_opened ){ 
25791     wlog_cr;
25792     (mp->close_file)(mp->log_file); 
25793     mp->selector=mp->selector-2;
25794     if ( mp->selector==term_only ) {
25795       mp_print_nl(mp, "Transcript written on ");
25796 @.Transcript written...@>
25797       mp_print(mp, mp->log_name); mp_print_char(mp, '.');
25798     }
25799   }
25800   mp_print_ln(mp);
25801 }
25802
25803 @ @<Declarations@>=
25804 void mp_close_files_and_terminate (MP mp) ;
25805
25806 @ @<Close all open files in the |rd_file| and |wr_file| arrays@>=
25807 if (mp->rd_fname!=NULL) {
25808   for (k=0;k<=(int)mp->read_files-1;k++ ) {
25809     if ( mp->rd_fname[k]!=NULL ) {
25810       (mp->close_file)(mp->rd_file[k]);
25811    }
25812  }
25813 }
25814 if (mp->wr_fname!=NULL) {
25815   for (k=0;k<=(int)mp->write_files-1;k++) {
25816     if ( mp->wr_fname[k]!=NULL ) {
25817      (mp->close_file)(mp->wr_file[k]);
25818     }
25819   }
25820 }
25821
25822 @ @<Dealloc ...@>=
25823 for (k=0;k<(int)mp->max_read_files;k++ ) {
25824   if ( mp->rd_fname[k]!=NULL ) {
25825     (mp->close_file)(mp->rd_file[k]);
25826     mp_xfree(mp->rd_fname[k]); 
25827   }
25828 }
25829 mp_xfree(mp->rd_file);
25830 mp_xfree(mp->rd_fname);
25831 for (k=0;k<(int)mp->max_write_files;k++) {
25832   if ( mp->wr_fname[k]!=NULL ) {
25833     (mp->close_file)(mp->wr_file[k]);
25834     mp_xfree(mp->wr_fname[k]); 
25835   }
25836 }
25837 mp_xfree(mp->wr_file);
25838 mp_xfree(mp->wr_fname);
25839
25840
25841 @ We want to produce a \.{TFM} file if and only if |mp_fontmaking| is positive.
25842
25843 We reclaim all of the variable-size memory at this point, so that
25844 there is no chance of another memory overflow after the memory capacity
25845 has already been exceeded.
25846
25847 @<Do all the finishing work on the \.{TFM} file@>=
25848 if ( mp->internal[mp_fontmaking]>0 ) {
25849   @<Make the dynamic memory into one big available node@>;
25850   @<Massage the \.{TFM} widths@>;
25851   mp_fix_design_size(mp); mp_fix_check_sum(mp);
25852   @<Massage the \.{TFM} heights, depths, and italic corrections@>;
25853   mp->internal[mp_fontmaking]=0; /* avoid loop in case of fatal error */
25854   @<Finish the \.{TFM} file@>;
25855 }
25856
25857 @ @<Make the dynamic memory into one big available node@>=
25858 mp->rover=lo_mem_stat_max+1; link(mp->rover)=empty_flag; mp->lo_mem_max=mp->hi_mem_min-1;
25859 if ( mp->lo_mem_max-mp->rover>max_halfword ) mp->lo_mem_max=max_halfword+mp->rover;
25860 node_size(mp->rover)=mp->lo_mem_max-mp->rover; 
25861 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
25862 link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null
25863
25864 @ The present section goes directly to the log file instead of using
25865 |print| commands, because there's no need for these strings to take
25866 up |str_pool| memory when a non-{\bf stat} version of \MP\ is being used.
25867
25868 @<Output statistics...@>=
25869 if ( mp->log_opened ) { 
25870   char s[128];
25871   wlog_ln(" ");
25872   wlog_ln("Here is how much of MetaPost's memory you used:");
25873 @.Here is how much...@>
25874   snprintf(s,128," %i string%s out of %i",(int)mp->max_strs_used-mp->init_str_use,
25875           (mp->max_strs_used!=mp->init_str_use+1 ? "s" : ""),
25876           (int)(mp->max_strings-1-mp->init_str_use));
25877   wlog_ln(s);
25878   snprintf(s,128," %i string characters out of %i",
25879            (int)mp->max_pl_used-mp->init_pool_ptr,
25880            (int)mp->pool_size-mp->init_pool_ptr);
25881   wlog_ln(s);
25882   snprintf(s,128," %i words of memory out of %i",
25883            (int)mp->lo_mem_max+mp->mem_end-mp->hi_mem_min+2,
25884            (int)mp->mem_end+1);
25885   wlog_ln(s);
25886   snprintf(s,128," %i symbolic tokens out of %i", (int)mp->st_count, (int)mp->hash_size);
25887   wlog_ln(s);
25888   snprintf(s,128," %ii, %in, %ip, %ib stack positions out of %ii, %in, %ip, %ib",
25889            (int)mp->max_in_stack,(int)mp->int_ptr,
25890            (int)mp->max_param_stack,(int)mp->max_buf_stack+1,
25891            (int)mp->stack_size,(int)mp->max_internal,(int)mp->param_size,(int)mp->buf_size);
25892   wlog_ln(s);
25893   snprintf(s,128," %i string compactions (moved %i characters, %i strings)",
25894           (int)mp->pact_count,(int)mp->pact_chars,(int)mp->pact_strs);
25895   wlog_ln(s);
25896 }
25897
25898 @ We get to the |final_cleanup| routine when \&{end} or \&{dump} has
25899 been scanned.
25900
25901 @<Last-minute...@>=
25902 void mp_final_cleanup (MP mp) {
25903   small_number c; /* 0 for \&{end}, 1 for \&{dump} */
25904   c=mp->cur_mod;
25905   if ( mp->job_name==NULL ) mp_open_log_file(mp);
25906   while ( mp->input_ptr>0 ) {
25907     if ( token_state ) mp_end_token_list(mp);
25908     else  mp_end_file_reading(mp);
25909   }
25910   while ( mp->loop_ptr!=null ) mp_stop_iteration(mp);
25911   while ( mp->open_parens>0 ) { 
25912     mp_print(mp, " )"); decr(mp->open_parens);
25913   };
25914   while ( mp->cond_ptr!=null ) {
25915     mp_print_nl(mp, "(end occurred when ");
25916 @.end occurred...@>
25917     mp_print_cmd_mod(mp, fi_or_else,mp->cur_if);
25918     /* `\.{if}' or `\.{elseif}' or `\.{else}' */
25919     if ( mp->if_line!=0 ) {
25920       mp_print(mp, " on line "); mp_print_int(mp, mp->if_line);
25921     }
25922     mp_print(mp, " was incomplete)");
25923     mp->if_line=if_line_field(mp->cond_ptr);
25924     mp->cur_if=name_type(mp->cond_ptr); mp->cond_ptr=link(mp->cond_ptr);
25925   }
25926   if ( mp->history!=mp_spotless )
25927     if ( ((mp->history==mp_warning_issued)||(mp->interaction<mp_error_stop_mode)) )
25928       if ( mp->selector==term_and_log ) {
25929     mp->selector=term_only;
25930     mp_print_nl(mp, "(see the transcript file for additional information)");
25931 @.see the transcript file...@>
25932     mp->selector=term_and_log;
25933   }
25934   if ( c==1 ) {
25935     if (mp->ini_version) {
25936       mp_store_mem_file(mp); return;
25937     }
25938     mp_print_nl(mp, "(dump is performed only by INIMP)"); return;
25939 @.dump...only by INIMP@>
25940   }
25941 }
25942
25943 @ @<Declarations@>=
25944 void mp_final_cleanup (MP mp) ;
25945 void mp_init_prim (MP mp) ;
25946 void mp_init_tab (MP mp) ;
25947
25948 @ @<Last-minute...@>=
25949 void mp_init_prim (MP mp) { /* initialize all the primitives */
25950   @<Put each...@>;
25951 }
25952 @#
25953 void mp_init_tab (MP mp) { /* initialize other tables */
25954   integer k; /* all-purpose index */
25955   @<Initialize table entries (done by \.{INIMP} only)@>;
25956 }
25957
25958
25959 @ When we begin the following code, \MP's tables may still contain garbage;
25960 the strings might not even be present. Thus we must proceed cautiously to get
25961 bootstrapped in.
25962
25963 But when we finish this part of the program, \MP\ is ready to call on the
25964 |main_control| routine to do its work.
25965
25966 @<Get the first line...@>=
25967
25968   @<Initialize the input routines@>;
25969   if ( (mp->mem_ident==NULL)||(mp->buffer[loc]=='&') ) {
25970     if ( mp->mem_ident!=NULL ) {
25971       mp_do_initialize(mp); /* erase preloaded mem */
25972     }
25973     if ( ! mp_open_mem_file(mp) ) return mp_fatal_error_stop;
25974     if ( ! mp_load_mem_file(mp) ) {
25975       (mp->close_file)(mp->mem_file); 
25976       return mp_fatal_error_stop;
25977     }
25978     (mp->close_file)( mp->mem_file);
25979     while ( (loc<limit)&&(mp->buffer[loc]==' ') ) incr(loc);
25980   }
25981   mp->buffer[limit]='%';
25982   mp_fix_date_and_time(mp);
25983   mp->sys_random_seed = (scaled)(mp->get_random_seed)(mp);
25984   mp_init_randoms(mp, mp->sys_random_seed);
25985   @<Initialize the print |selector|...@>;
25986   if ( loc<limit ) if ( mp->buffer[loc]!='\\' ) 
25987     mp_start_input(mp); /* \&{input} assumed */
25988 }
25989
25990 @ @<Run inimpost commands@>=
25991 {
25992   mp_get_strings_started(mp);
25993   mp_init_tab(mp); /* initialize the tables */
25994   mp_init_prim(mp); /* call |primitive| for each primitive */
25995   mp->init_str_use=mp->str_ptr; mp->init_pool_ptr=mp->pool_ptr;
25996   mp->max_str_ptr=mp->str_ptr; mp->max_pool_ptr=mp->pool_ptr;
25997   mp_fix_date_and_time(mp);
25998 }
25999
26000
26001 @* \[47] Debugging.
26002 Once \MP\ is working, you should be able to diagnose most errors with
26003 the \.{show} commands and other diagnostic features. But for the initial
26004 stages of debugging, and for the revelation of really deep mysteries, you
26005 can compile \MP\ with a few more aids, including the \PASCAL\ runtime
26006 checks and its debugger. An additional routine called |debug_help|
26007 will also come into play when you type `\.D' after an error message;
26008 |debug_help| also occurs just before a fatal error causes \MP\ to succumb.
26009 @^debugging@>
26010 @^system dependencies@>
26011
26012 The interface to |debug_help| is primitive, but it is good enough when used
26013 with a \PASCAL\ debugger that allows you to set breakpoints and to read
26014 variables and change their values. After getting the prompt `\.{debug \#}', you
26015 type either a negative number (this exits |debug_help|), or zero (this
26016 goes to a location where you can set a breakpoint, thereby entering into
26017 dialog with the \PASCAL\ debugger), or a positive number |m| followed by
26018 an argument |n|. The meaning of |m| and |n| will be clear from the
26019 program below. (If |m=13|, there is an additional argument, |l|.)
26020 @.debug \#@>
26021
26022 @<Last-minute...@>=
26023 void mp_debug_help (MP mp) { /* routine to display various things */
26024   integer k;
26025   int l,m,n;
26026   char *aline;
26027   size_t len;
26028   while (1) { 
26029     wake_up_terminal;
26030     mp_print_nl(mp, "debug # (-1 to exit):"); update_terminal;
26031 @.debug \#@>
26032     m = 0;
26033     aline = (mp->read_ascii_file)(mp->term_in, &len);
26034     if (len) { sscanf(aline,"%i",&m); xfree(aline); }
26035     if ( m<=0 )
26036       return;
26037     n = 0 ;
26038     aline = (mp->read_ascii_file)(mp->term_in, &len);
26039     if (len) { sscanf(aline,"%i",&n); xfree(aline); }
26040     switch (m) {
26041     @<Numbered cases for |debug_help|@>;
26042     default: mp_print(mp, "?"); break;
26043     }
26044   }
26045 }
26046
26047 @ @<Numbered cases...@>=
26048 case 1: mp_print_word(mp, mp->mem[n]); /* display |mem[n]| in all forms */
26049   break;
26050 case 2: mp_print_int(mp, info(n));
26051   break;
26052 case 3: mp_print_int(mp, link(n));
26053   break;
26054 case 4: mp_print_int(mp, eq_type(n)); mp_print_char(mp, ':'); mp_print_int(mp, equiv(n));
26055   break;
26056 case 5: mp_print_variable_name(mp, n);
26057   break;
26058 case 6: mp_print_int(mp, mp->internal[n]);
26059   break;
26060 case 7: mp_do_show_dependencies(mp);
26061   break;
26062 case 9: mp_show_token_list(mp, n,null,100000,0);
26063   break;
26064 case 10: mp_print_str(mp, n);
26065   break;
26066 case 11: mp_check_mem(mp, n>0); /* check wellformedness; print new busy locations if |n>0| */
26067   break;
26068 case 12: mp_search_mem(mp, n); /* look for pointers to |n| */
26069   break;
26070 case 13: 
26071   l = 0;  
26072   aline = (mp->read_ascii_file)(mp->term_in, &len);
26073   if (len) { sscanf(aline,"%i",&l); xfree(aline); }
26074   mp_print_cmd_mod(mp, n,l); 
26075   break;
26076 case 14: for (k=0;k<=n;k++) mp_print_str(mp, mp->buffer[k]);
26077   break;
26078 case 15: mp->panicking=! mp->panicking;
26079   break;
26080
26081
26082 @ Saving the filename template
26083
26084 @<Save the filename template@>=
26085
26086   if ( mp->filename_template!=0 ) delete_str_ref(mp->filename_template);
26087   if ( length(mp->cur_exp)==0 ) mp->filename_template=0;
26088   else { 
26089     mp->filename_template=mp->cur_exp; add_str_ref(mp->filename_template);
26090   }
26091 }
26092
26093 @* \[48] System-dependent changes.
26094 This section should be replaced, if necessary, by any special
26095 modification of the program
26096 that are necessary to make \MP\ work at a particular installation.
26097 It is usually best to design your change file so that all changes to
26098 previous sections preserve the section numbering; then everybody's version
26099 will be consistent with the published program. More extensive changes,
26100 which introduce new sections, can be inserted here; then only the index
26101 itself will get a new section number.
26102 @^system dependencies@>
26103
26104 @* \[49] Index.
26105 Here is where you can find all uses of each identifier in the program,
26106 with underlined entries pointing to where the identifier was defined.
26107 If the identifier is only one letter long, however, you get to see only
26108 the underlined entries. {\sl All references are to section numbers instead of
26109 page numbers.}
26110
26111 This index also lists error messages and other aspects of the program
26112 that you might want to look up some day. For example, the entry
26113 for ``system dependencies'' lists all sections that should receive
26114 special attention from people who are installing \MP\ in a new
26115 operating environment. A list of various things that can't happen appears
26116 under ``this can't happen''.
26117 Approximately 25 sections are listed under ``inner loop''; these account
26118 for more than 60\pct! of \MP's running time, exclusive of input and output.