mempcy should be faster
[mplib] / src / texk / web2c / mpdir / lib / mp.w
1 % $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $
2 % MetaPost, by John Hobby.  Public domain.
3
4 % Much of this program was copied with permission from MF.web Version 1.9
5 % It interprets a language very similar to D.E. Knuth's METAFONT, but with
6 % changes designed to make it more suitable for PostScript output.
7
8 % TeX is a trademark of the American Mathematical Society.
9 % METAFONT is a trademark of Addison-Wesley Publishing Company.
10 % PostScript is a trademark of Adobe Systems Incorporated.
11
12 % Here is TeX material that gets inserted after \input webmac
13 \def\hang{\hangindent 3em\noindent\ignorespaces}
14 \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
15 \def\PASCAL{Pascal}
16 \def\ps{PostScript}
17 \def\ph{\hbox{Pascal-H}}
18 \def\psqrt#1{\sqrt{\mathstrut#1}}
19 \def\k{_{k+1}}
20 \def\pct!{{\char`\%}} % percent sign in ordinary text
21 \font\tenlogo=logo10 % font used for the METAFONT logo
22 \font\logos=logosl10
23 \def\MF{{\tenlogo META}\-{\tenlogo FONT}}
24 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
25 \def\[#1]{#1.} % from pascal web
26 \def\<#1>{$\langle#1\rangle$}
27 \def\section{\mathhexbox278}
28 \let\swap=\leftrightarrow
29 \def\round{\mathop{\rm round}\nolimits}
30 \mathchardef\vb="026A % synonym for `\|'
31
32 \def\(#1){} % this is used to make section names sort themselves better
33 \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
34 \def\title{MetaPost}
35 \def\glob{15} % this should be the section number of "<Global...>"
36 \def\gglob{23, 28} % this should be the next two sections of "<Global...>"
37 \pdfoutput=1
38 \pageno=3
39
40 @* \[1] Introduction.
41 This is \MP, a graphics-language processor based on D. E. Knuth's \MF.
42
43 The main purpose of the following program is to explain the algorithms of \MP\
44 as clearly as possible. As a result, the program will not necessarily be very
45 efficient when a particular \PASCAL\ compiler has translated it into a
46 particular machine language. However, the program has been written so that it
47 can be tuned to run efficiently in a wide variety of operating environments
48 by making comparatively few changes. Such flexibility is possible because
49 the documentation that follows is written in the \.{WEB} language, which is
50 at a higher level than \PASCAL; the preprocessing step that converts \.{WEB}
51 to \PASCAL\ is able to introduce most of the necessary refinements.
52 Semi-automatic translation to other languages is also feasible, because the
53 program below does not make extensive use of features that are peculiar to
54 \PASCAL.
55
56 A large piece of software like \MP\ has inherent complexity that cannot
57 be reduced below a certain level of difficulty, although each individual
58 part is fairly simple by itself. The \.{WEB} language is intended to make
59 the algorithms as readable as possible, by reflecting the way the
60 individual program pieces fit together and by providing the
61 cross-references that connect different parts. Detailed comments about
62 what is going on, and about why things were done in certain ways, have
63 been liberally sprinkled throughout the program.  These comments explain
64 features of the implementation, but they rarely attempt to explain the
65 \MP\ language itself, since the reader is supposed to be familiar with
66 {\sl The {\logos METAFONT\/}book} as well as the manual
67 @.WEB@>
68 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
69 {\sl A User's Manual for MetaPost}, Computing Science Technical Report 162,
70 AT\AM T Bell Laboratories.
71
72 @ The present implementation is a preliminary version, but the possibilities
73 for new features are limited by the desire to remain as nearly compatible
74 with \MF\ as possible.
75
76 On the other hand, the \.{WEB} description can be extended without changing
77 the core of the program, and it has been designed so that such
78 extensions are not extremely difficult to make.
79 The |banner| string defined here should be changed whenever \MP\
80 undergoes any modifications, so that it will be clear which version of
81 \MP\ might be the guilty party when a problem arises.
82 @^extensions to \MP@>
83 @^system dependencies@>
84
85 @d banner "This is MetaPost, Version 1.002" /* printed when \MP\ starts */
86 @d metapost_version "1.002"
87 @d mplib_version "0.10"
88 @d version_string " (Cweb version 0.10)"
89
90 @ Different \PASCAL s have slightly different conventions, and the present
91 @:PASCAL H}{\ph@>
92 program is expressed in a version of \PASCAL\ that D. E. Knuth used for \MF.
93 Constructions that apply to
94 this particular compiler, which we shall call \ph, should help the
95 reader see how to make an appropriate interface for other systems
96 if necessary. (\ph\ is Charles Hedrick's modification of a compiler
97 @^Hedrick, Charles Locke@>
98 for the DECsystem-10 that was originally developed at the University of
99 Hamburg; cf.\ {\sl SOFTWARE---Practice \AM\ Experience \bf6} (1976),
100 29--42. The \MP\ program below is intended to be adaptable, without
101 extensive changes, to most other versions of \PASCAL\ and commonly used
102 \PASCAL-to-C translators, so it does not fully
103 @:C@>
104 use the admirable features of \ph. Indeed, a conscious effort has been
105 made here to avoid using several idiosyncratic features of standard
106 \PASCAL\ itself, so that most of the code can be translated mechanically
107 into other high-level languages. For example, the `\&{with}' and `\\{new}'
108 features are not used, nor are pointer types, set types, or enumerated
109 scalar types; there are no `\&{var}' parameters, except in the case of files;
110 there are no tag fields on variant records; there are no |real| variables;
111 no procedures are declared local to other procedures.)
112
113 The portions of this program that involve system-dependent code, where
114 changes might be necessary because of differences between \PASCAL\ compilers
115 and/or differences between
116 operating systems, can be identified by looking at the sections whose
117 numbers are listed under `system dependencies' in the index. Furthermore,
118 the index entries for `dirty \PASCAL' list all places where the restrictions
119 of \PASCAL\ have not been followed perfectly, for one reason or another.
120 @^system dependencies@>
121 @^dirty \PASCAL@>
122
123 @ The program begins with a normal \PASCAL\ program heading, whose
124 components will be filled in later, using the conventions of \.{WEB}.
125 @.WEB@>
126 For example, the portion of the program called `\X\glob:Global
127 variables\X' below will be replaced by a sequence of variable declarations
128 that starts in $\section\glob$ of this documentation. In this way, we are able
129 to define each individual global variable when we are prepared to
130 understand what it means; we do not have to define all of the globals at
131 once.  Cross references in $\section\glob$, where it says ``See also
132 sections \gglob, \dots,'' also make it possible to look at the set of
133 all global variables, if desired.  Similar remarks apply to the other
134 portions of the program heading.
135
136 Actually the heading shown here is not quite normal: The |program| line
137 does not mention any |output| file, because \ph\ would ask the \MP\ user
138 to specify a file name if |output| were specified here.
139 @^system dependencies@>
140
141 @d true 1
142 @d false 0
143  
144 @(mplib.h@>=
145 #  ifndef LIBAVL_ALLOCATOR
146 #    define LIBAVL_ALLOCATOR
147     struct libavl_allocator {
148         void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
149         void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
150     };
151 #  endif
152 typedef struct psout_data_struct * psout_data;
153 typedef struct MP_instance * MP;
154 typedef int boolean;
155 typedef signed int integer;
156 @<Types in the outer block@>
157 typedef struct MP_options {
158   @<Option variables@>
159 } MP_options;
160 @<Declare helpers@>;
161 @<Exported function headers@>
162
163 @ @(mpmp.h@>=
164 @<Constants in the outer block@>
165 typedef struct MP_instance {
166   @<Global variables@>
167 } MP_instance;
168
169 @ @c 
170 #include <stdio.h>
171 #include <stdlib.h>
172 #include <string.h>
173 #include <stdarg.h>
174 #include <assert.h>
175 #include <unistd.h> /* for access() */
176 #include <time.h> /* for struct tm \& co */
177 #include "mplib.h"
178 #include "mpmp.h" /* internal header */
179 #include "mppsout.h" /* internal header */
180 @h
181 @<Declarations@>
182 @<Basic printing procedures@>
183 @<Error handling procedures@>
184
185 @ Here are the functions that set up the \MP\ instance.
186
187 @<Declarations@> =
188 @<Declare |mp_reallocate| functions@>;
189 struct MP_options *mp_options (void) {
190   struct MP_options *opt;
191   opt = xmalloc(1,sizeof(MP_options));
192   memset (opt,0,sizeof(MP_options));
193   return opt;
194
195 MP mp_new (struct MP_options *opt) {
196   MP mp;
197   mp = xmalloc(1,sizeof(MP_instance));
198   @<Set |ini_version|@>;
199   @<Allocate or initialize variables@>
200   if (opt->main_memory>mp->mem_max)
201     mp_reallocate_memory(mp,opt->main_memory);
202   mp_reallocate_paths(mp,1000);
203   mp_reallocate_fonts(mp,8);
204   mp->term_in = stdin;
205   mp->term_out = stdout;
206   return mp;
207 }
208 void mp_free (MP mp) {
209   int k; /* loop variable */
210   @<Dealloc variables@>
211   xfree(mp);
212 }
213
214 @ @c
215 boolean mp_initialize (MP mp) { /* this procedure gets things started properly */
216   @<Local variables for initialization@>
217   mp->history=fatal_error_stop; /* in case we quit during initialization */
218   t_open_out; /* open the terminal for output */
219   @<Check the ``constant'' values...@>;
220   if ( mp->bad>0 ) {
221     fprintf(stdout,"Ouch---my internal constants have been clobbered!\n"
222                    "---case %i",(int)mp->bad);
223 @.Ouch...clobbered@>
224     return false;
225   }
226   @<Set initial values of key variables@>
227   if (mp->ini_version) {
228     @<Run inimpost commands@>;
229   }
230   @<Initialize the output routines@>;
231   @<Get the first line of input and prepare to start@>;
232   mp_set_job_id(mp,mp->internal[year],mp->internal[month],
233                        mp->internal[day],mp->internal[mp_time]);
234   mp_init_map_file(mp, mp->troff_mode);
235   mp->history=spotless; /* ready to go! */
236   if (mp->troff_mode) {
237     mp->internal[gtroffmode]=unity; 
238     mp->internal[prologues]=unity; 
239   }
240   if ( mp->start_sym>0 ) { /* insert the `\&{everyjob}' symbol */
241     mp->cur_sym=mp->start_sym; mp_back_input(mp);
242   }
243   return true;
244 }
245
246
247 @<Exported function headers@>=
248 extern struct MP_options *mp_options (void);
249 extern MP mp_new (struct MP_options *opt) ;
250 extern void mp_free (MP mp);
251 extern boolean mp_initialize (MP mp);
252
253
254 @ The overall \MP\ program begins with the heading just shown, after which
255 comes a bunch of procedure declarations and function declarations.
256 Finally we will get to the main program, which begins with the
257 comment `|start_here|'. If you want to skip down to the
258 main program now, you can look up `|start_here|' in the index.
259 But the author suggests that the best way to understand this program
260 is to follow pretty much the order of \MP's components as they appear in the
261 \.{WEB} description you are now reading, since the present ordering is
262 intended to combine the advantages of the ``bottom up'' and ``top down''
263 approaches to the problem of understanding a somewhat complicated system.
264
265 @ Some of the code below is intended to be used only when diagnosing the
266 strange behavior that sometimes occurs when \MP\ is being installed or
267 when system wizards are fooling around with \MP\ without quite knowing
268 what they are doing. Such code will not normally be compiled; it is
269 delimited by the preprocessor test `|#ifdef DEBUG .. #endif|'.
270
271 @ This program has two important variations: (1) There is a long and slow
272 version called \.{INIMP}, which does the extra calculations needed to
273 @.INIMP@>
274 initialize \MP's internal tables; and (2)~there is a shorter and faster
275 production version, which cuts the initialization to a bare minimum.
276
277 Which is which is decided at runtime.
278
279 @ The following parameters can be changed at compile time to extend or
280 reduce \MP's capacity. They may have different values in \.{INIMP} and
281 in production versions of \MP.
282 @.INIMP@>
283 @^system dependencies@>
284
285 @<Constants...@>=
286 #define file_name_size 255 /* file names shouldn't be longer than this */
287 #define bistack_size 1500 /* size of stack for bisection algorithms;
288   should probably be left at this value */
289
290 @ Like the preceding parameters, the following quantities can be changed
291 at compile time to extend or reduce \MP's capacity. But if they are changed,
292 it is necessary to rerun the initialization program \.{INIMP}
293 @.INIMP@>
294 to generate new tables for the production \MP\ program.
295 One can't simply make helter-skelter changes to the following constants,
296 since certain rather complex initialization
297 numbers are computed from them. 
298
299 @ @<Glob...@>=
300 int max_strings; /* maximum number of strings; must not exceed |max_halfword| */
301 int pool_size; /* maximum number of characters in strings, including all
302   error messages and help texts, and the names of all identifiers */
303 int error_line; /* width of context lines on terminal error messages */
304 int half_error_line; /* width of first lines of contexts in terminal
305   error messages; should be between 30 and |error_line-15| */
306 int max_print_line; /* width of longest text lines output; should be at least 60 */
307 int mem_max; /* greatest index in \MP's internal |mem| array;
308   must be strictly less than |max_halfword|;
309   must be equal to |mem_top| in \.{INIMP}, otherwise |>=mem_top| */
310 int mem_top; /* largest index in the |mem| array dumped by \.{INIMP};
311   must not be greater than |mem_max| */
312 int hash_size; /* maximum number of symbolic tokens,
313   must be less than |max_halfword-3*param_size| */
314 int hash_prime; /* a prime number equal to about 85\pct! of |hash_size| */
315 int param_size; /* maximum number of simultaneous macro parameters */
316 int max_in_open; /* maximum number of input files and error insertions that
317   can be going on simultaneously */
318
319 @ @<Option variables@>=
320 int error_line;
321 int half_error_line;
322 int max_print_line;
323 int main_memory;
324 int hash_size; 
325 int hash_prime; 
326 int param_size; 
327 int max_in_open; 
328
329
330 @d set_value(a,b,c) do { a=c; if (b>c) a=b; } while (0)
331
332 @<Allocate or ...@>=
333 mp->max_strings=500;
334 mp->pool_size=10000;
335 set_value(mp->error_line,opt->error_line,79);
336 set_value(mp->half_error_line,opt->half_error_line,50);
337 set_value(mp->max_print_line,opt->max_print_line,79);
338 mp->mem_max=5000;
339 mp->mem_top=5000;
340 set_value(mp->hash_size,opt->hash_size,9500);
341 set_value(mp->hash_prime,opt->hash_prime,7919);
342 set_value(mp->param_size,opt->param_size,150);
343 set_value(mp->max_in_open,opt->max_in_open,10);
344
345
346 @ In case somebody has inadvertently made bad settings of the ``constants,''
347 \MP\ checks them using a global variable called |bad|.
348
349 This is the first of many sections of \MP\ where global variables are
350 defined.
351
352 @<Glob...@>=
353 integer bad; /* is some ``constant'' wrong? */
354
355 @ Later on we will say `\ignorespaces|if (mem_max>=max_halfword) bad=10;|',
356 or something similar. (We can't do that until |max_halfword| has been defined.)
357
358 @<Check the ``constant'' values for consistency@>=
359 mp->bad=0;
360 if ( (mp->half_error_line<30)||(mp->half_error_line>mp->error_line-15) ) mp->bad=1;
361 if ( mp->max_print_line<60 ) mp->bad=2;
362 if ( mp->mem_top<=1100 ) mp->bad=4;
363 if (mp->hash_prime>mp->hash_size ) mp->bad=5;
364
365 @ Labels are given symbolic names by the following definitions, so that
366 occasional |goto| statements will be meaningful. We insert the label
367 `|exit|:' just before the `\ignorespaces|end|\unskip' of a procedure in
368 which we have used the `|return|' statement defined below; the label
369 `|restart|' is occasionally used at the very beginning of a procedure; and
370 the label `|reswitch|' is occasionally used just prior to a |case|
371 statement in which some cases change the conditions and we wish to branch
372 to the newly applicable case.  Loops that are set up with the |loop|
373 construction defined below are commonly exited by going to `|done|' or to
374 `|found|' or to `|not_found|', and they are sometimes repeated by going to
375 `|continue|'.  If two or more parts of a subroutine start differently but
376 end up the same, the shared code may be gathered together at
377 `|common_ending|'.
378
379 Incidentally, this program never declares a label that isn't actually used,
380 because some fussy \PASCAL\ compilers will complain about redundant labels.
381
382 @d label_exit 10 /* go here to leave a procedure */
383 @d restart 20 /* go here to start a procedure again */
384 @d reswitch 21 /* go here to start a case statement again */
385 @d continue 22 /* go here to resume a loop */
386 @d done 30 /* go here to exit a loop */
387 @d done1 31 /* like |done|, when there is more than one loop */
388 @d done2 32 /* for exiting the second loop in a long block */
389 @d done3 33 /* for exiting the third loop in a very long block */
390 @d done4 34 /* for exiting the fourth loop in an extremely long block */
391 @d done5 35 /* for exiting the fifth loop in an immense block */
392 @d done6 36 /* for exiting the sixth loop in a block */
393 @d found 40 /* go here when you've found it */
394 @d found1 41 /* like |found|, when there's more than one per routine */
395 @d found2 42 /* like |found|, when there's more than two per routine */
396 @d found3 43 /* like |found|, when there's more than three per routine */
397 @d not_found 45 /* go here when you've found nothing */
398 @d common_ending 50 /* go here when you want to merge with another branch */
399
400 @ Here are some macros for common programming idioms.
401
402 @d incr(A)   (A)=(A)+1 /* increase a variable by unity */
403 @d decr(A)   (A)=(A)-1 /* decrease a variable by unity */
404 @d negate(A)   (A)=-(A) /* change the sign of a variable */
405 @d odd(A)   ((A)%2==1)
406 @d chr(A)   (A)
407 @d do_nothing   /* empty statement */
408 @d Return   goto exit /* terminate a procedure call */
409 @f return   nil /* \.{WEB} will henceforth say |return| instead of \\{return} */
410
411 @* \[2] The character set.
412 In order to make \MP\ readily portable to a wide variety of
413 computers, all of its input text is converted to an internal eight-bit
414 code that includes standard ASCII, the ``American Standard Code for
415 Information Interchange.''  This conversion is done immediately when each
416 character is read in. Conversely, characters are converted from ASCII to
417 the user's external representation just before they are output to a
418 text file.
419 @^ASCII code@>
420
421 Such an internal code is relevant to users of \MP\ only with respect to
422 the \&{char} and \&{ASCII} operations, and the comparison of strings.
423
424 @ Characters of text that have been converted to \MP's internal form
425 are said to be of type |ASCII_code|, which is a subrange of the integers.
426
427 @<Types...@>=
428 typedef unsigned char ASCII_code; /* eight-bit numbers */
429
430 @ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
431 character sets were common, so it did not make provision for lowercase
432 letters. Nowadays, of course, we need to deal with both capital and small
433 letters in a convenient way, especially in a program for font design;
434 so the present specification of \MP\ has been written under the assumption
435 that the \PASCAL\ compiler and run-time system permit the use of text files
436 with more than 64 distinguishable characters. More precisely, we assume that
437 the character set contains at least the letters and symbols associated
438 with ASCII codes 040 through 0176; all of these characters are now
439 available on most computer terminals.
440
441 Since we are dealing with more characters than were present in the first
442 \PASCAL\ compilers, we have to decide what to call the associated data
443 type. Some \PASCAL s use the original name |char| for the
444 characters in text files, even though there now are more than 64 such
445 characters, while other \PASCAL s consider |char| to be a 64-element
446 subrange of a larger data type that has some other name.
447
448 In order to accommodate this difference, we shall use the name |text_char|
449 to stand for the data type of the characters that are converted to and
450 from |ASCII_code| when they are input and output. We shall also assume
451 that |text_char| consists of the elements |chr(first_text_char)| through
452 |chr(last_text_char)|, inclusive. The following definitions should be
453 adjusted if necessary.
454 @^system dependencies@>
455
456 @d first_text_char 0 /* ordinal number of the smallest element of |text_char| */
457 @d last_text_char 255 /* ordinal number of the largest element of |text_char| */
458
459 @<Types...@>=
460 typedef unsigned char text_char; /* the data type of characters in text files */
461
462 @ @<Local variables for init...@>=
463 integer i;
464
465 @ The \MP\ processor converts between ASCII code and
466 the user's external character set by means of arrays |xord| and |xchr|
467 that are analogous to \PASCAL's |ord| and |chr| functions.
468
469 @d xchr(A) mp->xchr[(A)]
470 @d xord(A) mp->xord[(A)]
471
472 @<Glob...@>=
473 ASCII_code xord[256];  /* specifies conversion of input characters */
474 text_char xchr[256];  /* specifies conversion of output characters */
475
476 @ The core system assumes all 8-bit is acceptable.  If it is not,
477 a change file has to alter the below section.
478 @^system dependencies@>
479
480 Additionally, people with extended character sets can
481 assign codes arbitrarily, giving an |xchr| equivalent to whatever
482 characters the users of \MP\ are allowed to have in their input files.
483 Appropriate changes to \MP's |char_class| table should then be made.
484 (Unlike \TeX, each installation of \MP\ has a fixed assignment of category
485 codes, called the |char_class|.) Such changes make portability of programs
486 more difficult, so they should be introduced cautiously if at all.
487 @^character set dependencies@>
488 @^system dependencies@>
489
490 @<Set initial ...@>=
491 for (i=0;i<=0377;i++) { xchr(i)=i; }
492
493 @ The following system-independent code makes the |xord| array contain a
494 suitable inverse to the information in |xchr|. Note that if |xchr[i]=xchr[j]|
495 where |i<j<0177|, the value of |xord[xchr[i]]| will turn out to be
496 |j| or more; hence, standard ASCII code numbers will be used instead of
497 codes below 040 in case there is a coincidence.
498
499 @<Set initial ...@>=
500 for (i=first_text_char;i<=last_text_char;i++) { 
501    xord(chr(i))=0177;
502 }
503 for (i=0200;i<=0377;i++) { xord(xchr(i))=i;}
504 for (i=0;i<=0176;i++) { xord(xchr(i))=i;}
505
506 @* \[3] Input and output.
507 The bane of portability is the fact that different operating systems treat
508 input and output quite differently, perhaps because computer scientists
509 have not given sufficient attention to this problem. People have felt somehow
510 that input and output are not part of ``real'' programming. Well, it is true
511 that some kinds of programming are more fun than others. With existing
512 input/output conventions being so diverse and so messy, the only sources of
513 joy in such parts of the code are the rare occasions when one can find a
514 way to make the program a little less bad than it might have been. We have
515 two choices, either to attack I/O now and get it over with, or to postpone
516 I/O until near the end. Neither prospect is very attractive, so let's
517 get it over with.
518
519 The basic operations we need to do are (1)~inputting and outputting of
520 text, to or from a file or the user's terminal; (2)~inputting and
521 outputting of eight-bit bytes, to or from a file; (3)~instructing the
522 operating system to initiate (``open'') or to terminate (``close'') input or
523 output from a specified file; (4)~testing whether the end of an input
524 file has been reached; (5)~display of bits on the user's screen.
525 The bit-display operation will be discussed in a later section; we shall
526 deal here only with more traditional kinds of I/O.
527
528 @ Finding files happens in a slightly roundabout fashion: the \MP\
529 instance object contains a field that holds a function pointer that finds a
530 file, and returns its name, or NULL. For this, it receives three
531 parameters: the non-qualified name |fname|, the intended |fopen|
532 operation type |fmode|, and the type of the file |ftype|.
533
534 The file types that are passed on in |ftype| can be  used to 
535 differentiate file searches if a library like kpathsea is used,
536 the fopen mode is passed along for the same reason.
537
538 @<Types...@>=
539 typedef unsigned char eight_bits ; /* unsigned one-byte quantity */
540 enum {
541   mp_filetype_program = 1, /* \MP\ language input */
542   mp_filetype_log,  /* the log file */
543   mp_filetype_postscript, /* the postscript output */
544   mp_filetype_text,  /* text files for readfrom and writeto primitives */
545   mp_filetype_memfile, /* memory dumps */
546   mp_filetype_metrics, /* TeX font metric files */
547   mp_filetype_fontmap, /* PostScript font mapping files */
548   mp_filetype_font, /*  PostScript type1 font programs */
549   mp_filetype_encoding, /*  PostScript font encoding files */
550 };
551 typedef char *(*file_finder)(char *, char *, int);
552
553 @ @<Glob...@>=
554 file_finder find_file;
555
556 @ @<Option variables@>=
557 file_finder find_file;
558
559 @ The default function for finding files is |mp_find_file|. It is 
560 pretty stupid: it will only find files in the current directory.
561
562 @c
563 char *mp_find_file (char *fname, char *fmode, int ftype)  {
564   if (fmode[0] != 'r' || access (fname,R_OK) || ftype)  
565      return xstrdup(fname);
566   return NULL;
567 }
568
569 @ This has to be done very early on, so it is best to put it in with
570 the |mp_new| allocations
571
572 @d set_callback_option(A) do { mp->A = mp_##A;
573   if (opt->A!=NULL) mp->A = opt->A;
574 } while (0)
575
576 @<Allocate or initialize ...@>=
577 set_callback_option(find_file);
578
579 @ Because |mp_find_file| is used so early, it has to be in the helpers
580 section.
581
582 @<Declare helpers@>=
583 char *mp_find_file (char *fname, char *fmode, int ftype) ;
584
585 @ The function to open files can now be very short.
586
587 @c
588 FILE *mp_open_file(MP mp, char *fname, char *fmode, int ftype)  {
589   char *s = (mp->find_file)(fname,fmode,ftype);
590   if (s!=NULL) {
591     FILE *f = fopen(s, fmode);
592     xfree(s);
593     return f;   
594   }
595   return NULL;
596 }
597
598 @ This is a legacy interface: (almost) all file names pass through |name_of_file|.
599
600 @<Glob...@>=
601 char name_of_file[file_name_size+1]; /* the name of a system file */
602 int name_length;/* this many characters are actually
603   relevant in |name_of_file| (the rest are blank) */
604 boolean print_found_names; /* configuration parameter */
605
606 @ @<Option variables@>=
607 boolean print_found_names; /* configuration parameter */
608
609 @ If this parameter is true, the terminal and log will report the found
610 file names for input files instead of the requested ones. 
611 It is off by default because it creates an extra filename lookup.
612
613 @<Allocate or initialize ...@>=
614 mp->print_found_names = (opt->print_found_names>0 ? true : false);
615
616 @ \MP's file-opening procedures return |false| if no file identified by
617 |name_of_file| could be opened.
618
619 The |OPEN_FILE| macro takes care of the |print_found_names| parameter.
620 It is not used for opening a mem file for read, because that file name 
621 is never printed.
622
623 @d OPEN_FILE(A) do {
624   if (mp->print_found_names) {
625     char *s = (mp->find_file)(mp->name_of_file,A,ftype);
626     if (s!=NULL) {
627       *f = mp_open_file(mp,mp->name_of_file,A, ftype); 
628       strncpy(mp->name_of_file,s,file_name_size);
629       xfree(s);
630     } else {
631       *f = NULL;
632     }
633   } else {
634     *f = mp_open_file(mp,mp->name_of_file,A, ftype); 
635   }
636 } while (0);
637 return (*f ? true : false)
638
639 @c 
640 boolean mp_a_open_in (MP mp, FILE **f, int ftype) {
641   /* open a text file for input */
642   OPEN_FILE("r");
643 }
644 @#
645 boolean mp_w_open_in (MP mp, FILE **f) {
646   /* open a word file for input */
647   *f = mp_open_file(mp,mp->name_of_file,"rb",mp_filetype_memfile); 
648   return (*f ? true : false);
649 }
650 @#
651 boolean mp_a_open_out (MP mp, FILE **f, int ftype) {
652   /* open a text file for output */
653   OPEN_FILE("w");
654 }
655 @#
656 boolean mp_b_open_out (MP mp, FILE **f, int ftype) {
657   /* open a binary file for output */
658   OPEN_FILE("wb");
659 }
660 @#
661 boolean mp_w_open_out (MP mp, FILE**f) {
662   /* open a word file for output */
663   int ftype = mp_filetype_memfile;
664   OPEN_FILE("wb");
665 }
666
667 @ @<Exported...@>=
668 FILE *mp_open_file(MP mp, char *fname, char *fmode, int ftype);
669
670 @ Binary input and output are done with \PASCAL's ordinary |get| and |put|
671 procedures, so we don't have to make any other special arrangements for
672 binary~I/O. Text output is also easy to do with standard \PASCAL\ routines.
673 The treatment of text input is more difficult, however, because
674 of the necessary translation to |ASCII_code| values.
675 \MP's conventions should be efficient, and they should
676 blend nicely with the user's operating environment.
677
678 @ Input from text files is read one line at a time, using a routine called
679 |input_ln|. This function is defined in terms of global variables called
680 |buffer|, |first|, and |last| that will be described in detail later; for
681 now, it suffices for us to know that |buffer| is an array of |ASCII_code|
682 values, and that |first| and |last| are indices into this array
683 representing the beginning and ending of a line of text.
684
685 @<Glob...@>=
686 size_t buf_size; /* maximum number of characters simultaneously present in
687                     current lines of open files */
688 ASCII_code *buffer; /* lines of characters being read */
689 size_t first; /* the first unused position in |buffer| */
690 size_t last; /* end of the line just input to |buffer| */
691 size_t max_buf_stack; /* largest index used in |buffer| */
692
693 @ @<Allocate or initialize ...@>=
694 mp->buf_size = 200;
695 mp->buffer = xmalloc((mp->buf_size+1),sizeof(ASCII_code));
696
697 @ @<Dealloc variables@>=
698 xfree(mp->buffer);
699
700 @ @c
701 void mp_reallocate_buffer(MP mp, size_t l) {
702   ASCII_code *buffer;
703   if (l>max_halfword) {
704     mp_confusion(mp,"buffer size"); /* can't happen (I hope) */
705   }
706   buffer = xmalloc((l+1),sizeof(ASCII_code));
707   memcpy(buffer,mp->buffer,(mp->buf_size+1));
708   xfree(mp->buffer);
709   mp->buffer = buffer ;
710   mp->buf_size = l;
711 }
712
713 @ The |input_ln| function brings the next line of input from the specified
714 field into available positions of the buffer array and returns the value
715 |true|, unless the file has already been entirely read, in which case it
716 returns |false| and sets |last:=first|.  In general, the |ASCII_code|
717 numbers that represent the next line of the file are input into
718 |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
719 global variable |last| is set equal to |first| plus the length of the
720 line. Trailing blanks are removed from the line; thus, either |last=first|
721 (in which case the line was entirely blank) or |buffer[last-1]<>" "|.
722 @^inner loop@>
723
724 An overflow error is given, however, if the normal actions of |input_ln|
725 would make |last>=buf_size|; this is done so that other parts of \MP\
726 can safely look at the contents of |buffer[last+1]| without overstepping
727 the bounds of the |buffer| array. Upon entry to |input_ln|, the condition
728 |first<buf_size| will always hold, so that there is always room for an
729 ``empty'' line.
730
731 The variable |max_buf_stack|, which is used to keep track of how large
732 the |buf_size| parameter must be to accommodate the present job, is
733 also kept up to date by |input_ln|.
734
735 If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get|
736 before looking at the first character of the line; this skips over
737 an |eoln| that was in |f^|. The procedure does not do a |get| when it
738 reaches the end of the line; therefore it can be used to acquire input
739 from the user's terminal as well as from ordinary text files.
740
741 Standard \PASCAL\ says that a file should have |eoln| immediately
742 before |eof|, but \MP\ needs only a weaker restriction: If |eof|
743 occurs in the middle of a line, the system function |eoln| should return
744 a |true| result (even though |f^| will be undefined).
745
746 @c 
747 boolean mp_input_ln (MP mp,FILE *  f, boolean bypass_eoln) {
748   /* inputs the next line or returns |false| */
749   int last_nonblank; /* |last| with trailing blanks removed */
750   int c;
751   if ( bypass_eoln ) {
752     c = fgetc(f);
753     if (c==EOF)
754       return false;
755     if (c!='\n' && c!='\r') {
756       ungetc(c,f);
757     }
758   }
759   /* input the first character of the line into |f^| */
760   mp->last=mp->first; /* cf.\ Matthew 19\thinspace:\thinspace30 */
761   c = fgetc(f);
762   if (c==EOF)
763         return false;
764   last_nonblank=mp->first;
765   while (c!=EOF && c!='\n' && c!='\r') { 
766     if ( mp->last>=mp->max_buf_stack ) { 
767       mp->max_buf_stack=mp->last+1;
768       if ( mp->max_buf_stack==mp->buf_size ) {
769         mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
770       }
771     }
772     mp->buffer[mp->last]=xord(c); 
773     incr(mp->last);
774     if ( mp->buffer[mp->last-1]!=' ' ) 
775       last_nonblank=mp->last;
776     c = fgetc(f); 
777   } 
778   if (c!=EOF) {
779     ungetc(c,f);
780   }
781   mp->last=last_nonblank; 
782   return true;
783 }
784
785 @ The user's terminal acts essentially like other files of text, except
786 that it is used both for input and for output. When the terminal is
787 considered an input file, the file variable is called |term_in|, and when it
788 is considered an output file the file variable is |term_out|.
789 @^system dependencies@>
790
791 @<Glob...@>=
792 FILE * term_in; /* the terminal as an input file */
793 FILE * term_out; /* the terminal as an output file */
794
795 @ Here is how to open the terminal files. In the default configuration,
796 nothing happens except that the command line (if there is one) is copied
797 to the input buffer.  The variable |command_line| will be filled by the 
798 |main| procedure. The copying can not be done earlier in the program 
799 logic because in the |INI| version, the |buffer| is also used for primitive 
800 initialization.
801
802 @^system dependencies@>
803
804 @d t_open_out  /* open the terminal for text output */
805 @d t_open_in  do { /* open the terminal for text input */
806     if (mp->command_line!=NULL) {
807       mp->last = strlen(mp->command_line);
808       strncpy((char *)mp->buffer,mp->command_line,mp->last);
809       xfree(mp->command_line);
810     }
811 } while (0)
812
813 @<Glob...@>=
814 char *command_line;
815
816 @ @<Option variables@>=
817 char *command_line;
818
819 @ @<Allocate or initialize ...@>=
820 mp->command_line = opt->command_line;
821
822 @ Sometimes it is necessary to synchronize the input/output mixture that
823 happens on the user's terminal, and three system-dependent
824 procedures are used for this
825 purpose. The first of these, |update_terminal|, is called when we want
826 to make sure that everything we have output to the terminal so far has
827 actually left the computer's internal buffers and been sent.
828 The second, |clear_terminal|, is called when we wish to cancel any
829 input that the user may have typed ahead (since we are about to
830 issue an unexpected error message). The third, |wake_up_terminal|,
831 is supposed to revive the terminal if the user has disabled it by
832 some instruction to the operating system.  The following macros show how
833 these operations can be specified in \ph:
834 @^system dependencies@>
835
836 @d update_terminal   fflush(mp->term_out) /* empty the terminal output buffer */
837 @d clear_terminal   do_nothing /* clear the terminal input buffer */
838 @d wake_up_terminal  fflush(mp->term_out) /* cancel the user's cancellation of output */
839
840 @ We need a special routine to read the first line of \MP\ input from
841 the user's terminal. This line is different because it is read before we
842 have opened the transcript file; there is sort of a ``chicken and
843 egg'' problem here. If the user types `\.{input cmr10}' on the first
844 line, or if some macro invoked by that line does such an \.{input},
845 the transcript file will be named `\.{cmr10.log}'; but if no \.{input}
846 commands are performed during the first line of terminal input, the transcript
847 file will acquire its default name `\.{mpout.log}'. (The transcript file
848 will not contain error messages generated by the first line before the
849 first \.{input} command.)
850
851 The first line is even more special if we are lucky enough to have an operating
852 system that treats \MP\ differently from a run-of-the-mill \PASCAL\ object
853 program. It's nice to let the user start running a \MP\ job by typing
854 a command line like `\.{MP cmr10}'; in such a case, \MP\ will operate
855 as if the first line of input were `\.{cmr10}', i.e., the first line will
856 consist of the remainder of the command line, after the part that invoked \MP.
857
858 @ Different systems have different ways to get started. But regardless of
859 what conventions are adopted, the routine that initializes the terminal
860 should satisfy the following specifications:
861
862 \yskip\textindent{1)}It should open file |term_in| for input from the
863   terminal. (The file |term_out| will already be open for output to the
864   terminal.)
865
866 \textindent{2)}If the user has given a command line, this line should be
867   considered the first line of terminal input. Otherwise the
868   user should be prompted with `\.{**}', and the first line of input
869   should be whatever is typed in response.
870
871 \textindent{3)}The first line of input, which might or might not be a
872   command line, should appear in locations |first| to |last-1| of the
873   |buffer| array.
874
875 \textindent{4)}The global variable |loc| should be set so that the
876   character to be read next by \MP\ is in |buffer[loc]|. This
877   character should not be blank, and we should have |loc<last|.
878
879 \yskip\noindent(It may be necessary to prompt the user several times
880 before a non-blank line comes in. The prompt is `\.{**}' instead of the
881 later `\.*' because the meaning is slightly different: `\.{input}' need
882 not be typed immediately after~`\.{**}'.)
883
884 @d loc mp->cur_input.loc_field /* location of first unread character in |buffer| */
885
886 @ The following program does the required initialization
887 without retrieving a possible command line.
888 It should be clear how to modify this routine to deal with command lines,
889 if the system permits them.
890 @^system dependencies@>
891
892 @c 
893 boolean mp_init_terminal (MP mp) { /* gets the terminal input started */
894   t_open_in; 
895   if (mp->last!=0) {
896     loc = mp->first = 0;
897         return true;
898   }
899   while (1) { 
900     wake_up_terminal; fprintf(mp->term_out,"**"); update_terminal;
901 @.**@>
902     if ( ! mp_input_ln(mp, mp->term_in,true) ) { /* this shouldn't happen */
903       fprintf(mp->term_out,"\n! End of file on the terminal... why?");
904 @.End of file on the terminal@>
905       return false;
906     }
907     loc=mp->first;
908     while ( (loc<(int)mp->last)&&(mp->buffer[loc]==' ') ) 
909       incr(loc);
910     if ( loc<(int)mp->last ) { 
911       return true; /* return unless the line was all blank */
912     };
913     fprintf(mp->term_out,"Please type the name of your input file.\n");
914   }
915 }
916
917 @ @<Declarations@>=
918 boolean mp_init_terminal (MP mp) ;
919
920
921 @* \[4] String handling.
922 Symbolic token names and diagnostic messages are variable-length strings
923 of eight-bit characters. Since \PASCAL\ does not have a well-developed string
924 mechanism, \MP\ does all of its string processing by homegrown methods.
925
926 \MP\ uses strings more extensively than \MF\ does, but the necessary
927 operations can still be handled with a fairly simple data structure.
928 The array |str_pool| contains all of the (eight-bit) ASCII codes in all
929 of the strings, and the array |str_start| contains indices of the starting
930 points of each string. Strings are referred to by integer numbers, so that
931 string number |s| comprises the characters |str_pool[j]| for
932 |str_start[s]<=j<str_start[ss]| where |ss=next_str[s]|.  The string pool
933 is allocated sequentially and |str_pool[pool_ptr]| is the next unused
934 location.  The first string number not currently in use is |str_ptr|
935 and |next_str[str_ptr]| begins a list of free string numbers.  String
936 pool entries |str_start[str_ptr]| up to |pool_ptr| are reserved for a
937 string currently being constructed.
938
939 String numbers 0 to 255 are reserved for strings that correspond to single
940 ASCII characters. This is in accordance with the conventions of \.{WEB},
941 @.WEB@>
942 which converts single-character strings into the ASCII code number of the
943 single character involved, while it converts other strings into integers
944 and builds a string pool file. Thus, when the string constant \.{"."} appears
945 in the program below, \.{WEB} converts it into the integer 46, which is the
946 ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
947 into some integer greater than~255. String number 46 will presumably be the
948 single character `\..'\thinspace; but some ASCII codes have no standard visible
949 representation, and \MP\ may need to be able to print an arbitrary
950 ASCII character, so the first 256 strings are used to specify exactly what
951 should be printed for each of the 256 possibilities.
952
953 @<Types...@>=
954 typedef int pool_pointer; /* for variables that point into |str_pool| */
955 typedef int str_number; /* for variables that point into |str_start| */
956
957 @ @<Glob...@>=
958 ASCII_code *str_pool; /* the characters */
959 pool_pointer *str_start; /* the starting pointers */
960 str_number *next_str; /* for linking strings in order */
961 pool_pointer pool_ptr; /* first unused position in |str_pool| */
962 str_number str_ptr; /* number of the current string being created */
963 pool_pointer init_pool_ptr; /* the starting value of |pool_ptr| */
964 str_number init_str_use; /* the initial number of strings in use */
965 pool_pointer max_pool_ptr; /* the maximum so far of |pool_ptr| */
966 str_number max_str_ptr; /* the maximum so far of |str_ptr| */
967
968 @ @<Allocate or initialize ...@>=
969 mp->str_pool  = xmalloc ((mp->pool_size +1),sizeof(ASCII_code));
970 mp->str_start = xmalloc ((mp->max_strings+1),sizeof(pool_pointer));
971 mp->next_str  = xmalloc ((mp->max_strings+1),sizeof(str_number));
972
973 @ @<Dealloc variables@>=
974 xfree(mp->str_pool);
975 xfree(mp->str_start);
976 xfree(mp->next_str);
977
978 @ Most printing is done from |char *|s, but sometimes not. Here are
979 functions that convert an internal string into a |char *| for use
980 by the printing routines, and vice versa.
981
982 @d str(A) mp_str(mp,A)
983 @d rts(A) mp_rts(mp,A)
984
985 @<Exported function headers@>=
986 int mp_xstrcmp (const char *a, const char *b);
987 char * mp_str (MP mp, str_number s);
988
989 @ @<Declarations@>=
990 str_number mp_rts (MP mp, char *s);
991 str_number mp_make_string (MP mp);
992
993 @ The attempt to catch interrupted strings that is in |mp_rts|, is not 
994 very good: it does not handle nesting over more than one level.
995
996 @c 
997 int mp_xstrcmp (const char *a, const char *b) {
998         if (a==NULL && b==NULL) 
999           return 0;
1000     if (a==NULL)
1001       return -1;
1002     if (b==NULL)
1003       return 1;
1004     return strcmp(a,b);
1005 }
1006
1007 @ @c
1008 char * mp_str (MP mp, str_number ss) {
1009   char *s;
1010   int len;
1011   if (ss==mp->str_ptr) {
1012     return NULL;
1013   } else {
1014     len = length(ss);
1015     s = xmalloc(len+1,sizeof(char));
1016     strncpy(s,(char *)(mp->str_pool+(mp->str_start[ss])),len);
1017     s[len] = 0;
1018     return (char *)s;
1019   }
1020 }
1021 str_number mp_rts (MP mp, char *s) {
1022   int r; /* the new string */ 
1023   int old; /* a possible string in progress */
1024   int i=0;
1025   if (strlen(s)==0) {
1026     return 256;
1027   } else if (strlen(s)==1) {
1028     return s[0];
1029   } else {
1030    old=0;
1031    str_room((integer)strlen(s));
1032    if (mp->str_start[mp->str_ptr]<mp->pool_ptr)
1033      old = mp_make_string(mp);
1034    while (*s) {
1035      append_char(*s);
1036      s++;
1037    }
1038    r = mp_make_string(mp);
1039    if (old!=0) {
1040       str_room(length(old));
1041       while (i<length(old)) {
1042         append_char((mp->str_start[old]+i));
1043       } 
1044       mp_flush_string(mp,old);
1045     }
1046     return r;
1047   }
1048 }
1049
1050 @ Except for |strs_used_up|, the following string statistics are only
1051 maintained when code between |stat| $\ldots$ |tats| delimiters is not
1052 commented out:
1053
1054 @<Glob...@>=
1055 integer strs_used_up; /* strings in use or unused but not reclaimed */
1056 integer pool_in_use; /* total number of cells of |str_pool| actually in use */
1057 integer strs_in_use; /* total number of strings actually in use */
1058 integer max_pl_used; /* maximum |pool_in_use| so far */
1059 integer max_strs_used; /* maximum |strs_in_use| so far */
1060
1061 @ Several of the elementary string operations are performed using \.{WEB}
1062 macros instead of \PASCAL\ procedures, because many of the
1063 operations are done quite frequently and we want to avoid the
1064 overhead of procedure calls. For example, here is
1065 a simple macro that computes the length of a string.
1066 @.WEB@>
1067
1068 @d str_stop(A) mp->str_start[mp->next_str[(A)]] /* one cell past the end of string
1069   number \# */
1070 @d length(A) (str_stop((A))-mp->str_start[(A)]) /* the number of characters in string \# */
1071
1072 @ The length of the current string is called |cur_length|.  If we decide that
1073 the current string is not needed, |flush_cur_string| resets |pool_ptr| so that
1074 |cur_length| becomes zero.
1075
1076 @d cur_length   (mp->pool_ptr - mp->str_start[mp->str_ptr])
1077 @d flush_cur_string   mp->pool_ptr=mp->str_start[mp->str_ptr]
1078
1079 @ Strings are created by appending character codes to |str_pool|.
1080 The |append_char| macro, defined here, does not check to see if the
1081 value of |pool_ptr| has gotten too high; this test is supposed to be
1082 made before |append_char| is used.
1083
1084 To test if there is room to append |l| more characters to |str_pool|,
1085 we shall write |str_room(l)|, which tries to make sure there is enough room
1086 by compacting the string pool if necessary.  If this does not work,
1087 |do_compaction| aborts \MP\ and gives an apologetic error message.
1088
1089 @d append_char(A)   /* put |ASCII_code| \# at the end of |str_pool| */
1090 { mp->str_pool[mp->pool_ptr]=(A); incr(mp->pool_ptr);
1091 }
1092 @d str_room(A)   /* make sure that the pool hasn't overflowed */
1093   { if ( mp->pool_ptr+(A) > mp->max_pool_ptr ) {
1094     if ( mp->pool_ptr+(A) > mp->pool_size ) mp_do_compaction(mp, (A));
1095     else mp->max_pool_ptr=mp->pool_ptr+(A); }
1096   }
1097
1098 @ The following routine is similar to |str_room(1)| but it uses the
1099 argument |mp->pool_size| to prevent |do_compaction| from aborting when
1100 string space is exhausted.
1101
1102 @<Declare the procedure called |unit_str_room|@>=
1103 void mp_unit_str_room (MP mp);
1104
1105 @ @c
1106 void mp_unit_str_room (MP mp) { 
1107   if ( mp->pool_ptr>=mp->pool_size ) mp_do_compaction(mp, mp->pool_size);
1108   if ( mp->pool_ptr>=mp->max_pool_ptr ) mp->max_pool_ptr=mp->pool_ptr+1;
1109 }
1110
1111 @ \MP's string expressions are implemented in a brute-force way: Every
1112 new string or substring that is needed is simply copied into the string pool.
1113 Space is eventually reclaimed by a procedure called |do_compaction| with
1114 the aid of a simple system system of reference counts.
1115 @^reference counts@>
1116
1117 The number of references to string number |s| will be |str_ref[s]|. The
1118 special value |str_ref[s]=max_str_ref=127| is used to denote an unknown
1119 positive number of references; such strings will never be recycled. If
1120 a string is ever referred to more than 126 times, simultaneously, we
1121 put it in this category. Hence a single byte suffices to store each |str_ref|.
1122
1123 @d max_str_ref 127 /* ``infinite'' number of references */
1124 @d add_str_ref(A) { if ( mp->str_ref[(A)]<max_str_ref ) incr(mp->str_ref[(A)]);
1125   }
1126
1127 @<Glob...@>=
1128 int *str_ref;
1129
1130 @ @<Allocate or initialize ...@>=
1131 mp->str_ref = xmalloc ((mp->max_strings+1),sizeof(int));
1132
1133 @ @<Dealloc variables@>=
1134 xfree(mp->str_ref);
1135
1136 @ Here's what we do when a string reference disappears:
1137
1138 @d delete_str_ref(A)  { 
1139     if ( mp->str_ref[(A)]<max_str_ref ) {
1140        if ( mp->str_ref[(A)]>1 ) decr(mp->str_ref[(A)]); 
1141        else mp_flush_string(mp, (A));
1142     }
1143   }
1144
1145 @<Declare the procedure called |flush_string|@>=
1146 void mp_flush_string (MP mp,str_number s) ;
1147
1148
1149 @ We can't flush the first set of static strings at all, so there 
1150 is no point in trying
1151
1152 @c
1153 void mp_flush_string (MP mp,str_number s) { 
1154   if (length(s)>1) {
1155     mp->pool_in_use=mp->pool_in_use-length(s);
1156     decr(mp->strs_in_use);
1157     if ( mp->next_str[s]!=mp->str_ptr ) {
1158       mp->str_ref[s]=0;
1159     } else { 
1160       mp->str_ptr=s;
1161       decr(mp->strs_used_up);
1162     }
1163     mp->pool_ptr=mp->str_start[mp->str_ptr];
1164   }
1165 }
1166
1167 @ C literals cannot be simply added, they need to be set so they can't
1168 be flushed.
1169
1170 @d intern(A) mp_intern(mp,(A))
1171
1172 @c
1173 str_number mp_intern (MP mp, char *s) {
1174   str_number r ;
1175   r = rts(s);
1176   mp->str_ref[r] = max_str_ref;
1177   return r;
1178 }
1179
1180 @ @<Declarations@>=
1181 str_number mp_intern (MP mp, char *s);
1182
1183
1184 @ Once a sequence of characters has been appended to |str_pool|, it
1185 officially becomes a string when the function |make_string| is called.
1186 This function returns the identification number of the new string as its
1187 value.
1188
1189 When getting the next unused string number from the linked list, we pretend
1190 that
1191 $$ \hbox{|max_str_ptr+1|, |max_str_ptr+2|, $\ldots$, |mp->max_strings|} $$
1192 are linked sequentially even though the |next_str| entries have not been
1193 initialized yet.  We never allow |str_ptr| to reach |mp->max_strings|;
1194 |do_compaction| is responsible for making sure of this.
1195
1196 @<Declarations@>=
1197 @<Declare the procedure called |do_compaction|@>;
1198 @<Declare the procedure called |unit_str_room|@>;
1199 str_number mp_make_string (MP mp);
1200
1201 @ @c 
1202 str_number mp_make_string (MP mp) { /* current string enters the pool */
1203   str_number s; /* the new string */
1204 RESTART: 
1205   s=mp->str_ptr;
1206   mp->str_ptr=mp->next_str[s];
1207   if ( mp->str_ptr>mp->max_str_ptr ) {
1208     if ( mp->str_ptr==mp->max_strings ) { 
1209       mp->str_ptr=s;
1210       mp_do_compaction(mp, 0);
1211       goto RESTART;
1212     } else {
1213 #ifdef DEBUG 
1214       if ( mp->strs_used_up!=mp->max_str_ptr ) mp_confusion(mp, "s");
1215 @:this can't happen s}{\quad \.s@>
1216 #endif
1217       mp->max_str_ptr=mp->str_ptr;
1218       mp->next_str[mp->str_ptr]=mp->max_str_ptr+1;
1219     }
1220   }
1221   mp->str_ref[s]=1;
1222   mp->str_start[mp->str_ptr]=mp->pool_ptr;
1223   incr(mp->strs_used_up);
1224   incr(mp->strs_in_use);
1225   mp->pool_in_use=mp->pool_in_use+length(s);
1226   if ( mp->pool_in_use>mp->max_pl_used ) 
1227     mp->max_pl_used=mp->pool_in_use;
1228   if ( mp->strs_in_use>mp->max_strs_used ) 
1229     mp->max_strs_used=mp->strs_in_use;
1230   return s;
1231 }
1232
1233 @ The most interesting string operation is string pool compaction.  The idea
1234 is to recover unused space in the |str_pool| array by recopying the strings
1235 to close the gaps created when some strings become unused.  All string
1236 numbers~$k$ where |str_ref[k]=0| are to be linked into the list of free string
1237 numbers after |str_ptr|.  If this fails to free enough pool space we issue an
1238 |overflow| error unless |needed=mp->pool_size|.  Calling |do_compaction|
1239 with |needed=mp->pool_size| supresses all overflow tests.
1240
1241 The compaction process starts with |last_fixed_str| because all lower numbered
1242 strings are permanently allocated with |max_str_ref| in their |str_ref| entries.
1243
1244 @<Glob...@>=
1245 str_number last_fixed_str; /* last permanently allocated string */
1246 str_number fixed_str_use; /* number of permanently allocated strings */
1247
1248 @ @<Declare the procedure called |do_compaction|@>=
1249 void mp_do_compaction (MP mp, pool_pointer needed) ;
1250
1251 @ @c
1252 void mp_do_compaction (MP mp, pool_pointer needed) {
1253   str_number str_use; /* a count of strings in use */
1254   str_number r,s,t; /* strings being manipulated */
1255   pool_pointer p,q; /* destination and source for copying string characters */
1256   @<Advance |last_fixed_str| as far as possible and set |str_use|@>;
1257   r=mp->last_fixed_str;
1258   s=mp->next_str[r];
1259   p=mp->str_start[s];
1260   while ( s!=mp->str_ptr ) { 
1261     while ( mp->str_ref[s]==0 ) {
1262       @<Advance |s| and add the old |s| to the list of free string numbers;
1263         then |break| if |s=str_ptr|@>;
1264     }
1265     r=s; s=mp->next_str[s];
1266     incr(str_use);
1267     @<Move string |r| back so that |str_start[r]=p|; make |p| the location
1268      after the end of the string@>;
1269   }
1270   @<Move the current string back so that it starts at |p|@>;
1271   if ( needed<mp->pool_size ) {
1272     @<Make sure that there is room for another string with |needed| characters@>;
1273   }
1274   @<Account for the compaction and make sure the statistics agree with the
1275      global versions@>;
1276   mp->strs_used_up=str_use;
1277 }
1278
1279 @ @<Advance |last_fixed_str| as far as possible and set |str_use|@>=
1280 t=mp->next_str[mp->last_fixed_str];
1281 while (t!=mp->str_ptr && mp->str_ref[t]==max_str_ref) {
1282   incr(mp->fixed_str_use);
1283   mp->last_fixed_str=t;
1284   t=mp->next_str[t];
1285 }
1286 str_use=mp->fixed_str_use
1287
1288 @ Because of the way |flush_string| has been written, it should never be
1289 necessary to |break| here.  The extra line of code seems worthwhile to
1290 preserve the generality of |do_compaction|.
1291
1292 @<Advance |s| and add the old |s| to the list of free string numbers;...@>=
1293 {
1294 t=s;
1295 s=mp->next_str[s];
1296 mp->next_str[r]=s;
1297 mp->next_str[t]=mp->next_str[mp->str_ptr];
1298 mp->next_str[mp->str_ptr]=t;
1299 if ( s==mp->str_ptr ) break;
1300 }
1301
1302 @ The string currently starts at |str_start[r]| and ends just before
1303 |str_start[s]|.  We don't change |str_start[s]| because it might be needed
1304 to locate the next string.
1305
1306 @<Move string |r| back so that |str_start[r]=p|; make |p| the location...@>=
1307 q=mp->str_start[r];
1308 mp->str_start[r]=p;
1309 while ( q<mp->str_start[s] ) { 
1310   mp->str_pool[p]=mp->str_pool[q];
1311   incr(p); incr(q);
1312 }
1313
1314 @ Pointers |str_start[str_ptr]| and |pool_ptr| have not been updated.  When
1315 we do this, anything between them should be moved.
1316
1317 @ @<Move the current string back so that it starts at |p|@>=
1318 q=mp->str_start[mp->str_ptr];
1319 mp->str_start[mp->str_ptr]=p;
1320 while ( q<mp->pool_ptr ) { 
1321   mp->str_pool[p]=mp->str_pool[q];
1322   incr(p); incr(q);
1323 }
1324 mp->pool_ptr=p
1325
1326 @ We must remember that |str_ptr| is not allowed to reach |mp->max_strings|.
1327
1328 @<Make sure that there is room for another string with |needed| char...@>=
1329 if ( str_use>=mp->max_strings-1 )
1330   mp_reallocate_strings (mp,str_use);
1331 if ( mp->pool_ptr+needed>mp->max_pool_ptr ) {
1332   mp_reallocate_pool(mp, mp->pool_ptr+needed);
1333   mp->max_pool_ptr=mp->pool_ptr+needed;
1334 }
1335
1336 @ @<Declarations@>=
1337 void mp_reallocate_strings (MP mp, str_number str_use) ;
1338 void mp_reallocate_pool(MP mp, pool_pointer needed) ;
1339
1340 @ @c 
1341 void mp_reallocate_strings (MP mp, str_number str_use) { 
1342   while ( str_use>=mp->max_strings-1 ) {
1343     int l = mp->max_strings + (mp->max_strings>>2);
1344     XREALLOC (mp->str_ref,   l, int);
1345     XREALLOC (mp->str_start, l, pool_pointer);
1346     XREALLOC (mp->next_str,  l, str_number);
1347     mp->max_strings = l;
1348   }
1349 }
1350 void mp_reallocate_pool(MP mp, pool_pointer needed) {
1351   while ( needed>mp->pool_size ) {
1352     int l = mp->pool_size + (mp->pool_size>>2);
1353         XREALLOC (mp->str_pool, l, ASCII_code);
1354     mp->pool_size = l;
1355   }
1356 }
1357
1358 @ @<Account for the compaction and make sure the statistics agree with...@>=
1359 if ( (mp->str_start[mp->str_ptr]!=mp->pool_in_use)||(str_use!=mp->strs_in_use) )
1360   mp_confusion(mp, "string");
1361 @:this can't happen string}{\quad string@>
1362 incr(mp->pact_count);
1363 mp->pact_chars=mp->pact_chars+mp->pool_ptr-str_stop(mp->last_fixed_str);
1364 mp->pact_strs=mp->pact_strs+str_use-mp->fixed_str_use;
1365 #ifdef DEBUG
1366 s=mp->str_ptr; t=str_use;
1367 while ( s<=mp->max_str_ptr ){
1368   if ( t>mp->max_str_ptr ) mp_confusion(mp, "\"");
1369   incr(t); s=mp->next_str[s];
1370 };
1371 if ( t<=mp->max_str_ptr ) mp_confusion(mp, "\"");
1372 #endif
1373
1374 @ A few more global variables are needed to keep track of statistics when
1375 |stat| $\ldots$ |tats| blocks are not commented out.
1376
1377 @<Glob...@>=
1378 integer pact_count; /* number of string pool compactions so far */
1379 integer pact_chars; /* total number of characters moved during compactions */
1380 integer pact_strs; /* total number of strings moved during compactions */
1381
1382 @ @<Initialize compaction statistics@>=
1383 mp->pact_count=0;
1384 mp->pact_chars=0;
1385 mp->pact_strs=0;
1386
1387 @ The following subroutine compares string |s| with another string of the
1388 same length that appears in |buffer| starting at position |k|;
1389 the result is |true| if and only if the strings are equal.
1390
1391 @c 
1392 boolean mp_str_eq_buf (MP mp,str_number s, integer k) {
1393   /* test equality of strings */
1394   pool_pointer j; /* running index */
1395   j=mp->str_start[s];
1396   while ( j<str_stop(s) ) { 
1397     if ( mp->str_pool[j++]!=mp->buffer[k++] ) 
1398       return false;
1399   }
1400   return true;
1401 }
1402
1403 @ Here is a similar routine, but it compares two strings in the string pool,
1404 and it does not assume that they have the same length. If the first string
1405 is lexicographically greater than, less than, or equal to the second,
1406 the result is respectively positive, negative, or zero.
1407
1408 @c 
1409 integer mp_str_vs_str (MP mp, str_number s, str_number t) {
1410   /* test equality of strings */
1411   pool_pointer j,k; /* running indices */
1412   integer ls,lt; /* lengths */
1413   integer l; /* length remaining to test */
1414   ls=length(s); lt=length(t);
1415   if ( ls<=lt ) l=ls; else l=lt;
1416   j=mp->str_start[s]; k=mp->str_start[t];
1417   while ( l-->0 ) { 
1418     if ( mp->str_pool[j]!=mp->str_pool[k] ) {
1419        return (mp->str_pool[j]-mp->str_pool[k]); 
1420     }
1421     incr(j); incr(k);
1422   }
1423   return (ls-lt);
1424 }
1425
1426 @ The initial values of |str_pool|, |str_start|, |pool_ptr|,
1427 and |str_ptr| are computed by the \.{INIMP} program, based in part
1428 on the information that \.{WEB} has output while processing \MP.
1429 @.INIMP@>
1430 @^string pool@>
1431
1432 @c 
1433 void mp_get_strings_started (MP mp) { 
1434   /* initializes the string pool,
1435     but returns |false| if something goes wrong */
1436   int k; /* small indices or counters */
1437   str_number g; /* a new string */
1438   mp->pool_ptr=0; mp->str_ptr=0; mp->max_pool_ptr=0; mp->max_str_ptr=0;
1439   mp->str_start[0]=0;
1440   mp->next_str[0]=1;
1441   mp->pool_in_use=0; mp->strs_in_use=0;
1442   mp->max_pl_used=0; mp->max_strs_used=0;
1443   @<Initialize compaction statistics@>;
1444   mp->strs_used_up=0;
1445   @<Make the first 256 strings@>;
1446   g=mp_make_string(mp); /* string 256 == "" */
1447   mp->str_ref[g]=max_str_ref;
1448   mp->last_fixed_str=mp->str_ptr-1;
1449   mp->fixed_str_use=mp->str_ptr;
1450   return;
1451 }
1452
1453 @ @<Declarations@>=
1454 void mp_get_strings_started (MP mp);
1455
1456 @ The first 256 strings will consist of a single character only.
1457
1458 @<Make the first 256...@>=
1459 for (k=0;k<=255;k++) { 
1460   append_char(k);
1461   g=mp_make_string(mp); 
1462   mp->str_ref[g]=max_str_ref;
1463 }
1464
1465 @ The first 128 strings will contain 95 standard ASCII characters, and the
1466 other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
1467 unless a system-dependent change is made here. Installations that have
1468 an extended character set, where for example |xchr[032]=@t\.{'^^Z'}@>|,
1469 would like string 032 to be printed as the single character 032 instead
1470 of the three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand,
1471 even people with an extended character set will want to represent string
1472 015 by \.{\^\^M}, since 015 is ASCII's ``carriage return'' code; the idea is
1473 to produce visible strings instead of tabs or line-feeds or carriage-returns
1474 or bell-rings or characters that are treated anomalously in text files.
1475
1476 Unprintable characters of codes 128--255 are, similarly, rendered
1477 \.{\^\^80}--\.{\^\^ff}.
1478
1479 The boolean expression defined here should be |true| unless \MP\ internal
1480 code number~|k| corresponds to a non-troublesome visible symbol in the
1481 local character set.
1482 If character |k| cannot be printed, and |k<0200|, then character |k+0100| or
1483 |k-0100| must be printable; moreover, ASCII codes |[060..071, 0141..0146]|
1484 must be printable.
1485 @^character set dependencies@>
1486 @^system dependencies@>
1487
1488 @<Character |k| cannot be printed@>=
1489   (k<' ')||(k>'~')
1490
1491 @* \[5] On-line and off-line printing.
1492 Messages that are sent to a user's terminal and to the transcript-log file
1493 are produced by several `|print|' procedures. These procedures will
1494 direct their output to a variety of places, based on the setting of
1495 the global variable |selector|, which has the following possible
1496 values:
1497
1498 \yskip
1499 \hang |term_and_log|, the normal setting, prints on the terminal and on the
1500   transcript file.
1501
1502 \hang |log_only|, prints only on the transcript file.
1503
1504 \hang |term_only|, prints only on the terminal.
1505
1506 \hang |no_print|, doesn't print at all. This is used only in rare cases
1507   before the transcript file is open.
1508
1509 \hang |ps_file_only| prints only on the \ps\ output file.
1510
1511 \hang |pseudo|, puts output into a cyclic buffer that is used
1512   by the |show_context| routine; when we get to that routine we shall discuss
1513   the reasoning behind this curious mode.
1514
1515 \hang |new_string|, appends the output to the current string in the
1516   string pool.
1517
1518 \hang |>=write_file| prints on one of the files used for the \&{write}
1519 @:write_}{\&{write} primitive@>
1520   command.
1521
1522 \yskip
1523 \noindent The symbolic names `|term_and_log|', etc., have been assigned
1524 numeric codes that satisfy the convenient relations |no_print+1=term_only|,
1525 |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.  These
1526 relations are not used when |selector| could be |pseudo|, |new_string|,
1527 or |ps_file_only|.  We need not check for unprintable characters when
1528 |selector<pseudo|.
1529
1530 Four additional global variables, |tally|, |term_offset|, |file_offset|,
1531 and |ps_offset| record the number of characters that have been printed
1532 since they were most recently cleared to zero. We use |tally| to record
1533 the length of (possibly very long) stretches of printing; |term_offset|,
1534 |file_offset|, and |ps_offset|, on the other hand, keep track of how many
1535 characters have appeared so far on the current line that has been output
1536 to the terminal, the transcript file, or the \ps\ output file, respectively.
1537
1538 @d new_string 0 /* printing is deflected to the string pool */
1539 @d ps_file_only 1 /* printing goes to the \ps\ output file */
1540 @d pseudo 2 /* special |selector| setting for |show_context| */
1541 @d no_print 3 /* |selector| setting that makes data disappear */
1542 @d term_only 4 /* printing is destined for the terminal only */
1543 @d log_only 5 /* printing is destined for the transcript file only */
1544 @d term_and_log 6 /* normal |selector| setting */
1545 @d write_file 7 /* first write file selector */
1546
1547 @<Glob...@>=
1548 FILE * log_file; /* transcript of \MP\ session */
1549 FILE * ps_file; /* the generic font output goes here */
1550 unsigned int selector; /* where to print a message */
1551 unsigned char dig[23]; /* digits in a number being output */
1552 integer tally; /* the number of characters recently printed */
1553 unsigned int term_offset;
1554   /* the number of characters on the current terminal line */
1555 unsigned int file_offset;
1556   /* the number of characters on the current file line */
1557 integer ps_offset;
1558   /* the number of characters on the current \ps\ file line */
1559 ASCII_code *trick_buf; /* circular buffer for pseudoprinting */
1560 integer trick_count; /* threshold for pseudoprinting, explained later */
1561 integer first_count; /* another variable for pseudoprinting */
1562
1563 @ @<Allocate or initialize ...@>=
1564 memset(mp->dig,0,23);
1565 mp->trick_buf = xmalloc((mp->error_line+1),sizeof(ASCII_code));
1566
1567 @ @<Dealloc variables@>=
1568 xfree(mp->trick_buf);
1569
1570 @ @<Initialize the output routines@>=
1571 mp->selector=term_only; mp->tally=0; mp->term_offset=0; mp->file_offset=0; mp->ps_offset=0;
1572
1573 @ Macro abbreviations for output to the terminal and to the log file are
1574 defined here for convenience. Some systems need special conventions
1575 for terminal output, and it is possible to adhere to those conventions
1576 by changing |wterm|, |wterm_ln|, and |wterm_cr| here.
1577 @^system dependencies@>
1578
1579 @d wterm(A)    fprintf(mp->term_out,"%s",(A))
1580 @d wterm_chr(A)fprintf(mp->term_out,"%c",(A))
1581 @d wterm_ln(A) fprintf(mp->term_out,"\n%s",(A))
1582 @d wterm_cr    fprintf(mp->term_out,"\n")
1583 @d wlog(A)     fprintf(mp->log_file,"%s",(A))
1584 @d wlog_chr(A) fprintf(mp->log_file,"%c",(A))
1585 @d wlog_ln(A)  fprintf(mp->log_file,"\n%s",(A))
1586 @d wlog_cr     fprintf(mp->log_file, "\n")
1587 @d wps(A)      fprintf(mp->ps_file,"%s",(A))
1588 @d wps_chr(A)  fprintf(mp->ps_file,"%c",(A))
1589 @d wps_ln(A)   fprintf(mp->ps_file,,"\n%s",(A))
1590 @d wps_cr      fprintf(mp->ps_file,"\n")
1591
1592 @ To end a line of text output, we call |print_ln|.  Cases |0..max_write_files|
1593 use an array |wr_file| that will be declared later.
1594
1595 @d mp_print_text(A) mp_print_str(mp,text((A)))
1596
1597 @<Exported...@>=
1598 void mp_print_ln (MP mp);
1599 void mp_print_visible_char (MP mp, ASCII_code s); 
1600 void mp_print_char (MP mp, ASCII_code k);
1601 void mp_print (MP mp, char *s);
1602 void mp_print_str (MP mp, str_number s);
1603 void mp_print_nl (MP mp, char *s);
1604 void mp_print_two (MP mp,scaled x, scaled y) ;
1605 void mp_print_scaled (MP mp,scaled s);
1606
1607 @ @<Basic print...@>=
1608 void mp_print_ln (MP mp) { /* prints an end-of-line */
1609  switch (mp->selector) {
1610   case term_and_log: 
1611     wterm_cr; wlog_cr;
1612     mp->term_offset=0;  mp->file_offset=0;
1613     break;
1614   case log_only: 
1615     wlog_cr; mp->file_offset=0;
1616     break;
1617   case term_only: 
1618     wterm_cr; mp->term_offset=0;
1619     break;
1620   case ps_file_only: 
1621     wps_cr; mp->ps_offset=0;
1622     break;
1623   case no_print:
1624   case pseudo: 
1625   case new_string: 
1626     break;
1627   default: 
1628     fprintf(mp->wr_file[(mp->selector-write_file)],"\n");
1629   }
1630 } /* note that |tally| is not affected */
1631
1632 @ The |print_visible_char| procedure sends one character to the desired
1633 destination, using the |xchr| array to map it into an external character
1634 compatible with |input_ln|.  (It assumes that it is always called with
1635 a visible ASCII character.)  All printing comes through |print_ln| or
1636 |print_char|, which ultimately calls |print_visible_char|, hence these
1637 routines are the ones that limit lines to at most |max_print_line| characters.
1638 But we must make an exception for the \ps\ output file since it is not safe
1639 to cut up lines arbitrarily in \ps.
1640
1641 Procedure |unit_str_room| needs to be declared |forward| here because it calls
1642 |do_compaction| and |do_compaction| can call the error routines.  Actually,
1643 |unit_str_room| avoids |overflow| errors but it can call |confusion|.
1644
1645 @<Basic printing...@>=
1646 void mp_print_visible_char (MP mp, ASCII_code s) { /* prints a single character */
1647   switch (mp->selector) {
1648   case term_and_log: 
1649     wterm_chr(xchr(s)); wlog_chr(xchr(s));
1650     incr(mp->term_offset); incr(mp->file_offset);
1651     if ( mp->term_offset==(unsigned)mp->max_print_line ) { 
1652        wterm_cr; mp->term_offset=0;
1653     };
1654     if ( mp->file_offset==(unsigned)mp->max_print_line ) { 
1655        wlog_cr; mp->file_offset=0;
1656     };
1657     break;
1658   case log_only: 
1659     wlog_chr(xchr(s)); incr(mp->file_offset);
1660     if ( mp->file_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1661     break;
1662   case term_only: 
1663     wterm_chr(xchr(s)); incr(mp->term_offset);
1664     if ( mp->term_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1665     break;
1666   case ps_file_only: 
1667     if ( s==13 ) {
1668       wps_cr; mp->ps_offset=0;
1669     } else {
1670       wps_chr(xchr(s)); incr(mp->ps_offset);
1671     };
1672     break;
1673   case no_print: 
1674     break;
1675   case pseudo: 
1676     if ( mp->tally<mp->trick_count ) 
1677       mp->trick_buf[mp->tally % mp->error_line]=s;
1678     break;
1679   case new_string: 
1680     if ( mp->pool_ptr>=mp->max_pool_ptr ) { 
1681       mp_unit_str_room(mp);
1682       if ( mp->pool_ptr>=mp->pool_size ) 
1683         goto DONE; /* drop characters if string space is full */
1684     };
1685     append_char(s);
1686     break;
1687   default:
1688     fprintf(mp->wr_file[(mp->selector-write_file)],"%c",xchr(s));
1689   }
1690 DONE:
1691   incr(mp->tally);
1692 }
1693
1694 @ The |print_char| procedure sends one character to the desired destination.
1695 File names and string expressions might contain |ASCII_code| values that
1696 can't be printed using |print_visible_char|.  These characters will be
1697 printed in three- or four-symbol form like `\.{\^\^A}' or `\.{\^\^e4}'.
1698 (This procedure assumes that it is safe to bypass all checks for unprintable
1699 characters when |selector| is in the range |0..max_write_files-1| or when
1700 |selector=ps_file_only|.  In the former case the user might want to write
1701 unprintable characters, and in the latter case the \ps\ printing routines
1702 check their arguments themselves before calling |print_char| or |print|.)
1703
1704 @d print_lc_hex(A) do { l=(A);
1705     mp_print_visible_char(mp, (l<10 ? l+'0' : l-10+'a'));
1706   } while (0)
1707
1708 @<Basic printing...@>=
1709 void mp_print_char (MP mp, ASCII_code k) { /* prints a single character */
1710   int l; /* small index or counter */
1711   if ( mp->selector<pseudo || mp->selector>=write_file) {
1712     mp_print_visible_char(mp, k);
1713   } else if ( @<Character |k| cannot be printed@> ) { 
1714     mp_print(mp, "^^"); 
1715     if ( k<0100 ) { 
1716       mp_print_visible_char(mp, k+0100); 
1717     } else if ( k<0200 ) { 
1718       mp_print_visible_char(mp, k-0100); 
1719     } else { 
1720       print_lc_hex(k / 16);  
1721       print_lc_hex(k % 16); 
1722     }
1723   } else {
1724     mp_print_visible_char(mp, k);
1725   }
1726 };
1727
1728 @ An entire string is output by calling |print|. Note that if we are outputting
1729 the single standard ASCII character \.c, we could call |print("c")|, since
1730 |"c"=99| is the number of a single-character string, as explained above. But
1731 |print_char("c")| is quicker, so \MP\ goes directly to the |print_char|
1732 routine when it knows that this is safe. (The present implementation
1733 assumes that it is always safe to print a visible ASCII character.)
1734 @^system dependencies@>
1735
1736 @<Basic print...@>=
1737 void mp_do_print (MP mp, char *ss, unsigned int len) { /* prints string |s| */
1738   unsigned int j = 0;
1739   while ( j<len ){ 
1740     mp_print_char(mp, ss[j]); incr(j);
1741   }
1742 }
1743
1744
1745 @<Basic print...@>=
1746 void mp_print (MP mp, char *ss) {
1747   mp_do_print(mp, ss, strlen(ss));
1748 }
1749 void mp_print_str (MP mp, str_number s) {
1750   pool_pointer j; /* current character code position */
1751   if ( (s<0)||(s>mp->max_str_ptr) ) {
1752      mp_do_print(mp,"???",3); /* this can't happen */
1753 @.???@>
1754   }
1755   j=mp->str_start[s];
1756   mp_do_print(mp, (char *)(mp->str_pool+j), (str_stop(s)-j));
1757 }
1758
1759
1760 @ Here is the very first thing that \MP\ prints: a headline that identifies
1761 the version number and base name. The |term_offset| variable is temporarily
1762 incorrect, but the discrepancy is not serious since we assume that the banner
1763 and mem identifier together will occupy at most |max_print_line|
1764 character positions.
1765
1766 @<Initialize the output...@>=
1767 wterm (banner);
1768 wterm (version_string);
1769 if (mp->mem_ident!=NULL) 
1770   mp_print(mp,mp->mem_ident); 
1771 mp_print_ln(mp);
1772 update_terminal;
1773
1774 @ The procedure |print_nl| is like |print|, but it makes sure that the
1775 string appears at the beginning of a new line.
1776
1777 @<Basic print...@>=
1778 void mp_print_nl (MP mp, char *s) { /* prints string |s| at beginning of line */
1779   switch(mp->selector) {
1780   case term_and_log: 
1781     if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_ln(mp);
1782     break;
1783   case log_only: 
1784     if ( mp->file_offset>0 ) mp_print_ln(mp);
1785     break;
1786   case term_only: 
1787     if ( mp->term_offset>0 ) mp_print_ln(mp);
1788     break;
1789   case ps_file_only: 
1790     if ( mp->ps_offset>0 ) mp_print_ln(mp);
1791     break;
1792   case no_print:
1793   case pseudo:
1794   case new_string: 
1795         break;
1796   } /* there are no other cases */
1797   mp_print(mp, s);
1798 }
1799
1800 @ An array of digits in the range |0..9| is printed by |print_the_digs|.
1801
1802 @<Basic print...@>=
1803 void mp_print_the_digs (MP mp, eight_bits k) {
1804   /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
1805   while ( k>0 ){ 
1806     decr(k); mp_print_char(mp, '0'+mp->dig[k]);
1807   }
1808 };
1809
1810 @ The following procedure, which prints out the decimal representation of a
1811 given integer |n|, has been written carefully so that it works properly
1812 if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div|
1813 to negative arguments, since such operations are not implemented consistently
1814 by all \PASCAL\ compilers.
1815
1816 @<Basic print...@>=
1817 void mp_print_int (MP mp,integer n) { /* prints an integer in decimal form */
1818   integer m; /* used to negate |n| in possibly dangerous cases */
1819   int k = 0; /* index to current digit; we assume that $|n|<10^{23}$ */
1820   if ( n<0 ) { 
1821     mp_print_char(mp, '-');
1822     if ( n>-100000000 ) {
1823           negate(n);
1824     } else  { 
1825           m=-1-n; n=m / 10; m=(m % 10)+1; k=1;
1826       if ( m<10 ) {
1827         mp->dig[0]=m;
1828       } else { 
1829         mp->dig[0]=0; incr(n);
1830       }
1831     }
1832   }
1833   do {  
1834     mp->dig[k]=n % 10; n=n / 10; incr(k);
1835   } while (n!=0);
1836   mp_print_the_digs(mp, k);
1837 };
1838
1839 @ @<Exported...@>=
1840 void mp_print_int (MP mp,integer n);
1841
1842 @ \MP\ also makes use of a trivial procedure to print two digits. The
1843 following subroutine is usually called with a parameter in the range |0<=n<=99|.
1844
1845 @c 
1846 void mp_print_dd (MP mp,integer n) { /* prints two least significant digits */
1847   n=abs(n) % 100; 
1848   mp_print_char(mp, '0'+(n / 10));
1849   mp_print_char(mp, '0'+(n % 10));
1850 }
1851
1852 @ Here is a procedure that asks the user to type a line of input,
1853 assuming that the |selector| setting is either |term_only| or |term_and_log|.
1854 The input is placed into locations |first| through |last-1| of the
1855 |buffer| array, and echoed on the transcript file if appropriate.
1856
1857 This procedure is never called when |interaction<mp_scroll_mode|.
1858
1859 @d prompt_input(A) do { 
1860     wake_up_terminal; mp_print(mp, (A)); mp_term_input(mp);
1861   } while (0) /* prints a string and gets a line of input */
1862
1863 @c 
1864 void mp_term_input (MP mp) { /* gets a line from the terminal */
1865   size_t k; /* index into |buffer| */
1866   update_terminal; /* Now the user sees the prompt for sure */
1867   if (!mp_input_ln(mp, mp->term_in,true)) 
1868     mp_fatal_error(mp, "End of file on the terminal!");
1869 @.End of file on the terminal@>
1870   mp->term_offset=0; /* the user's line ended with \<\rm return> */
1871   decr(mp->selector); /* prepare to echo the input */
1872   if ( mp->last!=mp->first ) {
1873     for (k=mp->first;k<=mp->last-1;k++) {
1874       mp_print_char(mp, mp->buffer[k]);
1875     }
1876   }
1877   mp_print_ln(mp); 
1878   mp->buffer[mp->last]='%'; 
1879   incr(mp->selector); /* restore previous status */
1880 };
1881
1882 @* \[6] Reporting errors.
1883 When something anomalous is detected, \MP\ typically does something like this:
1884 $$\vbox{\halign{#\hfil\cr
1885 |print_err("Something anomalous has been detected");|\cr
1886 |help3("This is the first line of my offer to help.")|\cr
1887 |("This is the second line. I'm trying to")|\cr
1888 |("explain the best way for you to proceed.");|\cr
1889 |error;|\cr}}$$
1890 A two-line help message would be given using |help2|, etc.; these informal
1891 helps should use simple vocabulary that complements the words used in the
1892 official error message that was printed. (Outside the U.S.A., the help
1893 messages should preferably be translated into the local vernacular. Each
1894 line of help is at most 60 characters long, in the present implementation,
1895 so that |max_print_line| will not be exceeded.)
1896
1897 The |print_err| procedure supplies a `\.!' before the official message,
1898 and makes sure that the terminal is awake if a stop is going to occur.
1899 The |error| procedure supplies a `\..' after the official message, then it
1900 shows the location of the error; and if |interaction=error_stop_mode|,
1901 it also enters into a dialog with the user, during which time the help
1902 message may be printed.
1903 @^system dependencies@>
1904
1905 @ The global variable |interaction| has four settings, representing increasing
1906 amounts of user interaction:
1907
1908 @<Types...@>=
1909 enum { 
1910  mp_unspecified_mode=0, /* extra value for command-line switch */
1911  mp_batch_mode, /* omits all stops and omits terminal output */
1912  mp_nonstop_mode, /* omits all stops */
1913  mp_scroll_mode, /* omits error stops */
1914  mp_error_stop_mode, /* stops at every opportunity to interact */
1915 };
1916
1917 @ @<Glob...@>=
1918 int interaction; /* current level of interaction */
1919
1920 @ @<Option variables@>=
1921 int interaction; /* current level of interaction */
1922
1923 @ Set it here so it can be overwritten by the commandline
1924
1925 @<Allocate or initialize ...@>=
1926 mp->interaction=opt->interaction;
1927 if (mp->interaction==mp_unspecified_mode || mp->interaction>mp_error_stop_mode) 
1928   mp->interaction=mp_error_stop_mode;
1929 if (mp->interaction<mp_unspecified_mode) 
1930   mp->interaction=mp_batch_mode;
1931
1932
1933
1934 @d print_err(A) mp_print_err(mp,(A))
1935
1936 @<Exported...@>=
1937 void mp_print_err(MP mp, char * A);
1938
1939 @ @c
1940 void mp_print_err(MP mp, char * A) { 
1941   if ( mp->interaction==mp_error_stop_mode ) 
1942     wake_up_terminal;
1943   mp_print_nl(mp, "! "); 
1944   mp_print(mp, A);
1945 @.!\relax@>
1946 }
1947
1948
1949 @ \MP\ is careful not to call |error| when the print |selector| setting
1950 might be unusual. The only possible values of |selector| at the time of
1951 error messages are
1952
1953 \yskip\hang|no_print| (when |interaction=mp_batch_mode|
1954   and |log_file| not yet open);
1955
1956 \hang|term_only| (when |interaction>mp_batch_mode| and |log_file| not yet open);
1957
1958 \hang|log_only| (when |interaction=mp_batch_mode| and |log_file| is open);
1959
1960 \hang|term_and_log| (when |interaction>mp_batch_mode| and |log_file| is open).
1961
1962 @<Initialize the print |selector| based on |interaction|@>=
1963 if ( mp->interaction==mp_batch_mode ) mp->selector=no_print; else mp->selector=term_only
1964
1965 @ A global variable |deletions_allowed| is set |false| if the |get_next|
1966 routine is active when |error| is called; this ensures that |get_next|
1967 will never be called recursively.
1968 @^recursion@>
1969
1970 The global variable |history| records the worst level of error that
1971 has been detected. It has four possible values: |spotless|, |warning_issued|,
1972 |error_message_issued|, and |fatal_error_stop|.
1973
1974 Another global variable, |error_count|, is increased by one when an
1975 |error| occurs without an interactive dialog, and it is reset to zero at
1976 the end of every statement.  If |error_count| reaches 100, \MP\ decides
1977 that there is no point in continuing further.
1978
1979 @d spotless 0 /* |history| value when nothing has been amiss yet */
1980 @d warning_issued 1 /* |history| value when |begin_diagnostic| has been called */
1981 @d error_message_issued 2 /* |history| value when |error| has been called */
1982 @d fatal_error_stop 3 /* |history| value when termination was premature */
1983
1984 @<Glob...@>=
1985 boolean deletions_allowed; /* is it safe for |error| to call |get_next|? */
1986 int history; /* has the source input been clean so far? */
1987 int error_count; /* the number of scrolled errors since the last statement ended */
1988
1989 @ The value of |history| is initially |fatal_error_stop|, but it will
1990 be changed to |spotless| if \MP\ survives the initialization process.
1991
1992 @<Allocate or ...@>=
1993 mp->deletions_allowed=true; mp->error_count=0; /* |history| is initialized elsewhere */
1994
1995 @ Since errors can be detected almost anywhere in \MP, we want to declare the
1996 error procedures near the beginning of the program. But the error procedures
1997 in turn use some other procedures, which need to be declared |forward|
1998 before we get to |error| itself.
1999
2000 It is possible for |error| to be called recursively if some error arises
2001 when |get_next| is being used to delete a token, and/or if some fatal error
2002 occurs while \MP\ is trying to fix a non-fatal one. But such recursion
2003 @^recursion@>
2004 is never more than two levels deep.
2005
2006 @<Declarations@>=
2007 void mp_get_next (MP mp);
2008 void mp_term_input (MP mp);
2009 void mp_show_context (MP mp);
2010 void mp_begin_file_reading (MP mp);
2011 void mp_open_log_file (MP mp);
2012 void mp_clear_for_error_prompt (MP mp);
2013 void mp_debug_help (MP mp);
2014 @<Declare the procedure called |flush_string|@>
2015
2016 @ @<Exported...@>=
2017 void mp_normalize_selector (MP mp);
2018
2019 @ Individual lines of help are recorded in the array |help_line|, which
2020 contains entries in positions |0..(help_ptr-1)|. They should be printed
2021 in reverse order, i.e., with |help_line[0]| appearing last.
2022
2023 @d hlp1(A) mp->help_line[0]=(A); }
2024 @d hlp2(A) mp->help_line[1]=(A); hlp1
2025 @d hlp3(A) mp->help_line[2]=(A); hlp2
2026 @d hlp4(A) mp->help_line[3]=(A); hlp3
2027 @d hlp5(A) mp->help_line[4]=(A); hlp4
2028 @d hlp6(A) mp->help_line[5]=(A); hlp5
2029 @d help0 mp->help_ptr=0 /* sometimes there might be no help */
2030 @d help1  { mp->help_ptr=1; hlp1 /* use this with one help line */
2031 @d help2  { mp->help_ptr=2; hlp2 /* use this with two help lines */
2032 @d help3  { mp->help_ptr=3; hlp3 /* use this with three help lines */
2033 @d help4  { mp->help_ptr=4; hlp4 /* use this with four help lines */
2034 @d help5  { mp->help_ptr=5; hlp5 /* use this with five help lines */
2035 @d help6  { mp->help_ptr=6; hlp6 /* use this with six help lines */
2036
2037 @<Glob...@>=
2038 char * help_line[6]; /* helps for the next |error| */
2039 unsigned int help_ptr; /* the number of help lines present */
2040 boolean use_err_help; /* should the |err_help| string be shown? */
2041 str_number err_help; /* a string set up by \&{errhelp} */
2042 str_number filename_template; /* a string set up by \&{filenametemplate} */
2043
2044 @ @<Allocate or ...@>=
2045 mp->help_ptr=0; mp->use_err_help=false; mp->err_help=0; mp->filename_template=0;
2046
2047 @ The |jump_out| procedure just cuts across all active procedure levels and
2048 goes to |end_of_MP|. This is the only nonlocal |goto| statement in the
2049 whole program. It is used when there is no recovery from a particular error.
2050
2051 Some \PASCAL\ compilers do not implement non-local |goto| statements.
2052 @^system dependencies@>
2053 In such cases the body of |jump_out| should simply be
2054 `|close_files_and_terminate|;\thinspace' followed by a call on some system
2055 procedure that quietly terminates the program.
2056
2057 @<Error hand...@>=
2058 void mp_jump_out (MP mp) { 
2059  exit(mp->history);
2060 };
2061
2062 @ Here now is the general |error| routine.
2063
2064 @<Error hand...@>=
2065 void mp_error (MP mp) { /* completes the job of error reporting */
2066   ASCII_code c; /* what the user types */
2067   integer s1,s2,s3; /* used to save global variables when deleting tokens */
2068   pool_pointer j; /* character position being printed */
2069   if ( mp->history<error_message_issued ) mp->history=error_message_issued;
2070   mp_print_char(mp, '.'); mp_show_context(mp);
2071   if ( mp->interaction==mp_error_stop_mode ) {
2072     @<Get user's advice and |return|@>;
2073   }
2074   incr(mp->error_count);
2075   if ( mp->error_count==100 ) { 
2076     mp_print_nl(mp,"(That makes 100 errors; please try again.)");
2077 @.That makes 100 errors...@>
2078     mp->history=fatal_error_stop; mp_jump_out(mp);
2079   }
2080   @<Put help message on the transcript file@>;
2081 }
2082 void mp_warn (MP mp, char *msg) {
2083   int saved_selector = mp->selector;
2084   mp_normalize_selector(mp);
2085   mp_print_nl(mp,"Warning: ");
2086   mp_print(mp,msg);
2087   mp->selector = saved_selector;
2088 }
2089
2090 @ @<Exported...@>=
2091 void mp_error (MP mp);
2092 void mp_warn (MP mp, char *msg);
2093
2094
2095 @ @<Get user's advice...@>=
2096 while (1) { 
2097 CONTINUE:
2098   mp_clear_for_error_prompt(mp); prompt_input("? ");
2099 @.?\relax@>
2100   if ( mp->last==mp->first ) return;
2101   c=mp->buffer[mp->first];
2102   if ( c>='a' ) c=c+'A'-'a'; /* convert to uppercase */
2103   @<Interpret code |c| and |return| if done@>;
2104 }
2105
2106 @ It is desirable to provide an `\.E' option here that gives the user
2107 an easy way to return from \MP\ to the system editor, with the offending
2108 line ready to be edited. But such an extension requires some system
2109 wizardry, so the present implementation simply types out the name of the
2110 file that should be
2111 edited and the relevant line number.
2112 @^system dependencies@>
2113
2114 @<Types...@>=
2115 typedef void (*run_editor_command)(MP, char *, int);
2116
2117 @ @<Glob...@>=
2118 run_editor_command run_editor;
2119
2120 @ @<Option variables@>=
2121 run_editor_command run_editor;
2122
2123 @ @<Allocate or initialize ...@>=
2124 set_callback_option(run_editor);
2125
2126 @ @<Exported function headers@>=
2127 void mp_run_editor (MP mp, char *fname, int fline);
2128
2129 @ @c void mp_run_editor (MP mp, char *fname, int fline) {
2130     mp_print_nl(mp, "You want to edit file ");
2131 @.You want to edit file x@>
2132     mp_print(mp, fname);
2133     mp_print(mp, " at line "); 
2134     mp_print_int(mp, fline);
2135     mp->interaction=mp_scroll_mode; 
2136     mp_jump_out(mp);
2137 }
2138
2139
2140 There is a secret `\.D' option available when the debugging routines haven't
2141 been commented~out.
2142 @^debugging@>
2143
2144 @<Interpret code |c| and |return| if done@>=
2145 switch (c) {
2146 case '0': case '1': case '2': case '3': case '4':
2147 case '5': case '6': case '7': case '8': case '9': 
2148   if ( mp->deletions_allowed ) {
2149     @<Delete |c-"0"| tokens and |continue|@>;
2150   }
2151   break;
2152 #ifdef DEBUG
2153 case 'D': 
2154   mp_debug_help(mp); continue; 
2155   break;
2156 #endif
2157 case 'E': 
2158   if ( mp->file_ptr>0 ){ 
2159     (mp->run_editor)(mp, 
2160                      str(mp->input_stack[mp->file_ptr].name_field), 
2161                      mp_true_line(mp));
2162   }
2163   break;
2164 case 'H': 
2165   @<Print the help information and |continue|@>;
2166   break;
2167 case 'I':
2168   @<Introduce new material from the terminal and |return|@>;
2169   break;
2170 case 'Q': case 'R': case 'S':
2171   @<Change the interaction level and |return|@>;
2172   break;
2173 case 'X':
2174   mp->interaction=mp_scroll_mode; mp_jump_out(mp);
2175   break;
2176 default:
2177   break;
2178 }
2179 @<Print the menu of available options@>
2180
2181 @ @<Print the menu...@>=
2182
2183   mp_print(mp, "Type <return> to proceed, S to scroll future error messages,");
2184 @.Type <return> to proceed...@>
2185   mp_print_nl(mp, "R to run without stopping, Q to run quietly,");
2186   mp_print_nl(mp, "I to insert something, ");
2187   if ( mp->file_ptr>0 ) 
2188     mp_print(mp, "E to edit your file,");
2189   if ( mp->deletions_allowed )
2190     mp_print_nl(mp, "1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
2191   mp_print_nl(mp, "H for help, X to quit.");
2192 }
2193
2194 @ Here the author of \MP\ apologizes for making use of the numerical
2195 relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
2196 |mp_batch_mode|, |mp_nonstop_mode|, |mp_scroll_mode|.
2197 @^Knuth, Donald Ervin@>
2198
2199 @<Change the interaction...@>=
2200
2201   mp->error_count=0; mp->interaction=mp_batch_mode+c-'Q';
2202   mp_print(mp, "OK, entering ");
2203   switch (c) {
2204   case 'Q': mp_print(mp, "batchmode"); decr(mp->selector); break;
2205   case 'R': mp_print(mp, "nonstopmode"); break;
2206   case 'S': mp_print(mp, "scrollmode"); break;
2207   } /* there are no other cases */
2208   mp_print(mp, "..."); mp_print_ln(mp); update_terminal; return;
2209 }
2210
2211 @ When the following code is executed, |buffer[(first+1)..(last-1)]| may
2212 contain the material inserted by the user; otherwise another prompt will
2213 be given. In order to understand this part of the program fully, you need
2214 to be familiar with \MP's input stacks.
2215
2216 @<Introduce new material...@>=
2217
2218   mp_begin_file_reading(mp); /* enter a new syntactic level for terminal input */
2219   if ( mp->last>mp->first+1 ) { 
2220     loc=mp->first+1; mp->buffer[mp->first]=' ';
2221   } else { 
2222    prompt_input("insert>"); loc=mp->first;
2223 @.insert>@>
2224   };
2225   mp->first=mp->last+1; mp->cur_input.limit_field=mp->last; return;
2226 }
2227
2228 @ We allow deletion of up to 99 tokens at a time.
2229
2230 @<Delete |c-"0"| tokens...@>=
2231
2232   s1=mp->cur_cmd; s2=mp->cur_mod; s3=mp->cur_sym; mp->OK_to_interrupt=false;
2233   if ( (mp->last>mp->first+1) && (mp->buffer[mp->first+1]>='0')&&(mp->buffer[mp->first+1]<='9') )
2234     c=c*10+mp->buffer[mp->first+1]-'0'*11;
2235   else 
2236     c=c-'0';
2237   while ( c>0 ) { 
2238     mp_get_next(mp); /* one-level recursive call of |error| is possible */
2239     @<Decrease the string reference count, if the current token is a string@>;
2240     decr(c);
2241   };
2242   mp->cur_cmd=s1; mp->cur_mod=s2; mp->cur_sym=s3; mp->OK_to_interrupt=true;
2243   help2("I have just deleted some text, as you asked.")
2244        ("You can now delete more, or insert, or whatever.");
2245   mp_show_context(mp); 
2246   goto CONTINUE;
2247 }
2248
2249 @ @<Print the help info...@>=
2250
2251   if ( mp->use_err_help ) { 
2252     @<Print the string |err_help|, possibly on several lines@>;
2253     mp->use_err_help=false;
2254   } else { 
2255     if ( mp->help_ptr==0 ) {
2256       help2("Sorry, I don't know how to help in this situation.")
2257            ("Maybe you should try asking a human?");
2258      }
2259     do { 
2260       decr(mp->help_ptr); mp_print(mp, mp->help_line[mp->help_ptr]); mp_print_ln(mp);
2261     } while (mp->help_ptr!=0);
2262   };
2263   help4("Sorry, I already gave what help I could...")
2264        ("Maybe you should try asking a human?")
2265        ("An error might have occurred before I noticed any problems.")
2266        ("``If all else fails, read the instructions.''");
2267   goto CONTINUE;
2268 }
2269
2270 @ @<Print the string |err_help|, possibly on several lines@>=
2271 j=mp->str_start[mp->err_help];
2272 while ( j<str_stop(mp->err_help) ) { 
2273   if ( mp->str_pool[j]!='%' ) mp_print_str(mp, mp->str_pool[j]);
2274   else if ( j+1==str_stop(mp->err_help) ) mp_print_ln(mp);
2275   else if ( mp->str_pool[j+1]!='%' ) mp_print_ln(mp);
2276   else  { incr(j); mp_print_char(mp, '%'); };
2277   incr(j);
2278 }
2279
2280 @ @<Put help message on the transcript file@>=
2281 if ( mp->interaction>mp_batch_mode ) decr(mp->selector); /* avoid terminal output */
2282 if ( mp->use_err_help ) { 
2283   mp_print_nl(mp, "");
2284   @<Print the string |err_help|, possibly on several lines@>;
2285 } else { 
2286   while ( mp->help_ptr>0 ){ 
2287     decr(mp->help_ptr); mp_print_nl(mp, mp->help_line[mp->help_ptr]);
2288   };
2289 }
2290 mp_print_ln(mp);
2291 if ( mp->interaction>mp_batch_mode ) incr(mp->selector); /* re-enable terminal output */
2292 mp_print_ln(mp)
2293
2294 @ In anomalous cases, the print selector might be in an unknown state;
2295 the following subroutine is called to fix things just enough to keep
2296 running a bit longer.
2297
2298 @c 
2299 void mp_normalize_selector (MP mp) { 
2300   if ( mp->log_opened ) mp->selector=term_and_log;
2301   else mp->selector=term_only;
2302   if ( mp->job_name==NULL ) mp_open_log_file(mp);
2303   if ( mp->interaction==mp_batch_mode ) decr(mp->selector);
2304 }
2305
2306 @ The following procedure prints \MP's last words before dying.
2307
2308 @d succumb { if ( mp->interaction==mp_error_stop_mode )
2309     mp->interaction=mp_scroll_mode; /* no more interaction */
2310   if ( mp->log_opened ) mp_error(mp);
2311   /* if ( mp->interaction>mp_batch_mode ) mp_debug_help(mp); */
2312   mp->history=fatal_error_stop; mp_jump_out(mp); /* irrecoverable error */
2313   }
2314
2315 @<Error hand...@>=
2316 void mp_fatal_error (MP mp, char *s) { /* prints |s|, and that's it */
2317   mp_normalize_selector(mp);
2318   print_err("Emergency stop"); help1(s); succumb;
2319 @.Emergency stop@>
2320 }
2321
2322 @ @<Exported...@>=
2323 void mp_fatal_error (MP mp, char *s);
2324
2325
2326 @ Here is the most dreaded error message.
2327
2328 @<Error hand...@>=
2329 void mp_overflow (MP mp, char *s, integer n) { /* stop due to finiteness */
2330   mp_normalize_selector(mp);
2331   print_err("MetaPost capacity exceeded, sorry [");
2332 @.MetaPost capacity exceeded ...@>
2333   mp_print(mp, s); mp_print_char(mp, '='); mp_print_int(mp, n); mp_print_char(mp, ']');
2334   help2("If you really absolutely need more capacity,")
2335        ("you can ask a wizard to enlarge me.");
2336   succumb;
2337 }
2338
2339 @ @<Declarations@>=
2340 void mp_overflow (MP mp, char *s, integer n);
2341
2342 @ The program might sometime run completely amok, at which point there is
2343 no choice but to stop. If no previous error has been detected, that's bad
2344 news; a message is printed that is really intended for the \MP\
2345 maintenance person instead of the user (unless the user has been
2346 particularly diabolical).  The index entries for `this can't happen' may
2347 help to pinpoint the problem.
2348 @^dry rot@>
2349
2350 @<Declarations@>=
2351 void mp_confusion (MP mp,char *s);
2352
2353 @ @<Error hand...@>=
2354 void mp_confusion (MP mp,char *s) {
2355   /* consistency check violated; |s| tells where */
2356   mp_normalize_selector(mp);
2357   if ( mp->history<error_message_issued ) { 
2358     print_err("This can't happen ("); mp_print(mp, s); mp_print_char(mp, ')');
2359 @.This can't happen@>
2360     help1("I'm broken. Please show this to someone who can fix can fix");
2361   } else { 
2362     print_err("I can\'t go on meeting you like this");
2363 @.I can't go on...@>
2364     help2("One of your faux pas seems to have wounded me deeply...")
2365          ("in fact, I'm barely conscious. Please fix it and try again.");
2366   }
2367   succumb;
2368 }
2369
2370 @ Users occasionally want to interrupt \MP\ while it's running.
2371 If the \PASCAL\ runtime system allows this, one can implement
2372 a routine that sets the global variable |interrupt| to some nonzero value
2373 when such an interrupt is signaled. Otherwise there is probably at least
2374 a way to make |interrupt| nonzero using the \PASCAL\ debugger.
2375 @^system dependencies@>
2376 @^debugging@>
2377
2378 @d check_interrupt { if ( mp->interrupt!=0 )
2379    mp_pause_for_instructions(mp); }
2380
2381 @<Global...@>=
2382 integer interrupt; /* should \MP\ pause for instructions? */
2383 boolean OK_to_interrupt; /* should interrupts be observed? */
2384
2385 @ @<Allocate or ...@>=
2386 mp->interrupt=0; mp->OK_to_interrupt=true;
2387
2388 @ When an interrupt has been detected, the program goes into its
2389 highest interaction level and lets the user have the full flexibility of
2390 the |error| routine.  \MP\ checks for interrupts only at times when it is
2391 safe to do this.
2392
2393 @c 
2394 void mp_pause_for_instructions (MP mp) { 
2395   if ( mp->OK_to_interrupt ) { 
2396     mp->interaction=mp_error_stop_mode;
2397     if ( (mp->selector==log_only)||(mp->selector==no_print) )
2398       incr(mp->selector);
2399     print_err("Interruption");
2400 @.Interruption@>
2401     help3("You rang?")
2402          ("Try to insert some instructions for me (e.g.,`I show x'),")
2403          ("unless you just want to quit by typing `X'.");
2404     mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
2405     mp->interrupt=0;
2406   }
2407 }
2408
2409 @ Many of \MP's error messages state that a missing token has been
2410 inserted behind the scenes. We can save string space and program space
2411 by putting this common code into a subroutine.
2412
2413 @c 
2414 void mp_missing_err (MP mp, char *s) { 
2415   print_err("Missing `"); mp_print(mp, s); mp_print(mp, "' has been inserted");
2416 @.Missing...inserted@>
2417 }
2418
2419 @* \[7] Arithmetic with scaled numbers.
2420 The principal computations performed by \MP\ are done entirely in terms of
2421 integers less than $2^{31}$ in magnitude; thus, the arithmetic specified in this
2422 program can be carried out in exactly the same way on a wide variety of
2423 computers, including some small ones.
2424 @^small computers@>
2425
2426 But \PASCAL\ does not define the |div|
2427 operation in the case of negative dividends; for example, the result of
2428 |(-2*n-1) div 2| is |-(n+1)| on some computers and |-n| on others.
2429 There are two principal types of arithmetic: ``translation-preserving,''
2430 in which the identity |(a+q*b)div b=(a div b)+q| is valid; and
2431 ``negation-preserving,'' in which |(-a)div b=-(a div b)|. This leads to
2432 two \MP s, which can produce different results, although the differences
2433 should be negligible when the language is being used properly.
2434 The \TeX\ processor has been defined carefully so that both varieties
2435 of arithmetic will produce identical output, but it would be too
2436 inefficient to constrain \MP\ in a similar way.
2437
2438 @d el_gordo   017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */
2439
2440 @ One of \MP's most common operations is the calculation of
2441 $\lfloor{a+b\over2}\rfloor$,
2442 the midpoint of two given integers |a| and~|b|. The only decent way to do
2443 this in \PASCAL\ is to write `|(a+b) div 2|'; but on most machines it is
2444 far more efficient to calculate `|(a+b)| right shifted one bit'.
2445
2446 Therefore the midpoint operation will always be denoted by `|half(a+b)|'
2447 in this program. If \MP\ is being implemented with languages that permit
2448 binary shifting, the |half| macro should be changed to make this operation
2449 as efficient as possible.  Since some languages have shift operators that can
2450 only be trusted to work on positive numbers, there is also a macro |halfp|
2451 that is used only when the quantity being halved is known to be positive
2452 or zero.
2453
2454 @d half(A) ((A)) / 2
2455 @d halfp(A) ((A)) / 2
2456
2457 @ A single computation might use several subroutine calls, and it is
2458 desirable to avoid producing multiple error messages in case of arithmetic
2459 overflow. So the routines below set the global variable |arith_error| to |true|
2460 instead of reporting errors directly to the user.
2461
2462 @<Glob...@>=
2463 boolean arith_error; /* has arithmetic overflow occurred recently? */
2464
2465 @ @<Allocate or ...@>=
2466 mp->arith_error=false;
2467
2468 @ At crucial points the program will say |check_arith|, to test if
2469 an arithmetic error has been detected.
2470
2471 @d check_arith { if ( mp->arith_error ) mp_clear_arith(mp); }
2472
2473 @c 
2474 void mp_clear_arith (MP mp) { 
2475   print_err("Arithmetic overflow");
2476 @.Arithmetic overflow@>
2477   help4("Uh, oh. A little while ago one of the quantities that I was")
2478        ("computing got too large, so I'm afraid your answers will be")
2479        ("somewhat askew. You'll probably have to adopt different")
2480        ("tactics next time. But I shall try to carry on anyway.");
2481   mp_error(mp); 
2482   mp->arith_error=false;
2483 }
2484
2485 @ Addition is not always checked to make sure that it doesn't overflow,
2486 but in places where overflow isn't too unlikely the |slow_add| routine
2487 is used.
2488
2489 @c integer mp_slow_add (MP mp,integer x, integer y) { 
2490   if ( x>=0 )  {
2491     if ( y<=el_gordo-x ) { 
2492       return x+y;
2493     } else  { 
2494       mp->arith_error=true; 
2495           return el_gordo;
2496     }
2497   } else  if ( -y<=el_gordo+x ) {
2498     return x+y;
2499   } else { 
2500     mp->arith_error=true; 
2501         return -el_gordo;
2502   }
2503 }
2504
2505 @ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
2506 of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
2507 positions from the right end of a binary computer word.
2508
2509 @d quarter_unit   040000 /* $2^{14}$, represents 0.250000 */
2510 @d half_unit   0100000 /* $2^{15}$, represents 0.50000 */
2511 @d three_quarter_unit   0140000 /* $3\cdot2^{14}$, represents 0.75000 */
2512 @d unity   0200000 /* $2^{16}$, represents 1.00000 */
2513 @d two   0400000 /* $2^{17}$, represents 2.00000 */
2514 @d three   0600000 /* $2^{17}+2^{16}$, represents 3.00000 */
2515
2516 @<Types...@>=
2517 typedef integer scaled; /* this type is used for scaled integers */
2518 typedef unsigned char small_number; /* this type is self-explanatory */
2519
2520 @ The following function is used to create a scaled integer from a given decimal
2521 fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
2522 given in |dig[i]|, and the calculation produces a correctly rounded result.
2523
2524 @c 
2525 scaled mp_round_decimals (MP mp,small_number k) {
2526   /* converts a decimal fraction */
2527  integer a = 0; /* the accumulator */
2528  while ( k-->0 ) { 
2529     a=(a+mp->dig[k]*two) / 10;
2530   }
2531   return halfp(a+1);
2532 }
2533
2534 @ Conversely, here is a procedure analogous to |print_int|. If the output
2535 of this procedure is subsequently read by \MP\ and converted by the
2536 |round_decimals| routine above, it turns out that the original value will
2537 be reproduced exactly. A decimal point is printed only if the value is
2538 not an integer. If there is more than one way to print the result with
2539 the optimum number of digits following the decimal point, the closest
2540 possible value is given.
2541
2542 The invariant relation in the \&{repeat} loop is that a sequence of
2543 decimal digits yet to be printed will yield the original number if and only if
2544 they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
2545 We can stop if and only if $f=0$ satisfies this condition; the loop will
2546 terminate before $s$ can possibly become zero.
2547
2548 @<Basic printing...@>=
2549 void mp_print_scaled (MP mp,scaled s) { /* prints scaled real, rounded to five  digits */
2550   scaled delta; /* amount of allowable inaccuracy */
2551   if ( s<0 ) { 
2552         mp_print_char(mp, '-'); 
2553     negate(s); /* print the sign, if negative */
2554   }
2555   mp_print_int(mp, s / unity); /* print the integer part */
2556   s=10*(s % unity)+5;
2557   if ( s!=5 ) { 
2558     delta=10; 
2559     mp_print_char(mp, '.');
2560     do {  
2561       if ( delta>unity )
2562         s=s+0100000-(delta / 2); /* round the final digit */
2563       mp_print_char(mp, '0'+(s / unity)); 
2564       s=10*(s % unity); 
2565       delta=delta*10;
2566     } while (s>delta);
2567   }
2568 }
2569
2570 @ We often want to print two scaled quantities in parentheses,
2571 separated by a comma.
2572
2573 @<Basic printing...@>=
2574 void mp_print_two (MP mp,scaled x, scaled y) { /* prints `|(x,y)|' */
2575   mp_print_char(mp, '('); 
2576   mp_print_scaled(mp, x); 
2577   mp_print_char(mp, ','); 
2578   mp_print_scaled(mp, y);
2579   mp_print_char(mp, ')');
2580 }
2581
2582 @ The |scaled| quantities in \MP\ programs are generally supposed to be
2583 less than $2^{12}$ in absolute value, so \MP\ does much of its internal
2584 arithmetic with 28~significant bits of precision. A |fraction| denotes
2585 a scaled integer whose binary point is assumed to be 28 bit positions
2586 from the right.
2587
2588 @d fraction_half 01000000000 /* $2^{27}$, represents 0.50000000 */
2589 @d fraction_one 02000000000 /* $2^{28}$, represents 1.00000000 */
2590 @d fraction_two 04000000000 /* $2^{29}$, represents 2.00000000 */
2591 @d fraction_three 06000000000 /* $3\cdot2^{28}$, represents 3.00000000 */
2592 @d fraction_four 010000000000 /* $2^{30}$, represents 4.00000000 */
2593
2594 @<Types...@>=
2595 typedef integer fraction; /* this type is used for scaled fractions */
2596
2597 @ In fact, the two sorts of scaling discussed above aren't quite
2598 sufficient; \MP\ has yet another, used internally to keep track of angles
2599 in units of $2^{-20}$ degrees.
2600
2601 @d forty_five_deg 0264000000 /* $45\cdot2^{20}$, represents $45^\circ$ */
2602 @d ninety_deg 0550000000 /* $90\cdot2^{20}$, represents $90^\circ$ */
2603 @d one_eighty_deg 01320000000 /* $180\cdot2^{20}$, represents $180^\circ$ */
2604 @d three_sixty_deg 02640000000 /* $360\cdot2^{20}$, represents $360^\circ$ */
2605
2606 @<Types...@>=
2607 typedef integer angle; /* this type is used for scaled angles */
2608
2609 @ The |make_fraction| routine produces the |fraction| equivalent of
2610 |p/q|, given integers |p| and~|q|; it computes the integer
2611 $f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
2612 positive. If |p| and |q| are both of the same scaled type |t|,
2613 the ``type relation'' |make_fraction(t,t)=fraction| is valid;
2614 and it's also possible to use the subroutine ``backwards,'' using
2615 the relation |make_fraction(t,fraction)=t| between scaled types.
2616
2617 If the result would have magnitude $2^{31}$ or more, |make_fraction|
2618 sets |arith_error:=true|. Most of \MP's internal computations have
2619 been designed to avoid this sort of error.
2620
2621 If this subroutine were programmed in assembly language on a typical
2622 machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
2623 double-precision product can often be input to a fixed-point division
2624 instruction. But when we are restricted to \PASCAL\ arithmetic it
2625 is necessary either to resort to multiple-precision maneuvering
2626 or to use a simple but slow iteration. The multiple-precision technique
2627 would be about three times faster than the code adopted here, but it
2628 would be comparatively long and tricky, involving about sixteen
2629 additional multiplications and divisions.
2630
2631 This operation is part of \MP's ``inner loop''; indeed, it will
2632 consume nearly 10\pct! of the running time (exclusive of input and output)
2633 if the code below is left unchanged. A machine-dependent recoding
2634 will therefore make \MP\ run faster. The present implementation
2635 is highly portable, but slow; it avoids multiplication and division
2636 except in the initial stage. System wizards should be careful to
2637 replace it with a routine that is guaranteed to produce identical
2638 results in all cases.
2639 @^system dependencies@>
2640
2641 As noted below, a few more routines should also be replaced by machine-dependent
2642 code, for efficiency. But when a procedure is not part of the ``inner loop,''
2643 such changes aren't advisable; simplicity and robustness are
2644 preferable to trickery, unless the cost is too high.
2645 @^inner loop@>
2646
2647 @<Exported...@>=
2648 fraction mp_make_fraction (MP mp,integer p, integer q);
2649 integer mp_take_scaled (MP mp,integer q, scaled f) ;
2650
2651 @ If FIXPT is not defined, we need these preprocessor values
2652
2653 @d ELGORDO  0x7fffffff
2654 @d TWEXP31  2147483648.0
2655 @d TWEXP28  268435456.0
2656 @d TWEXP16 65536.0
2657 @d TWEXP_16 (1.0/65536.0)
2658 @d TWEXP_28 (1.0/268435456.0)
2659
2660
2661 @c 
2662 fraction mp_make_fraction (MP mp,integer p, integer q) {
2663 #ifdef FIXPT
2664   integer f; /* the fraction bits, with a leading 1 bit */
2665   integer n; /* the integer part of $\vert p/q\vert$ */
2666   integer be_careful; /* disables certain compiler optimizations */
2667   boolean negative = false; /* should the result be negated? */
2668   if ( p<0 ) {
2669     negate(p); negative=true;
2670   }
2671   if ( q<=0 ) { 
2672 #ifdef DEBUG
2673     if ( q==0 ) mp_confusion(mp, '/');
2674 #endif
2675 @:this can't happen /}{\quad \./@>
2676     negate(q); negative = ! negative;
2677   };
2678   n=p / q; p=p % q;
2679   if ( n>=8 ){ 
2680     mp->arith_error=true;
2681     return ( negative ? -el_gordo : el_gordo);
2682   } else { 
2683     n=(n-1)*fraction_one;
2684     @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>;
2685     return (negative ? (-(f+n)) : (f+n));
2686   }
2687 #else /* FIXPT */
2688     register double d;
2689         register integer i;
2690 #ifdef DEBUG
2691         if (q==0) mp_confusion(mp,'/'); 
2692 #endif /* DEBUG */
2693         d = TWEXP28 * (double)p /(double)q;
2694         if ((p^q) >= 0) {
2695                 d += 0.5;
2696                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
2697                 i = (integer) d;
2698                 if (d==i && ( ((q>0 ? -q : q)&077777)
2699                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2700         } else {
2701                 d -= 0.5;
2702                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
2703                 i = (integer) d;
2704                 if (d==i && ( ((q>0 ? q : -q)&077777)
2705                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2706         }
2707         return i;
2708 #endif /* FIXPT */
2709 }
2710
2711 @ The |repeat| loop here preserves the following invariant relations
2712 between |f|, |p|, and~|q|:
2713 (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
2714 $p_0$ is the original value of~$p$.
2715
2716 Notice that the computation specifies
2717 |(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
2718 Let us hope that optimizing compilers do not miss this point; a
2719 special variable |be_careful| is used to emphasize the necessary
2720 order of computation. Optimizing compilers should keep |be_careful|
2721 in a register, not store it in memory.
2722 @^inner loop@>
2723
2724 @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>=
2725 {
2726   f=1;
2727   do {  
2728     be_careful=p-q; p=be_careful+p;
2729     if ( p>=0 ) { 
2730       f=f+f+1;
2731     } else  { 
2732       f+=f; p=p+q;
2733     }
2734   } while (f<fraction_one);
2735   be_careful=p-q;
2736   if ( be_careful+p>=0 ) incr(f);
2737 }
2738
2739 @ The dual of |make_fraction| is |take_fraction|, which multiplies a
2740 given integer~|q| by a fraction~|f|. When the operands are positive, it
2741 computes $p=\lfloor qf/2^{28}+{1\over2}\rfloor$, a symmetric function
2742 of |q| and~|f|.
2743
2744 This routine is even more ``inner loopy'' than |make_fraction|;
2745 the present implementation consumes almost 20\pct! of \MP's computation
2746 time during typical jobs, so a machine-language substitute is advisable.
2747 @^inner loop@> @^system dependencies@>
2748
2749 @<Declarations@>=
2750 integer mp_take_fraction (MP mp,integer q, fraction f) ;
2751
2752 @ @c 
2753 #ifdef FIXPT
2754 integer mp_take_fraction (MP mp,integer q, fraction f) {
2755   integer p; /* the fraction so far */
2756   boolean negative; /* should the result be negated? */
2757   integer n; /* additional multiple of $q$ */
2758   integer be_careful; /* disables certain compiler optimizations */
2759   @<Reduce to the case that |f>=0| and |q>0|@>;
2760   if ( f<fraction_one ) { 
2761     n=0;
2762   } else { 
2763     n=f / fraction_one; f=f % fraction_one;
2764     if ( q<=el_gordo / n ) { 
2765       n=n*q ; 
2766     } else { 
2767       mp->arith_error=true; n=el_gordo;
2768     }
2769   }
2770   f=f+fraction_one;
2771   @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>;
2772   be_careful=n-el_gordo;
2773   if ( be_careful+p>0 ){ 
2774     mp->arith_error=true; n=el_gordo-p;
2775   }
2776   if ( negative ) 
2777         return (-(n+p));
2778   else 
2779     return (n+p);
2780 #else /* FIXPT */
2781 integer mp_take_fraction (MP mp,integer p, fraction q) {
2782     register double d;
2783         register integer i;
2784         d = (double)p * (double)q * TWEXP_28;
2785         if ((p^q) >= 0) {
2786                 d += 0.5;
2787                 if (d>=TWEXP31) {
2788                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2789                                 mp->arith_error = true;
2790                         return ELGORDO;
2791                 }
2792                 i = (integer) d;
2793                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2794         } else {
2795                 d -= 0.5;
2796                 if (d<= -TWEXP31) {
2797                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2798                                 mp->arith_error = true;
2799                         return -ELGORDO;
2800                 }
2801                 i = (integer) d;
2802                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2803         }
2804         return i;
2805 #endif /* FIXPT */
2806 }
2807
2808 @ @<Reduce to the case that |f>=0| and |q>0|@>=
2809 if ( f>=0 ) {
2810   negative=false;
2811 } else { 
2812   negate( f); negative=true;
2813 }
2814 if ( q<0 ) { 
2815   negate(q); negative=! negative;
2816 }
2817
2818 @ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
2819 =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
2820 $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
2821 @^inner loop@>
2822
2823 @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>=
2824 p=fraction_half; /* that's $2^{27}$; the invariants hold now with $k=28$ */
2825 if ( q<fraction_four ) {
2826   do {  
2827     if ( odd(f) ) p=halfp(p+q); else p=halfp(p);
2828     f=halfp(f);
2829   } while (f!=1);
2830 } else  {
2831   do {  
2832     if ( odd(f) ) p=p+halfp(q-p); else p=halfp(p);
2833     f=halfp(f);
2834   } while (f!=1);
2835 }
2836
2837
2838 @ When we want to multiply something by a |scaled| quantity, we use a scheme
2839 analogous to |take_fraction| but with a different scaling.
2840 Given positive operands, |take_scaled|
2841 computes the quantity $p=\lfloor qf/2^{16}+{1\over2}\rfloor$.
2842
2843 Once again it is a good idea to use a machine-language replacement if
2844 possible; otherwise |take_scaled| will use more than 2\pct! of the running time
2845 when the Computer Modern fonts are being generated.
2846 @^inner loop@>
2847
2848 @c 
2849 #ifdef FIXPT
2850 integer mp_take_scaled (MP mp,integer q, scaled f) {
2851   integer p; /* the fraction so far */
2852   boolean negative; /* should the result be negated? */
2853   integer n; /* additional multiple of $q$ */
2854   integer be_careful; /* disables certain compiler optimizations */
2855   @<Reduce to the case that |f>=0| and |q>0|@>;
2856   if ( f<unity ) { 
2857     n=0;
2858   } else  { 
2859     n=f / unity; f=f % unity;
2860     if ( q<=el_gordo / n ) {
2861       n=n*q;
2862     } else  { 
2863       mp->arith_error=true; n=el_gordo;
2864     }
2865   }
2866   f=f+unity;
2867   @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>;
2868   be_careful=n-el_gordo;
2869   if ( be_careful+p>0 ) { 
2870     mp->arith_error=true; n=el_gordo-p;
2871   }
2872   return ( negative ?(-(n+p)) :(n+p));
2873 #else /* FIXPT */
2874 integer mp_take_scaled (MP mp,integer p, scaled q) {
2875     register double d;
2876         register integer i;
2877         d = (double)p * (double)q * TWEXP_16;
2878         if ((p^q) >= 0) {
2879                 d += 0.5;
2880                 if (d>=TWEXP31) {
2881                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2882                                 mp->arith_error = true;
2883                         return ELGORDO;
2884                 }
2885                 i = (integer) d;
2886                 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
2887         } else {
2888                 d -= 0.5;
2889                 if (d<= -TWEXP31) {
2890                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2891                                 mp->arith_error = true;
2892                         return -ELGORDO;
2893                 }
2894                 i = (integer) d;
2895                 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2896         }
2897         return i;
2898 #endif /* FIXPT */
2899 }
2900
2901 @ @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>=
2902 p=half_unit; /* that's $2^{15}$; the invariants hold now with $k=16$ */
2903 @^inner loop@>
2904 if ( q<fraction_four ) {
2905   do {  
2906     p = (odd(f) ? halfp(p+q) : halfp(p));
2907     f=halfp(f);
2908   } while (f!=1);
2909 } else {
2910   do {  
2911     p = (odd(f) ? p+halfp(q-p) : halfp(p));
2912     f=halfp(f);
2913   } while (f!=1);
2914 }
2915
2916 @ For completeness, there's also |make_scaled|, which computes a
2917 quotient as a |scaled| number instead of as a |fraction|.
2918 In other words, the result is $\lfloor2^{16}p/q+{1\over2}\rfloor$, if the
2919 operands are positive. \ (This procedure is not used especially often,
2920 so it is not part of \MP's inner loop.)
2921
2922 @c 
2923 scaled mp_make_scaled (MP mp,integer p, integer q) {
2924 #ifdef FIXPT 
2925   integer f; /* the fraction bits, with a leading 1 bit */
2926   integer n; /* the integer part of $\vert p/q\vert$ */
2927   boolean negative; /* should the result be negated? */
2928   integer be_careful; /* disables certain compiler optimizations */
2929   if ( p>=0 ) negative=false;
2930   else  { negate(p); negative=true; };
2931   if ( q<=0 ) { 
2932 #ifdef DEBUG 
2933     if ( q==0 ) mp_confusion(mp, "/");
2934 @:this can't happen /}{\quad \./@>
2935 #endif
2936     negate(q); negative=! negative;
2937   }
2938   n=p / q; p=p % q;
2939   if ( n>=0100000 ) { 
2940     mp->arith_error=true;
2941     return (negative ? (-el_gordo) : el_gordo);
2942   } else  { 
2943     n=(n-1)*unity;
2944     @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>;
2945     return ( negative ? (-(f+n)) :(f+n));
2946   }
2947 #else /* FIXPT */
2948     register double d;
2949         register integer i;
2950 #ifdef DEBUG
2951         if (q==0) mp_confusion(mp,"/"); 
2952 #endif /* DEBUG */
2953         d = TWEXP16 * (double)p /(double)q;
2954         if ((p^q) >= 0) {
2955                 d += 0.5;
2956                 if (d>=TWEXP31) {mp->arith_error=true; return ELGORDO;}
2957                 i = (integer) d;
2958                 if (d==i && ( ((q>0 ? -q : q)&077777)
2959                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2960         } else {
2961                 d -= 0.5;
2962                 if (d<= -TWEXP31) {mp->arith_error=true; return -ELGORDO;}
2963                 i = (integer) d;
2964                 if (d==i && ( ((q>0 ? q : -q)&077777)
2965                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2966         }
2967         return i;
2968 #endif /* FIXPT */
2969 }
2970
2971 @ @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>=
2972 f=1;
2973 do {  
2974   be_careful=p-q; p=be_careful+p;
2975   if ( p>=0 ) f=f+f+1;
2976   else  { f+=f; p=p+q; };
2977 } while (f<unity);
2978 be_careful=p-q;
2979 if ( be_careful+p>=0 ) incr(f)
2980
2981 @ Here is a typical example of how the routines above can be used.
2982 It computes the function
2983 $${1\over3\tau}f(\theta,\phi)=
2984 {\tau^{-1}\bigl(2+\sqrt2\,(\sin\theta-{1\over16}\sin\phi)
2985  (\sin\phi-{1\over16}\sin\theta)(\cos\theta-\cos\phi)\bigr)\over
2986 3\,\bigl(1+{1\over2}(\sqrt5-1)\cos\theta+{1\over2}(3-\sqrt5\,)\cos\phi\bigr)},$$
2987 where $\tau$ is a |scaled| ``tension'' parameter. This is \MP's magic
2988 fudge factor for placing the first control point of a curve that starts
2989 at an angle $\theta$ and ends at an angle $\phi$ from the straight path.
2990 (Actually, if the stated quantity exceeds 4, \MP\ reduces it to~4.)
2991
2992 The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$.
2993 (It's a sum of eight terms whose absolute values can be bounded using
2994 relations such as $\sin\theta\cos\theta\L{1\over2}$.) Thus the numerator
2995 is positive; and since the tension $\tau$ is constrained to be at least
2996 $3\over4$, the numerator is less than $16\over3$. The denominator is
2997 nonnegative and at most~6.  Hence the fixed-point calculations below
2998 are guaranteed to stay within the bounds of a 32-bit computer word.
2999
3000 The angles $\theta$ and $\phi$ are given implicitly in terms of |fraction|
3001 arguments |st|, |ct|, |sf|, and |cf|, representing $\sin\theta$, $\cos\theta$,
3002 $\sin\phi$, and $\cos\phi$, respectively.
3003
3004 @c 
3005 fraction mp_velocity (MP mp,fraction st, fraction ct, fraction sf,
3006                       fraction cf, scaled t) {
3007   integer acc,num,denom; /* registers for intermediate calculations */
3008   acc=mp_take_fraction(mp, st-(sf / 16), sf-(st / 16));
3009   acc=mp_take_fraction(mp, acc,ct-cf);
3010   num=fraction_two+mp_take_fraction(mp, acc,379625062);
3011                    /* $2^{28}\sqrt2\approx379625062.497$ */
3012   denom=fraction_three+mp_take_fraction(mp, ct,497706707)+mp_take_fraction(mp, cf,307599661);
3013                       /* $3\cdot2^{27}\cdot(\sqrt5-1)\approx497706706.78$ and
3014                          $3\cdot2^{27}\cdot(3-\sqrt5\,)\approx307599661.22$ */
3015   if ( t!=unity ) num=mp_make_scaled(mp, num,t);
3016   /* |make_scaled(fraction,scaled)=fraction| */
3017   if ( num / 4>=denom ) 
3018     return fraction_four;
3019   else 
3020     return mp_make_fraction(mp, num, denom);
3021 }
3022
3023 @ The following somewhat different subroutine tests rigorously if $ab$ is
3024 greater than, equal to, or less than~$cd$,
3025 given integers $(a,b,c,d)$. In most cases a quick decision is reached.
3026 The result is $+1$, 0, or~$-1$ in the three respective cases.
3027
3028 @d mp_ab_vs_cd(M,A,B,C,D) mp_do_ab_vs_cd(A,B,C,D)
3029
3030 @c 
3031 integer mp_do_ab_vs_cd (integer a,integer b, integer c, integer d) {
3032   integer q,r; /* temporary registers */
3033   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
3034   while (1) { 
3035     q = a / d; r = c / b;
3036     if ( q!=r )
3037       return ( q>r ? 1 : -1);
3038     q = a % d; r = c % b;
3039     if ( r==0 )
3040       return (q ? 1 : 0);
3041     if ( q==0 ) return -1;
3042     a=b; b=q; c=d; d=r;
3043   } /* now |a>d>0| and |c>b>0| */
3044 }
3045
3046 @ @<Reduce to the case that |a...@>=
3047 if ( a<0 ) { negate(a); negate(b);  };
3048 if ( c<0 ) { negate(c); negate(d);  };
3049 if ( d<=0 ) { 
3050   if ( b>=0 ) {
3051     if ( (a==0||b==0)&&(c==0||d==0) ) return 0;
3052     else return 1;
3053   }
3054   if ( d==0 )
3055     return ( a==0 ? 0 : -1);
3056   q=a; a=c; c=q; q=-b; b=-d; d=q;
3057 } else if ( b<=0 ) { 
3058   if ( b<0 ) if ( a>0 ) return -1;
3059   return (c==0 ? 0 : -1);
3060 }
3061
3062 @ We conclude this set of elementary routines with some simple rounding
3063 and truncation operations that are coded in a machine-independent fashion.
3064 The routines are slightly complicated because we want them to work
3065 without overflow whenever $-2^{31}\L x<2^{31}$.
3066
3067 @<Declarations@>=
3068 #define mp_floor_scaled(M,i) ((i)&(-65536))
3069 #define mp_round_unscaled(M,i) (((i>>15)+1)>>1)
3070 #define mp_round_fraction(M,i) (((i>>11)+1)>>1)
3071
3072
3073 @* \[8] Algebraic and transcendental functions.
3074 \MP\ computes all of the necessary special functions from scratch, without
3075 relying on |real| arithmetic or system subroutines for sines, cosines, etc.
3076
3077 @ To get the square root of a |scaled| number |x|, we want to calculate
3078 $s=\lfloor 2^8\!\sqrt x +{1\over2}\rfloor$. If $x>0$, this is the unique
3079 integer such that $2^{16}x-s\L s^2<2^{16}x+s$. The following subroutine
3080 determines $s$ by an iterative method that maintains the invariant
3081 relations $x=2^{46-2k}x_0\bmod 2^{30}$, $0<y=\lfloor 2^{16-2k}x_0\rfloor
3082 -s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$
3083 might, however, be zero at the start of the first iteration.
3084
3085 @<Declarations@>=
3086 scaled mp_square_rt (MP mp,scaled x) ;
3087
3088 @ @c 
3089 scaled mp_square_rt (MP mp,scaled x) {
3090   small_number k; /* iteration control counter */
3091   integer y,q; /* registers for intermediate calculations */
3092   if ( x<=0 ) { 
3093     @<Handle square root of zero or negative argument@>;
3094   } else { 
3095     k=23; q=2;
3096     while ( x<fraction_two ) { /* i.e., |while x<@t$2^{29}$@>|\unskip */
3097       decr(k); x=x+x+x+x;
3098     }
3099     if ( x<fraction_four ) y=0;
3100     else  { x=x-fraction_four; y=1; };
3101     do {  
3102       @<Decrease |k| by 1, maintaining the invariant
3103       relations between |x|, |y|, and~|q|@>;
3104     } while (k!=0);
3105     return (halfp(q));
3106   }
3107 }
3108
3109 @ @<Handle square root of zero...@>=
3110
3111   if ( x<0 ) { 
3112     print_err("Square root of ");
3113 @.Square root...replaced by 0@>
3114     mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3115     help2("Since I don't take square roots of negative numbers,")
3116          ("I'm zeroing this one. Proceed, with fingers crossed.");
3117     mp_error(mp);
3118   };
3119   return 0;
3120 }
3121
3122 @ @<Decrease |k| by 1, maintaining...@>=
3123 x+=x; y+=y;
3124 if ( x>=fraction_four ) { /* note that |fraction_four=@t$2^{30}$@>| */
3125   x=x-fraction_four; incr(y);
3126 };
3127 x+=x; y=y+y-q; q+=q;
3128 if ( x>=fraction_four ) { x=x-fraction_four; incr(y); };
3129 if ( y>q ){ y=y-q; q=q+2; }
3130 else if ( y<=0 )  { q=q-2; y=y+q;  };
3131 decr(k)
3132
3133 @ Pythagorean addition $\psqrt{a^2+b^2}$ is implemented by an elegant
3134 iterative scheme due to Cleve Moler and Donald Morrison [{\sl IBM Journal
3135 @^Moler, Cleve Barry@>
3136 @^Morrison, Donald Ross@>
3137 of Research and Development\/ \bf27} (1983), 577--581]. It modifies |a| and~|b|
3138 in such a way that their Pythagorean sum remains invariant, while the
3139 smaller argument decreases.
3140
3141 @c 
3142 integer mp_pyth_add (MP mp,integer a, integer b) {
3143   fraction r; /* register used to transform |a| and |b| */
3144   boolean big; /* is the result dangerously near $2^{31}$? */
3145   a=abs(a); b=abs(b);
3146   if ( a<b ) { r=b; b=a; a=r; }; /* now |0<=b<=a| */
3147   if ( b>0 ) {
3148     if ( a<fraction_two ) {
3149       big=false;
3150     } else { 
3151       a=a / 4; b=b / 4; big=true;
3152     }; /* we reduced the precision to avoid arithmetic overflow */
3153     @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>;
3154     if ( big ) {
3155       if ( a<fraction_two ) {
3156         a=a+a+a+a;
3157       } else  { 
3158         mp->arith_error=true; a=el_gordo;
3159       };
3160     }
3161   }
3162   return a;
3163 }
3164
3165 @ The key idea here is to reflect the vector $(a,b)$ about the
3166 line through $(a,b/2)$.
3167
3168 @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>=
3169 while (1) {  
3170   r=mp_make_fraction(mp, b,a);
3171   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3172   if ( r==0 ) break;
3173   r=mp_make_fraction(mp, r,fraction_four+r);
3174   a=a+mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3175 }
3176
3177
3178 @ Here is a similar algorithm for $\psqrt{a^2-b^2}$.
3179 It converges slowly when $b$ is near $a$, but otherwise it works fine.
3180
3181 @c 
3182 integer mp_pyth_sub (MP mp,integer a, integer b) {
3183   fraction r; /* register used to transform |a| and |b| */
3184   boolean big; /* is the input dangerously near $2^{31}$? */
3185   a=abs(a); b=abs(b);
3186   if ( a<=b ) {
3187     @<Handle erroneous |pyth_sub| and set |a:=0|@>;
3188   } else { 
3189     if ( a<fraction_four ) {
3190       big=false;
3191     } else  { 
3192       a=halfp(a); b=halfp(b); big=true;
3193     }
3194     @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>;
3195     if ( big ) a=a+a;
3196   }
3197   return a;
3198 }
3199
3200 @ @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>=
3201 while (1) { 
3202   r=mp_make_fraction(mp, b,a);
3203   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3204   if ( r==0 ) break;
3205   r=mp_make_fraction(mp, r,fraction_four-r);
3206   a=a-mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3207 }
3208
3209 @ @<Handle erroneous |pyth_sub| and set |a:=0|@>=
3210
3211   if ( a<b ){ 
3212     print_err("Pythagorean subtraction "); mp_print_scaled(mp, a);
3213     mp_print(mp, "+-+"); mp_print_scaled(mp, b); 
3214     mp_print(mp, " has been replaced by 0");
3215 @.Pythagorean...@>
3216     help2("Since I don't take square roots of negative numbers,")
3217          ("I'm zeroing this one. Proceed, with fingers crossed.");
3218     mp_error(mp);
3219   }
3220   a=0;
3221 }
3222
3223 @ The subroutines for logarithm and exponential involve two tables.
3224 The first is simple: |two_to_the[k]| equals $2^k$. The second involves
3225 a bit more calculation, which the author claims to have done correctly:
3226 |spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
3227 2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
3228 nearest integer.
3229
3230 @d two_to_the(A) (1<<(A))
3231
3232 @<Constants ...@>=
3233 static const integer spec_log[29] = { 0, /* special logarithms */
3234 93032640, 38612034, 17922280, 8662214, 4261238, 2113709,
3235 1052693, 525315, 262400, 131136, 65552, 32772, 16385,
3236 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 1 };
3237
3238 @ @<Local variables for initialization@>=
3239 integer k; /* all-purpose loop index */
3240
3241
3242 @ Here is the routine that calculates $2^8$ times the natural logarithm
3243 of a |scaled| quantity; it is an integer approximation to $2^{24}\ln(x/2^{16})$,
3244 when |x| is a given positive integer.
3245
3246 The method is based on exercise 1.2.2--25 in {\sl The Art of Computer
3247 Programming\/}: During the main iteration we have $1\L 2^{-30}x<1/(1-2^{1-k})$,
3248 and the logarithm of $2^{30}x$ remains to be added to an accumulator
3249 register called~$y$. Three auxiliary bits of accuracy are retained in~$y$
3250 during the calculation, and sixteen auxiliary bits to extend |y| are
3251 kept in~|z| during the initial argument reduction. (We add
3252 $100\cdot2^{16}=6553600$ to~|z| and subtract 100 from~|y| so that |z| will
3253 not become negative; also, the actual amount subtracted from~|y| is~96,
3254 not~100, because we want to add~4 for rounding before the final division by~8.)
3255
3256 @c 
3257 scaled mp_m_log (MP mp,scaled x) {
3258   integer y,z; /* auxiliary registers */
3259   integer k; /* iteration counter */
3260   if ( x<=0 ) {
3261      @<Handle non-positive logarithm@>;
3262   } else  { 
3263     y=1302456956+4-100; /* $14\times2^{27}\ln2\approx1302456956.421063$ */
3264     z=27595+6553600; /* and $2^{16}\times .421063\approx 27595$ */
3265     while ( x<fraction_four ) {
3266        x+=x; y=y-93032639; z=z-48782;
3267     } /* $2^{27}\ln2\approx 93032639.74436163$ and $2^{16}\times.74436163\approx 48782$ */
3268     y=y+(z / unity); k=2;
3269     while ( x>fraction_four+4 ) {
3270       @<Increase |k| until |x| can be multiplied by a
3271         factor of $2^{-k}$, and adjust $y$ accordingly@>;
3272     }
3273     return (y / 8);
3274   }
3275 }
3276
3277 @ @<Increase |k| until |x| can...@>=
3278
3279   z=((x-1) / two_to_the(k))+1; /* $z=\lceil x/2^k\rceil$ */
3280   while ( x<fraction_four+z ) { z=halfp(z+1); k=k+1; };
3281   y=y+spec_log[k]; x=x-z;
3282 }
3283
3284 @ @<Handle non-positive logarithm@>=
3285
3286   print_err("Logarithm of ");
3287 @.Logarithm...replaced by 0@>
3288   mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3289   help2("Since I don't take logs of non-positive numbers,")
3290        ("I'm zeroing this one. Proceed, with fingers crossed.");
3291   mp_error(mp); 
3292   return 0;
3293 }
3294
3295 @ Conversely, the exponential routine calculates $\exp(x/2^8)$,
3296 when |x| is |scaled|. The result is an integer approximation to
3297 $2^{16}\exp(x/2^{24})$, when |x| is regarded as an integer.
3298
3299 @c 
3300 scaled mp_m_exp (MP mp,scaled x) {
3301   small_number k; /* loop control index */
3302   integer y,z; /* auxiliary registers */
3303   if ( x>174436200 ) {
3304     /* $2^{24}\ln((2^{31}-1)/2^{16})\approx 174436199.51$ */
3305     mp->arith_error=true; 
3306     return el_gordo;
3307   } else if ( x<-197694359 ) {
3308         /* $2^{24}\ln(2^{-1}/2^{16})\approx-197694359.45$ */
3309     return 0;
3310   } else { 
3311     if ( x<=0 ) { 
3312        z=-8*x; y=04000000; /* $y=2^{20}$ */
3313     } else { 
3314       if ( x<=127919879 ) { 
3315         z=1023359037-8*x;
3316         /* $2^{27}\ln((2^{31}-1)/2^{20})\approx 1023359037.125$ */
3317       } else {
3318        z=8*(174436200-x); /* |z| is always nonnegative */
3319       }
3320       y=el_gordo;
3321     };
3322     @<Multiply |y| by $\exp(-z/2^{27})$@>;
3323     if ( x<=127919879 ) 
3324        return ((y+8) / 16);
3325      else 
3326        return y;
3327   }
3328 }
3329
3330 @ The idea here is that subtracting |spec_log[k]| from |z| corresponds
3331 to multiplying |y| by $1-2^{-k}$.
3332
3333 A subtle point (which had to be checked) was that if $x=127919879$, the
3334 value of~|y| will decrease so that |y+8| doesn't overflow. In fact,
3335 $z$ will be 5 in this case, and |y| will decrease by~64 when |k=25|
3336 and by~16 when |k=27|.
3337
3338 @<Multiply |y| by...@>=
3339 k=1;
3340 while ( z>0 ) { 
3341   while ( z>=spec_log[k] ) { 
3342     z-=spec_log[k];
3343     y=y-1-((y-two_to_the(k-1)) / two_to_the(k));
3344   }
3345   incr(k);
3346 }
3347
3348 @ The trigonometric subroutines use an auxiliary table such that
3349 |spec_atan[k]| contains an approximation to the |angle| whose tangent
3350 is~$1/2^k$. $\arctan2^{-k}$ times $2^{20}\cdot180/\pi$ 
3351
3352 @<Constants ...@>=
3353 static const angle spec_atan[27] = { 0, 27855475, 14718068, 7471121, 3750058, 
3354 1876857, 938658, 469357, 234682, 117342, 58671, 29335, 14668, 7334, 3667, 
3355 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1 };
3356
3357 @ Given integers |x| and |y|, not both zero, the |n_arg| function
3358 returns the |angle| whose tangent points in the direction $(x,y)$.
3359 This subroutine first determines the correct octant, then solves the
3360 problem for |0<=y<=x|, then converts the result appropriately to
3361 return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|.
3362 (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of
3363 |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.)
3364
3365 The octants are represented in a ``Gray code,'' since that turns out
3366 to be computationally simplest.
3367
3368 @d negate_x 1
3369 @d negate_y 2
3370 @d switch_x_and_y 4
3371 @d first_octant 1
3372 @d second_octant (first_octant+switch_x_and_y)
3373 @d third_octant (first_octant+switch_x_and_y+negate_x)
3374 @d fourth_octant (first_octant+negate_x)
3375 @d fifth_octant (first_octant+negate_x+negate_y)
3376 @d sixth_octant (first_octant+switch_x_and_y+negate_x+negate_y)
3377 @d seventh_octant (first_octant+switch_x_and_y+negate_y)
3378 @d eighth_octant (first_octant+negate_y)
3379
3380 @c 
3381 angle mp_n_arg (MP mp,integer x, integer y) {
3382   angle z; /* auxiliary register */
3383   integer t; /* temporary storage */
3384   small_number k; /* loop counter */
3385   int octant; /* octant code */
3386   if ( x>=0 ) {
3387     octant=first_octant;
3388   } else { 
3389     negate(x); octant=first_octant+negate_x;
3390   }
3391   if ( y<0 ) { 
3392     negate(y); octant=octant+negate_y;
3393   }
3394   if ( x<y ) { 
3395     t=y; y=x; x=t; octant=octant+switch_x_and_y;
3396   }
3397   if ( x==0 ) { 
3398     @<Handle undefined arg@>; 
3399   } else { 
3400     @<Set variable |z| to the arg of $(x,y)$@>;
3401     @<Return an appropriate answer based on |z| and |octant|@>;
3402   }
3403 }
3404
3405 @ @<Handle undefined arg@>=
3406
3407   print_err("angle(0,0) is taken as zero");
3408 @.angle(0,0)...zero@>
3409   help2("The `angle' between two identical points is undefined.")
3410        ("I'm zeroing this one. Proceed, with fingers crossed.");
3411   mp_error(mp); 
3412   return 0;
3413 }
3414
3415 @ @<Return an appropriate answer...@>=
3416 switch (octant) {
3417 case first_octant: return z;
3418 case second_octant: return (ninety_deg-z);
3419 case third_octant: return (ninety_deg+z);
3420 case fourth_octant: return (one_eighty_deg-z);
3421 case fifth_octant: return (z-one_eighty_deg);
3422 case sixth_octant: return (-z-ninety_deg);
3423 case seventh_octant: return (z-ninety_deg);
3424 case eighth_octant: return (-z);
3425 }; /* there are no other cases */
3426 return 0
3427
3428 @ At this point we have |x>=y>=0|, and |x>0|. The numbers are scaled up
3429 or down until $2^{28}\L x<2^{29}$, so that accurate fixed-point calculations
3430 will be made.
3431
3432 @<Set variable |z| to the arg...@>=
3433 while ( x>=fraction_two ) { 
3434   x=halfp(x); y=halfp(y);
3435 }
3436 z=0;
3437 if ( y>0 ) { 
3438  while ( x<fraction_one ) { 
3439     x+=x; y+=y; 
3440  };
3441  @<Increase |z| to the arg of $(x,y)$@>;
3442 }
3443
3444 @ During the calculations of this section, variables |x| and~|y|
3445 represent actual coordinates $(x,2^{-k}y)$. We will maintain the
3446 condition |x>=y|, so that the tangent will be at most $2^{-k}$.
3447 If $x<2y$, the tangent is greater than $2^{-k-1}$. The transformation
3448 $(a,b)\mapsto(a+b\tan\phi,b-a\tan\phi)$ replaces $(a,b)$ by
3449 coordinates whose angle has decreased by~$\phi$; in the special case
3450 $a=x$, $b=2^{-k}y$, and $\tan\phi=2^{-k-1}$, this operation reduces
3451 to the particularly simple iteration shown here. [Cf.~John E. Meggitt,
3452 @^Meggitt, John E.@>
3453 {\sl IBM Journal of Research and Development\/ \bf6} (1962), 210--226.]
3454
3455 The initial value of |x| will be multiplied by at most
3456 $(1+{1\over2})(1+{1\over8})(1+{1\over32})\cdots\approx 1.7584$; hence
3457 there is no chance of integer overflow.
3458
3459 @<Increase |z|...@>=
3460 k=0;
3461 do {  
3462   y+=y; incr(k);
3463   if ( y>x ){ 
3464     z=z+spec_atan[k]; t=x; x=x+(y / two_to_the(k+k)); y=y-t;
3465   };
3466 } while (k!=15);
3467 do {  
3468   y+=y; incr(k);
3469   if ( y>x ) { z=z+spec_atan[k]; y=y-x; };
3470 } while (k!=26)
3471
3472 @ Conversely, the |n_sin_cos| routine takes an |angle| and produces the sine
3473 and cosine of that angle. The results of this routine are
3474 stored in global integer variables |n_sin| and |n_cos|.
3475
3476 @<Glob...@>=
3477 fraction n_sin;fraction n_cos; /* results computed by |n_sin_cos| */
3478
3479 @ Given an integer |z| that is $2^{20}$ times an angle $\theta$ in degrees,
3480 the purpose of |n_sin_cos(z)| is to set
3481 |x=@t$r\cos\theta$@>| and |y=@t$r\sin\theta$@>| (approximately),
3482 for some rather large number~|r|. The maximum of |x| and |y|
3483 will be between $2^{28}$ and $2^{30}$, so that there will be hardly
3484 any loss of accuracy. Then |x| and~|y| are divided by~|r|.
3485
3486 @c 
3487 void mp_n_sin_cos (MP mp,angle z) { /* computes a multiple of the sine
3488                                        and cosine */ 
3489   small_number k; /* loop control variable */
3490   int q; /* specifies the quadrant */
3491   fraction r; /* magnitude of |(x,y)| */
3492   integer x,y,t; /* temporary registers */
3493   while ( z<0 ) z=z+three_sixty_deg;
3494   z=z % three_sixty_deg; /* now |0<=z<three_sixty_deg| */
3495   q=z / forty_five_deg; z=z % forty_five_deg;
3496   x=fraction_one; y=x;
3497   if ( ! odd(q) ) z=forty_five_deg-z;
3498   @<Subtract angle |z| from |(x,y)|@>;
3499   @<Convert |(x,y)| to the octant determined by~|q|@>;
3500   r=mp_pyth_add(mp, x,y); 
3501   mp->n_cos=mp_make_fraction(mp, x,r); 
3502   mp->n_sin=mp_make_fraction(mp, y,r);
3503 }
3504
3505 @ In this case the octants are numbered sequentially.
3506
3507 @<Convert |(x,...@>=
3508 switch (q) {
3509 case 0: break;
3510 case 1: t=x; x=y; y=t; break;
3511 case 2: t=x; x=-y; y=t; break;
3512 case 3: negate(x); break;
3513 case 4: negate(x); negate(y); break;
3514 case 5: t=x; x=-y; y=-t; break;
3515 case 6: t=x; x=y; y=-t; break;
3516 case 7: negate(y); break;
3517 } /* there are no other cases */
3518
3519 @ The main iteration of |n_sin_cos| is similar to that of |n_arg| but
3520 applied in reverse. The values of |spec_atan[k]| decrease slowly enough
3521 that this loop is guaranteed to terminate before the (nonexistent) value
3522 |spec_atan[27]| would be required.
3523
3524 @<Subtract angle |z|...@>=
3525 k=1;
3526 while ( z>0 ){ 
3527   if ( z>=spec_atan[k] ) { 
3528     z=z-spec_atan[k]; t=x;
3529     x=t+y / two_to_the(k);
3530     y=y-t / two_to_the(k);
3531   }
3532   incr(k);
3533 }
3534 if ( y<0 ) y=0 /* this precaution may never be needed */
3535
3536 @ And now let's complete our collection of numeric utility routines
3537 by considering random number generation.
3538 \MP\ generates pseudo-random numbers with the additive scheme recommended
3539 in Section 3.6 of {\sl The Art of Computer Programming}; however, the
3540 results are random fractions between 0 and |fraction_one-1|, inclusive.
3541
3542 There's an auxiliary array |randoms| that contains 55 pseudo-random
3543 fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
3544 we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
3545 The global variable |j_random| tells which element has most recently
3546 been consumed.
3547 The global variable |sys_random_seed| was introduced in version 0.9,
3548 for the sole reason of stressing the fact that the initial value of the
3549 random seed is system-dependant. The pascal code below will initialize
3550 this variable to |(internal[time] div unity)+internal[day]|, but this is
3551 not good enough on modern fast machines that are capable of running
3552 multiple MetaPost processes within the same second.
3553 @^system dependencies@>
3554
3555 @<Glob...@>=
3556 fraction randoms[55]; /* the last 55 random values generated */
3557 int j_random; /* the number of unused |randoms| */
3558 scaled sys_random_seed; /* the default random seed */
3559
3560 @ @<Types...@>=
3561 typedef scaled (*get_random_seed_command)(MP mp);
3562
3563 @ @<Glob...@>=
3564 get_random_seed_command get_random_seed;
3565
3566 @ @<Option variables@>=
3567 get_random_seed_command get_random_seed;
3568
3569 @ @<Allocate or initialize ...@>=
3570 set_callback_option(get_random_seed);
3571
3572 @ @<Exported function headers@>=
3573 scaled mp_get_random_seed (MP mp);
3574
3575 @ @c 
3576 scaled mp_get_random_seed (MP mp) {
3577   return (mp->internal[mp_time] / unity)+mp->internal[day];
3578 }
3579
3580 @ To consume a random fraction, the program below will say `|next_random|'
3581 and then it will fetch |randoms[j_random]|.
3582
3583 @d next_random { if ( mp->j_random==0 ) mp_new_randoms(mp);
3584   else decr(mp->j_random); }
3585
3586 @c 
3587 void mp_new_randoms (MP mp) {
3588   int k; /* index into |randoms| */
3589   fraction x; /* accumulator */
3590   for (k=0;k<=23;k++) { 
3591    x=mp->randoms[k]-mp->randoms[k+31];
3592     if ( x<0 ) x=x+fraction_one;
3593     mp->randoms[k]=x;
3594   }
3595   for (k=24;k<= 54;k++){ 
3596     x=mp->randoms[k]-mp->randoms[k-24];
3597     if ( x<0 ) x=x+fraction_one;
3598     mp->randoms[k]=x;
3599   }
3600   mp->j_random=54;
3601 }
3602
3603 @ @<Declarations@>=
3604 void mp_init_randoms (MP mp,scaled seed);
3605
3606 @ To initialize the |randoms| table, we call the following routine.
3607
3608 @c 
3609 void mp_init_randoms (MP mp,scaled seed) {
3610   fraction j,jj,k; /* more or less random integers */
3611   int i; /* index into |randoms| */
3612   j=abs(seed);
3613   while ( j>=fraction_one ) j=halfp(j);
3614   k=1;
3615   for (i=0;i<=54;i++ ){ 
3616     jj=k; k=j-k; j=jj;
3617     if ( k<0 ) k=k+fraction_one;
3618     mp->randoms[(i*21)% 55]=j;
3619   }
3620   mp_new_randoms(mp); 
3621   mp_new_randoms(mp); 
3622   mp_new_randoms(mp); /* ``warm up'' the array */
3623 }
3624
3625 @ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
3626 or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
3627
3628 Note that the call of |take_fraction| will produce the values 0 and~|x|
3629 with about half the probability that it will produce any other particular
3630 values between 0 and~|x|, because it rounds its answers.
3631
3632 @c 
3633 scaled mp_unif_rand (MP mp,scaled x) {
3634   scaled y; /* trial value */
3635   next_random; y=mp_take_fraction(mp, abs(x),mp->randoms[mp->j_random]);
3636   if ( y==abs(x) ) return 0;
3637   else if ( x>0 ) return y;
3638   else return (-y);
3639 }
3640
3641 @ Finally, a normal deviate with mean zero and unit standard deviation
3642 can readily be obtained with the ratio method (Algorithm 3.4.1R in
3643 {\sl The Art of Computer Programming\/}).
3644
3645 @c 
3646 scaled mp_norm_rand (MP mp) {
3647   integer x,u,l; /* what the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$ */
3648   do { 
3649     do {  
3650       next_random;
3651       x=mp_take_fraction(mp, 112429,mp->randoms[mp->j_random]-fraction_half);
3652       /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */
3653       next_random; u=mp->randoms[mp->j_random];
3654     } while (abs(x)>=u);
3655     x=mp_make_fraction(mp, x,u);
3656     l=139548960-mp_m_log(mp, u); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */
3657   } while (mp_ab_vs_cd(mp, 1024,l,x,x)<0);
3658   return x;
3659 }
3660
3661 @* \[9] Packed data.
3662 In order to make efficient use of storage space, \MP\ bases its major data
3663 structures on a |memory_word|, which contains either a (signed) integer,
3664 possibly scaled, or a small number of fields that are one half or one
3665 quarter of the size used for storing integers.
3666
3667 If |x| is a variable of type |memory_word|, it contains up to four
3668 fields that can be referred to as follows:
3669 $$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
3670 |x|&.|int|&(an |integer|)\cr
3671 |x|&.|sc|\qquad&(a |scaled| integer)\cr
3672 |x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
3673 |x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
3674   field)\cr
3675 |x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
3676   &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
3677 This is somewhat cumbersome to write, and not very readable either, but
3678 macros will be used to make the notation shorter and more transparent.
3679 The code below gives a formal definition of |memory_word| and
3680 its subsidiary types, using packed variant records. \MP\ makes no
3681 assumptions about the relative positions of the fields within a word.
3682
3683 @d max_quarterword 0x3FFF /* largest allowable value in a |quarterword| */
3684 @d max_halfword 0xFFFFFFF /* largest allowable value in a |halfword| */
3685
3686 @ Here are the inequalities that the quarterword and halfword values
3687 must satisfy (or rather, the inequalities that they mustn't satisfy):
3688
3689 @<Check the ``constant''...@>=
3690 if (mp->ini_version) {
3691   if ( mp->mem_max!=mp->mem_top ) mp->bad=8;
3692 } else {
3693   if ( mp->mem_max<mp->mem_top ) mp->bad=8;
3694 }
3695 if ( max_quarterword<255 ) mp->bad=9;
3696 if ( max_halfword<65535 ) mp->bad=10;
3697 if ( max_quarterword>max_halfword ) mp->bad=11;
3698 if ( mp->mem_max>=max_halfword ) mp->bad=12;
3699 if ( mp->max_strings>max_halfword ) mp->bad=13;
3700
3701 @ The macros |qi| and |qo| are used for input to and output 
3702 from quarterwords. These are legacy macros.
3703 @^system dependencies@>
3704
3705 @d qo(A) (A) /* to read eight bits from a quarterword */
3706 @d qi(A) (A) /* to store eight bits in a quarterword */
3707
3708 @ The reader should study the following definitions closely:
3709 @^system dependencies@>
3710
3711 @d sc cint /* |scaled| data is equivalent to |integer| */
3712
3713 @<Types...@>=
3714 typedef short quarterword; /* 1/4 of a word */
3715 typedef int halfword; /* 1/2 of a word */
3716 typedef union {
3717   struct {
3718     halfword RH, LH;
3719   } v;
3720   struct { /* Make B0,B1 overlap the most significant bytes of LH.  */
3721     halfword junk;
3722     quarterword B0, B1;
3723   } u;
3724 } two_halves;
3725 typedef struct {
3726   struct {
3727     quarterword B2, B3, B0, B1;
3728   } u;
3729 } four_quarters;
3730 typedef union {
3731   two_halves hh;
3732   integer cint;
3733   four_quarters qqqq;
3734 } memory_word;
3735 #define b0 u.B0
3736 #define b1 u.B1
3737 #define b2 u.B2
3738 #define b3 u.B3
3739 #define rh v.RH
3740 #define lh v.LH
3741
3742 @ When debugging, we may want to print a |memory_word| without knowing
3743 what type it is; so we print it in all modes.
3744 @^dirty \PASCAL@>@^debugging@>
3745
3746 @c 
3747 void mp_print_word (MP mp,memory_word w) {
3748   /* prints |w| in all ways */
3749   mp_print_int(mp, w.cint); mp_print_char(mp, ' ');
3750   mp_print_scaled(mp, w.sc); mp_print_char(mp, ' '); 
3751   mp_print_scaled(mp, w.sc / 010000); mp_print_ln(mp);
3752   mp_print_int(mp, w.hh.lh); mp_print_char(mp, '='); 
3753   mp_print_int(mp, w.hh.b0); mp_print_char(mp, ':');
3754   mp_print_int(mp, w.hh.b1); mp_print_char(mp, ';'); 
3755   mp_print_int(mp, w.hh.rh); mp_print_char(mp, ' ');
3756   mp_print_int(mp, w.qqqq.b0); mp_print_char(mp, ':'); 
3757   mp_print_int(mp, w.qqqq.b1); mp_print_char(mp, ':');
3758   mp_print_int(mp, w.qqqq.b2); mp_print_char(mp, ':'); 
3759   mp_print_int(mp, w.qqqq.b3);
3760 }
3761
3762
3763 @* \[10] Dynamic memory allocation.
3764
3765 The \MP\ system does nearly all of its own memory allocation, so that it
3766 can readily be transported into environments that do not have automatic
3767 facilities for strings, garbage collection, etc., and so that it can be in
3768 control of what error messages the user receives. The dynamic storage
3769 requirements of \MP\ are handled by providing a large array |mem| in
3770 which consecutive blocks of words are used as nodes by the \MP\ routines.
3771
3772 Pointer variables are indices into this array, or into another array
3773 called |eqtb| that will be explained later. A pointer variable might
3774 also be a special flag that lies outside the bounds of |mem|, so we
3775 allow pointers to assume any |halfword| value. The minimum memory
3776 index represents a null pointer.
3777
3778 @d null 0 /* the null pointer */
3779
3780 @<Types...@>=
3781 typedef halfword pointer; /* a flag or a location in |mem| or |eqtb| */
3782
3783 @ The |mem| array is divided into two regions that are allocated separately,
3784 but the dividing line between these two regions is not fixed; they grow
3785 together until finding their ``natural'' size in a particular job.
3786 Locations less than or equal to |lo_mem_max| are used for storing
3787 variable-length records consisting of two or more words each. This region
3788 is maintained using an algorithm similar to the one described in exercise
3789 2.5--19 of {\sl The Art of Computer Programming}. However, no size field
3790 appears in the allocated nodes; the program is responsible for knowing the
3791 relevant size when a node is freed. Locations greater than or equal to
3792 |hi_mem_min| are used for storing one-word records; a conventional
3793 \.{AVAIL} stack is used for allocation in this region.
3794
3795 Locations of |mem| between |0| and |mem_top| may be dumped as part
3796 of preloaded format files, by the \.{INIMP} preprocessor.
3797 @.INIMP@>
3798 Production versions of \MP\ may extend the memory at the top end in order to
3799 provide more space; these locations, between |mem_top| and |mem_max|,
3800 are always used for single-word nodes.
3801
3802 The key pointers that govern |mem| allocation have a prescribed order:
3803 $$\hbox{|null=0<lo_mem_max<hi_mem_min<mem_top<=mem_end<=mem_max|.}$$
3804
3805 @<Glob...@>=
3806 memory_word *mem; /* the big dynamic storage area */
3807 pointer lo_mem_max; /* the largest location of variable-size memory in use */
3808 pointer hi_mem_min; /* the smallest location of one-word memory in use */
3809
3810
3811
3812 @d xfree(A) do { mp_xfree(A); A=NULL; } while (0)
3813 @d xrealloc mp_xrealloc
3814 @d xmalloc  mp_xmalloc
3815 @d xstrdup  mp_xstrdup
3816 @d XREALLOC(a,b,c) a = xrealloc(a,(b+1),sizeof(c));
3817
3818 @<Declare helpers@>=
3819 void mp_xfree (void *x);
3820 void *mp_xrealloc (void *p, size_t nmem, size_t size) ;
3821 void *mp_xmalloc (size_t nmem, size_t size) ;
3822 char *mp_xstrdup(const char *s);
3823
3824 @ The |max_size_test| guards against overflow, on the assumption that
3825 |size_t| is at least 31bits wide.
3826
3827 @d max_size_test 0x7FFFFFFF
3828
3829 @c
3830 void mp_xfree (void *x) {
3831   if (x!=NULL) free(x);
3832 }
3833 void  *mp_xrealloc (void *p, size_t nmem, size_t size) {
3834   void *w ; 
3835   if ((max_size_test/size)<nmem) {
3836     fprintf(stderr,"Memory size overflow!\n");
3837     exit(1);
3838   }
3839   w = realloc (p,(nmem*size));
3840   if (w==NULL) {
3841     fprintf(stderr,"Out of memory!\n");
3842     exit(1);
3843   }
3844   return w;
3845 }
3846 void  *mp_xmalloc (size_t nmem, size_t size) {
3847   void *w;
3848   if ((max_size_test/size)<nmem) {
3849     fprintf(stderr,"Memory size overflow!\n");
3850     exit(1);
3851   }
3852   w = malloc (nmem*size);
3853   if (w==NULL) {
3854     fprintf(stderr,"Out of memory!\n");
3855     exit(1);
3856   }
3857   return w;
3858 }
3859 char *mp_xstrdup(const char *s) {
3860   char *w; 
3861   if (s==NULL)
3862     return NULL;
3863   w = strdup(s);
3864   if (w==NULL) {
3865     fprintf(stderr,"Out of memory!\n");
3866     exit(1);
3867   }
3868   return w;
3869 }
3870
3871
3872
3873 @<Allocate or initialize ...@>=
3874 mp->mem = xmalloc ((mp->mem_max+1),sizeof (memory_word));
3875 memset(mp->mem,0,(mp->mem_max+1)*sizeof (memory_word));
3876
3877 @ @<Dealloc variables@>=
3878 xfree(mp->mem);
3879
3880 @ Users who wish to study the memory requirements of particular applications can
3881 can use optional special features that keep track of current and
3882 maximum memory usage. When code between the delimiters |stat| $\ldots$
3883 |tats| is not ``commented out,'' \MP\ will run a bit slower but it will
3884 report these statistics when |tracing_stats| is positive.
3885
3886 @<Glob...@>=
3887 integer var_used; integer dyn_used; /* how much memory is in use */
3888
3889 @ Let's consider the one-word memory region first, since it's the
3890 simplest. The pointer variable |mem_end| holds the highest-numbered location
3891 of |mem| that has ever been used. The free locations of |mem| that
3892 occur between |hi_mem_min| and |mem_end|, inclusive, are of type
3893 |two_halves|, and we write |info(p)| and |link(p)| for the |lh|
3894 and |rh| fields of |mem[p]| when it is of this type. The single-word
3895 free locations form a linked list
3896 $$|avail|,\;\hbox{|link(avail)|},\;\hbox{|link(link(avail))|},\;\ldots$$
3897 terminated by |null|.
3898
3899 @d link(A)   mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3900 @d info(A)   mp->mem[(A)].hh.lh /* the |info| field of a memory word */
3901
3902 @<Glob...@>=
3903 pointer avail; /* head of the list of available one-word nodes */
3904 pointer mem_end; /* the last one-word node used in |mem| */
3905
3906 @ If one-word memory is exhausted, it might mean that the user has forgotten
3907 a token like `\&{enddef}' or `\&{endfor}'. We will define some procedures
3908 later that try to help pinpoint the trouble.
3909
3910 @c 
3911 @<Declare the procedure called |show_token_list|@>;
3912 @<Declare the procedure called |runaway|@>
3913
3914 @ The function |get_avail| returns a pointer to a new one-word node whose
3915 |link| field is null. However, \MP\ will halt if there is no more room left.
3916 @^inner loop@>
3917
3918 @c 
3919 pointer mp_get_avail (MP mp) { /* single-word node allocation */
3920   pointer p; /* the new node being got */
3921   p=mp->avail; /* get top location in the |avail| stack */
3922   if ( p!=null ) {
3923     mp->avail=link(mp->avail); /* and pop it off */
3924   } else if ( mp->mem_end<mp->mem_max ) { /* or go into virgin territory */
3925     incr(mp->mem_end); p=mp->mem_end;
3926   } else { 
3927     decr(mp->hi_mem_min); p=mp->hi_mem_min;
3928     if ( mp->hi_mem_min<=mp->lo_mem_max ) { 
3929       mp_runaway(mp); /* if memory is exhausted, display possible runaway text */
3930       mp_overflow(mp, "main memory size",mp->mem_max);
3931       /* quit; all one-word nodes are busy */
3932 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
3933     }
3934   }
3935   link(p)=null; /* provide an oft-desired initialization of the new node */
3936   incr(mp->dyn_used);/* maintain statistics */
3937   return p;
3938 };
3939
3940 @ Conversely, a one-word node is recycled by calling |free_avail|.
3941
3942 @d free_avail(A)  /* single-word node liberation */
3943   { link((A))=mp->avail; mp->avail=(A); decr(mp->dyn_used);  }
3944
3945 @ There's also a |fast_get_avail| routine, which saves the procedure-call
3946 overhead at the expense of extra programming. This macro is used in
3947 the places that would otherwise account for the most calls of |get_avail|.
3948 @^inner loop@>
3949
3950 @d fast_get_avail(A) { 
3951   (A)=mp->avail; /* avoid |get_avail| if possible, to save time */
3952   if ( (A)==null ) { (A)=mp_get_avail(mp); } 
3953   else { mp->avail=link((A)); link((A))=null;  incr(mp->dyn_used); }
3954   }
3955
3956 @ The available-space list that keeps track of the variable-size portion
3957 of |mem| is a nonempty, doubly-linked circular list of empty nodes,
3958 pointed to by the roving pointer |rover|.
3959
3960 Each empty node has size 2 or more; the first word contains the special
3961 value |max_halfword| in its |link| field and the size in its |info| field;
3962 the second word contains the two pointers for double linking.
3963
3964 Each nonempty node also has size 2 or more. Its first word is of type
3965 |two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
3966 Otherwise there is complete flexibility with respect to the contents
3967 of its other fields and its other words.
3968
3969 (We require |mem_max<max_halfword| because terrible things can happen
3970 when |max_halfword| appears in the |link| field of a nonempty node.)
3971
3972 @d empty_flag   max_halfword /* the |link| of an empty variable-size node */
3973 @d is_empty(A)   (link((A))==empty_flag) /* tests for empty node */
3974 @d node_size   info /* the size field in empty variable-size nodes */
3975 @d llink(A)   info((A)+1) /* left link in doubly-linked list of empty nodes */
3976 @d rlink(A)   link((A)+1) /* right link in doubly-linked list of empty nodes */
3977
3978 @<Glob...@>=
3979 pointer rover; /* points to some node in the list of empties */
3980
3981 @ A call to |get_node| with argument |s| returns a pointer to a new node
3982 of size~|s|, which must be 2~or more. The |link| field of the first word
3983 of this new node is set to null. An overflow stop occurs if no suitable
3984 space exists.
3985
3986 If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
3987 areas and returns the value |max_halfword|.
3988
3989 @<Declarations@>=
3990 pointer mp_get_node (MP mp,integer s) ;
3991
3992 @ @c 
3993 pointer mp_get_node (MP mp,integer s) { /* variable-size node allocation */
3994   pointer p; /* the node currently under inspection */
3995   pointer q;  /* the node physically after node |p| */
3996   integer r; /* the newly allocated node, or a candidate for this honor */
3997   integer t,tt; /* temporary registers */
3998 @^inner loop@>
3999  RESTART: 
4000   p=mp->rover; /* start at some free node in the ring */
4001   do {  
4002     @<Try to allocate within node |p| and its physical successors,
4003      and |goto found| if allocation was possible@>;
4004     p=rlink(p); /* move to the next node in the ring */
4005   } while (p!=mp->rover); /* repeat until the whole list has been traversed */
4006   if ( s==010000000000 ) { 
4007     return max_halfword;
4008   };
4009   if ( mp->lo_mem_max+2<mp->hi_mem_min ) {
4010     if ( mp->lo_mem_max+2<=max_halfword ) {
4011       @<Grow more variable-size memory and |goto restart|@>;
4012     }
4013   }
4014   mp_overflow(mp, "main memory size",mp->mem_max);
4015   /* sorry, nothing satisfactory is left */
4016 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4017 FOUND: 
4018   link(r)=null; /* this node is now nonempty */
4019   mp->var_used=mp->var_used+s; /* maintain usage statistics */
4020   return r;
4021 }
4022
4023 @ The lower part of |mem| grows by 1000 words at a time, unless
4024 we are very close to going under. When it grows, we simply link
4025 a new node into the available-space list. This method of controlled
4026 growth helps to keep the |mem| usage consecutive when \MP\ is
4027 implemented on ``virtual memory'' systems.
4028 @^virtual memory@>
4029
4030 @<Grow more variable-size memory and |goto restart|@>=
4031
4032   if ( mp->hi_mem_min-mp->lo_mem_max>=1998 ) {
4033     t=mp->lo_mem_max+1000;
4034   } else {
4035     t=mp->lo_mem_max+1+(mp->hi_mem_min-mp->lo_mem_max) / 2; 
4036     /* |lo_mem_max+2<=t<hi_mem_min| */
4037   }
4038   if ( t>max_halfword ) t=max_halfword;
4039   p=llink(mp->rover); q=mp->lo_mem_max; rlink(p)=q; llink(mp->rover)=q;
4040   rlink(q)=mp->rover; llink(q)=p; link(q)=empty_flag; node_size(q)=t-mp->lo_mem_max;
4041   mp->lo_mem_max=t; link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4042   mp->rover=q; 
4043   goto RESTART;
4044 }
4045
4046 @ @<Try to allocate...@>=
4047 q=p+node_size(p); /* find the physical successor */
4048 while ( is_empty(q) ) { /* merge node |p| with node |q| */
4049   t=rlink(q); tt=llink(q);
4050 @^inner loop@>
4051   if ( q==mp->rover ) mp->rover=t;
4052   llink(t)=tt; rlink(tt)=t;
4053   q=q+node_size(q);
4054 }
4055 r=q-s;
4056 if ( r>p+1 ) {
4057   @<Allocate from the top of node |p| and |goto found|@>;
4058 }
4059 if ( r==p ) { 
4060   if ( rlink(p)!=p ) {
4061     @<Allocate entire node |p| and |goto found|@>;
4062   }
4063 }
4064 node_size(p)=q-p /* reset the size in case it grew */
4065
4066 @ @<Allocate from the top...@>=
4067
4068   node_size(p)=r-p; /* store the remaining size */
4069   mp->rover=p; /* start searching here next time */
4070   goto FOUND;
4071 }
4072
4073 @ Here we delete node |p| from the ring, and let |rover| rove around.
4074
4075 @<Allocate entire...@>=
4076
4077   mp->rover=rlink(p); t=llink(p);
4078   llink(mp->rover)=t; rlink(t)=mp->rover;
4079   goto FOUND;
4080 }
4081
4082 @ Conversely, when some variable-size node |p| of size |s| is no longer needed,
4083 the operation |free_node(p,s)| will make its words available, by inserting
4084 |p| as a new empty node just before where |rover| now points.
4085
4086 @<Declarations@>=
4087 void mp_free_node (MP mp, pointer p, halfword s) ;
4088
4089 @ @c 
4090 void mp_free_node (MP mp, pointer p, halfword s) { /* variable-size node
4091   liberation */
4092   pointer q; /* |llink(rover)| */
4093   node_size(p)=s; link(p)=empty_flag;
4094 @^inner loop@>
4095   q=llink(mp->rover); llink(p)=q; rlink(p)=mp->rover; /* set both links */
4096   llink(mp->rover)=p; rlink(q)=p; /* insert |p| into the ring */
4097   mp->var_used=mp->var_used-s; /* maintain statistics */
4098 }
4099
4100 @ Just before \.{INIMP} writes out the memory, it sorts the doubly linked
4101 available space list. The list is probably very short at such times, so a
4102 simple insertion sort is used. The smallest available location will be
4103 pointed to by |rover|, the next-smallest by |rlink(rover)|, etc.
4104
4105 @c 
4106 void mp_sort_avail (MP mp) { /* sorts the available variable-size nodes
4107   by location */
4108   pointer p,q,r; /* indices into |mem| */
4109   pointer old_rover; /* initial |rover| setting */
4110   p=mp_get_node(mp, 010000000000); /* merge adjacent free areas */
4111   p=rlink(mp->rover); rlink(mp->rover)=max_halfword; old_rover=mp->rover;
4112   while ( p!=old_rover ) {
4113     @<Sort |p| into the list starting at |rover|
4114      and advance |p| to |rlink(p)|@>;
4115   }
4116   p=mp->rover;
4117   while ( rlink(p)!=max_halfword ) { 
4118     llink(rlink(p))=p; p=rlink(p);
4119   };
4120   rlink(p)=mp->rover; llink(mp->rover)=p;
4121 }
4122
4123 @ The following |while| loop is guaranteed to
4124 terminate, since the list that starts at
4125 |rover| ends with |max_halfword| during the sorting procedure.
4126
4127 @<Sort |p|...@>=
4128 if ( p<mp->rover ) { 
4129   q=p; p=rlink(q); rlink(q)=mp->rover; mp->rover=q;
4130 } else  { 
4131   q=mp->rover;
4132   while ( rlink(q)<p ) q=rlink(q);
4133   r=rlink(p); rlink(p)=rlink(q); rlink(q)=p; p=r;
4134 }
4135
4136 @* \[11] Memory layout.
4137 Some areas of |mem| are dedicated to fixed usage, since static allocation is
4138 more efficient than dynamic allocation when we can get away with it. For
4139 example, locations |0| to |1| are always used to store a
4140 two-word dummy token whose second word is zero.
4141 The following macro definitions accomplish the static allocation by giving
4142 symbolic names to the fixed positions. Static variable-size nodes appear
4143 in locations |0| through |lo_mem_stat_max|, and static single-word nodes
4144 appear in locations |hi_mem_stat_min| through |mem_top|, inclusive.
4145
4146 @d null_dash (2) /* the first two words are reserved for a null value */
4147 @d dep_head (null_dash+3) /* we will define |dash_node_size=3| */
4148 @d zero_val (dep_head+2) /* two words for a permanently zero value */
4149 @d temp_val (zero_val+2) /* two words for a temporary value node */
4150 @d end_attr temp_val /* we use |end_attr+2| only */
4151 @d inf_val (end_attr+2) /* and |inf_val+1| only */
4152 @d test_pen (inf_val+2)
4153   /* nine words for a pen used when testing the turning number */
4154 @d bad_vardef (test_pen+9) /* two words for \&{vardef} error recovery */
4155 @d lo_mem_stat_max (bad_vardef+1)  /* largest statically
4156   allocated word in the variable-size |mem| */
4157 @#
4158 @d sentinel mp->mem_top /* end of sorted lists */
4159 @d temp_head (mp->mem_top-1) /* head of a temporary list of some kind */
4160 @d hold_head (mp->mem_top-2) /* head of a temporary list of another kind */
4161 @d spec_head (mp->mem_top-3) /* head of a list of unprocessed \&{special} items */
4162 @d hi_mem_stat_min (mp->mem_top-3) /* smallest statically allocated word in
4163   the one-word |mem| */
4164
4165 @ The following code gets the dynamic part of |mem| off to a good start,
4166 when \MP\ is initializing itself the slow way.
4167
4168 @<Initialize table entries (done by \.{INIMP} only)@>=
4169 @^data structure assumptions@>
4170 mp->rover=lo_mem_stat_max+1; /* initialize the dynamic memory */
4171 link(mp->rover)=empty_flag;
4172 node_size(mp->rover)=1000; /* which is a 1000-word available node */
4173 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
4174 mp->lo_mem_max=mp->rover+1000; link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4175 for (k=hi_mem_stat_min;k<=(int)mp->mem_top;k++) {
4176   mp->mem[k]=mp->mem[mp->lo_mem_max]; /* clear list heads */
4177 }
4178 mp->avail=null; mp->mem_end=mp->mem_top;
4179 mp->hi_mem_min=hi_mem_stat_min; /* initialize the one-word memory */
4180 mp->var_used=lo_mem_stat_max+1; 
4181 mp->dyn_used=mp->mem_top+1-(hi_mem_stat_min);  /* initialize statistics */
4182 @<Initialize a pen at |test_pen| so that it fits in nine words@>;
4183
4184 @ The procedure |flush_list(p)| frees an entire linked list of one-word
4185 nodes that starts at a given position, until coming to |sentinel| or a
4186 pointer that is not in the one-word region. Another procedure,
4187 |flush_node_list|, frees an entire linked list of one-word and two-word
4188 nodes, until coming to a |null| pointer.
4189 @^inner loop@>
4190
4191 @c 
4192 void mp_flush_list (MP mp,pointer p) { /* makes list of single-word nodes  available */
4193   pointer q,r; /* list traversers */
4194   if ( p>=mp->hi_mem_min ) if ( p!=sentinel ) { 
4195     r=p;
4196     do {  
4197       q=r; r=link(r); 
4198       decr(mp->dyn_used);
4199       if ( r<mp->hi_mem_min ) break;
4200     } while (r!=sentinel);
4201   /* now |q| is the last node on the list */
4202     link(q)=mp->avail; mp->avail=p;
4203   }
4204 }
4205 @#
4206 void mp_flush_node_list (MP mp,pointer p) {
4207   pointer q; /* the node being recycled */
4208   while ( p!=null ){ 
4209     q=p; p=link(p);
4210     if ( q<mp->hi_mem_min ) 
4211       mp_free_node(mp, q,2);
4212     else 
4213       free_avail(q);
4214   }
4215 }
4216
4217 @ If \MP\ is extended improperly, the |mem| array might get screwed up.
4218 For example, some pointers might be wrong, or some ``dead'' nodes might not
4219 have been freed when the last reference to them disappeared. Procedures
4220 |check_mem| and |search_mem| are available to help diagnose such
4221 problems. These procedures make use of two arrays called |free| and
4222 |was_free| that are present only if \MP's debugging routines have
4223 been included. (You may want to decrease the size of |mem| while you
4224 @^debugging@>
4225 are debugging.)
4226
4227 Because |boolean|s are typedef-d as ints, it is better to use
4228 unsigned chars here.
4229
4230 @<Glob...@>=
4231 unsigned char *free; /* free cells */
4232 unsigned char *was_free; /* previously free cells */
4233 pointer was_mem_end; pointer was_lo_max; pointer was_hi_min;
4234   /* previous |mem_end|, |lo_mem_max|,and |hi_mem_min| */
4235 boolean panicking; /* do we want to check memory constantly? */
4236
4237 @ @<Allocate or initialize ...@>=
4238 mp->free = xmalloc ((mp->mem_max+1),sizeof (unsigned char));
4239 mp->was_free = xmalloc ((mp->mem_max+1), sizeof (unsigned char));
4240
4241 @ @<Dealloc variables@>=
4242 xfree(mp->free);
4243 xfree(mp->was_free);
4244
4245 @ @<Allocate or ...@>=
4246 mp->was_mem_end=0; /* indicate that everything was previously free */
4247 mp->was_lo_max=0; mp->was_hi_min=mp->mem_max;
4248 mp->panicking=false;
4249
4250 @ @<Declare |mp_reallocate| functions@>=
4251 void mp_reallocate_memory(MP mp, int l) ;
4252
4253 @ @c
4254 void mp_reallocate_memory(MP mp, int l) {
4255    XREALLOC(mp->free,     l, unsigned char);
4256    XREALLOC(mp->was_free, l, unsigned char);
4257    if (mp->mem) {
4258          int newarea = l-mp->mem_max;
4259      XREALLOC(mp->mem,      l, memory_word);
4260      memset (mp->mem+(mp->mem_max+1),0,sizeof(memory_word)*(newarea));
4261    } else {
4262      XREALLOC(mp->mem,      l, memory_word);
4263      memset(mp->mem,0,sizeof(memory_word)*(l+1));
4264    }
4265    mp->mem_max = l;
4266    if (mp->ini_version) 
4267      mp->mem_top = l;
4268 }
4269
4270
4271
4272 @ Procedure |check_mem| makes sure that the available space lists of
4273 |mem| are well formed, and it optionally prints out all locations
4274 that are reserved now but were free the last time this procedure was called.
4275
4276 @c 
4277 void mp_check_mem (MP mp,boolean print_locs ) {
4278   pointer p,q,r; /* current locations of interest in |mem| */
4279   boolean clobbered; /* is something amiss? */
4280   for (p=0;p<=mp->lo_mem_max;p++) {
4281     mp->free[p]=false; /* you can probably do this faster */
4282   }
4283   for (p=mp->hi_mem_min;p<= mp->mem_end;p++) {
4284     mp->free[p]=false; /* ditto */
4285   }
4286   @<Check single-word |avail| list@>;
4287   @<Check variable-size |avail| list@>;
4288   @<Check flags of unavailable nodes@>;
4289   @<Check the list of linear dependencies@>;
4290   if ( print_locs ) {
4291     @<Print newly busy locations@>;
4292   }
4293   memcpy(mp->was_free,mp->free, sizeof(char)*(mp->mem_end+1));
4294   mp->was_mem_end=mp->mem_end; 
4295   mp->was_lo_max=mp->lo_mem_max; 
4296   mp->was_hi_min=mp->hi_mem_min;
4297 }
4298
4299 @ @<Check single-word...@>=
4300 p=mp->avail; q=null; clobbered=false;
4301 while ( p!=null ) { 
4302   if ( (p>mp->mem_end)||(p<mp->hi_mem_min) ) clobbered=true;
4303   else if ( mp->free[p] ) clobbered=true;
4304   if ( clobbered ) { 
4305     mp_print_nl(mp, "AVAIL list clobbered at ");
4306 @.AVAIL list clobbered...@>
4307     mp_print_int(mp, q); break;
4308   }
4309   mp->free[p]=true; q=p; p=link(q);
4310 }
4311
4312 @ @<Check variable-size...@>=
4313 p=mp->rover; q=null; clobbered=false;
4314 do {  
4315   if ( (p>=mp->lo_mem_max)||(p<0) ) clobbered=true;
4316   else if ( (rlink(p)>=mp->lo_mem_max)||(rlink(p)<0) ) clobbered=true;
4317   else if (  !(is_empty(p))||(node_size(p)<2)||
4318    (p+node_size(p)>mp->lo_mem_max)|| (llink(rlink(p))!=p) ) clobbered=true;
4319   if ( clobbered ) { 
4320     mp_print_nl(mp, "Double-AVAIL list clobbered at ");
4321 @.Double-AVAIL list clobbered...@>
4322     mp_print_int(mp, q); break;
4323   }
4324   for (q=p;q<=p+node_size(p)-1;q++) { /* mark all locations free */
4325     if ( mp->free[q] ) { 
4326       mp_print_nl(mp, "Doubly free location at ");
4327 @.Doubly free location...@>
4328       mp_print_int(mp, q); break;
4329     }
4330     mp->free[q]=true;
4331   }
4332   q=p; p=rlink(p);
4333 } while (p!=mp->rover)
4334
4335
4336 @ @<Check flags...@>=
4337 p=0;
4338 while ( p<=mp->lo_mem_max ) { /* node |p| should not be empty */
4339   if ( is_empty(p) ) {
4340     mp_print_nl(mp, "Bad flag at "); mp_print_int(mp, p);
4341 @.Bad flag...@>
4342   }
4343   while ( (p<=mp->lo_mem_max) && ! mp->free[p] ) incr(p);
4344   while ( (p<=mp->lo_mem_max) && mp->free[p] ) incr(p);
4345 }
4346
4347 @ @<Print newly busy...@>=
4348
4349   @<Do intialization required before printing new busy locations@>;
4350   mp_print_nl(mp, "New busy locs:");
4351 @.New busy locs@>
4352   for (p=0;p<= mp->lo_mem_max;p++ ) {
4353     if ( ! mp->free[p] && ((p>mp->was_lo_max) || mp->was_free[p]) ) {
4354       @<Indicate that |p| is a new busy location@>;
4355     }
4356   }
4357   for (p=mp->hi_mem_min;p<=mp->mem_end;p++ ) {
4358     if ( ! mp->free[p] &&
4359         ((p<mp->was_hi_min) || (p>mp->was_mem_end) || mp->was_free[p]) ) {
4360       @<Indicate that |p| is a new busy location@>;
4361     }
4362   }
4363   @<Finish printing new busy locations@>;
4364 }
4365
4366 @ There might be many new busy locations so we are careful to print contiguous
4367 blocks compactly.  During this operation |q| is the last new busy location and
4368 |r| is the start of the block containing |q|.
4369
4370 @<Indicate that |p| is a new busy location@>=
4371
4372   if ( p>q+1 ) { 
4373     if ( q>r ) { 
4374       mp_print(mp, ".."); mp_print_int(mp, q);
4375     }
4376     mp_print_char(mp, ' '); mp_print_int(mp, p);
4377     r=p;
4378   }
4379   q=p;
4380 }
4381
4382 @ @<Do intialization required before printing new busy locations@>=
4383 q=mp->mem_max; r=mp->mem_max
4384
4385 @ @<Finish printing new busy locations@>=
4386 if ( q>r ) { 
4387   mp_print(mp, ".."); mp_print_int(mp, q);
4388 }
4389
4390 @ The |search_mem| procedure attempts to answer the question ``Who points
4391 to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
4392 that might not be of type |two_halves|. Strictly speaking, this is
4393 @^dirty \PASCAL@>
4394 undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to
4395 point to |p| purely by coincidence). But for debugging purposes, we want
4396 to rule out the places that do {\sl not\/} point to |p|, so a few false
4397 drops are tolerable.
4398
4399 @c
4400 void mp_search_mem (MP mp, pointer p) { /* look for pointers to |p| */
4401   integer q; /* current position being searched */
4402   for (q=0;q<=mp->lo_mem_max;q++) { 
4403     if ( link(q)==p ){ 
4404       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4405     }
4406     if ( info(q)==p ) { 
4407       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4408     }
4409   }
4410   for (q=mp->hi_mem_min;q<=mp->mem_end;q++) {
4411     if ( link(q)==p ) {
4412       mp_print_nl(mp, "LINK("); mp_print_int(mp, q); mp_print_char(mp, ')');
4413     }
4414     if ( info(q)==p ) {
4415       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, ')');
4416     }
4417   }
4418   @<Search |eqtb| for equivalents equal to |p|@>;
4419 }
4420
4421 @* \[12] The command codes.
4422 Before we can go much further, we need to define symbolic names for the internal
4423 code numbers that represent the various commands obeyed by \MP. These codes
4424 are somewhat arbitrary, but not completely so. For example,
4425 some codes have been made adjacent so that |case| statements in the
4426 program need not consider cases that are widely spaced, or so that |case|
4427 statements can be replaced by |if| statements. A command can begin an
4428 expression if and only if its code lies between |min_primary_command| and
4429 |max_primary_command|, inclusive. The first token of a statement that doesn't
4430 begin with an expression has a command code between |min_command| and
4431 |max_statement_command|, inclusive. Anything less than |min_command| is
4432 eliminated during macro expansions, and anything no more than |max_pre_command|
4433 is eliminated when expanding \TeX\ material.  Ranges such as
4434 |min_secondary_command..max_secondary_command| are used when parsing
4435 expressions, but the relative ordering within such a range is generally not
4436 critical.
4437
4438 The ordering of the highest-numbered commands
4439 (|comma<semicolon<end_group<stop|) is crucial for the parsing and
4440 error-recovery methods of this program as is the ordering |if_test<fi_or_else|
4441 for the smallest two commands.  The ordering is also important in the ranges
4442 |numeric_token..plus_or_minus| and |left_brace..ampersand|.
4443
4444 At any rate, here is the list, for future reference.
4445
4446 @d start_tex 1 /* begin \TeX\ material (\&{btex}, \&{verbatimtex}) */
4447 @d etex_marker 2 /* end \TeX\ material (\&{etex}) */
4448 @d mpx_break 3 /* stop reading an \.{MPX} file (\&{mpxbreak}) */
4449 @d max_pre_command mpx_break
4450 @d if_test 4 /* conditional text (\&{if}) */
4451 @d fi_or_else 5 /* delimiters for conditionals (\&{elseif}, \&{else}, \&{fi} */
4452 @d input 6 /* input a source file (\&{input}, \&{endinput}) */
4453 @d iteration 7 /* iterate (\&{for}, \&{forsuffixes}, \&{forever}, \&{endfor}) */
4454 @d repeat_loop 8 /* special command substituted for \&{endfor} */
4455 @d exit_test 9 /* premature exit from a loop (\&{exitif}) */
4456 @d relax 10 /* do nothing (\.{\char`\\}) */
4457 @d scan_tokens 11 /* put a string into the input buffer */
4458 @d expand_after 12 /* look ahead one token */
4459 @d defined_macro 13 /* a macro defined by the user */
4460 @d min_command (defined_macro+1)
4461 @d save_command 14 /* save a list of tokens (\&{save}) */
4462 @d interim_command 15 /* save an internal quantity (\&{interim}) */
4463 @d let_command 16 /* redefine a symbolic token (\&{let}) */
4464 @d new_internal 17 /* define a new internal quantity (\&{newinternal}) */
4465 @d macro_def 18 /* define a macro (\&{def}, \&{vardef}, etc.) */
4466 @d ship_out_command 19 /* output a character (\&{shipout}) */
4467 @d add_to_command 20 /* add to edges (\&{addto}) */
4468 @d bounds_command 21  /* add bounding path to edges (\&{setbounds}, \&{clip}) */
4469 @d tfm_command 22 /* command for font metric info (\&{ligtable}, etc.) */
4470 @d protection_command 23 /* set protection flag (\&{outer}, \&{inner}) */
4471 @d show_command 24 /* diagnostic output (\&{show}, \&{showvariable}, etc.) */
4472 @d mode_command 25 /* set interaction level (\&{batchmode}, etc.) */
4473 @d random_seed 26 /* initialize random number generator (\&{randomseed}) */
4474 @d message_command 27 /* communicate to user (\&{message}, \&{errmessage}) */
4475 @d every_job_command 28 /* designate a starting token (\&{everyjob}) */
4476 @d delimiters 29 /* define a pair of delimiters (\&{delimiters}) */
4477 @d special_command 30 /* output special info (\&{special})
4478                        or font map info (\&{fontmapfile}, \&{fontmapline}) */
4479 @d write_command 31 /* write text to a file (\&{write}) */
4480 @d type_name 32 /* declare a type (\&{numeric}, \&{pair}, etc. */
4481 @d max_statement_command type_name
4482 @d min_primary_command type_name
4483 @d left_delimiter 33 /* the left delimiter of a matching pair */
4484 @d begin_group 34 /* beginning of a group (\&{begingroup}) */
4485 @d nullary 35 /* an operator without arguments (e.g., \&{normaldeviate}) */
4486 @d unary 36 /* an operator with one argument (e.g., \&{sqrt}) */
4487 @d str_op 37 /* convert a suffix to a string (\&{str}) */
4488 @d cycle 38 /* close a cyclic path (\&{cycle}) */
4489 @d primary_binary 39 /* binary operation taking `\&{of}' (e.g., \&{point}) */
4490 @d capsule_token 40 /* a value that has been put into a token list */
4491 @d string_token 41 /* a string constant (e.g., |"hello"|) */
4492 @d internal_quantity 42 /* internal numeric parameter (e.g., \&{pausing}) */
4493 @d min_suffix_token internal_quantity
4494 @d tag_token 43 /* a symbolic token without a primitive meaning */
4495 @d numeric_token 44 /* a numeric constant (e.g., \.{3.14159}) */
4496 @d max_suffix_token numeric_token
4497 @d plus_or_minus 45 /* either `\.+' or `\.-' */
4498 @d max_primary_command plus_or_minus /* should also be |numeric_token+1| */
4499 @d min_tertiary_command plus_or_minus
4500 @d tertiary_secondary_macro 46 /* a macro defined by \&{secondarydef} */
4501 @d tertiary_binary 47 /* an operator at the tertiary level (e.g., `\.{++}') */
4502 @d max_tertiary_command tertiary_binary
4503 @d left_brace 48 /* the operator `\.{\char`\{}' */
4504 @d min_expression_command left_brace
4505 @d path_join 49 /* the operator `\.{..}' */
4506 @d ampersand 50 /* the operator `\.\&' */
4507 @d expression_tertiary_macro 51 /* a macro defined by \&{tertiarydef} */
4508 @d expression_binary 52 /* an operator at the expression level (e.g., `\.<') */
4509 @d equals 53 /* the operator `\.=' */
4510 @d max_expression_command equals
4511 @d and_command 54 /* the operator `\&{and}' */
4512 @d min_secondary_command and_command
4513 @d secondary_primary_macro 55 /* a macro defined by \&{primarydef} */
4514 @d slash 56 /* the operator `\./' */
4515 @d secondary_binary 57 /* an operator at the binary level (e.g., \&{shifted}) */
4516 @d max_secondary_command secondary_binary
4517 @d param_type 58 /* type of parameter (\&{primary}, \&{expr}, \&{suffix}, etc.) */
4518 @d controls 59 /* specify control points explicitly (\&{controls}) */
4519 @d tension 60 /* specify tension between knots (\&{tension}) */
4520 @d at_least 61 /* bounded tension value (\&{atleast}) */
4521 @d curl_command 62 /* specify curl at an end knot (\&{curl}) */
4522 @d macro_special 63 /* special macro operators (\&{quote}, \.{\#\AT!}, etc.) */
4523 @d right_delimiter 64 /* the right delimiter of a matching pair */
4524 @d left_bracket 65 /* the operator `\.[' */
4525 @d right_bracket 66 /* the operator `\.]' */
4526 @d right_brace 67 /* the operator `\.{\char`\}}' */
4527 @d with_option 68 /* option for filling (\&{withpen}, \&{withweight}, etc.) */
4528 @d thing_to_add 69
4529   /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */
4530 @d of_token 70 /* the operator `\&{of}' */
4531 @d to_token 71 /* the operator `\&{to}' */
4532 @d step_token 72 /* the operator `\&{step}' */
4533 @d until_token 73 /* the operator `\&{until}' */
4534 @d within_token 74 /* the operator `\&{within}' */
4535 @d lig_kern_token 75
4536   /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}, etc. */
4537 @d assignment 76 /* the operator `\.{:=}' */
4538 @d skip_to 77 /* the operation `\&{skipto}' */
4539 @d bchar_label 78 /* the operator `\.{\char'174\char'174:}' */
4540 @d double_colon 79 /* the operator `\.{::}' */
4541 @d colon 80 /* the operator `\.:' */
4542 @#
4543 @d comma 81 /* the operator `\.,', must be |colon+1| */
4544 @d end_of_statement (mp->cur_cmd>comma)
4545 @d semicolon 82 /* the operator `\.;', must be |comma+1| */
4546 @d end_group 83 /* end a group (\&{endgroup}), must be |semicolon+1| */
4547 @d stop 84 /* end a job (\&{end}, \&{dump}), must be |end_group+1| */
4548 @d max_command_code stop
4549 @d outer_tag (max_command_code+1) /* protection code added to command code */
4550
4551 @<Types...@>=
4552 typedef int command_code;
4553
4554 @ Variables and capsules in \MP\ have a variety of ``types,''
4555 distinguished by the code numbers defined here. These numbers are also
4556 not completely arbitrary.  Things that get expanded must have types
4557 |>mp_independent|; a type remaining after expansion is numeric if and only if
4558 its code number is at least |numeric_type|; objects containing numeric
4559 parts must have types between |transform_type| and |pair_type|;
4560 all other types must be smaller than |transform_type|; and among the types
4561 that are not unknown or vacuous, the smallest two must be |boolean_type|
4562 and |string_type| in that order.
4563  
4564 @d undefined 0 /* no type has been declared */
4565 @d unknown_tag 1 /* this constant is added to certain type codes below */
4566 @d unknown_types mp_unknown_boolean: case mp_unknown_string:
4567   case mp_unknown_pen: case mp_unknown_picture: case mp_unknown_path
4568
4569 @<Types...@>=
4570 enum {
4571 mp_vacuous=1, /* no expression was present */
4572 mp_boolean_type, /* \&{boolean} with a known value */
4573 mp_unknown_boolean,
4574 mp_string_type, /* \&{string} with a known value */
4575 mp_unknown_string,
4576 mp_pen_type, /* \&{pen} with a known value */
4577 mp_unknown_pen,
4578 mp_path_type, /* \&{path} with a known value */
4579 mp_unknown_path,
4580 mp_picture_type, /* \&{picture} with a known value */
4581 mp_unknown_picture,
4582 mp_transform_type, /* \&{transform} variable or capsule */
4583 mp_color_type, /* \&{color} variable or capsule */
4584 mp_cmykcolor_type, /* \&{cmykcolor} variable or capsule */
4585 mp_pair_type, /* \&{pair} variable or capsule */
4586 mp_numeric_type, /* variable that has been declared \&{numeric} but not used */
4587 mp_known, /* \&{numeric} with a known value */
4588 mp_dependent, /* a linear combination with |fraction| coefficients */
4589 mp_proto_dependent, /* a linear combination with |scaled| coefficients */
4590 mp_independent, /* \&{numeric} with unknown value */
4591 mp_token_list, /* variable name or suffix argument or text argument */
4592 mp_structured, /* variable with subscripts and attributes */
4593 mp_unsuffixed_macro, /* variable defined with \&{vardef} but no \.{\AT!\#} */
4594 mp_suffixed_macro /* variable defined with \&{vardef} and \.{\AT!\#} */
4595 };
4596
4597 @ @<Declarations@>=
4598 void mp_print_type (MP mp,small_number t) ;
4599
4600 @ @<Basic printing procedures@>=
4601 void mp_print_type (MP mp,small_number t) { 
4602   switch (t) {
4603   case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
4604   case mp_boolean_type:mp_print(mp, "boolean"); break;
4605   case mp_unknown_boolean:mp_print(mp, "unknown boolean"); break;
4606   case mp_string_type:mp_print(mp, "string"); break;
4607   case mp_unknown_string:mp_print(mp, "unknown string"); break;
4608   case mp_pen_type:mp_print(mp, "pen"); break;
4609   case mp_unknown_pen:mp_print(mp, "unknown pen"); break;
4610   case mp_path_type:mp_print(mp, "path"); break;
4611   case mp_unknown_path:mp_print(mp, "unknown path"); break;
4612   case mp_picture_type:mp_print(mp, "picture"); break;
4613   case mp_unknown_picture:mp_print(mp, "unknown picture"); break;
4614   case mp_transform_type:mp_print(mp, "transform"); break;
4615   case mp_color_type:mp_print(mp, "color"); break;
4616   case mp_cmykcolor_type:mp_print(mp, "cmykcolor"); break;
4617   case mp_pair_type:mp_print(mp, "pair"); break;
4618   case mp_known:mp_print(mp, "known numeric"); break;
4619   case mp_dependent:mp_print(mp, "dependent"); break;
4620   case mp_proto_dependent:mp_print(mp, "proto-dependent"); break;
4621   case mp_numeric_type:mp_print(mp, "numeric"); break;
4622   case mp_independent:mp_print(mp, "independent"); break;
4623   case mp_token_list:mp_print(mp, "token list"); break;
4624   case mp_structured:mp_print(mp, "mp_structured"); break;
4625   case mp_unsuffixed_macro:mp_print(mp, "unsuffixed macro"); break;
4626   case mp_suffixed_macro:mp_print(mp, "suffixed macro"); break;
4627   default: mp_print(mp, "undefined"); break;
4628   }
4629 }
4630
4631 @ Values inside \MP\ are stored in two-word nodes that have a |name_type|
4632 as well as a |type|. The possibilities for |name_type| are defined
4633 here; they will be explained in more detail later.
4634
4635 @<Types...@>=
4636 enum {
4637  mp_root=0, /* |name_type| at the top level of a variable */
4638  mp_saved_root, /* same, when the variable has been saved */
4639  mp_structured_root, /* |name_type| where a |mp_structured| branch occurs */
4640  mp_subscr, /* |name_type| in a subscript node */
4641  mp_attr, /* |name_type| in an attribute node */
4642  mp_x_part_sector, /* |name_type| in the \&{xpart} of a node */
4643  mp_y_part_sector, /* |name_type| in the \&{ypart} of a node */
4644  mp_xx_part_sector, /* |name_type| in the \&{xxpart} of a node */
4645  mp_xy_part_sector, /* |name_type| in the \&{xypart} of a node */
4646  mp_yx_part_sector, /* |name_type| in the \&{yxpart} of a node */
4647  mp_yy_part_sector, /* |name_type| in the \&{yypart} of a node */
4648  mp_red_part_sector, /* |name_type| in the \&{redpart} of a node */
4649  mp_green_part_sector, /* |name_type| in the \&{greenpart} of a node */
4650  mp_blue_part_sector, /* |name_type| in the \&{bluepart} of a node */
4651  mp_cyan_part_sector, /* |name_type| in the \&{redpart} of a node */
4652  mp_magenta_part_sector, /* |name_type| in the \&{greenpart} of a node */
4653  mp_yellow_part_sector, /* |name_type| in the \&{bluepart} of a node */
4654  mp_black_part_sector, /* |name_type| in the \&{greenpart} of a node */
4655  mp_grey_part_sector, /* |name_type| in the \&{bluepart} of a node */
4656  mp_capsule, /* |name_type| in stashed-away subexpressions */
4657  mp_token  /* |name_type| in a numeric token or string token */
4658 };
4659
4660 @ Primitive operations that produce values have a secondary identification
4661 code in addition to their command code; it's something like genera and species.
4662 For example, `\.*' has the command code |primary_binary|, and its
4663 secondary identification is |times|. The secondary codes start at 30 so that
4664 they don't overlap with the type codes; some type codes (e.g., |mp_string_type|)
4665 are used as operators as well as type identifications.  The relative values
4666 are not critical, except for |true_code..false_code|, |or_op..and_op|,
4667 and |filled_op..bounded_op|.  The restrictions are that
4668 |and_op-false_code=or_op-true_code|, that the ordering of
4669 |x_part...blue_part| must match that of |x_part_sector..mp_blue_part_sector|,
4670 and the ordering of |filled_op..bounded_op| must match that of the code
4671 values they test for.
4672
4673 @d true_code 30 /* operation code for \.{true} */
4674 @d false_code 31 /* operation code for \.{false} */
4675 @d null_picture_code 32 /* operation code for \.{nullpicture} */
4676 @d null_pen_code 33 /* operation code for \.{nullpen} */
4677 @d job_name_op 34 /* operation code for \.{jobname} */
4678 @d read_string_op 35 /* operation code for \.{readstring} */
4679 @d pen_circle 36 /* operation code for \.{pencircle} */
4680 @d normal_deviate 37 /* operation code for \.{normaldeviate} */
4681 @d read_from_op 38 /* operation code for \.{readfrom} */
4682 @d close_from_op 39 /* operation code for \.{closefrom} */
4683 @d odd_op 40 /* operation code for \.{odd} */
4684 @d known_op 41 /* operation code for \.{known} */
4685 @d unknown_op 42 /* operation code for \.{unknown} */
4686 @d not_op 43 /* operation code for \.{not} */
4687 @d decimal 44 /* operation code for \.{decimal} */
4688 @d reverse 45 /* operation code for \.{reverse} */
4689 @d make_path_op 46 /* operation code for \.{makepath} */
4690 @d make_pen_op 47 /* operation code for \.{makepen} */
4691 @d oct_op 48 /* operation code for \.{oct} */
4692 @d hex_op 49 /* operation code for \.{hex} */
4693 @d ASCII_op 50 /* operation code for \.{ASCII} */
4694 @d char_op 51 /* operation code for \.{char} */
4695 @d length_op 52 /* operation code for \.{length} */
4696 @d turning_op 53 /* operation code for \.{turningnumber} */
4697 @d color_model_part 54 /* operation code for \.{colormodel} */
4698 @d x_part 55 /* operation code for \.{xpart} */
4699 @d y_part 56 /* operation code for \.{ypart} */
4700 @d xx_part 57 /* operation code for \.{xxpart} */
4701 @d xy_part 58 /* operation code for \.{xypart} */
4702 @d yx_part 59 /* operation code for \.{yxpart} */
4703 @d yy_part 60 /* operation code for \.{yypart} */
4704 @d red_part 61 /* operation code for \.{redpart} */
4705 @d green_part 62 /* operation code for \.{greenpart} */
4706 @d blue_part 63 /* operation code for \.{bluepart} */
4707 @d cyan_part 64 /* operation code for \.{cyanpart} */
4708 @d magenta_part 65 /* operation code for \.{magentapart} */
4709 @d yellow_part 66 /* operation code for \.{yellowpart} */
4710 @d black_part 67 /* operation code for \.{blackpart} */
4711 @d grey_part 68 /* operation code for \.{greypart} */
4712 @d font_part 69 /* operation code for \.{fontpart} */
4713 @d text_part 70 /* operation code for \.{textpart} */
4714 @d path_part 71 /* operation code for \.{pathpart} */
4715 @d pen_part 72 /* operation code for \.{penpart} */
4716 @d dash_part 73 /* operation code for \.{dashpart} */
4717 @d sqrt_op 74 /* operation code for \.{sqrt} */
4718 @d m_exp_op 75 /* operation code for \.{mexp} */
4719 @d m_log_op 76 /* operation code for \.{mlog} */
4720 @d sin_d_op 77 /* operation code for \.{sind} */
4721 @d cos_d_op 78 /* operation code for \.{cosd} */
4722 @d floor_op 79 /* operation code for \.{floor} */
4723 @d uniform_deviate 80 /* operation code for \.{uniformdeviate} */
4724 @d char_exists_op 81 /* operation code for \.{charexists} */
4725 @d font_size 82 /* operation code for \.{fontsize} */
4726 @d ll_corner_op 83 /* operation code for \.{llcorner} */
4727 @d lr_corner_op 84 /* operation code for \.{lrcorner} */
4728 @d ul_corner_op 85 /* operation code for \.{ulcorner} */
4729 @d ur_corner_op 86 /* operation code for \.{urcorner} */
4730 @d arc_length 87 /* operation code for \.{arclength} */
4731 @d angle_op 88 /* operation code for \.{angle} */
4732 @d cycle_op 89 /* operation code for \.{cycle} */
4733 @d filled_op 90 /* operation code for \.{filled} */
4734 @d stroked_op 91 /* operation code for \.{stroked} */
4735 @d textual_op 92 /* operation code for \.{textual} */
4736 @d clipped_op 93 /* operation code for \.{clipped} */
4737 @d bounded_op 94 /* operation code for \.{bounded} */
4738 @d plus 95 /* operation code for \.+ */
4739 @d minus 96 /* operation code for \.- */
4740 @d times 97 /* operation code for \.* */
4741 @d over 98 /* operation code for \./ */
4742 @d pythag_add 99 /* operation code for \.{++} */
4743 @d pythag_sub 100 /* operation code for \.{+-+} */
4744 @d or_op 101 /* operation code for \.{or} */
4745 @d and_op 102 /* operation code for \.{and} */
4746 @d less_than 103 /* operation code for \.< */
4747 @d less_or_equal 104 /* operation code for \.{<=} */
4748 @d greater_than 105 /* operation code for \.> */
4749 @d greater_or_equal 106 /* operation code for \.{>=} */
4750 @d equal_to 107 /* operation code for \.= */
4751 @d unequal_to 108 /* operation code for \.{<>} */
4752 @d concatenate 109 /* operation code for \.\& */
4753 @d rotated_by 110 /* operation code for \.{rotated} */
4754 @d slanted_by 111 /* operation code for \.{slanted} */
4755 @d scaled_by 112 /* operation code for \.{scaled} */
4756 @d shifted_by 113 /* operation code for \.{shifted} */
4757 @d transformed_by 114 /* operation code for \.{transformed} */
4758 @d x_scaled 115 /* operation code for \.{xscaled} */
4759 @d y_scaled 116 /* operation code for \.{yscaled} */
4760 @d z_scaled 117 /* operation code for \.{zscaled} */
4761 @d in_font 118 /* operation code for \.{infont} */
4762 @d intersect 119 /* operation code for \.{intersectiontimes} */
4763 @d double_dot 120 /* operation code for improper \.{..} */
4764 @d substring_of 121 /* operation code for \.{substring} */
4765 @d min_of substring_of
4766 @d subpath_of 122 /* operation code for \.{subpath} */
4767 @d direction_time_of 123 /* operation code for \.{directiontime} */
4768 @d point_of 124 /* operation code for \.{point} */
4769 @d precontrol_of 125 /* operation code for \.{precontrol} */
4770 @d postcontrol_of 126 /* operation code for \.{postcontrol} */
4771 @d pen_offset_of 127 /* operation code for \.{penoffset} */
4772 @d arc_time_of 128 /* operation code for \.{arctime} */
4773 @d mp_version 129 /* operation code for \.{mpversion} */
4774
4775 @c void mp_print_op (MP mp,quarterword c) { 
4776   if (c<=mp_numeric_type ) {
4777     mp_print_type(mp, c);
4778   } else {
4779     switch (c) {
4780     case true_code:mp_print(mp, "true"); break;
4781     case false_code:mp_print(mp, "false"); break;
4782     case null_picture_code:mp_print(mp, "nullpicture"); break;
4783     case null_pen_code:mp_print(mp, "nullpen"); break;
4784     case job_name_op:mp_print(mp, "jobname"); break;
4785     case read_string_op:mp_print(mp, "readstring"); break;
4786     case pen_circle:mp_print(mp, "pencircle"); break;
4787     case normal_deviate:mp_print(mp, "normaldeviate"); break;
4788     case read_from_op:mp_print(mp, "readfrom"); break;
4789     case close_from_op:mp_print(mp, "closefrom"); break;
4790     case odd_op:mp_print(mp, "odd"); break;
4791     case known_op:mp_print(mp, "known"); break;
4792     case unknown_op:mp_print(mp, "unknown"); break;
4793     case not_op:mp_print(mp, "not"); break;
4794     case decimal:mp_print(mp, "decimal"); break;
4795     case reverse:mp_print(mp, "reverse"); break;
4796     case make_path_op:mp_print(mp, "makepath"); break;
4797     case make_pen_op:mp_print(mp, "makepen"); break;
4798     case oct_op:mp_print(mp, "oct"); break;
4799     case hex_op:mp_print(mp, "hex"); break;
4800     case ASCII_op:mp_print(mp, "ASCII"); break;
4801     case char_op:mp_print(mp, "char"); break;
4802     case length_op:mp_print(mp, "length"); break;
4803     case turning_op:mp_print(mp, "turningnumber"); break;
4804     case x_part:mp_print(mp, "xpart"); break;
4805     case y_part:mp_print(mp, "ypart"); break;
4806     case xx_part:mp_print(mp, "xxpart"); break;
4807     case xy_part:mp_print(mp, "xypart"); break;
4808     case yx_part:mp_print(mp, "yxpart"); break;
4809     case yy_part:mp_print(mp, "yypart"); break;
4810     case red_part:mp_print(mp, "redpart"); break;
4811     case green_part:mp_print(mp, "greenpart"); break;
4812     case blue_part:mp_print(mp, "bluepart"); break;
4813     case cyan_part:mp_print(mp, "cyanpart"); break;
4814     case magenta_part:mp_print(mp, "magentapart"); break;
4815     case yellow_part:mp_print(mp, "yellowpart"); break;
4816     case black_part:mp_print(mp, "blackpart"); break;
4817     case grey_part:mp_print(mp, "greypart"); break;
4818     case color_model_part:mp_print(mp, "colormodel"); break;
4819     case font_part:mp_print(mp, "fontpart"); break;
4820     case text_part:mp_print(mp, "textpart"); break;
4821     case path_part:mp_print(mp, "pathpart"); break;
4822     case pen_part:mp_print(mp, "penpart"); break;
4823     case dash_part:mp_print(mp, "dashpart"); break;
4824     case sqrt_op:mp_print(mp, "sqrt"); break;
4825     case m_exp_op:mp_print(mp, "mexp"); break;
4826     case m_log_op:mp_print(mp, "mlog"); break;
4827     case sin_d_op:mp_print(mp, "sind"); break;
4828     case cos_d_op:mp_print(mp, "cosd"); break;
4829     case floor_op:mp_print(mp, "floor"); break;
4830     case uniform_deviate:mp_print(mp, "uniformdeviate"); break;
4831     case char_exists_op:mp_print(mp, "charexists"); break;
4832     case font_size:mp_print(mp, "fontsize"); break;
4833     case ll_corner_op:mp_print(mp, "llcorner"); break;
4834     case lr_corner_op:mp_print(mp, "lrcorner"); break;
4835     case ul_corner_op:mp_print(mp, "ulcorner"); break;
4836     case ur_corner_op:mp_print(mp, "urcorner"); break;
4837     case arc_length:mp_print(mp, "arclength"); break;
4838     case angle_op:mp_print(mp, "angle"); break;
4839     case cycle_op:mp_print(mp, "cycle"); break;
4840     case filled_op:mp_print(mp, "filled"); break;
4841     case stroked_op:mp_print(mp, "stroked"); break;
4842     case textual_op:mp_print(mp, "textual"); break;
4843     case clipped_op:mp_print(mp, "clipped"); break;
4844     case bounded_op:mp_print(mp, "bounded"); break;
4845     case plus:mp_print_char(mp, '+'); break;
4846     case minus:mp_print_char(mp, '-'); break;
4847     case times:mp_print_char(mp, '*'); break;
4848     case over:mp_print_char(mp, '/'); break;
4849     case pythag_add:mp_print(mp, "++"); break;
4850     case pythag_sub:mp_print(mp, "+-+"); break;
4851     case or_op:mp_print(mp, "or"); break;
4852     case and_op:mp_print(mp, "and"); break;
4853     case less_than:mp_print_char(mp, '<'); break;
4854     case less_or_equal:mp_print(mp, "<="); break;
4855     case greater_than:mp_print_char(mp, '>'); break;
4856     case greater_or_equal:mp_print(mp, ">="); break;
4857     case equal_to:mp_print_char(mp, '='); break;
4858     case unequal_to:mp_print(mp, "<>"); break;
4859     case concatenate:mp_print(mp, "&"); break;
4860     case rotated_by:mp_print(mp, "rotated"); break;
4861     case slanted_by:mp_print(mp, "slanted"); break;
4862     case scaled_by:mp_print(mp, "scaled"); break;
4863     case shifted_by:mp_print(mp, "shifted"); break;
4864     case transformed_by:mp_print(mp, "transformed"); break;
4865     case x_scaled:mp_print(mp, "xscaled"); break;
4866     case y_scaled:mp_print(mp, "yscaled"); break;
4867     case z_scaled:mp_print(mp, "zscaled"); break;
4868     case in_font:mp_print(mp, "infont"); break;
4869     case intersect:mp_print(mp, "intersectiontimes"); break;
4870     case substring_of:mp_print(mp, "substring"); break;
4871     case subpath_of:mp_print(mp, "subpath"); break;
4872     case direction_time_of:mp_print(mp, "directiontime"); break;
4873     case point_of:mp_print(mp, "point"); break;
4874     case precontrol_of:mp_print(mp, "precontrol"); break;
4875     case postcontrol_of:mp_print(mp, "postcontrol"); break;
4876     case pen_offset_of:mp_print(mp, "penoffset"); break;
4877     case arc_time_of:mp_print(mp, "arctime"); break;
4878     case mp_version:mp_print(mp, "mpversion"); break;
4879     default: mp_print(mp, ".."); break;
4880     }
4881   }
4882 }
4883
4884 @ \MP\ also has a bunch of internal parameters that a user might want to
4885 fuss with. Every such parameter has an identifying code number, defined here.
4886
4887 @d tracing_titles 1 /* show titles online when they appear */
4888 @d tracing_equations 2 /* show each variable when it becomes known */
4889 @d tracing_capsules 3 /* show capsules too */
4890 @d tracing_choices 4 /* show the control points chosen for paths */
4891 @d tracing_specs 5 /* show path subdivision prior to filling with polygonal a pen */
4892 @d tracing_commands 6 /* show commands and operations before they are performed */
4893 @d tracing_restores 7 /* show when a variable or internal is restored */
4894 @d tracing_macros 8 /* show macros before they are expanded */
4895 @d tracing_output 9 /* show digitized edges as they are output */
4896 @d tracing_stats 10 /* show memory usage at end of job */
4897 @d tracing_lost_chars 11 /* show characters that aren't \&{infont} */
4898 @d tracing_online 12 /* show long diagnostics on terminal and in the log file */
4899 @d year 13 /* the current year (e.g., 1984) */
4900 @d month 14 /* the current month (e.g, 3 $\equiv$ March) */
4901 @d day 15 /* the current day of the month */
4902 @d mp_time 16 /* the number of minutes past midnight when this job started */
4903 @d char_code 17 /* the number of the next character to be output */
4904 @d char_ext 18 /* the extension code of the next character to be output */
4905 @d char_wd 19 /* the width of the next character to be output */
4906 @d char_ht 20 /* the height of the next character to be output */
4907 @d char_dp 21 /* the depth of the next character to be output */
4908 @d char_ic 22 /* the italic correction of the next character to be output */
4909 @d design_size 23 /* the unit of measure used for |char_wd..char_ic|, in points */
4910 @d pausing 24 /* positive to display lines on the terminal before they are read */
4911 @d showstopping 25 /* positive to stop after each \&{show} command */
4912 @d fontmaking 26 /* positive if font metric output is to be produced */
4913 @d linejoin 27 /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */
4914 @d linecap 28 /* as in \ps: 0 for butt, 1 for round, 2 for square */
4915 @d miterlimit 29 /* controls miter length as in \ps */
4916 @d warning_check 30 /* controls error message when variable value is large */
4917 @d boundary_char 31 /* the right boundary character for ligatures */
4918 @d prologues 32 /* positive to output conforming PostScript using built-in fonts */
4919 @d true_corners 33 /* positive to make \&{llcorner} etc. ignore \&{setbounds} */
4920 @d default_color_model 34 /* the default color model for unspecified items */
4921 @d restore_clip_color 35
4922 @d mpprocset 36 /* wether or not create PostScript command shortcuts */
4923 @d gtroffmode 37 /* whether the user specified |-troff| on the command line */
4924 @d max_given_internal 37
4925
4926 @<Glob...@>=
4927 scaled *internal;  /* the values of internal quantities */
4928 char **int_name;  /* their names */
4929 int int_ptr;  /* the maximum internal quantity defined so far */
4930 int max_internal; /* current maximum number of internal quantities */
4931 boolean troff_mode; 
4932
4933 @ @<Option variables@>=
4934 boolean troff_mode; 
4935
4936 @ @<Allocate or initialize ...@>=
4937 mp->max_internal=2*max_given_internal;
4938 mp->internal = xmalloc ((mp->max_internal+1), sizeof(scaled));
4939 mp->int_name = xmalloc ((mp->max_internal+1), sizeof(char *));
4940 mp->troff_mode=(opt->troff_mode>0 ? true : false);
4941
4942 @ @<Exported ...@>=
4943 int mp_troff_mode(MP mp);
4944
4945 @ @c
4946 int mp_troff_mode(MP mp) { return mp->troff_mode; }
4947
4948 @ @<Set initial ...@>=
4949 for (k=0;k<= mp->max_internal; k++ ) { 
4950    mp->internal[k]=0; 
4951    mp->int_name[k]=NULL; 
4952 }
4953 mp->int_ptr=max_given_internal;
4954
4955 @ The symbolic names for internal quantities are put into \MP's hash table
4956 by using a routine called |primitive|, which will be defined later. Let us
4957 enter them now, so that we don't have to list all those names again
4958 anywhere else.
4959
4960 @<Put each of \MP's primitives into the hash table@>=
4961 mp_primitive(mp, "tracingtitles",internal_quantity,tracing_titles);
4962 @:tracingtitles_}{\&{tracingtitles} primitive@>
4963 mp_primitive(mp, "tracingequations",internal_quantity,tracing_equations);
4964 @:tracing_equations_}{\&{tracingequations} primitive@>
4965 mp_primitive(mp, "tracingcapsules",internal_quantity,tracing_capsules);
4966 @:tracing_capsules_}{\&{tracingcapsules} primitive@>
4967 mp_primitive(mp, "tracingchoices",internal_quantity,tracing_choices);
4968 @:tracing_choices_}{\&{tracingchoices} primitive@>
4969 mp_primitive(mp, "tracingspecs",internal_quantity,tracing_specs);
4970 @:tracing_specs_}{\&{tracingspecs} primitive@>
4971 mp_primitive(mp, "tracingcommands",internal_quantity,tracing_commands);
4972 @:tracing_commands_}{\&{tracingcommands} primitive@>
4973 mp_primitive(mp, "tracingrestores",internal_quantity,tracing_restores);
4974 @:tracing_restores_}{\&{tracingrestores} primitive@>
4975 mp_primitive(mp, "tracingmacros",internal_quantity,tracing_macros);
4976 @:tracing_macros_}{\&{tracingmacros} primitive@>
4977 mp_primitive(mp, "tracingoutput",internal_quantity,tracing_output);
4978 @:tracing_output_}{\&{tracingoutput} primitive@>
4979 mp_primitive(mp, "tracingstats",internal_quantity,tracing_stats);
4980 @:tracing_stats_}{\&{tracingstats} primitive@>
4981 mp_primitive(mp, "tracinglostchars",internal_quantity,tracing_lost_chars);
4982 @:tracing_lost_chars_}{\&{tracinglostchars} primitive@>
4983 mp_primitive(mp, "tracingonline",internal_quantity,tracing_online);
4984 @:tracing_online_}{\&{tracingonline} primitive@>
4985 mp_primitive(mp, "year",internal_quantity,year);
4986 @:year_}{\&{year} primitive@>
4987 mp_primitive(mp, "month",internal_quantity,month);
4988 @:month_}{\&{month} primitive@>
4989 mp_primitive(mp, "day",internal_quantity,day);
4990 @:day_}{\&{day} primitive@>
4991 mp_primitive(mp, "time",internal_quantity,mp_time);
4992 @:time_}{\&{time} primitive@>
4993 mp_primitive(mp, "charcode",internal_quantity,char_code);
4994 @:char_code_}{\&{charcode} primitive@>
4995 mp_primitive(mp, "charext",internal_quantity,char_ext);
4996 @:char_ext_}{\&{charext} primitive@>
4997 mp_primitive(mp, "charwd",internal_quantity,char_wd);
4998 @:char_wd_}{\&{charwd} primitive@>
4999 mp_primitive(mp, "charht",internal_quantity,char_ht);
5000 @:char_ht_}{\&{charht} primitive@>
5001 mp_primitive(mp, "chardp",internal_quantity,char_dp);
5002 @:char_dp_}{\&{chardp} primitive@>
5003 mp_primitive(mp, "charic",internal_quantity,char_ic);
5004 @:char_ic_}{\&{charic} primitive@>
5005 mp_primitive(mp, "designsize",internal_quantity,design_size);
5006 @:design_size_}{\&{designsize} primitive@>
5007 mp_primitive(mp, "pausing",internal_quantity,pausing);
5008 @:pausing_}{\&{pausing} primitive@>
5009 mp_primitive(mp, "showstopping",internal_quantity,showstopping);
5010 @:showstopping_}{\&{showstopping} primitive@>
5011 mp_primitive(mp, "fontmaking",internal_quantity,fontmaking);
5012 @:fontmaking_}{\&{fontmaking} primitive@>
5013 mp_primitive(mp, "linejoin",internal_quantity,linejoin);
5014 @:linejoin_}{\&{linejoin} primitive@>
5015 mp_primitive(mp, "linecap",internal_quantity,linecap);
5016 @:linecap_}{\&{linecap} primitive@>
5017 mp_primitive(mp, "miterlimit",internal_quantity,miterlimit);
5018 @:miterlimit_}{\&{miterlimit} primitive@>
5019 mp_primitive(mp, "warningcheck",internal_quantity,warning_check);
5020 @:warning_check_}{\&{warningcheck} primitive@>
5021 mp_primitive(mp, "boundarychar",internal_quantity,boundary_char);
5022 @:boundary_char_}{\&{boundarychar} primitive@>
5023 mp_primitive(mp, "prologues",internal_quantity,prologues);
5024 @:prologues_}{\&{prologues} primitive@>
5025 mp_primitive(mp, "truecorners",internal_quantity,true_corners);
5026 @:true_corners_}{\&{truecorners} primitive@>
5027 mp_primitive(mp, "mpprocset",internal_quantity,mpprocset);
5028 @:mpprocset_}{\&{mpprocset} primitive@>
5029 mp_primitive(mp, "troffmode",internal_quantity,gtroffmode);
5030 @:troffmode_}{\&{troffmode} primitive@>
5031 mp_primitive(mp, "defaultcolormodel",internal_quantity,default_color_model);
5032 @:default_color_model_}{\&{defaultcolormodel} primitive@>
5033 mp_primitive(mp, "restoreclipcolor",internal_quantity,restore_clip_color);
5034 @:restore_clip_color_}{\&{restoreclipcolor} primitive@>
5035
5036 @ Colors can be specified in four color models. In the special
5037 case of |no_model|, MetaPost does not output any color operator to
5038 the postscript output.
5039
5040 Note: these values are passed directly on to |with_option|. This only
5041 works because the other possible values passed to |with_option| are
5042 8 and 10 respectively (from |with_pen| and |with_picture|).
5043
5044 There is a first state, that is only used for |gs_colormodel|. It flags
5045 the fact that there has not been any kind of color specification by
5046 the user so far in the game.
5047
5048 @d no_model 1
5049 @d grey_model 3
5050 @d rgb_model 5
5051 @d cmyk_model 7
5052 @d uninitialized_model 9
5053
5054 @<Initialize table entries (done by \.{INIMP} only)@>=
5055 mp->internal[default_color_model]=(rgb_model*unity);
5056 mp->internal[restore_clip_color]=unity;
5057
5058 @ Well, we do have to list the names one more time, for use in symbolic
5059 printouts.
5060
5061 @<Initialize table...@>=
5062 mp->int_name[tracing_titles]=xstrdup("tracingtitles");
5063 mp->int_name[tracing_equations]=xstrdup("tracingequations");
5064 mp->int_name[tracing_capsules]=xstrdup("tracingcapsules");
5065 mp->int_name[tracing_choices]=xstrdup("tracingchoices");
5066 mp->int_name[tracing_specs]=xstrdup("tracingspecs");
5067 mp->int_name[tracing_commands]=xstrdup("tracingcommands");
5068 mp->int_name[tracing_restores]=xstrdup("tracingrestores");
5069 mp->int_name[tracing_macros]=xstrdup("tracingmacros");
5070 mp->int_name[tracing_output]=xstrdup("tracingoutput");
5071 mp->int_name[tracing_stats]=xstrdup("tracingstats");
5072 mp->int_name[tracing_lost_chars]=xstrdup("tracinglostchars");
5073 mp->int_name[tracing_online]=xstrdup("tracingonline");
5074 mp->int_name[year]=xstrdup("year");
5075 mp->int_name[month]=xstrdup("month");
5076 mp->int_name[day]=xstrdup("day");
5077 mp->int_name[mp_time]=xstrdup("time");
5078 mp->int_name[char_code]=xstrdup("charcode");
5079 mp->int_name[char_ext]=xstrdup("charext");
5080 mp->int_name[char_wd]=xstrdup("charwd");
5081 mp->int_name[char_ht]=xstrdup("charht");
5082 mp->int_name[char_dp]=xstrdup("chardp");
5083 mp->int_name[char_ic]=xstrdup("charic");
5084 mp->int_name[design_size]=xstrdup("designsize");
5085 mp->int_name[pausing]=xstrdup("pausing");
5086 mp->int_name[showstopping]=xstrdup("showstopping");
5087 mp->int_name[fontmaking]=xstrdup("fontmaking");
5088 mp->int_name[linejoin]=xstrdup("linejoin");
5089 mp->int_name[linecap]=xstrdup("linecap");
5090 mp->int_name[miterlimit]=xstrdup("miterlimit");
5091 mp->int_name[warning_check]=xstrdup("warningcheck");
5092 mp->int_name[boundary_char]=xstrdup("boundarychar");
5093 mp->int_name[prologues]=xstrdup("prologues");
5094 mp->int_name[true_corners]=xstrdup("truecorners");
5095 mp->int_name[default_color_model]=xstrdup("defaultcolormodel");
5096 mp->int_name[mpprocset]=xstrdup("mpprocset");
5097 mp->int_name[gtroffmode]=xstrdup("troffmode");
5098 mp->int_name[restore_clip_color]=xstrdup("restoreclipcolor");
5099
5100 @ The following procedure, which is called just before \MP\ initializes its
5101 input and output, establishes the initial values of the date and time.
5102 @^system dependencies@>
5103
5104 Note that the values are |scaled| integers. Hence \MP\ can no longer
5105 be used after the year 32767.
5106
5107 @c 
5108 void mp_fix_date_and_time (MP mp) { 
5109   time_t clock = time ((time_t *) 0);
5110   struct tm *tmptr = localtime (&clock);
5111   mp->internal[mp_time]=
5112       (tmptr->tm_hour*60+tmptr->tm_min)*unity; /* minutes since midnight */
5113   mp->internal[day]=(tmptr->tm_mday)*unity; /* fourth day of the month */
5114   mp->internal[month]=(tmptr->tm_mon+1)*unity; /* seventh month of the year */
5115   mp->internal[year]=(tmptr->tm_year+1900)*unity; /* Anno Domini */
5116 }
5117
5118 @ @<Declarations@>=
5119 void mp_fix_date_and_time (MP mp) ;
5120
5121 @ \MP\ is occasionally supposed to print diagnostic information that
5122 goes only into the transcript file, unless |tracing_online| is positive.
5123 Now that we have defined |tracing_online| we can define
5124 two routines that adjust the destination of print commands:
5125
5126 @<Declarations@>=
5127 void mp_begin_diagnostic (MP mp) ;
5128 void mp_end_diagnostic (MP mp,boolean blank_line);
5129 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) ;
5130
5131 @ @<Basic printing...@>=
5132 @<Declare a function called |true_line|@>;
5133 void mp_begin_diagnostic (MP mp) { /* prepare to do some tracing */
5134   mp->old_setting=mp->selector;
5135   if ( mp->selector==ps_file_only ) mp->selector=mp->non_ps_setting;
5136   if ((mp->internal[tracing_online]<=0)&&(mp->selector==term_and_log)){ 
5137     decr(mp->selector);
5138     if ( mp->history==spotless ) mp->history=warning_issued;
5139   }
5140 }
5141 @#
5142 void mp_end_diagnostic (MP mp,boolean blank_line) {
5143   /* restore proper conditions after tracing */
5144   mp_print_nl(mp, "");
5145   if ( blank_line ) mp_print_ln(mp);
5146   mp->selector=mp->old_setting;
5147 }
5148
5149 @ The global variable |non_ps_setting| is initialized when it is time to print
5150 on |ps_file|.
5151
5152 @<Glob...@>=
5153 unsigned int old_setting;
5154 unsigned int non_ps_setting;
5155
5156 @ We will occasionally use |begin_diagnostic| in connection with line-number
5157 printing, as follows. (The parameter |s| is typically |"Path"| or
5158 |"Cycle spec"|, etc.)
5159
5160 @<Basic printing...@>=
5161 void mp_print_diagnostic (MP mp, char *s, char *t, boolean nuline) { 
5162   mp_begin_diagnostic(mp);
5163   if ( nuline ) mp_print_nl(mp, s); else mp_print(mp, s);
5164   mp_print(mp, " at line "); 
5165   mp_print_int(mp, mp_true_line(mp));
5166   mp_print(mp, t); mp_print_char(mp, ':');
5167 }
5168
5169 @ The 256 |ASCII_code| characters are grouped into classes by means of
5170 the |char_class| table. Individual class numbers have no semantic
5171 or syntactic significance, except in a few instances defined here.
5172 There's also |max_class|, which can be used as a basis for additional
5173 class numbers in nonstandard extensions of \MP.
5174
5175 @d digit_class 0 /* the class number of \.{0123456789} */
5176 @d period_class 1 /* the class number of `\..' */
5177 @d space_class 2 /* the class number of spaces and nonstandard characters */
5178 @d percent_class 3 /* the class number of `\.\%' */
5179 @d string_class 4 /* the class number of `\."' */
5180 @d right_paren_class 8 /* the class number of `\.)' */
5181 @d isolated_classes 5: case 6: case 7: case 8 /* characters that make length-one tokens only */
5182 @d letter_class 9 /* letters and the underline character */
5183 @d left_bracket_class 17 /* `\.[' */
5184 @d right_bracket_class 18 /* `\.]' */
5185 @d invalid_class 20 /* bad character in the input */
5186 @d max_class 20 /* the largest class number */
5187
5188 @<Glob...@>=
5189 int char_class[256]; /* the class numbers */
5190
5191 @ If changes are made to accommodate non-ASCII character sets, they should
5192 follow the guidelines in Appendix~C of {\sl The {\logos METAFONT\/}book}.
5193 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
5194 @^system dependencies@>
5195
5196 @<Set initial ...@>=
5197 for (k='0';k<='9';k++) 
5198   mp->char_class[k]=digit_class;
5199 mp->char_class['.']=period_class;
5200 mp->char_class[' ']=space_class;
5201 mp->char_class['%']=percent_class;
5202 mp->char_class['"']=string_class;
5203 mp->char_class[',']=5;
5204 mp->char_class[';']=6;
5205 mp->char_class['(']=7;
5206 mp->char_class[')']=right_paren_class;
5207 for (k='A';k<= 'Z';k++ )
5208   mp->char_class[k]=letter_class;
5209 for (k='a';k<='z';k++) 
5210   mp->char_class[k]=letter_class;
5211 mp->char_class['_']=letter_class;
5212 mp->char_class['<']=10;
5213 mp->char_class['=']=10;
5214 mp->char_class['>']=10;
5215 mp->char_class[':']=10;
5216 mp->char_class['|']=10;
5217 mp->char_class['`']=11;
5218 mp->char_class['\'']=11;
5219 mp->char_class['+']=12;
5220 mp->char_class['-']=12;
5221 mp->char_class['/']=13;
5222 mp->char_class['*']=13;
5223 mp->char_class['\\']=13;
5224 mp->char_class['!']=14;
5225 mp->char_class['?']=14;
5226 mp->char_class['#']=15;
5227 mp->char_class['&']=15;
5228 mp->char_class['@@']=15;
5229 mp->char_class['$']=15;
5230 mp->char_class['^']=16;
5231 mp->char_class['~']=16;
5232 mp->char_class['[']=left_bracket_class;
5233 mp->char_class[']']=right_bracket_class;
5234 mp->char_class['{']=19;
5235 mp->char_class['}']=19;
5236 for (k=0;k<' ';k++)
5237   mp->char_class[k]=invalid_class;
5238 mp->char_class['\t']=space_class;
5239 mp->char_class['\f']=space_class;
5240 for (k=127;k<=255;k++)
5241   mp->char_class[k]=invalid_class;
5242
5243 @* \[13] The hash table.
5244 Symbolic tokens are stored and retrieved by means of a fairly standard hash
5245 table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
5246 in {\sl The Art of Computer Programming\/}). Once a symbolic token enters the
5247 table, it is never removed.
5248
5249 The actual sequence of characters forming a symbolic token is
5250 stored in the |str_pool| array together with all the other strings. An
5251 auxiliary array |hash| consists of items with two halfword fields per
5252 word. The first of these, called |next(p)|, points to the next identifier
5253 belonging to the same coalesced list as the identifier corresponding to~|p|;
5254 and the other, called |text(p)|, points to the |str_start| entry for
5255 |p|'s identifier. If position~|p| of the hash table is empty, we have
5256 |text(p)=0|; if position |p| is either empty or the end of a coalesced
5257 hash list, we have |next(p)=0|.
5258
5259 An auxiliary pointer variable called |hash_used| is maintained in such a
5260 way that all locations |p>=hash_used| are nonempty. The global variable
5261 |st_count| tells how many symbolic tokens have been defined, if statistics
5262 are being kept.
5263
5264 The first 256 locations of |hash| are reserved for symbols of length one.
5265
5266 There's a parallel array called |eqtb| that contains the current equivalent
5267 values of each symbolic token. The entries of this array consist of
5268 two halfwords called |eq_type| (a command code) and |equiv| (a secondary
5269 piece of information that qualifies the |eq_type|).
5270
5271 @d next(A)   mp->hash[(A)].lh /* link for coalesced lists */
5272 @d text(A)   mp->hash[(A)].rh /* string number for symbolic token name */
5273 @d eq_type(A)   mp->eqtb[(A)].lh /* the current ``meaning'' of a symbolic token */
5274 @d equiv(A)   mp->eqtb[(A)].rh /* parametric part of a token's meaning */
5275 @d hash_base 257 /* hashing actually starts here */
5276 @d hash_is_full   (mp->hash_used==hash_base) /* are all positions occupied? */
5277
5278 @<Glob...@>=
5279 pointer hash_used; /* allocation pointer for |hash| */
5280 integer st_count; /* total number of known identifiers */
5281
5282 @ Certain entries in the hash table are ``frozen'' and not redefinable,
5283 since they are used in error recovery.
5284
5285 @d hash_top (hash_base+mp->hash_size) /* the first location of the frozen area */
5286 @d frozen_inaccessible hash_top /* |hash| location to protect the frozen area */
5287 @d frozen_repeat_loop (hash_top+1) /* |hash| location of a loop-repeat token */
5288 @d frozen_right_delimiter (hash_top+2) /* |hash| location of a permanent `\.)' */
5289 @d frozen_left_bracket (hash_top+3) /* |hash| location of a permanent `\.[' */
5290 @d frozen_slash (hash_top+4) /* |hash| location of a permanent `\./' */
5291 @d frozen_colon (hash_top+5) /* |hash| location of a permanent `\.:' */
5292 @d frozen_semicolon (hash_top+6) /* |hash| location of a permanent `\.;' */
5293 @d frozen_end_for (hash_top+7) /* |hash| location of a permanent \&{endfor} */
5294 @d frozen_end_def (hash_top+8) /* |hash| location of a permanent \&{enddef} */
5295 @d frozen_fi (hash_top+9) /* |hash| location of a permanent \&{fi} */
5296 @d frozen_end_group (hash_top+10) /* |hash| location of a permanent `\.{endgroup}' */
5297 @d frozen_etex (hash_top+11) /* |hash| location of a permanent \&{etex} */
5298 @d frozen_mpx_break (hash_top+12) /* |hash| location of a permanent \&{mpxbreak} */
5299 @d frozen_bad_vardef (hash_top+13) /* |hash| location of `\.{a bad variable}' */
5300 @d frozen_undefined (hash_top+14) /* |hash| location that never gets defined */
5301 @d hash_end (hash_top+14) /* the actual size of the |hash| and |eqtb| arrays */
5302
5303 @<Glob...@>=
5304 two_halves *hash; /* the hash table */
5305 two_halves *eqtb; /* the equivalents */
5306
5307 @ @<Allocate or initialize ...@>=
5308 mp->hash = xmalloc((hash_end+1),sizeof(two_halves));
5309 mp->eqtb = xmalloc((hash_end+1),sizeof(two_halves));
5310
5311 @ @<Dealloc variables@>=
5312 xfree(mp->hash);
5313 xfree(mp->eqtb);
5314
5315 @ @<Set init...@>=
5316 next(1)=0; text(1)=0; eq_type(1)=tag_token; equiv(1)=null;
5317 for (k=2;k<=hash_end;k++)  { 
5318   mp->hash[k]=mp->hash[1]; mp->eqtb[k]=mp->eqtb[1];
5319 }
5320
5321 @ @<Initialize table entries...@>=
5322 mp->hash_used=frozen_inaccessible; /* nothing is used */
5323 mp->st_count=0;
5324 text(frozen_bad_vardef)=intern("a bad variable");
5325 text(frozen_etex)=intern("etex");
5326 text(frozen_mpx_break)=intern("mpxbreak");
5327 text(frozen_fi)=intern("fi");
5328 text(frozen_end_group)=intern("endgroup");
5329 text(frozen_end_def)=intern("enddef");
5330 text(frozen_end_for)=intern("endfor");
5331 text(frozen_semicolon)=intern(";");
5332 text(frozen_colon)=intern(":");
5333 text(frozen_slash)=intern("/");
5334 text(frozen_left_bracket)=intern("[");
5335 text(frozen_right_delimiter)=intern(")");
5336 text(frozen_inaccessible)=intern(" INACCESSIBLE");
5337 eq_type(frozen_right_delimiter)=right_delimiter;
5338
5339 @ @<Check the ``constant'' values...@>=
5340 if ( hash_end+mp->max_internal>max_halfword ) mp->bad=17;
5341
5342 @ Here is the subroutine that searches the hash table for an identifier
5343 that matches a given string of length~|l| appearing in |buffer[j..
5344 (j+l-1)]|. If the identifier is not found, it is inserted; hence it
5345 will always be found, and the corresponding hash table address
5346 will be returned.
5347
5348 @c 
5349 pointer mp_id_lookup (MP mp,integer j, integer l) { /* search the hash table */
5350   integer h; /* hash code */
5351   pointer p; /* index in |hash| array */
5352   pointer k; /* index in |buffer| array */
5353   if (l==1) {
5354     @<Treat special case of length 1 and |break|@>;
5355   }
5356   @<Compute the hash code |h|@>;
5357   p=h+hash_base; /* we start searching here; note that |0<=h<hash_prime| */
5358   while (true)  { 
5359         if (text(p)>0 && length(text(p))==l && mp_str_eq_buf(mp, text(p),j)) 
5360       break;
5361     if ( next(p)==0 ) {
5362       @<Insert a new symbolic token after |p|, then
5363         make |p| point to it and |break|@>;
5364     }
5365     p=next(p);
5366   }
5367   return p;
5368 };
5369
5370 @ @<Treat special case of length 1...@>=
5371  p=mp->buffer[j]+1; text(p)=p-1; return p;
5372
5373
5374 @ @<Insert a new symbolic...@>=
5375 {
5376 if ( text(p)>0 ) { 
5377   do {  
5378     if ( hash_is_full )
5379       mp_overflow(mp, "hash size",mp->hash_size);
5380 @:MetaPost capacity exceeded hash size}{\quad hash size@>
5381     decr(mp->hash_used);
5382   } while (text(mp->hash_used)!=0); /* search for an empty location in |hash| */
5383   next(p)=mp->hash_used; 
5384   p=mp->hash_used;
5385 }
5386 str_room(l);
5387 for (k=j;k<=j+l-1;k++) {
5388   append_char(mp->buffer[k]);
5389 }
5390 text(p)=mp_make_string(mp); 
5391 mp->str_ref[text(p)]=max_str_ref;
5392 incr(mp->st_count);
5393 break;
5394 }
5395
5396
5397 @ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
5398 should be a prime number.  The theory of hashing tells us to expect fewer
5399 than two table probes, on the average, when the search is successful.
5400 [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
5401 @^Vitter, Jeffrey Scott@>
5402
5403 @<Compute the hash code |h|@>=
5404 h=mp->buffer[j];
5405 for (k=j+1;k<=j+l-1;k++){ 
5406   h=h+h+mp->buffer[k];
5407   while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
5408 }
5409
5410 @ @<Search |eqtb| for equivalents equal to |p|@>=
5411 for (q=1;q<=hash_end;q++) { 
5412   if ( equiv(q)==p ) { 
5413     mp_print_nl(mp, "EQUIV("); 
5414     mp_print_int(mp, q); 
5415     mp_print_char(mp, ')');
5416   }
5417 }
5418
5419 @ We need to put \MP's ``primitive'' symbolic tokens into the hash
5420 table, together with their command code (which will be the |eq_type|)
5421 and an operand (which will be the |equiv|). The |primitive| procedure
5422 does this, in a way that no \MP\ user can. The global value |cur_sym|
5423 contains the new |eqtb| pointer after |primitive| has acted.
5424
5425 @c 
5426 void mp_primitive (MP mp, char *ss, halfword c, halfword o) {
5427   pool_pointer k; /* index into |str_pool| */
5428   small_number j; /* index into |buffer| */
5429   small_number l; /* length of the string */
5430   str_number s;
5431   s = intern(ss);
5432   k=mp->str_start[s]; l=str_stop(s)-k;
5433   /* we will move |s| into the (empty) |buffer| */
5434   for (j=0;j<=l-1;j++) {
5435     mp->buffer[j]=mp->str_pool[k+j];
5436   }
5437   mp->cur_sym=mp_id_lookup(mp, 0,l);
5438   if ( s>=256 ) { /* we don't want to have the string twice */
5439     mp_flush_string(mp, text(mp->cur_sym)); text(mp->cur_sym)=s;
5440   };
5441   eq_type(mp->cur_sym)=c; 
5442   equiv(mp->cur_sym)=o;
5443 }
5444
5445
5446 @ Many of \MP's primitives need no |equiv|, since they are identifiable
5447 by their |eq_type| alone. These primitives are loaded into the hash table
5448 as follows:
5449
5450 @<Put each of \MP's primitives into the hash table@>=
5451 mp_primitive(mp, "..",path_join,0);
5452 @:.._}{\.{..} primitive@>
5453 mp_primitive(mp, "[",left_bracket,0); mp->eqtb[frozen_left_bracket]=mp->eqtb[mp->cur_sym];
5454 @:[ }{\.{[} primitive@>
5455 mp_primitive(mp, "]",right_bracket,0);
5456 @:] }{\.{]} primitive@>
5457 mp_primitive(mp, "}",right_brace,0);
5458 @:]]}{\.{\char`\}} primitive@>
5459 mp_primitive(mp, "{",left_brace,0);
5460 @:][}{\.{\char`\{} primitive@>
5461 mp_primitive(mp, ":",colon,0); mp->eqtb[frozen_colon]=mp->eqtb[mp->cur_sym];
5462 @:: }{\.{:} primitive@>
5463 mp_primitive(mp, "::",double_colon,0);
5464 @::: }{\.{::} primitive@>
5465 mp_primitive(mp, "||:",bchar_label,0);
5466 @:::: }{\.{\char'174\char'174:} primitive@>
5467 mp_primitive(mp, ":=",assignment,0);
5468 @::=_}{\.{:=} primitive@>
5469 mp_primitive(mp, ",",comma,0);
5470 @:, }{\., primitive@>
5471 mp_primitive(mp, ";",semicolon,0); mp->eqtb[frozen_semicolon]=mp->eqtb[mp->cur_sym];
5472 @:; }{\.; primitive@>
5473 mp_primitive(mp, "\\",relax,0);
5474 @:]]\\}{\.{\char`\\} primitive@>
5475 @#
5476 mp_primitive(mp, "addto",add_to_command,0);
5477 @:add_to_}{\&{addto} primitive@>
5478 mp_primitive(mp, "atleast",at_least,0);
5479 @:at_least_}{\&{atleast} primitive@>
5480 mp_primitive(mp, "begingroup",begin_group,0); mp->bg_loc=mp->cur_sym;
5481 @:begin_group_}{\&{begingroup} primitive@>
5482 mp_primitive(mp, "controls",controls,0);
5483 @:controls_}{\&{controls} primitive@>
5484 mp_primitive(mp, "curl",curl_command,0);
5485 @:curl_}{\&{curl} primitive@>
5486 mp_primitive(mp, "delimiters",delimiters,0);
5487 @:delimiters_}{\&{delimiters} primitive@>
5488 mp_primitive(mp, "endgroup",end_group,0);
5489  mp->eqtb[frozen_end_group]=mp->eqtb[mp->cur_sym]; mp->eg_loc=mp->cur_sym;
5490 @:endgroup_}{\&{endgroup} primitive@>
5491 mp_primitive(mp, "everyjob",every_job_command,0);
5492 @:every_job_}{\&{everyjob} primitive@>
5493 mp_primitive(mp, "exitif",exit_test,0);
5494 @:exit_if_}{\&{exitif} primitive@>
5495 mp_primitive(mp, "expandafter",expand_after,0);
5496 @:expand_after_}{\&{expandafter} primitive@>
5497 mp_primitive(mp, "interim",interim_command,0);
5498 @:interim_}{\&{interim} primitive@>
5499 mp_primitive(mp, "let",let_command,0);
5500 @:let_}{\&{let} primitive@>
5501 mp_primitive(mp, "newinternal",new_internal,0);
5502 @:new_internal_}{\&{newinternal} primitive@>
5503 mp_primitive(mp, "of",of_token,0);
5504 @:of_}{\&{of} primitive@>
5505 mp_primitive(mp, "randomseed",random_seed,0);
5506 @:random_seed_}{\&{randomseed} primitive@>
5507 mp_primitive(mp, "save",save_command,0);
5508 @:save_}{\&{save} primitive@>
5509 mp_primitive(mp, "scantokens",scan_tokens,0);
5510 @:scan_tokens_}{\&{scantokens} primitive@>
5511 mp_primitive(mp, "shipout",ship_out_command,0);
5512 @:ship_out_}{\&{shipout} primitive@>
5513 mp_primitive(mp, "skipto",skip_to,0);
5514 @:skip_to_}{\&{skipto} primitive@>
5515 mp_primitive(mp, "special",special_command,0);
5516 @:special}{\&{special} primitive@>
5517 mp_primitive(mp, "fontmapfile",special_command,1);
5518 @:fontmapfile}{\&{fontmapfile} primitive@>
5519 mp_primitive(mp, "fontmapline",special_command,2);
5520 @:fontmapline}{\&{fontmapline} primitive@>
5521 mp_primitive(mp, "step",step_token,0);
5522 @:step_}{\&{step} primitive@>
5523 mp_primitive(mp, "str",str_op,0);
5524 @:str_}{\&{str} primitive@>
5525 mp_primitive(mp, "tension",tension,0);
5526 @:tension_}{\&{tension} primitive@>
5527 mp_primitive(mp, "to",to_token,0);
5528 @:to_}{\&{to} primitive@>
5529 mp_primitive(mp, "until",until_token,0);
5530 @:until_}{\&{until} primitive@>
5531 mp_primitive(mp, "within",within_token,0);
5532 @:within_}{\&{within} primitive@>
5533 mp_primitive(mp, "write",write_command,0);
5534 @:write_}{\&{write} primitive@>
5535
5536 @ Each primitive has a corresponding inverse, so that it is possible to
5537 display the cryptic numeric contents of |eqtb| in symbolic form.
5538 Every call of |primitive| in this program is therefore accompanied by some
5539 straightforward code that forms part of the |print_cmd_mod| routine
5540 explained below.
5541
5542 @<Cases of |print_cmd_mod| for symbolic printing of primitives@>=
5543 case add_to_command:mp_print(mp, "addto"); break;
5544 case assignment:mp_print(mp, ":="); break;
5545 case at_least:mp_print(mp, "atleast"); break;
5546 case bchar_label:mp_print(mp, "||:"); break;
5547 case begin_group:mp_print(mp, "begingroup"); break;
5548 case colon:mp_print(mp, ":"); break;
5549 case comma:mp_print(mp, ","); break;
5550 case controls:mp_print(mp, "controls"); break;
5551 case curl_command:mp_print(mp, "curl"); break;
5552 case delimiters:mp_print(mp, "delimiters"); break;
5553 case double_colon:mp_print(mp, "::"); break;
5554 case end_group:mp_print(mp, "endgroup"); break;
5555 case every_job_command:mp_print(mp, "everyjob"); break;
5556 case exit_test:mp_print(mp, "exitif"); break;
5557 case expand_after:mp_print(mp, "expandafter"); break;
5558 case interim_command:mp_print(mp, "interim"); break;
5559 case left_brace:mp_print(mp, "{"); break;
5560 case left_bracket:mp_print(mp, "["); break;
5561 case let_command:mp_print(mp, "let"); break;
5562 case new_internal:mp_print(mp, "newinternal"); break;
5563 case of_token:mp_print(mp, "of"); break;
5564 case path_join:mp_print(mp, ".."); break;
5565 case random_seed:mp_print(mp, "randomseed"); break;
5566 case relax:mp_print_char(mp, '\\'); break;
5567 case right_brace:mp_print(mp, "}"); break;
5568 case right_bracket:mp_print(mp, "]"); break;
5569 case save_command:mp_print(mp, "save"); break;
5570 case scan_tokens:mp_print(mp, "scantokens"); break;
5571 case semicolon:mp_print(mp, ";"); break;
5572 case ship_out_command:mp_print(mp, "shipout"); break;
5573 case skip_to:mp_print(mp, "skipto"); break;
5574 case special_command: if ( m==2 ) mp_print(mp, "fontmapline"); else
5575                  if ( m==1 ) mp_print(mp, "fontmapfile"); else
5576                  mp_print(mp, "special"); break;
5577 case step_token:mp_print(mp, "step"); break;
5578 case str_op:mp_print(mp, "str"); break;
5579 case tension:mp_print(mp, "tension"); break;
5580 case to_token:mp_print(mp, "to"); break;
5581 case until_token:mp_print(mp, "until"); break;
5582 case within_token:mp_print(mp, "within"); break;
5583 case write_command:mp_print(mp, "write"); break;
5584
5585 @ We will deal with the other primitives later, at some point in the program
5586 where their |eq_type| and |equiv| values are more meaningful.  For example,
5587 the primitives for macro definitions will be loaded when we consider the
5588 routines that define macros.
5589 It is easy to find where each particular
5590 primitive was treated by looking in the index at the end; for example, the
5591 section where |"def"| entered |eqtb| is listed under `\&{def} primitive'.
5592
5593 @* \[14] Token lists.
5594 A \MP\ token is either symbolic or numeric or a string, or it denotes
5595 a macro parameter or capsule; so there are five corresponding ways to encode it
5596 @^token@>
5597 internally: (1)~A symbolic token whose hash code is~|p|
5598 is represented by the number |p|, in the |info| field of a single-word
5599 node in~|mem|. (2)~A numeric token whose |scaled| value is~|v| is
5600 represented in a two-word node of~|mem|; the |type| field is |known|,
5601 the |name_type| field is |token|, and the |value| field holds~|v|.
5602 The fact that this token appears in a two-word node rather than a
5603 one-word node is, of course, clear from the node address.
5604 (3)~A string token is also represented in a two-word node; the |type|
5605 field is |mp_string_type|, the |name_type| field is |token|, and the
5606 |value| field holds the corresponding |str_number|.  (4)~Capsules have
5607 |name_type=capsule|, and their |type| and |value| fields represent
5608 arbitrary values (in ways to be explained later).  (5)~Macro parameters
5609 are like symbolic tokens in that they appear in |info| fields of
5610 one-word nodes. The $k$th parameter is represented by |expr_base+k| if it
5611 is of type \&{expr}, or by |suffix_base+k| if it is of type \&{suffix}, or
5612 by |text_base+k| if it is of type \&{text}.  (Here |0<=k<param_size|.)
5613 Actual values of these parameters are kept in a separate stack, as we will
5614 see later.  The constants |expr_base|, |suffix_base|, and |text_base| are,
5615 of course, chosen so that there will be no confusion between symbolic
5616 tokens and parameters of various types.
5617
5618 Note that
5619 the `\\{type}' field of a node has nothing to do with ``type'' in a
5620 printer's sense. It's curious that the same word is used in such different ways.
5621
5622 @d type(A)   mp->mem[(A)].hh.b0 /* identifies what kind of value this is */
5623 @d name_type(A)   mp->mem[(A)].hh.b1 /* a clue to the name of this value */
5624 @d token_node_size 2 /* the number of words in a large token node */
5625 @d value_loc(A) ((A)+1) /* the word that contains the |value| field */
5626 @d value(A) mp->mem[value_loc((A))].cint /* the value stored in a large token node */
5627 @d expr_base (hash_end+1) /* code for the zeroth \&{expr} parameter */
5628 @d suffix_base (expr_base+mp->param_size) /* code for the zeroth \&{suffix} parameter */
5629 @d text_base (suffix_base+mp->param_size) /* code for the zeroth \&{text} parameter */
5630
5631 @<Check the ``constant''...@>=
5632 if ( text_base+mp->param_size>max_halfword ) mp->bad=18;
5633
5634 @ We have set aside a two word node beginning at |null| so that we can have
5635 |value(null)=0|.  We will make use of this coincidence later.
5636
5637 @<Initialize table entries...@>=
5638 link(null)=null; value(null)=0;
5639
5640 @ A numeric token is created by the following trivial routine.
5641
5642 @c 
5643 pointer mp_new_num_tok (MP mp,scaled v) {
5644   pointer p; /* the new node */
5645   p=mp_get_node(mp, token_node_size); value(p)=v;
5646   type(p)=mp_known; name_type(p)=mp_token; 
5647   return p;
5648 }
5649
5650 @ A token list is a singly linked list of nodes in |mem|, where
5651 each node contains a token and a link.  Here's a subroutine that gets rid
5652 of a token list when it is no longer needed.
5653
5654 @<Declarations@>=
5655 void mp_token_recycle (MP mp);
5656
5657
5658 @c void mp_flush_token_list (MP mp,pointer p) {
5659   pointer q; /* the node being recycled */
5660   while ( p!=null ) { 
5661     q=p; p=link(p);
5662     if ( q>=mp->hi_mem_min ) {
5663      free_avail(q);
5664     } else { 
5665       switch (type(q)) {
5666       case mp_vacuous: case mp_boolean_type: case mp_known:
5667         break;
5668       case mp_string_type:
5669         delete_str_ref(value(q));
5670         break;
5671       case unknown_types: case mp_pen_type: case mp_path_type: 
5672       case mp_picture_type: case mp_pair_type: case mp_color_type:
5673       case mp_cmykcolor_type: case mp_transform_type: case mp_dependent:
5674       case mp_proto_dependent: case mp_independent:
5675         mp->g_pointer=q; mp_token_recycle(mp);
5676         break;
5677       default: mp_confusion(mp, "token");
5678 @:this can't happen token}{\quad token@>
5679       }
5680       mp_free_node(mp, q,token_node_size);
5681     }
5682   }
5683 }
5684
5685 @ The procedure |show_token_list|, which prints a symbolic form of
5686 the token list that starts at a given node |p|, illustrates these
5687 conventions. The token list being displayed should not begin with a reference
5688 count. However, the procedure is intended to be fairly robust, so that if the
5689 memory links are awry or if |p| is not really a pointer to a token list,
5690 almost nothing catastrophic can happen.
5691
5692 An additional parameter |q| is also given; this parameter is either null
5693 or it points to a node in the token list where a certain magic computation
5694 takes place that will be explained later. (Basically, |q| is non-null when
5695 we are printing the two-line context information at the time of an error
5696 message; |q| marks the place corresponding to where the second line
5697 should begin.)
5698
5699 The generation will stop, and `\.{\char`\ ETC.}' will be printed, if the length
5700 of printing exceeds a given limit~|l|; the length of printing upon entry is
5701 assumed to be a given amount called |null_tally|. (Note that
5702 |show_token_list| sometimes uses itself recursively to print
5703 variable names within a capsule.)
5704 @^recursion@>
5705
5706 Unusual entries are printed in the form of all-caps tokens
5707 preceded by a space, e.g., `\.{\char`\ BAD}'.
5708
5709 @<Declarations@>=
5710 void mp_print_capsule (MP mp);
5711
5712 @ @<Declare the procedure called |show_token_list|@>=
5713 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5714                          integer null_tally) ;
5715
5716 @ @c
5717 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5718                          integer null_tally) {
5719   small_number class,c; /* the |char_class| of previous and new tokens */
5720   integer r,v; /* temporary registers */
5721   class=percent_class;
5722   mp->tally=null_tally;
5723   while ( (p!=null) && (mp->tally<l) ) { 
5724     if ( p==q ) 
5725       @<Do magic computation@>;
5726     @<Display token |p| and set |c| to its class;
5727       but |return| if there are problems@>;
5728     class=c; p=link(p);
5729   }
5730   if ( p!=null ) 
5731      mp_print(mp, " ETC.");
5732 @.ETC@>
5733   return;
5734 };
5735
5736 @ @<Display token |p| and set |c| to its class...@>=
5737 c=letter_class; /* the default */
5738 if ( (p<0)||(p>mp->mem_end) ) { 
5739   mp_print(mp, " CLOBBERED"); return;
5740 @.CLOBBERED@>
5741 }
5742 if ( p<mp->hi_mem_min ) { 
5743   @<Display two-word token@>;
5744 } else { 
5745   r=info(p);
5746   if ( r>=expr_base ) {
5747      @<Display a parameter token@>;
5748   } else {
5749     if ( r<1 ) {
5750       if ( r==0 ) { 
5751         @<Display a collective subscript@>
5752       } else {
5753         mp_print(mp, " IMPOSSIBLE");
5754 @.IMPOSSIBLE@>
5755       }
5756     } else { 
5757       r=text(r);
5758       if ( (r<0)||(r>mp->max_str_ptr) ) {
5759         mp_print(mp, " NONEXISTENT");
5760 @.NONEXISTENT@>
5761       } else {
5762        @<Print string |r| as a symbolic token
5763         and set |c| to its class@>;
5764       }
5765     }
5766   }
5767 }
5768
5769 @ @<Display two-word token@>=
5770 if ( name_type(p)==mp_token ) {
5771   if ( type(p)==mp_known ) {
5772     @<Display a numeric token@>;
5773   } else if ( type(p)!=mp_string_type ) {
5774     mp_print(mp, " BAD");
5775 @.BAD@>
5776   } else { 
5777     mp_print_char(mp, '"'); mp_print_str(mp, value(p)); mp_print_char(mp, '"');
5778     c=string_class;
5779   }
5780 } else if ((name_type(p)!=mp_capsule)||(type(p)<mp_vacuous)||(type(p)>mp_independent) ) {
5781   mp_print(mp, " BAD");
5782 } else { 
5783   mp->g_pointer=p; mp_print_capsule(mp); c=right_paren_class;
5784 }
5785
5786 @ @<Display a numeric token@>=
5787 if ( class==digit_class ) 
5788   mp_print_char(mp, ' ');
5789 v=value(p);
5790 if ( v<0 ){ 
5791   if ( class==left_bracket_class ) 
5792     mp_print_char(mp, ' ');
5793   mp_print_char(mp, '['); mp_print_scaled(mp, v); mp_print_char(mp, ']');
5794   c=right_bracket_class;
5795 } else { 
5796   mp_print_scaled(mp, v); c=digit_class;
5797 }
5798
5799
5800 @ Strictly speaking, a genuine token will never have |info(p)=0|.
5801 But we will see later (in the |print_variable_name| routine) that
5802 it is convenient to let |info(p)=0| stand for `\.{[]}'.
5803
5804 @<Display a collective subscript@>=
5805 {
5806 if ( class==left_bracket_class ) 
5807   mp_print_char(mp, ' ');
5808 mp_print(mp, "[]"); c=right_bracket_class;
5809 }
5810
5811 @ @<Display a parameter token@>=
5812 {
5813 if ( r<suffix_base ) { 
5814   mp_print(mp, "(EXPR"); r=r-(expr_base);
5815 @.EXPR@>
5816 } else if ( r<text_base ) { 
5817   mp_print(mp, "(SUFFIX"); r=r-(suffix_base);
5818 @.SUFFIX@>
5819 } else { 
5820   mp_print(mp, "(TEXT"); r=r-(text_base);
5821 @.TEXT@>
5822 }
5823 mp_print_int(mp, r); mp_print_char(mp, ')'); c=right_paren_class;
5824 }
5825
5826
5827 @ @<Print string |r| as a symbolic token...@>=
5828
5829 c=mp->char_class[mp->str_pool[mp->str_start[r]]];
5830 if ( c==class ) {
5831   switch (c) {
5832   case letter_class:mp_print_char(mp, '.'); break;
5833   case isolated_classes: break;
5834   default: mp_print_char(mp, ' '); break;
5835   }
5836 }
5837 mp_print_str(mp, r);
5838 }
5839
5840 @ The following procedures have been declared |forward| with no parameters,
5841 because the author dislikes \PASCAL's convention about |forward| procedures
5842 with parameters. It was necessary to do something, because |show_token_list|
5843 is recursive (although the recursion is limited to one level), and because
5844 |flush_token_list| is syntactically (but not semantically) recursive.
5845 @^recursion@>
5846
5847 @<Declare miscellaneous procedures that were declared |forward|@>=
5848 void mp_print_capsule (MP mp) { 
5849   mp_print_char(mp, '('); mp_print_exp(mp, mp->g_pointer,0); mp_print_char(mp, ')');
5850 };
5851 @#
5852 void mp_token_recycle (MP mp) { 
5853   mp_recycle_value(mp, mp->g_pointer);
5854 };
5855
5856 @ @<Glob...@>=
5857 pointer g_pointer; /* (global) parameter to the |forward| procedures */
5858
5859 @ Macro definitions are kept in \MP's memory in the form of token lists
5860 that have a few extra one-word nodes at the beginning.
5861
5862 The first node contains a reference count that is used to tell when the
5863 list is no longer needed. To emphasize the fact that a reference count is
5864 present, we shall refer to the |info| field of this special node as the
5865 |ref_count| field.
5866 @^reference counts@>
5867
5868 The next node or nodes after the reference count serve to describe the
5869 formal parameters. They either contain a code word that specifies all
5870 of the parameters, or they contain zero or more parameter tokens followed
5871 by the code `|general_macro|'.
5872
5873 @d ref_count info
5874   /* reference count preceding a macro definition or picture header */
5875 @d add_mac_ref(A) incr(ref_count((A))) /* make a new reference to a macro list */
5876 @d general_macro 0 /* preface to a macro defined with a parameter list */
5877 @d primary_macro 1 /* preface to a macro with a \&{primary} parameter */
5878 @d secondary_macro 2 /* preface to a macro with a \&{secondary} parameter */
5879 @d tertiary_macro 3 /* preface to a macro with a \&{tertiary} parameter */
5880 @d expr_macro 4 /* preface to a macro with an undelimited \&{expr} parameter */
5881 @d of_macro 5 /* preface to a macro with
5882   undelimited `\&{expr} |x| \&{of}~|y|' parameters */
5883 @d suffix_macro 6 /* preface to a macro with an undelimited \&{suffix} parameter */
5884 @d text_macro 7 /* preface to a macro with an undelimited \&{text} parameter */
5885
5886 @c 
5887 void mp_delete_mac_ref (MP mp,pointer p) {
5888   /* |p| points to the reference count of a macro list that is
5889     losing one reference */
5890   if ( ref_count(p)==null ) mp_flush_token_list(mp, p);
5891   else decr(ref_count(p));
5892 }
5893
5894 @ The following subroutine displays a macro, given a pointer to its
5895 reference count.
5896
5897 @c 
5898 @<Declare the procedure called |print_cmd_mod|@>;
5899 void mp_show_macro (MP mp, pointer p, integer q, integer l) {
5900   pointer r; /* temporary storage */
5901   p=link(p); /* bypass the reference count */
5902   while ( info(p)>text_macro ){ 
5903     r=link(p); link(p)=null;
5904     mp_show_token_list(mp, p,null,l,0); link(p)=r; p=r;
5905     if ( l>0 ) l=l-mp->tally; else return;
5906   } /* control printing of `\.{ETC.}' */
5907 @.ETC@>
5908   mp->tally=0;
5909   switch(info(p)) {
5910   case general_macro:mp_print(mp, "->"); break;
5911 @.->@>
5912   case primary_macro: case secondary_macro: case tertiary_macro:
5913     mp_print_char(mp, '<');
5914     mp_print_cmd_mod(mp, param_type,info(p)); 
5915     mp_print(mp, ">->");
5916     break;
5917   case expr_macro:mp_print(mp, "<expr>->"); break;
5918   case of_macro:mp_print(mp, "<expr>of<primary>->"); break;
5919   case suffix_macro:mp_print(mp, "<suffix>->"); break;
5920   case text_macro:mp_print(mp, "<text>->"); break;
5921   } /* there are no other cases */
5922   mp_show_token_list(mp, link(p),q,l-mp->tally,0);
5923 }
5924
5925 @* \[15] Data structures for variables.
5926 The variables of \MP\ programs can be simple, like `\.x', or they can
5927 combine the structural properties of arrays and records, like `\.{x20a.b}'.
5928 A \MP\ user assigns a type to a variable like \.{x20a.b} by saying, for
5929 example, `\.{boolean} \.{x20a.b}'. It's time for us to study how such
5930 things are represented inside of the computer.
5931
5932 Each variable value occupies two consecutive words, either in a two-word
5933 node called a value node, or as a two-word subfield of a larger node.  One
5934 of those two words is called the |value| field; it is an integer,
5935 containing either a |scaled| numeric value or the representation of some
5936 other type of quantity. (It might also be subdivided into halfwords, in
5937 which case it is referred to by other names instead of |value|.) The other
5938 word is broken into subfields called |type|, |name_type|, and |link|.  The
5939 |type| field is a quarterword that specifies the variable's type, and
5940 |name_type| is a quarterword from which \MP\ can reconstruct the
5941 variable's name (sometimes by using the |link| field as well).  Thus, only
5942 1.25 words are actually devoted to the value itself; the other
5943 three-quarters of a word are overhead, but they aren't wasted because they
5944 allow \MP\ to deal with sparse arrays and to provide meaningful diagnostics.
5945
5946 In this section we shall be concerned only with the structural aspects of
5947 variables, not their values. Later parts of the program will change the
5948 |type| and |value| fields, but we shall treat those fields as black boxes
5949 whose contents should not be touched.
5950
5951 However, if the |type| field is |mp_structured|, there is no |value| field,
5952 and the second word is broken into two pointer fields called |attr_head|
5953 and |subscr_head|. Those fields point to additional nodes that
5954 contain structural information, as we shall see.
5955
5956 @d subscr_head_loc(A)   (A)+1 /* where |value|, |subscr_head| and |attr_head| are */
5957 @d attr_head(A)   info(subscr_head_loc((A))) /* pointer to attribute info */
5958 @d subscr_head(A)   link(subscr_head_loc((A))) /* pointer to subscript info */
5959 @d value_node_size 2 /* the number of words in a value node */
5960
5961 @ An attribute node is three words long. Two of these words contain |type|
5962 and |value| fields as described above, and the third word contains
5963 additional information:  There is an |attr_loc| field, which contains the
5964 hash address of the token that names this attribute; and there's also a
5965 |parent| field, which points to the value node of |mp_structured| type at the
5966 next higher level (i.e., at the level to which this attribute is
5967 subsidiary).  The |name_type| in an attribute node is `|attr|'.  The
5968 |link| field points to the next attribute with the same parent; these are
5969 arranged in increasing order, so that |attr_loc(link(p))>attr_loc(p)|. The
5970 final attribute node links to the constant |end_attr|, whose |attr_loc|
5971 field is greater than any legal hash address. The |attr_head| in the
5972 parent points to a node whose |name_type| is |mp_structured_root|; this
5973 node represents the null attribute, i.e., the variable that is relevant
5974 when no attributes are attached to the parent. The |attr_head| node is either
5975 a value node, a subscript node, or an attribute node, depending on what
5976 the parent would be if it were not structured; but the subscript and
5977 attribute fields are ignored, so it effectively contains only the data of
5978 a value node. The |link| field in this special node points to an attribute
5979 node whose |attr_loc| field is zero; the latter node represents a collective
5980 subscript `\.{[]}' attached to the parent, and its |link| field points to
5981 the first non-special attribute node (or to |end_attr| if there are none).
5982
5983 A subscript node likewise occupies three words, with |type| and |value| fields
5984 plus extra information; its |name_type| is |subscr|. In this case the
5985 third word is called the |subscript| field, which is a |scaled| integer.
5986 The |link| field points to the subscript node with the next larger
5987 subscript, if any; otherwise the |link| points to the attribute node
5988 for collective subscripts at this level. We have seen that the latter node
5989 contains an upward pointer, so that the parent can be deduced.
5990
5991 The |name_type| in a parent-less value node is |root|, and the |link|
5992 is the hash address of the token that names this value.
5993
5994 In other words, variables have a hierarchical structure that includes
5995 enough threads running around so that the program is able to move easily
5996 between siblings, parents, and children. An example should be helpful:
5997 (The reader is advised to draw a picture while reading the following
5998 description, since that will help to firm up the ideas.)
5999 Suppose that `\.x' and `\.{x.a}' and `\.{x[]b}' and `\.{x5}'
6000 and `\.{x20b}' have been mentioned in a user's program, where
6001 \.{x[]b} has been declared to be of \&{boolean} type. Let |h(x)|, |h(a)|,
6002 and |h(b)| be the hash addresses of \.x, \.a, and~\.b. Then
6003 |eq_type(h(x))=name| and |equiv(h(x))=p|, where |p|~is a two-word value
6004 node with |name_type(p)=root| and |link(p)=h(x)|. We have |type(p)=mp_structured|,
6005 |attr_head(p)=q|, and |subscr_head(p)=r|, where |q| points to a value
6006 node and |r| to a subscript node. (Are you still following this? Use
6007 a pencil to draw a diagram.) The lone variable `\.x' is represented by
6008 |type(q)| and |value(q)|; furthermore
6009 |name_type(q)=mp_structured_root| and |link(q)=q1|, where |q1| points
6010 to an attribute node representing `\.{x[]}'. Thus |name_type(q1)=attr|,
6011 |attr_loc(q1)=collective_subscript=0|, |parent(q1)=p|,
6012 |type(q1)=mp_structured|, |attr_head(q1)=qq|, and |subscr_head(q1)=qq1|;
6013 |qq| is a value node with |type(qq)=mp_numeric_type| (assuming that \.{x5} is
6014 numeric, because |qq| represents `\.{x[]}' with no further attributes),
6015 |name_type(qq)=mp_structured_root|, and
6016 |link(qq)=qq1|. (Now pay attention to the next part.) Node |qq1| is
6017 an attribute node representing `\.{x[][]}', which has never yet
6018 occurred; its |type| field is |undefined|, and its |value| field is
6019 undefined. We have |name_type(qq1)=attr|, |attr_loc(qq1)=collective_subscript|,
6020 |parent(qq1)=q1|, and |link(qq1)=qq2|. Since |qq2| represents
6021 `\.{x[]b}', |type(qq2)=mp_unknown_boolean|; also |attr_loc(qq2)=h(b)|,
6022 |parent(qq2)=q1|, |name_type(qq2)=attr|, |link(qq2)=end_attr|.
6023 (Maybe colored lines will help untangle your picture.)
6024  Node |r| is a subscript node with |type| and |value|
6025 representing `\.{x5}'; |name_type(r)=subscr|, |subscript(r)=5.0|,
6026 and |link(r)=r1| is another subscript node. To complete the picture,
6027 see if you can guess what |link(r1)| is; give up? It's~|q1|.
6028 Furthermore |subscript(r1)=20.0|, |name_type(r1)=subscr|,
6029 |type(r1)=mp_structured|, |attr_head(r1)=qqq|, |subscr_head(r1)=qqq1|,
6030 and we finish things off with three more nodes
6031 |qqq|, |qqq1|, and |qqq2| hung onto~|r1|. (Perhaps you should start again
6032 with a larger sheet of paper.) The value of variable \.{x20b}
6033 appears in node~|qqq2|, as you can well imagine.
6034
6035 If the example in the previous paragraph doesn't make things crystal
6036 clear, a glance at some of the simpler subroutines below will reveal how
6037 things work out in practice.
6038
6039 The only really unusual thing about these conventions is the use of
6040 collective subscript attributes. The idea is to avoid repeating a lot of
6041 type information when many elements of an array are identical macros
6042 (for which distinct values need not be stored) or when they don't have
6043 all of the possible attributes. Branches of the structure below collective
6044 subscript attributes do not carry actual values except for macro identifiers;
6045 branches of the structure below subscript nodes do not carry significant
6046 information in their collective subscript attributes.
6047
6048 @d attr_loc_loc(A) ((A)+2) /* where the |attr_loc| and |parent| fields are */
6049 @d attr_loc(A) info(attr_loc_loc((A))) /* hash address of this attribute */
6050 @d parent(A) link(attr_loc_loc((A))) /* pointer to |mp_structured| variable */
6051 @d subscript_loc(A) ((A)+2) /* where the |subscript| field lives */
6052 @d subscript(A) mp->mem[subscript_loc((A))].sc /* subscript of this variable */
6053 @d attr_node_size 3 /* the number of words in an attribute node */
6054 @d subscr_node_size 3 /* the number of words in a subscript node */
6055 @d collective_subscript 0 /* code for the attribute `\.{[]}' */
6056
6057 @<Initialize table...@>=
6058 attr_loc(end_attr)=hash_end+1; parent(end_attr)=null;
6059
6060 @ Variables of type \&{pair} will have values that point to four-word
6061 nodes containing two numeric values. The first of these values has
6062 |name_type=mp_x_part_sector| and the second has |name_type=mp_y_part_sector|;
6063 the |link| in the first points back to the node whose |value| points
6064 to this four-word node.
6065
6066 Variables of type \&{transform} are similar, but in this case their
6067 |value| points to a 12-word node containing six values, identified by
6068 |x_part_sector|, |y_part_sector|, |mp_xx_part_sector|, |mp_xy_part_sector|,
6069 |mp_yx_part_sector|, and |mp_yy_part_sector|.
6070 Finally, variables of type \&{color} have three values in six words
6071 identified by |mp_red_part_sector|, |mp_green_part_sector|, and |mp_blue_part_sector|.
6072
6073 When an entire structured variable is saved, the |root| indication
6074 is temporarily replaced by |saved_root|.
6075
6076 Some variables have no name; they just are used for temporary storage
6077 while expressions are being evaluated. We call them {\sl capsules}.
6078
6079 @d x_part_loc(A) (A) /* where the \&{xpart} is found in a pair or transform node */
6080 @d y_part_loc(A) ((A)+2) /* where the \&{ypart} is found in a pair or transform node */
6081 @d xx_part_loc(A) ((A)+4) /* where the \&{xxpart} is found in a transform node */
6082 @d xy_part_loc(A) ((A)+6) /* where the \&{xypart} is found in a transform node */
6083 @d yx_part_loc(A) ((A)+8) /* where the \&{yxpart} is found in a transform node */
6084 @d yy_part_loc(A) ((A)+10) /* where the \&{yypart} is found in a transform node */
6085 @d red_part_loc(A) (A) /* where the \&{redpart} is found in a color node */
6086 @d green_part_loc(A) ((A)+2) /* where the \&{greenpart} is found in a color node */
6087 @d blue_part_loc(A) ((A)+4) /* where the \&{bluepart} is found in a color node */
6088 @d cyan_part_loc(A) (A) /* where the \&{cyanpart} is found in a color node */
6089 @d magenta_part_loc(A) ((A)+2) /* where the \&{magentapart} is found in a color node */
6090 @d yellow_part_loc(A) ((A)+4) /* where the \&{yellowpart} is found in a color node */
6091 @d black_part_loc(A) ((A)+6) /* where the \&{blackpart} is found in a color node */
6092 @d grey_part_loc(A) (A) /* where the \&{greypart} is found in a color node */
6093 @#
6094 @d pair_node_size 4 /* the number of words in a pair node */
6095 @d transform_node_size 12 /* the number of words in a transform node */
6096 @d color_node_size 6 /* the number of words in a color node */
6097 @d cmykcolor_node_size 8 /* the number of words in a color node */
6098
6099 @<Glob...@>=
6100 small_number big_node_size[mp_pair_type+1];
6101 small_number sector0[mp_pair_type+1];
6102 small_number sector_offset[mp_black_part_sector+1];
6103
6104 @ The |sector0| array gives for each big node type, |name_type| values
6105 for its first subfield; the |sector_offset| array gives for each
6106 |name_type| value, the offset from the first subfield in words;
6107 and the |big_node_size| array gives the size in words for each type of
6108 big node.
6109
6110 @<Set init...@>=
6111 mp->big_node_size[mp_transform_type]=transform_node_size;
6112 mp->big_node_size[mp_pair_type]=pair_node_size;
6113 mp->big_node_size[mp_color_type]=color_node_size;
6114 mp->big_node_size[mp_cmykcolor_type]=cmykcolor_node_size;
6115 mp->sector0[mp_transform_type]=mp_x_part_sector;
6116 mp->sector0[mp_pair_type]=mp_x_part_sector;
6117 mp->sector0[mp_color_type]=mp_red_part_sector;
6118 mp->sector0[mp_cmykcolor_type]=mp_cyan_part_sector;
6119 for (k=mp_x_part_sector;k<= mp_yy_part_sector;k++ ) {
6120   mp->sector_offset[k]=2*(k-mp_x_part_sector);
6121 }
6122 for (k=mp_red_part_sector;k<= mp_blue_part_sector ; k++) {
6123   mp->sector_offset[k]=2*(k-mp_red_part_sector);
6124 }
6125 for (k=mp_cyan_part_sector;k<= mp_black_part_sector;k++ ) {
6126   mp->sector_offset[k]=2*(k-mp_cyan_part_sector);
6127 }
6128
6129 @ If |type(p)=mp_pair_type| or |mp_transform_type| and if |value(p)=null|, the
6130 procedure call |init_big_node(p)| will allocate a pair or transform node
6131 for~|p|.  The individual parts of such nodes are initially of type
6132 |mp_independent|.
6133
6134 @c 
6135 void mp_init_big_node (MP mp,pointer p) {
6136   pointer q; /* the new node */
6137   small_number s; /* its size */
6138   s=mp->big_node_size[type(p)]; q=mp_get_node(mp, s);
6139   do {  
6140     s=s-2; 
6141     @<Make variable |q+s| newly independent@>;
6142     name_type(q+s)=halfp(s)+mp->sector0[type(p)]; 
6143     link(q+s)=null;
6144   } while (s!=0);
6145   link(q)=p; value(p)=q;
6146 }
6147
6148 @ The |id_transform| function creates a capsule for the
6149 identity transformation.
6150
6151 @c 
6152 pointer mp_id_transform (MP mp) {
6153   pointer p,q,r; /* list manipulation registers */
6154   p=mp_get_node(mp, value_node_size); type(p)=mp_transform_type;
6155   name_type(p)=mp_capsule; value(p)=null; mp_init_big_node(mp, p); q=value(p);
6156   r=q+transform_node_size;
6157   do {  
6158     r=r-2;
6159     type(r)=mp_known; value(r)=0;
6160   } while (r!=q);
6161   value(xx_part_loc(q))=unity; 
6162   value(yy_part_loc(q))=unity;
6163   return p;
6164 }
6165
6166 @ Tokens are of type |tag_token| when they first appear, but they point
6167 to |null| until they are first used as the root of a variable.
6168 The following subroutine establishes the root node on such grand occasions.
6169
6170 @c 
6171 void mp_new_root (MP mp,pointer x) {
6172   pointer p; /* the new node */
6173   p=mp_get_node(mp, value_node_size); type(p)=undefined; name_type(p)=mp_root;
6174   link(p)=x; equiv(x)=p;
6175 }
6176
6177 @ These conventions for variable representation are illustrated by the
6178 |print_variable_name| routine, which displays the full name of a
6179 variable given only a pointer to its two-word value packet.
6180
6181 @<Declarations@>=
6182 void mp_print_variable_name (MP mp, pointer p);
6183
6184 @ @c 
6185 void mp_print_variable_name (MP mp, pointer p) {
6186   pointer q; /* a token list that will name the variable's suffix */
6187   pointer r; /* temporary for token list creation */
6188   while ( name_type(p)>=mp_x_part_sector ) {
6189     @<Preface the output with a part specifier; |return| in the
6190       case of a capsule@>;
6191   }
6192   q=null;
6193   while ( name_type(p)>mp_saved_root ) {
6194     @<Ascend one level, pushing a token onto list |q|
6195      and replacing |p| by its parent@>;
6196   }
6197   r=mp_get_avail(mp); info(r)=link(p); link(r)=q;
6198   if ( name_type(p)==mp_saved_root ) mp_print(mp, "(SAVED)");
6199 @.SAVED@>
6200   mp_show_token_list(mp, r,null,el_gordo,mp->tally); 
6201   mp_flush_token_list(mp, r);
6202 }
6203
6204 @ @<Ascend one level, pushing a token onto list |q|...@>=
6205
6206   if ( name_type(p)==mp_subscr ) { 
6207     r=mp_new_num_tok(mp, subscript(p));
6208     do {  
6209       p=link(p);
6210     } while (name_type(p)!=mp_attr);
6211   } else if ( name_type(p)==mp_structured_root ) {
6212     p=link(p); goto FOUND;
6213   } else { 
6214     if ( name_type(p)!=mp_attr ) mp_confusion(mp, "var");
6215 @:this can't happen var}{\quad var@>
6216     r=mp_get_avail(mp); info(r)=attr_loc(p);
6217   }
6218   link(r)=q; q=r;
6219 FOUND:  
6220   p=parent(p);
6221 }
6222
6223 @ @<Preface the output with a part specifier...@>=
6224 { switch (name_type(p)) {
6225   case mp_x_part_sector: mp_print_char(mp, 'x'); break;
6226   case mp_y_part_sector: mp_print_char(mp, 'y'); break;
6227   case mp_xx_part_sector: mp_print(mp, "xx"); break;
6228   case mp_xy_part_sector: mp_print(mp, "xy"); break;
6229   case mp_yx_part_sector: mp_print(mp, "yx"); break;
6230   case mp_yy_part_sector: mp_print(mp, "yy"); break;
6231   case mp_red_part_sector: mp_print(mp, "red"); break;
6232   case mp_green_part_sector: mp_print(mp, "green"); break;
6233   case mp_blue_part_sector: mp_print(mp, "blue"); break;
6234   case mp_cyan_part_sector: mp_print(mp, "cyan"); break;
6235   case mp_magenta_part_sector: mp_print(mp, "magenta"); break;
6236   case mp_yellow_part_sector: mp_print(mp, "yellow"); break;
6237   case mp_black_part_sector: mp_print(mp, "black"); break;
6238   case mp_grey_part_sector: mp_print(mp, "grey"); break;
6239   case mp_capsule: 
6240     mp_print(mp, "%CAPSULE"); mp_print_int(mp, p-null); return;
6241     break;
6242 @.CAPSULE@>
6243   } /* there are no other cases */
6244   mp_print(mp, "part "); 
6245   p=link(p-mp->sector_offset[name_type(p)]);
6246 }
6247
6248 @ The |interesting| function returns |true| if a given variable is not
6249 in a capsule, or if the user wants to trace capsules.
6250
6251 @c 
6252 boolean mp_interesting (MP mp,pointer p) {
6253   small_number t; /* a |name_type| */
6254   if ( mp->internal[tracing_capsules]>0 ) {
6255     return true;
6256   } else { 
6257     t=name_type(p);
6258     if ( t>=mp_x_part_sector ) if ( t!=mp_capsule )
6259       t=name_type(link(p-mp->sector_offset[t]));
6260     return (t!=mp_capsule);
6261   }
6262 }
6263
6264 @ Now here is a subroutine that converts an unstructured type into an
6265 equivalent structured type, by inserting a |mp_structured| node that is
6266 capable of growing. This operation is done only when |name_type(p)=root|,
6267 |subscr|, or |attr|.
6268
6269 The procedure returns a pointer to the new node that has taken node~|p|'s
6270 place in the structure. Node~|p| itself does not move, nor are its
6271 |value| or |type| fields changed in any way.
6272
6273 @c 
6274 pointer mp_new_structure (MP mp,pointer p) {
6275   pointer q,r=0; /* list manipulation registers */
6276   switch (name_type(p)) {
6277   case mp_root: 
6278     q=link(p); r=mp_get_node(mp, value_node_size); equiv(q)=r;
6279     break;
6280   case mp_subscr: 
6281     @<Link a new subscript node |r| in place of node |p|@>;
6282     break;
6283   case mp_attr: 
6284     @<Link a new attribute node |r| in place of node |p|@>;
6285     break;
6286   default: 
6287     mp_confusion(mp, "struct");
6288 @:this can't happen struct}{\quad struct@>
6289     break;
6290   }
6291   link(r)=link(p); type(r)=mp_structured; name_type(r)=name_type(p);
6292   attr_head(r)=p; name_type(p)=mp_structured_root;
6293   q=mp_get_node(mp, attr_node_size); link(p)=q; subscr_head(r)=q;
6294   parent(q)=r; type(q)=undefined; name_type(q)=mp_attr; link(q)=end_attr;
6295   attr_loc(q)=collective_subscript; 
6296   return r;
6297 };
6298
6299 @ @<Link a new subscript node |r| in place of node |p|@>=
6300
6301   q=p;
6302   do {  
6303     q=link(q);
6304   } while (name_type(q)!=mp_attr);
6305   q=parent(q); r=subscr_head_loc(q); /* |link(r)=subscr_head(q)| */
6306   do {  
6307     q=r; r=link(r);
6308   } while (r!=p);
6309   r=mp_get_node(mp, subscr_node_size);
6310   link(q)=r; subscript(r)=subscript(p);
6311 }
6312
6313 @ If the attribute is |collective_subscript|, there are two pointers to
6314 node~|p|, so we must change both of them.
6315
6316 @<Link a new attribute node |r| in place of node |p|@>=
6317
6318   q=parent(p); r=attr_head(q);
6319   do {  
6320     q=r; r=link(r);
6321   } while (r!=p);
6322   r=mp_get_node(mp, attr_node_size); link(q)=r;
6323   mp->mem[attr_loc_loc(r)]=mp->mem[attr_loc_loc(p)]; /* copy |attr_loc| and |parent| */
6324   if ( attr_loc(p)==collective_subscript ) { 
6325     q=subscr_head_loc(parent(p));
6326     while ( link(q)!=p ) q=link(q);
6327     link(q)=r;
6328   }
6329 }
6330
6331 @ The |find_variable| routine is given a pointer~|t| to a nonempty token
6332 list of suffixes; it returns a pointer to the corresponding two-word
6333 value. For example, if |t| points to token \.x followed by a numeric
6334 token containing the value~7, |find_variable| finds where the value of
6335 \.{x7} is stored in memory. This may seem a simple task, and it
6336 usually is, except when \.{x7} has never been referenced before.
6337 Indeed, \.x may never have even been subscripted before; complexities
6338 arise with respect to updating the collective subscript information.
6339
6340 If a macro type is detected anywhere along path~|t|, or if the first
6341 item on |t| isn't a |tag_token|, the value |null| is returned.
6342 Otherwise |p| will be a non-null pointer to a node such that
6343 |undefined<type(p)<mp_structured|.
6344
6345 @d abort_find { return null; }
6346
6347 @c 
6348 pointer mp_find_variable (MP mp,pointer t) {
6349   pointer p,q,r,s; /* nodes in the ``value'' line */
6350   pointer pp,qq,rr,ss; /* nodes in the ``collective'' line */
6351   integer n; /* subscript or attribute */
6352   memory_word save_word; /* temporary storage for a word of |mem| */
6353 @^inner loop@>
6354   p=info(t); t=link(t);
6355   if ( (eq_type(p) % outer_tag) != tag_token ) abort_find;
6356   if ( equiv(p)==null ) mp_new_root(mp, p);
6357   p=equiv(p); pp=p;
6358   while ( t!=null ) { 
6359     @<Make sure that both nodes |p| and |pp| are of |mp_structured| type@>;
6360     if ( t<mp->hi_mem_min ) {
6361       @<Descend one level for the subscript |value(t)|@>
6362     } else {
6363       @<Descend one level for the attribute |info(t)|@>;
6364     }
6365     t=link(t);
6366   }
6367   if ( type(pp)>=mp_structured ) {
6368     if ( type(pp)==mp_structured ) pp=attr_head(pp); else abort_find;
6369   }
6370   if ( type(p)==mp_structured ) p=attr_head(p);
6371   if ( type(p)==undefined ) { 
6372     if ( type(pp)==undefined ) { type(pp)=mp_numeric_type; value(pp)=null; };
6373     type(p)=type(pp); value(p)=null;
6374   };
6375   return p;
6376 }
6377
6378 @ Although |pp| and |p| begin together, they diverge when a subscript occurs;
6379 |pp|~stays in the collective line while |p|~goes through actual subscript
6380 values.
6381
6382 @<Make sure that both nodes |p| and |pp|...@>=
6383 if ( type(pp)!=mp_structured ) { 
6384   if ( type(pp)>mp_structured ) abort_find;
6385   ss=mp_new_structure(mp, pp);
6386   if ( p==pp ) p=ss;
6387   pp=ss;
6388 }; /* now |type(pp)=mp_structured| */
6389 if ( type(p)!=mp_structured ) /* it cannot be |>mp_structured| */
6390   p=mp_new_structure(mp, p) /* now |type(p)=mp_structured| */
6391
6392 @ We want this part of the program to be reasonably fast, in case there are
6393 @^inner loop@>
6394 lots of subscripts at the same level of the data structure. Therefore
6395 we store an ``infinite'' value in the word that appears at the end of the
6396 subscript list, even though that word isn't part of a subscript node.
6397
6398 @<Descend one level for the subscript |value(t)|@>=
6399
6400   n=value(t);
6401   pp=link(attr_head(pp)); /* now |attr_loc(pp)=collective_subscript| */
6402   q=link(attr_head(p)); save_word=mp->mem[subscript_loc(q)];
6403   subscript(q)=el_gordo; s=subscr_head_loc(p); /* |link(s)=subscr_head(p)| */
6404   do {  
6405     r=s; s=link(s);
6406   } while (n>subscript(s));
6407   if ( n==subscript(s) ) {
6408     p=s;
6409   } else { 
6410     p=mp_get_node(mp, subscr_node_size); link(r)=p; link(p)=s;
6411     subscript(p)=n; name_type(p)=mp_subscr; type(p)=undefined;
6412   }
6413   mp->mem[subscript_loc(q)]=save_word;
6414 }
6415
6416 @ @<Descend one level for the attribute |info(t)|@>=
6417
6418   n=info(t);
6419   ss=attr_head(pp);
6420   do {  
6421     rr=ss; ss=link(ss);
6422   } while (n>attr_loc(ss));
6423   if ( n<attr_loc(ss) ) { 
6424     qq=mp_get_node(mp, attr_node_size); link(rr)=qq; link(qq)=ss;
6425     attr_loc(qq)=n; name_type(qq)=mp_attr; type(qq)=undefined;
6426     parent(qq)=pp; ss=qq;
6427   }
6428   if ( p==pp ) { 
6429     p=ss; pp=ss;
6430   } else { 
6431     pp=ss; s=attr_head(p);
6432     do {  
6433       r=s; s=link(s);
6434     } while (n>attr_loc(s));
6435     if ( n==attr_loc(s) ) {
6436       p=s;
6437     } else { 
6438       q=mp_get_node(mp, attr_node_size); link(r)=q; link(q)=s;
6439       attr_loc(q)=n; name_type(q)=mp_attr; type(q)=undefined;
6440       parent(q)=p; p=q;
6441     }
6442   }
6443 }
6444
6445 @ Variables lose their former values when they appear in a type declaration,
6446 or when they are defined to be macros or \&{let} equal to something else.
6447 A subroutine will be defined later that recycles the storage associated
6448 with any particular |type| or |value|; our goal now is to study a higher
6449 level process called |flush_variable|, which selectively frees parts of a
6450 variable structure.
6451
6452 This routine has some complexity because of examples such as
6453 `\hbox{\tt numeric x[]a[]b}'
6454 which recycles all variables of the form \.{x[i]a[j]b} (and no others), while
6455 `\hbox{\tt vardef x[]a[]=...}'
6456 discards all variables of the form \.{x[i]a[j]} followed by an arbitrary
6457 suffix, except for the collective node \.{x[]a[]} itself. The obvious way
6458 to handle such examples is to use recursion; so that's what we~do.
6459 @^recursion@>
6460
6461 Parameter |p| points to the root information of the variable;
6462 parameter |t| points to a list of one-word nodes that represent
6463 suffixes, with |info=collective_subscript| for subscripts.
6464
6465 @<Declarations@>=
6466 @<Declare subroutines for printing expressions@>
6467 @<Declare basic dependency-list subroutines@>
6468 @<Declare the recycling subroutines@>
6469 void mp_flush_cur_exp (MP mp,scaled v) ;
6470 @<Declare the procedure called |flush_below_variable|@>
6471
6472 @ @c 
6473 void mp_flush_variable (MP mp,pointer p, pointer t, boolean discard_suffixes) {
6474   pointer q,r; /* list manipulation */
6475   halfword n; /* attribute to match */
6476   while ( t!=null ) { 
6477     if ( type(p)!=mp_structured ) return;
6478     n=info(t); t=link(t);
6479     if ( n==collective_subscript ) { 
6480       r=subscr_head_loc(p); q=link(r); /* |q=subscr_head(p)| */
6481       while ( name_type(q)==mp_subscr ){ 
6482         mp_flush_variable(mp, q,t,discard_suffixes);
6483         if ( t==null ) {
6484           if ( type(q)==mp_structured ) r=q;
6485           else  { link(r)=link(q); mp_free_node(mp, q,subscr_node_size);   }
6486         } else {
6487           r=q;
6488         }
6489         q=link(r);
6490       }
6491     }
6492     p=attr_head(p);
6493     do {  
6494       r=p; p=link(p);
6495     } while (attr_loc(p)<n);
6496     if ( attr_loc(p)!=n ) return;
6497   }
6498   if ( discard_suffixes ) {
6499     mp_flush_below_variable(mp, p);
6500   } else { 
6501     if ( type(p)==mp_structured ) p=attr_head(p);
6502     mp_recycle_value(mp, p);
6503   }
6504 }
6505
6506 @ The next procedure is simpler; it wipes out everything but |p| itself,
6507 which becomes undefined.
6508
6509 @<Declare the procedure called |flush_below_variable|@>=
6510 void mp_flush_below_variable (MP mp, pointer p);
6511
6512 @ @c
6513 void mp_flush_below_variable (MP mp,pointer p) {
6514    pointer q,r; /* list manipulation registers */
6515   if ( type(p)!=mp_structured ) {
6516     mp_recycle_value(mp, p); /* this sets |type(p)=undefined| */
6517   } else { 
6518     q=subscr_head(p);
6519     while ( name_type(q)==mp_subscr ) { 
6520       mp_flush_below_variable(mp, q); r=q; q=link(q);
6521       mp_free_node(mp, r,subscr_node_size);
6522     }
6523     r=attr_head(p); q=link(r); mp_recycle_value(mp, r);
6524     if ( name_type(p)<=mp_saved_root ) mp_free_node(mp, r,value_node_size);
6525     else mp_free_node(mp, r,subscr_node_size);
6526     /* we assume that |subscr_node_size=attr_node_size| */
6527     do {  
6528       mp_flush_below_variable(mp, q); r=q; q=link(q); mp_free_node(mp, r,attr_node_size);
6529     } while (q!=end_attr);
6530     type(p)=undefined;
6531   }
6532 }
6533
6534 @ Just before assigning a new value to a variable, we will recycle the
6535 old value and make the old value undefined. The |und_type| routine
6536 determines what type of undefined value should be given, based on
6537 the current type before recycling.
6538
6539 @c 
6540 small_number mp_und_type (MP mp,pointer p) { 
6541   switch (type(p)) {
6542   case undefined: case mp_vacuous:
6543     return undefined;
6544   case mp_boolean_type: case mp_unknown_boolean:
6545     return mp_unknown_boolean;
6546   case mp_string_type: case mp_unknown_string:
6547     return mp_unknown_string;
6548   case mp_pen_type: case mp_unknown_pen:
6549     return mp_unknown_pen;
6550   case mp_path_type: case mp_unknown_path:
6551     return mp_unknown_path;
6552   case mp_picture_type: case mp_unknown_picture:
6553     return mp_unknown_picture;
6554   case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
6555   case mp_pair_type: case mp_numeric_type: 
6556     return type(p);
6557   case mp_known: case mp_dependent: case mp_proto_dependent: case mp_independent:
6558     return mp_numeric_type;
6559   } /* there are no other cases */
6560   return 0;
6561 }
6562
6563 @ The |clear_symbol| routine is used when we want to redefine the equivalent
6564 of a symbolic token. It must remove any variable structure or macro
6565 definition that is currently attached to that symbol. If the |saving|
6566 parameter is true, a subsidiary structure is saved instead of destroyed.
6567
6568 @c 
6569 void mp_clear_symbol (MP mp,pointer p, boolean saving) {
6570   pointer q; /* |equiv(p)| */
6571   q=equiv(p);
6572   switch (eq_type(p) % outer_tag)  {
6573   case defined_macro:
6574   case secondary_primary_macro:
6575   case tertiary_secondary_macro:
6576   case expression_tertiary_macro: 
6577     if ( ! saving ) mp_delete_mac_ref(mp, q);
6578     break;
6579   case tag_token:
6580     if ( q!=null ) {
6581       if ( saving ) {
6582         name_type(q)=mp_saved_root;
6583       } else { 
6584         mp_flush_below_variable(mp, q); mp_free_node(mp,q,value_node_size); 
6585       }
6586     }
6587     break;
6588   default:
6589     break;
6590   }
6591   mp->eqtb[p]=mp->eqtb[frozen_undefined];
6592 };
6593
6594 @* \[16] Saving and restoring equivalents.
6595 The nested structure given by \&{begingroup} and \&{endgroup}
6596 allows |eqtb| entries to be saved and restored, so that temporary changes
6597 can be made without difficulty.  When the user requests a current value to
6598 be saved, \MP\ puts that value into its ``save stack.'' An appearance of
6599 \&{endgroup} ultimately causes the old values to be removed from the save
6600 stack and put back in their former places.
6601
6602 The save stack is a linked list containing three kinds of entries,
6603 distinguished by their |info| fields. If |p| points to a saved item,
6604 then
6605
6606 \smallskip\hang
6607 |info(p)=0| stands for a group boundary; each \&{begingroup} contributes
6608 such an item to the save stack and each \&{endgroup} cuts back the stack
6609 until the most recent such entry has been removed.
6610
6611 \smallskip\hang
6612 |info(p)=q|, where |1<=q<=hash_end|, means that |mem[p+1]| holds the former
6613 contents of |eqtb[q]|. Such save stack entries are generated by \&{save}
6614 commands or suitable \&{interim} commands.
6615
6616 \smallskip\hang
6617 |info(p)=hash_end+q|, where |q>0|, means that |value(p)| is a |scaled|
6618 integer to be restored to internal parameter number~|q|. Such entries
6619 are generated by \&{interim} commands.
6620
6621 \smallskip\noindent
6622 The global variable |save_ptr| points to the top item on the save stack.
6623
6624 @d save_node_size 2 /* number of words per non-boundary save-stack node */
6625 @d saved_equiv(A) mp->mem[(A)+1].hh /* where an |eqtb| entry gets saved */
6626 @d save_boundary_item(A) { (A)=mp_get_avail(mp); info((A))=0;
6627   link((A))=mp->save_ptr; mp->save_ptr=(A);
6628   }
6629
6630 @<Glob...@>=
6631 pointer save_ptr; /* the most recently saved item */
6632
6633 @ @<Set init...@>=mp->save_ptr=null;
6634
6635 @ The |save_variable| routine is given a hash address |q|; it salts this
6636 address in the save stack, together with its current equivalent,
6637 then makes token~|q| behave as though it were brand new.
6638
6639 Nothing is stacked when |save_ptr=null|, however; there's no way to remove
6640 things from the stack when the program is not inside a group, so there's
6641 no point in wasting the space.
6642
6643 @c void mp_save_variable (MP mp,pointer q) {
6644   pointer p; /* temporary register */
6645   if ( mp->save_ptr!=null ){ 
6646     p=mp_get_node(mp, save_node_size); info(p)=q; link(p)=mp->save_ptr;
6647     saved_equiv(p)=mp->eqtb[q]; mp->save_ptr=p;
6648   }
6649   mp_clear_symbol(mp, q,(mp->save_ptr!=null));
6650 }
6651
6652 @ Similarly, |save_internal| is given the location |q| of an internal
6653 quantity like |tracing_pens|. It creates a save stack entry of the
6654 third kind.
6655
6656 @c void mp_save_internal (MP mp,halfword q) {
6657   pointer p; /* new item for the save stack */
6658   if ( mp->save_ptr!=null ){ 
6659      p=mp_get_node(mp, save_node_size); info(p)=hash_end+q;
6660     link(p)=mp->save_ptr; value(p)=mp->internal[q]; mp->save_ptr=p;
6661   }
6662 }
6663
6664 @ At the end of a group, the |unsave| routine restores all of the saved
6665 equivalents in reverse order. This routine will be called only when there
6666 is at least one boundary item on the save stack.
6667
6668 @c 
6669 void mp_unsave (MP mp) {
6670   pointer q; /* index to saved item */
6671   pointer p; /* temporary register */
6672   while ( info(mp->save_ptr)!=0 ) {
6673     q=info(mp->save_ptr);
6674     if ( q>hash_end ) {
6675       if ( mp->internal[tracing_restores]>0 ) {
6676         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6677         mp_print(mp, mp->int_name[q-(hash_end)]); mp_print_char(mp, '=');
6678         mp_print_scaled(mp, value(mp->save_ptr)); mp_print_char(mp, '}');
6679         mp_end_diagnostic(mp, false);
6680       }
6681       mp->internal[q-(hash_end)]=value(mp->save_ptr);
6682     } else { 
6683       if ( mp->internal[tracing_restores]>0 ) {
6684         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6685         mp_print_text(q); mp_print_char(mp, '}');
6686         mp_end_diagnostic(mp, false);
6687       }
6688       mp_clear_symbol(mp, q,false);
6689       mp->eqtb[q]=saved_equiv(mp->save_ptr);
6690       if ( eq_type(q) % outer_tag==tag_token ) {
6691         p=equiv(q);
6692         if ( p!=null ) name_type(p)=mp_root;
6693       }
6694     }
6695     p=link(mp->save_ptr); 
6696     mp_free_node(mp, mp->save_ptr,save_node_size); mp->save_ptr=p;
6697   }
6698   p=link(mp->save_ptr); free_avail(mp->save_ptr); mp->save_ptr=p;
6699 }
6700
6701 @* \[17] Data structures for paths.
6702 When a \MP\ user specifies a path, \MP\ will create a list of knots
6703 and control points for the associated cubic spline curves. If the
6704 knots are $z_0$, $z_1$, \dots, $z_n$, there are control points
6705 $z_k^+$ and $z_{k+1}^-$ such that the cubic splines between knots
6706 $z_k$ and $z_{k+1}$ are defined by B\'ezier's formula
6707 @:Bezier}{B\'ezier, Pierre Etienne@>
6708 $$\eqalign{z(t)&=B(z_k,z_k^+,z_{k+1}^-,z_{k+1};t)\cr
6709 &=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_{k+1}^-+t^3z_{k+1}\cr}$$
6710 for |0<=t<=1|.
6711
6712 There is a 8-word node for each knot $z_k$, containing one word of
6713 control information and six words for the |x| and |y| coordinates of
6714 $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears in the
6715 |left_type| and |right_type| fields, which each occupy a quarter of
6716 the first word in the node; they specify properties of the curve as it
6717 enters and leaves the knot. There's also a halfword |link| field,
6718 which points to the following knot, and a final supplementary word (of
6719 which only a quarter is used).
6720
6721 If the path is a closed contour, knots 0 and |n| are identical;
6722 i.e., the |link| in knot |n-1| points to knot~0. But if the path
6723 is not closed, the |left_type| of knot~0 and the |right_type| of knot~|n|
6724 are equal to |endpoint|. In the latter case the |link| in knot~|n| points
6725 to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used.
6726
6727 @d left_type(A)   mp->mem[(A)].hh.b0 /* characterizes the path entering this knot */
6728 @d right_type(A)   mp->mem[(A)].hh.b1 /* characterizes the path leaving this knot */
6729 @d endpoint 0 /* |left_type| at path beginning and |right_type| at path end */
6730 @d x_coord(A)   mp->mem[(A)+1].sc /* the |x| coordinate of this knot */
6731 @d y_coord(A)   mp->mem[(A)+2].sc /* the |y| coordinate of this knot */
6732 @d left_x(A)   mp->mem[(A)+3].sc /* the |x| coordinate of previous control point */
6733 @d left_y(A)   mp->mem[(A)+4].sc /* the |y| coordinate of previous control point */
6734 @d right_x(A)   mp->mem[(A)+5].sc /* the |x| coordinate of next control point */
6735 @d right_y(A)   mp->mem[(A)+6].sc /* the |y| coordinate of next control point */
6736 @d x_loc(A)   ((A)+1) /* where the |x| coordinate is stored in a knot */
6737 @d y_loc(A)   ((A)+2) /* where the |y| coordinate is stored in a knot */
6738 @d knot_coord(A)   mp->mem[(A)].sc /* |x| or |y| coordinate given |x_loc| or |y_loc| */
6739 @d left_coord(A)   mp->mem[(A)+2].sc
6740   /* coordinate of previous control point given |x_loc| or |y_loc| */
6741 @d right_coord(A)   mp->mem[(A)+4].sc
6742   /* coordinate of next control point given |x_loc| or |y_loc| */
6743 @d knot_node_size 8 /* number of words in a knot node */
6744
6745 @ Before the B\'ezier control points have been calculated, the memory
6746 space they will ultimately occupy is taken up by information that can be
6747 used to compute them. There are four cases:
6748
6749 \yskip
6750 \textindent{$\bullet$} If |right_type=open|, the curve should leave
6751 the knot in the same direction it entered; \MP\ will figure out a
6752 suitable direction.
6753
6754 \yskip
6755 \textindent{$\bullet$} If |right_type=curl|, the curve should leave the
6756 knot in a direction depending on the angle at which it enters the next
6757 knot and on the curl parameter stored in |right_curl|.
6758
6759 \yskip
6760 \textindent{$\bullet$} If |right_type=given|, the curve should leave the
6761 knot in a nonzero direction stored as an |angle| in |right_given|.
6762
6763 \yskip
6764 \textindent{$\bullet$} If |right_type=explicit|, the B\'ezier control
6765 point for leaving this knot has already been computed; it is in the
6766 |right_x| and |right_y| fields.
6767
6768 \yskip\noindent
6769 The rules for |left_type| are similar, but they refer to the curve entering
6770 the knot, and to \\{left} fields instead of \\{right} fields.
6771
6772 Non-|explicit| control points will be chosen based on ``tension'' parameters
6773 in the |left_tension| and |right_tension| fields. The
6774 `\&{atleast}' option is represented by negative tension values.
6775 @:at_least_}{\&{atleast} primitive@>
6776
6777 For example, the \MP\ path specification
6778 $$\.{z0..z1..tension atleast 1..\{curl 2\}z2..z3\{-1,-2\}..tension
6779   3 and 4..p},$$
6780 where \.p is the path `\.{z4..controls z45 and z54..z5}', will be represented
6781 by the six knots
6782 \def\lodash{\hbox to 1.1em{\thinspace\hrulefill\thinspace}}
6783 $$\vbox{\halign{#\hfil&&\qquad#\hfil\cr
6784 |left_type|&\\{left} info&|x_coord,y_coord|&|right_type|&\\{right} info\cr
6785 \noalign{\yskip}
6786 |endpoint|&\lodash$,\,$\lodash&$x_0,y_0$&|curl|&$1.0,1.0$\cr
6787 |open|&\lodash$,1.0$&$x_1,y_1$&|open|&\lodash$,-1.0$\cr
6788 |curl|&$2.0,-1.0$&$x_2,y_2$&|curl|&$2.0,1.0$\cr
6789 |given|&$d,1.0$&$x_3,y_3$&|given|&$d,3.0$\cr
6790 |open|&\lodash$,4.0$&$x_4,y_4$&|explicit|&$x_{45},y_{45}$\cr
6791 |explicit|&$x_{54},y_{54}$&$x_5,y_5$&|endpoint|&\lodash$,\,$\lodash\cr}}$$
6792 Here |d| is the |angle| obtained by calling |n_arg(-unity,-two)|.
6793 Of course, this example is more complicated than anything a normal user
6794 would ever write.
6795
6796 These types must satisfy certain restrictions because of the form of \MP's
6797 path syntax:
6798 (i)~|open| type never appears in the same node together with |endpoint|,
6799 |given|, or |curl|.
6800 (ii)~The |right_type| of a node is |explicit| if and only if the
6801 |left_type| of the following node is |explicit|.
6802 (iii)~|endpoint| types occur only at the ends, as mentioned above.
6803
6804 @d left_curl left_x /* curl information when entering this knot */
6805 @d left_given left_x /* given direction when entering this knot */
6806 @d left_tension left_y /* tension information when entering this knot */
6807 @d right_curl right_x /* curl information when leaving this knot */
6808 @d right_given right_x /* given direction when leaving this knot */
6809 @d right_tension right_y /* tension information when leaving this knot */
6810 @d explicit 1 /* |left_type| or |right_type| when control points are known */
6811 @d given 2 /* |left_type| or |right_type| when a direction is given */
6812 @d curl 3 /* |left_type| or |right_type| when a curl is desired */
6813 @d open 4 /* |left_type| or |right_type| when \MP\ should choose the direction */
6814
6815 @ Knots can be user-supplied, or they can be created by program code,
6816 like the |split_cubic| function, or |copy_path|. The distinction is
6817 needed for the cleanup routine that runs after |split_cubic|, because
6818 it should only delete knots it has previously inserted, and never
6819 anything that was user-supplied. In order to be able to differentiate
6820 one knot from another, we will set |originator(p):=metapost_user| when
6821 it appeared in the actual metapost program, and
6822 |originator(p):=program_code| in all other cases.
6823
6824 @d originator(A)   mp->mem[(A)+7].hh.b0 /* the creator of this knot */
6825 @d program_code 0 /* not created by a user */
6826 @d metapost_user 1 /* created by a user */
6827
6828 @ Here is a routine that prints a given knot list
6829 in symbolic form. It illustrates the conventions discussed above,
6830 and checks for anomalies that might arise while \MP\ is being debugged.
6831
6832 @<Declare subroutines for printing expressions@>=
6833 void mp_pr_path (MP mp,pointer h);
6834
6835 @ @c
6836 void mp_pr_path (MP mp,pointer h) {
6837   pointer p,q; /* for list traversal */
6838   p=h;
6839   do {  
6840     q=link(p);
6841     if ( (p==null)||(q==null) ) { 
6842       mp_print_nl(mp, "???"); return; /* this won't happen */
6843 @.???@>
6844     }
6845     @<Print information for adjacent knots |p| and |q|@>;
6846   DONE1:
6847     p=q;
6848     if ( (p!=h)||(left_type(h)!=endpoint) ) {
6849       @<Print two dots, followed by |given| or |curl| if present@>;
6850     }
6851   } while (p!=h);
6852   if ( left_type(h)!=endpoint ) 
6853     mp_print(mp, "cycle");
6854 }
6855
6856 @ @<Print information for adjacent knots...@>=
6857 mp_print_two(mp, x_coord(p),y_coord(p));
6858 switch (right_type(p)) {
6859 case endpoint: 
6860   if ( left_type(p)==open ) mp_print(mp, "{open?}"); /* can't happen */
6861 @.open?@>
6862   if ( (left_type(q)!=endpoint)||(q!=h) ) q=null; /* force an error */
6863   goto DONE1;
6864   break;
6865 case explicit: 
6866   @<Print control points between |p| and |q|, then |goto done1|@>;
6867   break;
6868 case open: 
6869   @<Print information for a curve that begins |open|@>;
6870   break;
6871 case curl:
6872 case given: 
6873   @<Print information for a curve that begins |curl| or |given|@>;
6874   break;
6875 default:
6876   mp_print(mp, "???"); /* can't happen */
6877 @.???@>
6878   break;
6879 }
6880 if ( left_type(q)<=explicit ) {
6881   mp_print(mp, "..control?"); /* can't happen */
6882 @.control?@>
6883 } else if ( (right_tension(p)!=unity)||(left_tension(q)!=unity) ) {
6884   @<Print tension between |p| and |q|@>;
6885 }
6886
6887 @ Since |n_sin_cos| produces |fraction| results, which we will print as if they
6888 were |scaled|, the magnitude of a |given| direction vector will be~4096.
6889
6890 @<Print two dots...@>=
6891
6892   mp_print_nl(mp, " ..");
6893   if ( left_type(p)==given ) { 
6894     mp_n_sin_cos(mp, left_given(p)); mp_print_char(mp, '{');
6895     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ',');
6896     mp_print_scaled(mp, mp->n_sin); mp_print_char(mp, '}');
6897   } else if ( left_type(p)==curl ){ 
6898     mp_print(mp, "{curl "); 
6899     mp_print_scaled(mp, left_curl(p)); mp_print_char(mp, '}');
6900   }
6901 }
6902
6903 @ @<Print tension between |p| and |q|@>=
6904
6905   mp_print(mp, "..tension ");
6906   if ( right_tension(p)<0 ) mp_print(mp, "atleast");
6907   mp_print_scaled(mp, abs(right_tension(p)));
6908   if ( right_tension(p)!=left_tension(q) ){ 
6909     mp_print(mp, " and ");
6910     if ( left_tension(q)<0 ) mp_print(mp, "atleast");
6911     mp_print_scaled(mp, abs(left_tension(q)));
6912   }
6913 }
6914
6915 @ @<Print control points between |p| and |q|, then |goto done1|@>=
6916
6917   mp_print(mp, "..controls "); 
6918   mp_print_two(mp, right_x(p),right_y(p)); 
6919   mp_print(mp, " and ");
6920   if ( left_type(q)!=explicit ) { 
6921     mp_print(mp, "??"); /* can't happen */
6922 @.??@>
6923   } else {
6924     mp_print_two(mp, left_x(q),left_y(q));
6925   }
6926   goto DONE1;
6927 }
6928
6929 @ @<Print information for a curve that begins |open|@>=
6930 if ( (left_type(p)!=explicit)&&(left_type(p)!=open) ) {
6931   mp_print(mp, "{open?}"); /* can't happen */
6932 @.open?@>
6933 }
6934
6935 @ A curl of 1 is shown explicitly, so that the user sees clearly that
6936 \MP's default curl is present.
6937
6938 The code here uses the fact that |left_curl==left_given| and
6939 |right_curl==right_given|.
6940
6941 @<Print information for a curve that begins |curl|...@>=
6942
6943   if ( left_type(p)==open )  
6944     mp_print(mp, "??"); /* can't happen */
6945 @.??@>
6946   if ( right_type(p)==curl ) { 
6947     mp_print(mp, "{curl "); mp_print_scaled(mp, right_curl(p));
6948   } else { 
6949     mp_n_sin_cos(mp, right_given(p)); mp_print_char(mp, '{');
6950     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, ','); 
6951     mp_print_scaled(mp, mp->n_sin);
6952   }
6953   mp_print_char(mp, '}');
6954 }
6955
6956 @ It is convenient to have another version of |pr_path| that prints the path
6957 as a diagnostic message.
6958
6959 @<Declare subroutines for printing expressions@>=
6960 void mp_print_path (MP mp,pointer h, char *s, boolean nuline) { 
6961   mp_print_diagnostic(mp, "Path", s, nuline); mp_print_ln(mp);
6962 @.Path at line...@>
6963   mp_pr_path(mp, h);
6964   mp_end_diagnostic(mp, true);
6965 }
6966
6967 @ If we want to duplicate a knot node, we can say |copy_knot|:
6968
6969 @c 
6970 pointer mp_copy_knot (MP mp,pointer p) {
6971   pointer q; /* the copy */
6972   int k; /* runs through the words of a knot node */
6973   q=mp_get_node(mp, knot_node_size);
6974   for (k=0;k<=knot_node_size-1;k++) {
6975     mp->mem[q+k]=mp->mem[p+k];
6976   }
6977   originator(q)=originator(p);
6978   return q;
6979 }
6980
6981 @ The |copy_path| routine makes a clone of a given path.
6982
6983 @c 
6984 pointer mp_copy_path (MP mp, pointer p) {
6985   pointer q,pp,qq; /* for list manipulation */
6986   q=mp_copy_knot(mp, p);
6987   qq=q; pp=link(p);
6988   while ( pp!=p ) { 
6989     link(qq)=mp_copy_knot(mp, pp);
6990     qq=link(qq);
6991     pp=link(pp);
6992   }
6993   link(qq)=q;
6994   return q;
6995 }
6996
6997 @ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure
6998 returns a pointer to the first node of the copy, if the path is a cycle,
6999 but to the final node of a non-cyclic copy. The global
7000 variable |path_tail| will point to the final node of the original path;
7001 this trick makes it easier to implement `\&{doublepath}'.
7002
7003 All node types are assumed to be |endpoint| or |explicit| only.
7004
7005 @c 
7006 pointer mp_htap_ypoc (MP mp,pointer p) {
7007   pointer q,pp,qq,rr; /* for list manipulation */
7008   q=mp_get_node(mp, knot_node_size); /* this will correspond to |p| */
7009   qq=q; pp=p;
7010   while (1) { 
7011     right_type(qq)=left_type(pp); left_type(qq)=right_type(pp);
7012     x_coord(qq)=x_coord(pp); y_coord(qq)=y_coord(pp);
7013     right_x(qq)=left_x(pp); right_y(qq)=left_y(pp);
7014     left_x(qq)=right_x(pp); left_y(qq)=right_y(pp);
7015     originator(qq)=originator(pp);
7016     if ( link(pp)==p ) { 
7017       link(q)=qq; mp->path_tail=pp; return q;
7018     }
7019     rr=mp_get_node(mp, knot_node_size); link(rr)=qq; qq=rr; pp=link(pp);
7020   }
7021 }
7022
7023 @ @<Glob...@>=
7024 pointer path_tail; /* the node that links to the beginning of a path */
7025
7026 @ When a cyclic list of knot nodes is no longer needed, it can be recycled by
7027 calling the following subroutine.
7028
7029 @<Declare the recycling subroutines@>=
7030 void mp_toss_knot_list (MP mp,pointer p) ;
7031
7032 @ @c
7033 void mp_toss_knot_list (MP mp,pointer p) {
7034   pointer q; /* the node being freed */
7035   pointer r; /* the next node */
7036   q=p;
7037   do {  
7038     r=link(q); 
7039     mp_free_node(mp, q,knot_node_size); q=r;
7040   } while (q!=p);
7041 }
7042
7043 @* \[18] Choosing control points.
7044 Now we must actually delve into one of \MP's more difficult routines,
7045 the |make_choices| procedure that chooses angles and control points for
7046 the splines of a curve when the user has not specified them explicitly.
7047 The parameter to |make_choices| points to a list of knots and
7048 path information, as described above.
7049
7050 A path decomposes into independent segments at ``breakpoint'' knots,
7051 which are knots whose left and right angles are both prespecified in
7052 some way (i.e., their |left_type| and |right_type| aren't both open).
7053
7054 @c 
7055 @<Declare the procedure called |solve_choices|@>;
7056 void mp_make_choices (MP mp,pointer knots) {
7057   pointer h; /* the first breakpoint */
7058   pointer p,q; /* consecutive breakpoints being processed */
7059   @<Other local variables for |make_choices|@>;
7060   check_arith; /* make sure that |arith_error=false| */
7061   if ( mp->internal[tracing_choices]>0 )
7062     mp_print_path(mp, knots,", before choices",true);
7063   @<If consecutive knots are equal, join them explicitly@>;
7064   @<Find the first breakpoint, |h|, on the path;
7065     insert an artificial breakpoint if the path is an unbroken cycle@>;
7066   p=h;
7067   do {  
7068     @<Fill in the control points between |p| and the next breakpoint,
7069       then advance |p| to that breakpoint@>;
7070   } while (p!=h);
7071   if ( mp->internal[tracing_choices]>0 )
7072     mp_print_path(mp, knots,", after choices",true);
7073   if ( mp->arith_error ) {
7074     @<Report an unexpected problem during the choice-making@>;
7075   }
7076 }
7077
7078 @ @<Report an unexpected problem during the choice...@>=
7079
7080   print_err("Some number got too big");
7081 @.Some number got too big@>
7082   help2("The path that I just computed is out of range.")
7083        ("So it will probably look funny. Proceed, for a laugh.");
7084   mp_put_get_error(mp); mp->arith_error=false;
7085 }
7086
7087 @ Two knots in a row with the same coordinates will always be joined
7088 by an explicit ``curve'' whose control points are identical with the
7089 knots.
7090
7091 @<If consecutive knots are equal, join them explicitly@>=
7092 p=knots;
7093 do {  
7094   q=link(p);
7095   if ( x_coord(p)==x_coord(q) && y_coord(p)==y_coord(q) && right_type(p)>explicit ) { 
7096     right_type(p)=explicit;
7097     if ( left_type(p)==open ) { 
7098       left_type(p)=curl; left_curl(p)=unity;
7099     }
7100     left_type(q)=explicit;
7101     if ( right_type(q)==open ) { 
7102       right_type(q)=curl; right_curl(q)=unity;
7103     }
7104     right_x(p)=x_coord(p); left_x(q)=x_coord(p);
7105     right_y(p)=y_coord(p); left_y(q)=y_coord(p);
7106   }
7107   p=q;
7108 } while (p!=knots)
7109
7110 @ If there are no breakpoints, it is necessary to compute the direction
7111 angles around an entire cycle. In this case the |left_type| of the first
7112 node is temporarily changed to |end_cycle|.
7113
7114 @d end_cycle (open+1)
7115
7116 @<Find the first breakpoint, |h|, on the path...@>=
7117 h=knots;
7118 while (1) { 
7119   if ( left_type(h)!=open ) break;
7120   if ( right_type(h)!=open ) break;
7121   h=link(h);
7122   if ( h==knots ) { 
7123     left_type(h)=end_cycle; break;
7124   }
7125 }
7126
7127 @ If |right_type(p)<given| and |q=link(p)|, we must have
7128 |right_type(p)=left_type(q)=explicit| or |endpoint|.
7129
7130 @<Fill in the control points between |p| and the next breakpoint...@>=
7131 q=link(p);
7132 if ( right_type(p)>=given ) { 
7133   while ( (left_type(q)==open)&&(right_type(q)==open) ) q=link(q);
7134   @<Fill in the control information between
7135     consecutive breakpoints |p| and |q|@>;
7136 } else if ( right_type(p)==endpoint ) {
7137   @<Give reasonable values for the unused control points between |p| and~|q|@>;
7138 }
7139 p=q
7140
7141 @ This step makes it possible to transform an explicitly computed path without
7142 checking the |left_type| and |right_type| fields.
7143
7144 @<Give reasonable values for the unused control points between |p| and~|q|@>=
7145
7146   right_x(p)=x_coord(p); right_y(p)=y_coord(p);
7147   left_x(q)=x_coord(q); left_y(q)=y_coord(q);
7148 }
7149
7150 @ Before we can go further into the way choices are made, we need to
7151 consider the underlying theory. The basic ideas implemented in |make_choices|
7152 are due to John Hobby, who introduced the notion of ``mock curvature''
7153 @^Hobby, John Douglas@>
7154 at a knot. Angles are chosen so that they preserve mock curvature when
7155 a knot is passed, and this has been found to produce excellent results.
7156
7157 It is convenient to introduce some notations that simplify the necessary
7158 formulas. Let $d_{k,k+1}=\vert z\k-z_k\vert$ be the (nonzero) distance
7159 between knots |k| and |k+1|; and let
7160 $${z\k-z_k\over z_k-z_{k-1}}={d_{k,k+1}\over d_{k-1,k}}e^{i\psi_k}$$
7161 so that a polygonal line from $z_{k-1}$ to $z_k$ to $z\k$ turns left
7162 through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$.
7163 The control points for the spline from $z_k$ to $z\k$ will be denoted by
7164 $$\eqalign{z_k^+&=z_k+
7165   \textstyle{1\over3}\rho_k e^{i\theta_k}(z\k-z_k),\cr
7166  z\k^-&=z\k-
7167   \textstyle{1\over3}\sigma\k e^{-i\phi\k}(z\k-z_k),\cr}$$
7168 where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the
7169 beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the
7170 corresponding ``offset angles.'' These angles satisfy the condition
7171 $$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$
7172 whenever the curve leaves an intermediate knot~|k| in the direction that
7173 it enters.
7174
7175 @ Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of
7176 the curve at its beginning and ending points. This means that
7177 $\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$,
7178 where $f(\theta,\phi)$ is \MP's standard velocity function defined in
7179 the |velocity| subroutine. The cubic spline $B(z_k^{\phantom+},z_k^+,
7180 z\k^-,z\k^{\phantom+};t)$
7181 has curvature
7182 @^curvature@>
7183 $${2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_{k,k+1}}
7184 \qquad{\rm and}\qquad
7185 {2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_{k,k+1}}$$
7186 at |t=0| and |t=1|, respectively. The mock curvature is the linear
7187 @^mock curvature@>
7188 approximation to this true curvature that arises in the limit for
7189 small $\theta_k$ and~$\phi\k$, if second-order terms are discarded.
7190 The standard velocity function satisfies
7191 $$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$
7192 hence the mock curvatures are respectively
7193 $${2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_{k,k+1}}
7194 \qquad{\rm and}\qquad
7195 {2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_{k,k+1}}.\eqno(**)$$
7196
7197 @ The turning angles $\psi_k$ are given, and equation $(*)$ above
7198 determines $\phi_k$ when $\theta_k$ is known, so the task of
7199 angle selection is essentially to choose appropriate values for each
7200 $\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables
7201 from $(**)$, we obtain a system of linear equations of the form
7202 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7203 where
7204 $$A_k={\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7205 \qquad B_k={3-\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7206 \qquad C_k={3-\beta\k\over\alpha_k^2d_{k,k+1}},
7207 \qquad D_k={\beta\k\over\alpha_k^2d_{k,k+1}}.$$
7208 The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$
7209 will be at most $4\over3$. It follows that $B_k\G{5\over4}A_k$ and
7210 $C_k\G{5\over4}D_k$; hence the equations are diagonally dominant;
7211 hence they have a unique solution. Moreover, in most cases the tensions
7212 are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the
7213 solution numerically stable, and there is an exponential damping
7214 effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by
7215 a factor of~$O(2^{-j})$.
7216
7217 @ However, we still must consider the angles at the starting and ending
7218 knots of a non-cyclic path. These angles might be given explicitly, or
7219 they might be specified implicitly in terms of an amount of ``curl.''
7220
7221 Let's assume that angles need to be determined for a non-cyclic path
7222 starting at $z_0$ and ending at~$z_n$. Then equations of the form
7223 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta_{k+1}=R_k$$
7224 have been given for $0<k<n$, and it will be convenient to introduce
7225 equations of the same form for $k=0$ and $k=n$, where
7226 $$A_0=B_0=C_n=D_n=0.$$
7227 If $\theta_0$ is supposed to have a given value $E_0$, we simply
7228 define $C_0=0$, $D_0=0$, and $R_0=E_0$. Otherwise a curl
7229 parameter, $\gamma_0$, has been specified at~$z_0$; this means
7230 that the mock curvature at $z_0$ should be $\gamma_0$ times the
7231 mock curvature at $z_1$; i.e.,
7232 $${2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_{01}}
7233 =\gamma_0{2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_{01}}.$$
7234 This equation simplifies to
7235 $$(\alpha_0\chi_0+3-\beta_1)\theta_0+
7236  \bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1=
7237  -\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$
7238 where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0=
7239 \chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$.
7240 It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$,
7241 hence the linear equations remain nonsingular.
7242
7243 Similar considerations apply at the right end, when the final angle $\phi_n$
7244 may or may not need to be determined. It is convenient to let $\psi_n=0$,
7245 hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$,
7246 or we have
7247 $$\bigl((3-\beta_n)\chi_n+\alpha_{n-1}\bigr)\theta_{n-1}+
7248 (\beta_n\chi_n+3-\alpha_{n-1})\theta_n=0,\qquad
7249   \chi_n={\beta_n^2\gamma_n\over\alpha_{n-1}^2}.$$
7250
7251 When |make_choices| chooses angles, it must compute the coefficients of
7252 these linear equations, then solve the equations. To compute the coefficients,
7253 it is necessary to compute arctangents of the given turning angles~$\psi_k$.
7254 When the equations are solved, the chosen directions $\theta_k$ are put
7255 back into the form of control points by essentially computing sines and
7256 cosines.
7257
7258 @ OK, we are ready to make the hard choices of |make_choices|.
7259 Most of the work is relegated to an auxiliary procedure
7260 called |solve_choices|, which has been introduced to keep
7261 |make_choices| from being extremely long.
7262
7263 @<Fill in the control information between...@>=
7264 @<Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$;
7265   set $n$ to the length of the path@>;
7266 @<Remove |open| types at the breakpoints@>;
7267 mp_solve_choices(mp, p,q,n)
7268
7269 @ It's convenient to precompute quantities that will be needed several
7270 times later. The values of |delta_x[k]| and |delta_y[k]| will be the
7271 coordinates of $z\k-z_k$, and the magnitude of this vector will be
7272 |delta[k]=@t$d_{k,k+1}$@>|. The path angle $\psi_k$ between $z_k-z_{k-1}$
7273 and $z\k-z_k$ will be stored in |psi[k]|.
7274
7275 @<Glob...@>=
7276 int path_size; /* maximum number of knots between breakpoints of a path */
7277 scaled *delta_x;
7278 scaled *delta_y;
7279 scaled *delta; /* knot differences */
7280 angle  *psi; /* turning angles */
7281
7282 @ @<Allocate or initialize ...@>=
7283 mp->delta_x = NULL;
7284 mp->delta_y = NULL;
7285 mp->delta = NULL;
7286 mp->psi = NULL;
7287
7288 @ @<Dealloc variables@>=
7289 xfree(mp->delta_x);
7290 xfree(mp->delta_y);
7291 xfree(mp->delta);
7292 xfree(mp->psi);
7293
7294 @ @<Other local variables for |make_choices|@>=
7295   int k,n; /* current and final knot numbers */
7296   pointer s,t; /* registers for list traversal */
7297   scaled delx,dely; /* directions where |open| meets |explicit| */
7298   fraction sine,cosine; /* trig functions of various angles */
7299
7300 @ @<Calculate the turning angles...@>=
7301 {
7302 RESTART:
7303   k=0; s=p; n=mp->path_size;
7304   do {  
7305     t=link(s);
7306     mp->delta_x[k]=x_coord(t)-x_coord(s);
7307     mp->delta_y[k]=y_coord(t)-y_coord(s);
7308     mp->delta[k]=mp_pyth_add(mp, mp->delta_x[k],mp->delta_y[k]);
7309     if ( k>0 ) { 
7310       sine=mp_make_fraction(mp, mp->delta_y[k-1],mp->delta[k-1]);
7311       cosine=mp_make_fraction(mp, mp->delta_x[k-1],mp->delta[k-1]);
7312       mp->psi[k]=mp_n_arg(mp, mp_take_fraction(mp, mp->delta_x[k],cosine)+
7313         mp_take_fraction(mp, mp->delta_y[k],sine),
7314         mp_take_fraction(mp, mp->delta_y[k],cosine)-
7315           mp_take_fraction(mp, mp->delta_x[k],sine));
7316     }
7317     incr(k); s=t;
7318     if ( k==mp->path_size ) {
7319       mp_reallocate_paths(mp, mp->path_size+(mp->path_size>>2));
7320       goto RESTART; /* retry, loop size has changed */
7321     }
7322     if ( s==q ) n=k;
7323   } while (! (k>=n)&&(left_type(s)!=end_cycle));
7324   if ( k==n ) mp->psi[n]=0; else mp->psi[k]=mp->psi[1];
7325 }
7326
7327 @ When we get to this point of the code, |right_type(p)| is either
7328 |given| or |curl| or |open|. If it is |open|, we must have
7329 |left_type(p)=end_cycle| or |left_type(p)=explicit|. In the latter
7330 case, the |open| type is converted to |given|; however, if the
7331 velocity coming into this knot is zero, the |open| type is
7332 converted to a |curl|, since we don't know the incoming direction.
7333
7334 Similarly, |left_type(q)| is either |given| or |curl| or |open| or
7335 |end_cycle|. The |open| possibility is reduced either to |given| or to |curl|.
7336
7337 @<Remove |open| types at the breakpoints@>=
7338 if ( left_type(q)==open ) { 
7339   delx=right_x(q)-x_coord(q); dely=right_y(q)-y_coord(q);
7340   if ( (delx==0)&&(dely==0) ) { 
7341     left_type(q)=curl; left_curl(q)=unity;
7342   } else { 
7343     left_type(q)=given; left_given(q)=mp_n_arg(mp, delx,dely);
7344   }
7345 }
7346 if ( (right_type(p)==open)&&(left_type(p)==explicit) ) { 
7347   delx=x_coord(p)-left_x(p); dely=y_coord(p)-left_y(p);
7348   if ( (delx==0)&&(dely==0) ) { 
7349     right_type(p)=curl; right_curl(p)=unity;
7350   } else { 
7351     right_type(p)=given; right_given(p)=mp_n_arg(mp, delx,dely);
7352   }
7353 }
7354
7355 @ Linear equations need to be solved whenever |n>1|; and also when |n=1|
7356 and exactly one of the breakpoints involves a curl. The simplest case occurs
7357 when |n=1| and there is a curl at both breakpoints; then we simply draw
7358 a straight line.
7359
7360 But before coding up the simple cases, we might as well face the general case,
7361 since we must deal with it sooner or later, and since the general case
7362 is likely to give some insight into the way simple cases can be handled best.
7363
7364 When there is no cycle, the linear equations to be solved form a tridiagonal
7365 system, and we can apply the standard technique of Gaussian elimination
7366 to convert that system to a sequence of equations of the form
7367 $$\theta_0+u_0\theta_1=v_0,\quad
7368 \theta_1+u_1\theta_2=v_1,\quad\ldots,\quad
7369 \theta_{n-1}+u_{n-1}\theta_n=v_{n-1},\quad
7370 \theta_n=v_n.$$
7371 It is possible to do this diagonalization while generating the equations.
7372 Once $\theta_n$ is known, it is easy to determine $\theta_{n-1}$, \dots,
7373 $\theta_1$, $\theta_0$; thus, the equations will be solved.
7374
7375 The procedure is slightly more complex when there is a cycle, but the
7376 basic idea will be nearly the same. In the cyclic case the right-hand
7377 sides will be $v_k+w_k\theta_0$ instead of simply $v_k$, and we will start
7378 the process off with $u_0=v_0=0$, $w_0=1$. The final equation will be not
7379 $\theta_n=v_n$ but $\theta_n+u_n\theta_1=v_n+w_n\theta_0$; an appropriate
7380 ending routine will take account of the fact that $\theta_n=\theta_0$ and
7381 eliminate the $w$'s from the system, after which the solution can be
7382 obtained as before.
7383
7384 When $u_k$, $v_k$, and $w_k$ are being computed, the three pointer
7385 variables |r|, |s|,~|t| will point respectively to knots |k-1|, |k|,
7386 and~|k+1|. The $u$'s and $w$'s are scaled by $2^{28}$, i.e., they are
7387 of type |fraction|; the $\theta$'s and $v$'s are of type |angle|.
7388
7389 @<Glob...@>=
7390 angle *theta; /* values of $\theta_k$ */
7391 fraction *uu; /* values of $u_k$ */
7392 angle *vv; /* values of $v_k$ */
7393 fraction *ww; /* values of $w_k$ */
7394
7395 @ @<Allocate or initialize ...@>=
7396 mp->theta = NULL;
7397 mp->uu = NULL;
7398 mp->vv = NULL;
7399 mp->ww = NULL;
7400
7401 @ @<Dealloc variables@>=
7402 xfree(mp->theta);
7403 xfree(mp->uu);
7404 xfree(mp->vv);
7405 xfree(mp->ww);
7406
7407 @ @<Declare |mp_reallocate| functions@>=
7408 void mp_reallocate_paths (MP mp, int l);
7409
7410 @ @c
7411 void mp_reallocate_paths (MP mp, int l) {
7412   XREALLOC (mp->delta_x, l, scaled);
7413   XREALLOC (mp->delta_y, l, scaled);
7414   XREALLOC (mp->delta,   l, scaled);
7415   XREALLOC (mp->psi,     l, angle);
7416   XREALLOC (mp->theta,   l, angle);
7417   XREALLOC (mp->uu,      l, fraction);
7418   XREALLOC (mp->vv,      l, angle);
7419   XREALLOC (mp->ww,      l, fraction);
7420   mp->path_size = l;
7421 }
7422
7423 @ Our immediate problem is to get the ball rolling by setting up the
7424 first equation or by realizing that no equations are needed, and to fit
7425 this initialization into a framework suitable for the overall computation.
7426
7427 @<Declare the procedure called |solve_choices|@>=
7428 @<Declare subroutines needed by |solve_choices|@>;
7429 void mp_solve_choices (MP mp,pointer p, pointer q, halfword n) {
7430   int k; /* current knot number */
7431   pointer r,s,t; /* registers for list traversal */
7432   @<Other local variables for |solve_choices|@>;
7433   k=0; s=p; r=0;
7434   while (1) { 
7435     t=link(s);
7436     if ( k==0 ) {
7437       @<Get the linear equations started; or |return|
7438         with the control points in place, if linear equations
7439         needn't be solved@>
7440     } else  { 
7441       switch (left_type(s)) {
7442       case end_cycle: case open:
7443         @<Set up equation to match mock curvatures
7444           at $z_k$; then |goto found| with $\theta_n$
7445           adjusted to equal $\theta_0$, if a cycle has ended@>;
7446         break;
7447       case curl:
7448         @<Set up equation for a curl at $\theta_n$
7449           and |goto found|@>;
7450         break;
7451       case given:
7452         @<Calculate the given value of $\theta_n$
7453           and |goto found|@>;
7454         break;
7455       } /* there are no other cases */
7456     }
7457     r=s; s=t; incr(k);
7458   }
7459 FOUND:
7460   @<Finish choosing angles and assigning control points@>;
7461 }
7462
7463 @ On the first time through the loop, we have |k=0| and |r| is not yet
7464 defined. The first linear equation, if any, will have $A_0=B_0=0$.
7465
7466 @<Get the linear equations started...@>=
7467 switch (right_type(s)) {
7468 case given: 
7469   if ( left_type(t)==given ) {
7470     @<Reduce to simple case of two givens  and |return|@>
7471   } else {
7472     @<Set up the equation for a given value of $\theta_0$@>;
7473   }
7474   break;
7475 case curl: 
7476   if ( left_type(t)==curl ) {
7477     @<Reduce to simple case of straight line and |return|@>
7478   } else {
7479     @<Set up the equation for a curl at $\theta_0$@>;
7480   }
7481   break;
7482 case open: 
7483   mp->uu[0]=0; mp->vv[0]=0; mp->ww[0]=fraction_one;
7484   /* this begins a cycle */
7485   break;
7486 } /* there are no other cases */
7487
7488 @ The general equation that specifies equality of mock curvature at $z_k$ is
7489 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7490 as derived above. We want to combine this with the already-derived equation
7491 $\theta_{k-1}+u_{k-1}\theta_k=v_{k-1}+w_{k-1}\theta_0$ in order to obtain
7492 a new equation
7493 $\theta_k+u_k\theta\k=v_k+w_k\theta_0$. This can be done by dividing the
7494 equation
7495 $$(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}
7496     -A_kw_{k-1}\theta_0$$
7497 by $B_k-u_{k-1}A_k+C_k$. The trick is to do this carefully with
7498 fixed-point arithmetic, avoiding the chance of overflow while retaining
7499 suitable precision.
7500
7501 The calculations will be performed in several registers that
7502 provide temporary storage for intermediate quantities.
7503
7504 @<Other local variables for |solve_choices|@>=
7505 fraction aa,bb,cc,ff,acc; /* temporary registers */
7506 scaled dd,ee; /* likewise, but |scaled| */
7507 scaled lt,rt; /* tension values */
7508
7509 @ @<Set up equation to match mock curvatures...@>=
7510 { @<Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$,
7511     $\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$,
7512     and $\\{cc}=(B_k-u_{k-1}A_k)/B_k$@>;
7513   @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>;
7514   mp->uu[k]=mp_take_fraction(mp, ff,bb);
7515   @<Calculate the values of $v_k$ and $w_k$@>;
7516   if ( left_type(s)==end_cycle ) {
7517     @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>;
7518   }
7519 }
7520
7521 @ Since tension values are never less than 3/4, the values |aa| and
7522 |bb| computed here are never more than 4/5.
7523
7524 @<Calculate the values $\\{aa}=...@>=
7525 if ( abs(right_tension(r))==unity) { 
7526   aa=fraction_half; dd=2*mp->delta[k];
7527 } else { 
7528   aa=mp_make_fraction(mp, unity,3*abs(right_tension(r))-unity);
7529   dd=mp_take_fraction(mp, mp->delta[k],
7530     fraction_three-mp_make_fraction(mp, unity,abs(right_tension(r))));
7531 }
7532 if ( abs(left_tension(t))==unity ){ 
7533   bb=fraction_half; ee=2*mp->delta[k-1];
7534 } else { 
7535   bb=mp_make_fraction(mp, unity,3*abs(left_tension(t))-unity);
7536   ee=mp_take_fraction(mp, mp->delta[k-1],
7537     fraction_three-mp_make_fraction(mp, unity,abs(left_tension(t))));
7538 }
7539 cc=fraction_one-mp_take_fraction(mp, mp->uu[k-1],aa)
7540
7541 @ The ratio to be calculated in this step can be written in the form
7542 $$\beta_k^2\cdot\\{ee}\over\beta_k^2\cdot\\{ee}+\alpha_k^2\cdot
7543   \\{cc}\cdot\\{dd},$$
7544 because of the quantities just calculated. The values of |dd| and |ee|
7545 will not be needed after this step has been performed.
7546
7547 @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>=
7548 dd=mp_take_fraction(mp, dd,cc); lt=abs(left_tension(s)); rt=abs(right_tension(s));
7549 if ( lt!=rt ) { /* $\beta_k^{-1}\ne\alpha_k^{-1}$ */
7550   if ( lt<rt ) { 
7551     ff=mp_make_fraction(mp, lt,rt);
7552     ff=mp_take_fraction(mp, ff,ff); /* $\alpha_k^2/\beta_k^2$ */
7553     dd=mp_take_fraction(mp, dd,ff);
7554   } else { 
7555     ff=mp_make_fraction(mp, rt,lt);
7556     ff=mp_take_fraction(mp, ff,ff); /* $\beta_k^2/\alpha_k^2$ */
7557     ee=mp_take_fraction(mp, ee,ff);
7558   }
7559 }
7560 ff=mp_make_fraction(mp, ee,ee+dd)
7561
7562 @ The value of $u_{k-1}$ will be |<=1| except when $k=1$ and the previous
7563 equation was specified by a curl. In that case we must use a special
7564 method of computation to prevent overflow.
7565
7566 Fortunately, the calculations turn out to be even simpler in this ``hard''
7567 case. The curl equation makes $w_0=0$ and $v_0=-u_0\psi_1$, hence
7568 $-B_1\psi_1-A_1v_0=-(B_1-u_0A_1)\psi_1=-\\{cc}\cdot B_1\psi_1$.
7569
7570 @<Calculate the values of $v_k$ and $w_k$@>=
7571 acc=-mp_take_fraction(mp, mp->psi[k+1],mp->uu[k]);
7572 if ( right_type(r)==curl ) { 
7573   mp->ww[k]=0;
7574   mp->vv[k]=acc-mp_take_fraction(mp, mp->psi[1],fraction_one-ff);
7575 } else { 
7576   ff=mp_make_fraction(mp, fraction_one-ff,cc); /* this is
7577     $B_k/(C_k+B_k-u_{k-1}A_k)<5$ */
7578   acc=acc-mp_take_fraction(mp, mp->psi[k],ff);
7579   ff=mp_take_fraction(mp, ff,aa); /* this is $A_k/(C_k+B_k-u_{k-1}A_k)$ */
7580   mp->vv[k]=acc-mp_take_fraction(mp, mp->vv[k-1],ff);
7581   if ( mp->ww[k-1]==0 ) mp->ww[k]=0;
7582   else mp->ww[k]=-mp_take_fraction(mp, mp->ww[k-1],ff);
7583 }
7584
7585 @ When a complete cycle has been traversed, we have $\theta_k+u_k\theta\k=
7586 v_k+w_k\theta_0$, for |1<=k<=n|. We would like to determine the value of
7587 $\theta_n$ and reduce the system to the form $\theta_k+u_k\theta\k=v_k$
7588 for |0<=k<n|, so that the cyclic case can be finished up just as if there
7589 were no cycle.
7590
7591 The idea in the following code is to observe that
7592 $$\eqalign{\theta_n&=v_n+w_n\theta_0-u_n\theta_1=\cdots\cr
7593 &=v_n+w_n\theta_0-u_n\bigl(v_1+w_1\theta_0-u_1(v_2+\cdots
7594   -u_{n-2}(v_{n-1}+w_{n-1}\theta_0-u_{n-1}\theta_0))\bigr),\cr}$$
7595 so we can solve for $\theta_n=\theta_0$.
7596
7597 @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>=
7598
7599 aa=0; bb=fraction_one; /* we have |k=n| */
7600 do {  decr(k);
7601 if ( k==0 ) k=n;
7602   aa=mp->vv[k]-mp_take_fraction(mp, aa,mp->uu[k]);
7603   bb=mp->ww[k]-mp_take_fraction(mp, bb,mp->uu[k]);
7604 } while (k!=n); /* now $\theta_n=\\{aa}+\\{bb}\cdot\theta_n$ */
7605 aa=mp_make_fraction(mp, aa,fraction_one-bb);
7606 mp->theta[n]=aa; mp->vv[0]=aa;
7607 for (k=1;k<=n-1;k++) {
7608   mp->vv[k]=mp->vv[k]+mp_take_fraction(mp, aa,mp->ww[k]);
7609 }
7610 goto FOUND;
7611 }
7612
7613 @ @d reduce_angle(A) if ( abs((A))>one_eighty_deg ) {
7614   if ( (A)>0 ) (A)=(A)-three_sixty_deg; else (A)=(A)+three_sixty_deg; }
7615
7616 @<Calculate the given value of $\theta_n$...@>=
7617
7618   mp->theta[n]=left_given(s)-mp_n_arg(mp, mp->delta_x[n-1],mp->delta_y[n-1]);
7619   reduce_angle(mp->theta[n]);
7620   goto FOUND;
7621 }
7622
7623 @ @<Set up the equation for a given value of $\theta_0$@>=
7624
7625   mp->vv[0]=right_given(s)-mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7626   reduce_angle(mp->vv[0]);
7627   mp->uu[0]=0; mp->ww[0]=0;
7628 }
7629
7630 @ @<Set up the equation for a curl at $\theta_0$@>=
7631 { cc=right_curl(s); lt=abs(left_tension(t)); rt=abs(right_tension(s));
7632   if ( (rt==unity)&&(lt==unity) )
7633     mp->uu[0]=mp_make_fraction(mp, cc+cc+unity,cc+two);
7634   else 
7635     mp->uu[0]=mp_curl_ratio(mp, cc,rt,lt);
7636   mp->vv[0]=-mp_take_fraction(mp, mp->psi[1],mp->uu[0]); mp->ww[0]=0;
7637 }
7638
7639 @ @<Set up equation for a curl at $\theta_n$...@>=
7640 { cc=left_curl(s); lt=abs(left_tension(s)); rt=abs(right_tension(r));
7641   if ( (rt==unity)&&(lt==unity) )
7642     ff=mp_make_fraction(mp, cc+cc+unity,cc+two);
7643   else 
7644     ff=mp_curl_ratio(mp, cc,lt,rt);
7645   mp->theta[n]=-mp_make_fraction(mp, mp_take_fraction(mp, mp->vv[n-1],ff),
7646     fraction_one-mp_take_fraction(mp, ff,mp->uu[n-1]));
7647   goto FOUND;
7648 }
7649
7650 @ The |curl_ratio| subroutine has three arguments, which our previous notation
7651 encourages us to call $\gamma$, $\alpha^{-1}$, and $\beta^{-1}$. It is
7652 a somewhat tedious program to calculate
7653 $${(3-\alpha)\alpha^2\gamma+\beta^3\over
7654   \alpha^3\gamma+(3-\beta)\beta^2},$$
7655 with the result reduced to 4 if it exceeds 4. (This reduction of curl
7656 is necessary only if the curl and tension are both large.)
7657 The values of $\alpha$ and $\beta$ will be at most~4/3.
7658
7659 @<Declare subroutines needed by |solve_choices|@>=
7660 fraction mp_curl_ratio (MP mp,scaled gamma, scaled a_tension, 
7661                         scaled b_tension) {
7662   fraction alpha,beta,num,denom,ff; /* registers */
7663   alpha=mp_make_fraction(mp, unity,a_tension);
7664   beta=mp_make_fraction(mp, unity,b_tension);
7665   if ( alpha<=beta ) {
7666     ff=mp_make_fraction(mp, alpha,beta); ff=mp_take_fraction(mp, ff,ff);
7667     gamma=mp_take_fraction(mp, gamma,ff);
7668     beta=beta / 010000; /* convert |fraction| to |scaled| */
7669     denom=mp_take_fraction(mp, gamma,alpha)+three-beta;
7670     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7671   } else { 
7672     ff=mp_make_fraction(mp, beta,alpha); ff=mp_take_fraction(mp, ff,ff);
7673     beta=mp_take_fraction(mp, beta,ff) / 010000; /* convert |fraction| to |scaled| */
7674     denom=mp_take_fraction(mp, gamma,alpha)+(ff / 1365)-beta;
7675       /* $1365\approx 2^{12}/3$ */
7676     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7677   }
7678   if ( num>=denom+denom+denom+denom ) return fraction_four;
7679   else return mp_make_fraction(mp, num,denom);
7680 }
7681
7682 @ We're in the home stretch now.
7683
7684 @<Finish choosing angles and assigning control points@>=
7685 for (k=n-1;k>=0;k--) {
7686   mp->theta[k]=mp->vv[k]-mp_take_fraction(mp,mp->theta[k+1],mp->uu[k]);
7687 }
7688 s=p; k=0;
7689 do {  
7690   t=link(s);
7691   mp_n_sin_cos(mp, mp->theta[k]); mp->st=mp->n_sin; mp->ct=mp->n_cos;
7692   mp_n_sin_cos(mp, -mp->psi[k+1]-mp->theta[k+1]); mp->sf=mp->n_sin; mp->cf=mp->n_cos;
7693   mp_set_controls(mp, s,t,k);
7694   incr(k); s=t;
7695 } while (k!=n)
7696
7697 @ The |set_controls| routine actually puts the control points into
7698 a pair of consecutive nodes |p| and~|q|. Global variables are used to
7699 record the values of $\sin\theta$, $\cos\theta$, $\sin\phi$, and
7700 $\cos\phi$ needed in this calculation.
7701
7702 @<Glob...@>=
7703 fraction st;
7704 fraction ct;
7705 fraction sf;
7706 fraction cf; /* sines and cosines */
7707
7708 @ @<Declare subroutines needed by |solve_choices|@>=
7709 void mp_set_controls (MP mp,pointer p, pointer q, integer k) {
7710   fraction rr,ss; /* velocities, divided by thrice the tension */
7711   scaled lt,rt; /* tensions */
7712   fraction sine; /* $\sin(\theta+\phi)$ */
7713   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7714   rr=mp_velocity(mp, mp->st,mp->ct,mp->sf,mp->cf,rt);
7715   ss=mp_velocity(mp, mp->sf,mp->cf,mp->st,mp->ct,lt);
7716   if ( (right_tension(p)<0)||(left_tension(q)<0) ) {
7717     @<Decrease the velocities,
7718       if necessary, to stay inside the bounding triangle@>;
7719   }
7720   right_x(p)=x_coord(p)+mp_take_fraction(mp, 
7721                           mp_take_fraction(mp, mp->delta_x[k],mp->ct)-
7722                           mp_take_fraction(mp, mp->delta_y[k],mp->st),rr);
7723   right_y(p)=y_coord(p)+mp_take_fraction(mp, 
7724                           mp_take_fraction(mp, mp->delta_y[k],mp->ct)+
7725                           mp_take_fraction(mp, mp->delta_x[k],mp->st),rr);
7726   left_x(q)=x_coord(q)-mp_take_fraction(mp, 
7727                          mp_take_fraction(mp, mp->delta_x[k],mp->cf)+
7728                          mp_take_fraction(mp, mp->delta_y[k],mp->sf),ss);
7729   left_y(q)=y_coord(q)-mp_take_fraction(mp, 
7730                          mp_take_fraction(mp, mp->delta_y[k],mp->cf)-
7731                          mp_take_fraction(mp, mp->delta_x[k],mp->sf),ss);
7732   right_type(p)=explicit; left_type(q)=explicit;
7733 }
7734
7735 @ The boundedness conditions $\\{rr}\L\sin\phi\,/\sin(\theta+\phi)$ and
7736 $\\{ss}\L\sin\theta\,/\sin(\theta+\phi)$ are to be enforced if $\sin\theta$,
7737 $\sin\phi$, and $\sin(\theta+\phi)$ all have the same sign. Otherwise
7738 there is no ``bounding triangle.''
7739 @:at_least_}{\&{atleast} primitive@>
7740
7741 @<Decrease the velocities, if necessary...@>=
7742 if (((mp->st>=0)&&(mp->sf>=0))||((mp->st<=0)&&(mp->sf<=0)) ) {
7743   sine=mp_take_fraction(mp, abs(mp->st),mp->cf)+
7744                             mp_take_fraction(mp, abs(mp->sf),mp->ct);
7745   if ( sine>0 ) {
7746     sine=mp_take_fraction(mp, sine,fraction_one+unity); /* safety factor */
7747     if ( right_tension(p)<0 )
7748      if ( mp_ab_vs_cd(mp, abs(mp->sf),fraction_one,rr,sine)<0 )
7749       rr=mp_make_fraction(mp, abs(mp->sf),sine);
7750     if ( left_tension(q)<0 )
7751      if ( mp_ab_vs_cd(mp, abs(mp->st),fraction_one,ss,sine)<0 )
7752       ss=mp_make_fraction(mp, abs(mp->st),sine);
7753   }
7754 }
7755
7756 @ Only the simple cases remain to be handled.
7757
7758 @<Reduce to simple case of two givens and |return|@>=
7759
7760   aa=mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7761   mp_n_sin_cos(mp, right_given(p)-aa); mp->ct=mp->n_cos; mp->st=mp->n_sin;
7762   mp_n_sin_cos(mp, left_given(q)-aa); mp->cf=mp->n_cos; mp->sf=-mp->n_sin;
7763   mp_set_controls(mp, p,q,0); return;
7764 }
7765
7766 @ @<Reduce to simple case of straight line and |return|@>=
7767
7768   right_type(p)=explicit; left_type(q)=explicit;
7769   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7770   if ( rt==unity ) {
7771     if ( mp->delta_x[0]>=0 ) right_x(p)=x_coord(p)+((mp->delta_x[0]+1) / 3);
7772     else right_x(p)=x_coord(p)+((mp->delta_x[0]-1) / 3);
7773     if ( mp->delta_y[0]>=0 ) right_y(p)=y_coord(p)+((mp->delta_y[0]+1) / 3);
7774     else right_y(p)=y_coord(p)+((mp->delta_y[0]-1) / 3);
7775   } else { 
7776     ff=mp_make_fraction(mp, unity,3*rt); /* $\alpha/3$ */
7777     right_x(p)=x_coord(p)+mp_take_fraction(mp, mp->delta_x[0],ff);
7778     right_y(p)=y_coord(p)+mp_take_fraction(mp, mp->delta_y[0],ff);
7779   }
7780   if ( lt==unity ) {
7781     if ( mp->delta_x[0]>=0 ) left_x(q)=x_coord(q)-((mp->delta_x[0]+1) / 3);
7782     else left_x(q)=x_coord(q)-((mp->delta_x[0]-1) / 3);
7783     if ( mp->delta_y[0]>=0 ) left_y(q)=y_coord(q)-((mp->delta_y[0]+1) / 3);
7784     else left_y(q)=y_coord(q)-((mp->delta_y[0]-1) / 3);
7785   } else  { 
7786     ff=mp_make_fraction(mp, unity,3*lt); /* $\beta/3$ */
7787     left_x(q)=x_coord(q)-mp_take_fraction(mp, mp->delta_x[0],ff);
7788     left_y(q)=y_coord(q)-mp_take_fraction(mp, mp->delta_y[0],ff);
7789   }
7790   return;
7791 }
7792
7793 @* \[19] Measuring paths.
7794 \MP's \&{llcorner}, \&{lrcorner}, \&{ulcorner}, and \&{urcorner} operators
7795 allow the user to measure the bounding box of anything that can go into a
7796 picture.  It's easy to get rough bounds on the $x$ and $y$ extent of a path
7797 by just finding the bounding box of the knots and the control points. We
7798 need a more accurate version of the bounding box, but we can still use the
7799 easy estimate to save time by focusing on the interesting parts of the path.
7800
7801 @ Computing an accurate bounding box involves a theme that will come up again
7802 and again. Given a Bernshte{\u\i}n polynomial
7803 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
7804 $$B(z_0,z_1,\ldots,z_n;t)=\sum_k{n\choose k}t^k(1-t)^{n-k}z_k,$$
7805 we can conveniently bisect its range as follows:
7806
7807 \smallskip
7808 \textindent{1)} Let $z_k^{(0)}=z_k$, for |0<=k<=n|.
7809
7810 \smallskip
7811 \textindent{2)} Let $z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$, for
7812 |0<=k<n-j|, for |0<=j<n|.
7813
7814 \smallskip\noindent
7815 Then
7816 $$B(z_0,z_1,\ldots,z_n;t)=B(z_0^{(0)},z_0^{(1)},\ldots,z_0^{(n)};2t)
7817  =B(z_0^{(n)},z_1^{(n-1)},\ldots,z_n^{(0)};2t-1).$$
7818 This formula gives us the coefficients of polynomials to use over the ranges
7819 $0\L t\L{1\over2}$ and ${1\over2}\L t\L1$.
7820
7821 @ Now here's a subroutine that's handy for all sorts of path computations:
7822 Given a quadratic polynomial $B(a,b,c;t)$, the |crossing_point| function
7823 returns the unique |fraction| value |t| between 0 and~1 at which
7824 $B(a,b,c;t)$ changes from positive to negative, or returns
7825 |t=fraction_one+1| if no such value exists. If |a<0| (so that $B(a,b,c;t)$
7826 is already negative at |t=0|), |crossing_point| returns the value zero.
7827
7828 @d no_crossing {  return (fraction_one+1); }
7829 @d one_crossing { return fraction_one; }
7830 @d zero_crossing { return 0; }
7831 @d mp_crossing_point(M,A,B,C) mp_do_crossing_point(A,B,C)
7832
7833 @c fraction mp_do_crossing_point (integer a, integer b, integer c) {
7834   integer d; /* recursive counter */
7835   integer x,xx,x0,x1,x2; /* temporary registers for bisection */
7836   if ( a<0 ) zero_crossing;
7837   if ( c>=0 ) { 
7838     if ( b>=0 ) {
7839       if ( c>0 ) { no_crossing; }
7840       else if ( (a==0)&&(b==0) ) { no_crossing;} 
7841       else { one_crossing; } 
7842     }
7843     if ( a==0 ) zero_crossing;
7844   } else if ( a==0 ) {
7845     if ( b<=0 ) zero_crossing;
7846   }
7847   @<Use bisection to find the crossing point, if one exists@>;
7848 }
7849
7850 @ The general bisection method is quite simple when $n=2$, hence
7851 |crossing_point| does not take much time. At each stage in the
7852 recursion we have a subinterval defined by |l| and~|j| such that
7853 $B(a,b,c;2^{-l}(j+t))=B(x_0,x_1,x_2;t)$, and we want to ``zero in'' on
7854 the subinterval where $x_0\G0$ and $\min(x_1,x_2)<0$.
7855
7856 It is convenient for purposes of calculation to combine the values
7857 of |l| and~|j| in a single variable $d=2^l+j$, because the operation
7858 of bisection then corresponds simply to doubling $d$ and possibly
7859 adding~1. Furthermore it proves to be convenient to modify
7860 our previous conventions for bisection slightly, maintaining the
7861 variables $X_0=2^lx_0$, $X_1=2^l(x_0-x_1)$, and $X_2=2^l(x_1-x_2)$.
7862 With these variables the conditions $x_0\ge0$ and $\min(x_1,x_2)<0$ are
7863 equivalent to $\max(X_1,X_1+X_2)>X_0\ge0$.
7864
7865 The following code maintains the invariant relations
7866 $0\L|x0|<\max(|x1|,|x1|+|x2|)$,
7867 $\vert|x1|\vert<2^{30}$, $\vert|x2|\vert<2^{30}$;
7868 it has been constructed in such a way that no arithmetic overflow
7869 will occur if the inputs satisfy
7870 $a<2^{30}$, $\vert a-b\vert<2^{30}$, and $\vert b-c\vert<2^{30}$.
7871
7872 @<Use bisection to find the crossing point...@>=
7873 d=1; x0=a; x1=a-b; x2=b-c;
7874 do {  
7875   x=half(x1+x2);
7876   if ( x1-x0>x0 ) { 
7877     x2=x; x0+=x0; d+=d;  
7878   } else { 
7879     xx=x1+x-x0;
7880     if ( xx>x0 ) { 
7881       x2=x; x0+=x0; d+=d;
7882     }  else { 
7883       x0=x0-xx;
7884       if ( x<=x0 ) { if ( x+x2<=x0 ) no_crossing; }
7885       x1=x; d=d+d+1;
7886     }
7887   }
7888 } while (d<fraction_one);
7889 return (d-fraction_one)
7890
7891 @ Here is a routine that computes the $x$ or $y$ coordinate of the point on
7892 a cubic corresponding to the |fraction| value~|t|.
7893
7894 It is convenient to define a \.{WEB} macro |t_of_the_way| such that
7895 |t_of_the_way(a,b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|.
7896
7897 @d t_of_the_way(A,B) ((A)-mp_take_fraction(mp,(A)-(B),t))
7898
7899 @c scaled mp_eval_cubic (MP mp,pointer p, pointer q, fraction t) {
7900   scaled x1,x2,x3; /* intermediate values */
7901   x1=t_of_the_way(knot_coord(p),right_coord(p));
7902   x2=t_of_the_way(right_coord(p),left_coord(q));
7903   x3=t_of_the_way(left_coord(q),knot_coord(q));
7904   x1=t_of_the_way(x1,x2);
7905   x2=t_of_the_way(x2,x3);
7906   return t_of_the_way(x1,x2);
7907 }
7908
7909 @ The actual bounding box information is stored in global variables.
7910 Since it is convenient to address the $x$ and $y$ information
7911 separately, we define arrays indexed by |x_code..y_code| and use
7912 macros to give them more convenient names.
7913
7914 @<Types...@>=
7915 enum {
7916   mp_x_code=0, /* index for |minx| and |maxx| */
7917   mp_y_code /* index for |miny| and |maxy| */
7918 };
7919
7920
7921 @d minx mp->bbmin[mp_x_code]
7922 @d maxx mp->bbmax[mp_x_code]
7923 @d miny mp->bbmin[mp_y_code]
7924 @d maxy mp->bbmax[mp_y_code]
7925
7926 @<Glob...@>=
7927 scaled bbmin[mp_y_code+1];
7928 scaled bbmax[mp_y_code+1]; 
7929 /* the result of procedures that compute bounding box information */
7930
7931 @ Now we're ready for the key part of the bounding box computation.
7932 The |bound_cubic| procedure updates |bbmin[c]| and |bbmax[c]| based on
7933 $$B(\hbox{|knot_coord(p)|}, \hbox{|right_coord(p)|},
7934     \hbox{|left_coord(q)|}, \hbox{|knot_coord(q)|};t)
7935 $$
7936 for $0<t\le1$.  In other words, the procedure adjusts the bounds to
7937 accommodate |knot_coord(q)| and any extremes over the range $0<t<1$.
7938 The |c| parameter is |x_code| or |y_code|.
7939
7940 @c void mp_bound_cubic (MP mp,pointer p, pointer q, small_number c) {
7941   boolean wavy; /* whether we need to look for extremes */
7942   scaled del1,del2,del3,del,dmax; /* proportional to the control
7943      points of a quadratic derived from a cubic */
7944   fraction t,tt; /* where a quadratic crosses zero */
7945   scaled x; /* a value that |bbmin[c]| and |bbmax[c]| must accommodate */
7946   x=knot_coord(q);
7947   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
7948   @<Check the control points against the bounding box and set |wavy:=true|
7949     if any of them lie outside@>;
7950   if ( wavy ) {
7951     del1=right_coord(p)-knot_coord(p);
7952     del2=left_coord(q)-right_coord(p);
7953     del3=knot_coord(q)-left_coord(q);
7954     @<Scale up |del1|, |del2|, and |del3| for greater accuracy;
7955       also set |del| to the first nonzero element of |(del1,del2,del3)|@>;
7956     if ( del<0 ) {
7957       negate(del1); negate(del2); negate(del3);
7958     };
7959     t=mp_crossing_point(mp, del1,del2,del3);
7960     if ( t<fraction_one ) {
7961       @<Test the extremes of the cubic against the bounding box@>;
7962     }
7963   }
7964 }
7965
7966 @ @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>=
7967 if ( x<mp->bbmin[c] ) mp->bbmin[c]=x;
7968 if ( x>mp->bbmax[c] ) mp->bbmax[c]=x
7969
7970 @ @<Check the control points against the bounding box and set...@>=
7971 wavy=true;
7972 if ( mp->bbmin[c]<=right_coord(p) )
7973   if ( right_coord(p)<=mp->bbmax[c] )
7974     if ( mp->bbmin[c]<=left_coord(q) )
7975       if ( left_coord(q)<=mp->bbmax[c] )
7976         wavy=false
7977
7978 @ If |del1=del2=del3=0|, it's impossible to obey the title of this
7979 section. We just set |del=0| in that case.
7980
7981 @<Scale up |del1|, |del2|, and |del3| for greater accuracy...@>=
7982 if ( del1!=0 ) del=del1;
7983 else if ( del2!=0 ) del=del2;
7984 else del=del3;
7985 if ( del!=0 ) {
7986   dmax=abs(del1);
7987   if ( abs(del2)>dmax ) dmax=abs(del2);
7988   if ( abs(del3)>dmax ) dmax=abs(del3);
7989   while ( dmax<fraction_half ) {
7990     dmax+=dmax; del1+=del1; del2+=del2; del3+=del3;
7991   }
7992 }
7993
7994 @ Since |crossing_point| has tried to choose |t| so that
7995 $B(|del1|,|del2|,|del3|;\tau)$ crosses zero at $\tau=|t|$ with negative
7996 slope, the value of |del2| computed below should not be positive.
7997 But rounding error could make it slightly positive in which case we
7998 must cut it to zero to avoid confusion.
7999
8000 @<Test the extremes of the cubic against the bounding box@>=
8001
8002   x=mp_eval_cubic(mp, p,q,t);
8003   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8004   del2=t_of_the_way(del2,del3);
8005     /* now |0,del2,del3| represent the derivative on the remaining interval */
8006   if ( del2>0 ) del2=0;
8007   tt=mp_crossing_point(mp, 0,-del2,-del3);
8008   if ( tt<fraction_one ) {
8009     @<Test the second extreme against the bounding box@>;
8010   }
8011 }
8012
8013 @ @<Test the second extreme against the bounding box@>=
8014 {
8015    x=mp_eval_cubic(mp, p,q,t_of_the_way(tt,fraction_one));
8016   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8017 }
8018
8019 @ Finding the bounding box of a path is basically a matter of applying
8020 |bound_cubic| twice for each pair of adjacent knots.
8021
8022 @c void mp_path_bbox (MP mp,pointer h) {
8023   pointer p,q; /* a pair of adjacent knots */
8024    minx=x_coord(h); miny=y_coord(h);
8025   maxx=minx; maxy=miny;
8026   p=h;
8027   do {  
8028     if ( right_type(p)==endpoint ) return;
8029     q=link(p);
8030     mp_bound_cubic(mp, x_loc(p),x_loc(q),mp_x_code);
8031     mp_bound_cubic(mp, y_loc(p),y_loc(q),mp_y_code);
8032     p=q;
8033   } while (p!=h);
8034 }
8035
8036 @ Another important way to measure a path is to find its arc length.  This
8037 is best done by using the general bisection algorithm to subdivide the path
8038 until obtaining ``well behaved'' subpaths whose arc lengths can be approximated
8039 by simple means.
8040
8041 Since the arc length is the integral with respect to time of the magnitude of
8042 the velocity, it is natural to use Simpson's rule for the approximation.
8043 @^Simpson's rule@>
8044 If $\dot B(t)$ is the spline velocity, Simpson's rule gives
8045 $$ \vb\dot B(0)\vb + 4\vb\dot B({1\over2})\vb + \vb\dot B(1)\vb \over 6 $$
8046 for the arc length of a path of length~1.  For a cubic spline
8047 $B(z_0,z_1,z_2,z_3;t)$, the time derivative $\dot B(t)$ is
8048 $3B(dz_0,dz_1,dz_2;t)$, where $dz_i=z_{i+1}-z_i$.  Hence the arc length
8049 approximation is
8050 $$ {\vb dz_0\vb \over 2} + 2\vb dz_{02}\vb + {\vb dz_2\vb \over 2}, $$
8051 where
8052 $$ dz_{02}={1\over2}\left({dz_0+dz_1\over 2}+{dz_1+dz_2\over 2}\right)$$
8053 is the result of the bisection algorithm.
8054
8055 @ The remaining problem is how to decide when a subpath is ``well behaved.''
8056 This could be done via the theoretical error bound for Simpson's rule,
8057 @^Simpson's rule@>
8058 but this is impractical because it requires an estimate of the fourth
8059 derivative of the quantity being integrated.  It is much easier to just perform
8060 a bisection step and see how much the arc length estimate changes.  Since the
8061 error for Simpson's rule is proportional to the fourth power of the sample
8062 spacing, the remaining error is typically about $1\over16$ of the amount of
8063 the change.  We say ``typically'' because the error has a pseudo-random behavior
8064 that could cause the two estimates to agree when each contain large errors.
8065
8066 To protect against disasters such as undetected cusps, the bisection process
8067 should always continue until all the $dz_i$ vectors belong to a single
8068 $90^\circ$ sector.  This ensures that no point on the spline can have velocity
8069 less than 70\% of the minimum of $\vb dz_0\vb$, $\vb dz_1\vb$ and $\vb dz_2\vb$.
8070 If such a spline happens to produce an erroneous arc length estimate that
8071 is little changed by bisection, the amount of the error is likely to be fairly
8072 small.  We will try to arrange things so that freak accidents of this type do
8073 not destroy the inverse relationship between the \&{arclength} and
8074 \&{arctime} operations.
8075 @:arclength_}{\&{arclength} primitive@>
8076 @:arctime_}{\&{arctime} primitive@>
8077
8078 @ The \&{arclength} and \&{arctime} operations are both based on a recursive
8079 @^recursion@>
8080 function that finds the arc length of a cubic spline given $dz_0$, $dz_1$,
8081 $dz_2$. This |arc_test| routine also takes an arc length goal |a_goal| and
8082 returns the time when the arc length reaches |a_goal| if there is such a time.
8083 Thus the return value is either an arc length less than |a_goal| or, if the
8084 arc length would be at least |a_goal|, it returns a time value decreased by
8085 |two|.  This allows the caller to use the sign of the result to distinguish
8086 between arc lengths and time values.  On certain types of overflow, it is
8087 possible for |a_goal| and the result of |arc_test| both to be |el_gordo|.
8088 Otherwise, the result is always less than |a_goal|.
8089
8090 Rather than halving the control point coordinates on each recursive call to
8091 |arc_test|, it is better to keep them proportional to velocity on the original
8092 curve and halve the results instead.  This means that recursive calls can
8093 potentially use larger error tolerances in their arc length estimates.  How
8094 much larger depends on to what extent the errors behave as though they are
8095 independent of each other.  To save computing time, we use optimistic assumptions
8096 and increase the tolerance by a factor of about $\sqrt2$ for each recursive
8097 call.
8098
8099 In addition to the tolerance parameter, |arc_test| should also have parameters
8100 for ${1\over3}\vb\dot B(0)\vb$, ${2\over3}\vb\dot B({1\over2})\vb$, and
8101 ${1\over3}\vb\dot B(1)\vb$.  These quantities are relatively expensive to compute
8102 and they are needed in different instances of |arc_test|.
8103
8104 @c @t\4@>@<Declare subroutines needed by |arc_test|@>;
8105 scaled mp_arc_test (MP mp, scaled dx0, scaled dy0, scaled dx1, scaled dy1, 
8106                     scaled dx2, scaled dy2, scaled  v0, scaled v02, 
8107                     scaled v2, scaled a_goal, scaled tol) {
8108   boolean simple; /* are the control points confined to a $90^\circ$ sector? */
8109   scaled dx01, dy01, dx12, dy12, dx02, dy02;  /* bisection results */
8110   scaled v002, v022;
8111     /* twice the velocity magnitudes at $t={1\over4}$ and $t={3\over4}$ */
8112   scaled arc; /* best arc length estimate before recursion */
8113   @<Other local variables in |arc_test|@>;
8114   @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,
8115     |dx2|, |dy2|@>;
8116   @<Initialize |v002|, |v022|, and the arc length estimate |arc|; if it overflows
8117     set |arc_test| and |return|@>;
8118   @<Test if the control points are confined to one quadrant or rotating them
8119     $45^\circ$ would put them in one quadrant.  Then set |simple| appropriately@>;
8120   if ( simple && (abs(arc-v02-halfp(v0+v2)) <= tol) ) {
8121     if ( arc < a_goal ) {
8122       return arc;
8123     } else {
8124        @<Estimate when the arc length reaches |a_goal| and set |arc_test| to
8125          that time minus |two|@>;
8126     }
8127   } else {
8128     @<Use one or two recursive calls to compute the |arc_test| function@>;
8129   }
8130 }
8131
8132 @ The |tol| value should by multiplied by $\sqrt 2$ before making recursive
8133 calls, but $1.5$ is an adequate approximation.  It is best to avoid using
8134 |make_fraction| in this inner loop.
8135 @^inner loop@>
8136
8137 @<Use one or two recursive calls to compute the |arc_test| function@>=
8138
8139   @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is as
8140     large as possible@>;
8141   tol = tol + halfp(tol);
8142   a = mp_arc_test(mp, dx0,dy0, dx01,dy01, dx02,dy02, v0, v002, 
8143                   halfp(v02), a_new, tol);
8144   if ( a<0 )  {
8145      return (-halfp(two-a));
8146   } else { 
8147     @<Update |a_new| to reduce |a_new+a_aux| by |a|@>;
8148     b = mp_arc_test(mp, dx02,dy02, dx12,dy12, dx2,dy2,
8149                     halfp(v02), v022, v2, a_new, tol);
8150     if ( b<0 )  
8151       return (-halfp(-b) - half_unit);
8152     else  
8153       return (a + half(b-a));
8154   }
8155 }
8156
8157 @ @<Other local variables in |arc_test|@>=
8158 scaled a,b; /* results of recursive calls */
8159 scaled a_new,a_aux; /* the sum of these gives the |a_goal| */
8160
8161 @ @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is...@>=
8162 a_aux = el_gordo - a_goal;
8163 if ( a_goal > a_aux ) {
8164   a_aux = a_goal - a_aux;
8165   a_new = el_gordo;
8166 } else { 
8167   a_new = a_goal + a_goal;
8168   a_aux = 0;
8169 }
8170
8171 @ There is no need to maintain |a_aux| at this point so we use it as a temporary
8172 to force the additions and subtractions to be done in an order that avoids
8173 overflow.
8174
8175 @<Update |a_new| to reduce |a_new+a_aux| by |a|@>=
8176 if ( a > a_aux ) {
8177   a_aux = a_aux - a;
8178   a_new = a_new + a_aux;
8179 }
8180
8181 @ This code assumes all {\it dx} and {\it dy} variables have magnitude less than
8182 |fraction_four|.  To simplify the rest of the |arc_test| routine, we strengthen
8183 this assumption by requiring the norm of each $({\it dx},{\it dy})$ pair to obey
8184 this bound.  Note that recursive calls will maintain this invariant.
8185
8186 @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,...@>=
8187 dx01 = half(dx0 + dx1);
8188 dx12 = half(dx1 + dx2);
8189 dx02 = half(dx01 + dx12);
8190 dy01 = half(dy0 + dy1);
8191 dy12 = half(dy1 + dy2);
8192 dy02 = half(dy01 + dy12)
8193
8194 @ We should be careful to keep |arc<el_gordo| so that calling |arc_test| with
8195 |a_goal=el_gordo| is guaranteed to yield the arc length.
8196
8197 @<Initialize |v002|, |v022|, and the arc length estimate |arc|;...@>=
8198 v002 = mp_pyth_add(mp, dx01+half(dx0+dx02), dy01+half(dy0+dy02));
8199 v022 = mp_pyth_add(mp, dx12+half(dx02+dx2), dy12+half(dy02+dy2));
8200 tmp = halfp(v02+2);
8201 arc1 = v002 + half(halfp(v0+tmp) - v002);
8202 arc = v022 + half(halfp(v2+tmp) - v022);
8203 if ( (arc < el_gordo-arc1) )  {
8204   arc = arc+arc1;
8205 } else { 
8206   mp->arith_error = true;
8207   if ( a_goal==el_gordo )  return (el_gordo);
8208   else return (-two);
8209 }
8210
8211 @ @<Other local variables in |arc_test|@>=
8212 scaled tmp, tmp2; /* all purpose temporary registers */
8213 scaled arc1; /* arc length estimate for the first half */
8214
8215 @ @<Test if the control points are confined to one quadrant or rotating...@>=
8216 simple = ((dx0>=0) && (dx1>=0) && (dx2>=0)) ||
8217          ((dx0<=0) && (dx1<=0) && (dx2<=0));
8218 if ( simple )
8219   simple = ((dy0>=0) && (dy1>=0) && (dy2>=0)) ||
8220            ((dy0<=0) && (dy1<=0) && (dy2<=0));
8221 if ( ! simple ) {
8222   simple = ((dx0>=dy0) && (dx1>=dy1) && (dx2>=dy2)) ||
8223            ((dx0<=dy0) && (dx1<=dy1) && (dx2<=dy2));
8224   if ( simple ) 
8225     simple = ((-dx0>=dy0) && (-dx1>=dy1) && (-dx2>=dy2)) ||
8226              ((-dx0<=dy0) && (-dx1<=dy1) && (-dx2<=dy2));
8227 }
8228
8229 @ Since Simpson's rule is based on approximating the integrand by a parabola,
8230 @^Simpson's rule@>
8231 it is appropriate to use the same approximation to decide when the integral
8232 reaches the intermediate value |a_goal|.  At this point
8233 $$\eqalign{
8234     {\vb\dot B(0)\vb\over 3} &= \hbox{|v0|}, \qquad
8235     {\vb\dot B({1\over4})\vb\over 3} = {\hbox{|v002|}\over 2}, \qquad
8236     {\vb\dot B({1\over2})\vb\over 3} = {\hbox{|v02|}\over 2}, \cr
8237     {\vb\dot B({3\over4})\vb\over 3} &= {\hbox{|v022|}\over 2}, \qquad
8238     {\vb\dot B(1)\vb\over 3} = \hbox{|v2|} \cr
8239 }
8240 $$
8241 and
8242 $$ {\vb\dot B(t)\vb\over 3} \approx
8243   \cases{B\left(\hbox{|v0|},
8244       \hbox{|v002|}-{1\over 2}\hbox{|v0|}-{1\over 4}\hbox{|v02|},
8245       {1\over 2}\hbox{|v02|}; 2t \right)&
8246     if $t\le{1\over 2}$\cr
8247   B\left({1\over 2}\hbox{|v02|},
8248       \hbox{|v022|}-{1\over 4}\hbox{|v02|}-{1\over 2}\hbox{|v2|},
8249       \hbox{|v2|}; 2t-1 \right)&
8250     if $t\ge{1\over 2}$.\cr}
8251  \eqno (*)
8252 $$
8253 We can integrate $\vb\dot B(t)\vb$ by using
8254 $$\int 3B(a,b,c;\tau)\,dt =
8255   {B(0,a,a+b,a+b+c;\tau) + {\rm constant} \over {d\tau\over dt}}.
8256 $$
8257
8258 This construction allows us to find the time when the arc length reaches
8259 |a_goal| by solving a cubic equation of the form
8260 $$ B(0,a,a+b,a+b+c;\tau) = x, $$
8261 where $\tau$ is $2t$ or $2t+1$, $x$ is |a_goal| or |a_goal-arc1|, and $a$, $b$,
8262 and $c$ are the Bernshte{\u\i}n coefficients from $(*)$ divided by
8263 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
8264 $d\tau\over dt$.  We shall define a function |solve_rising_cubic| that finds
8265 $\tau$ given $a$, $b$, $c$, and $x$.
8266
8267 @<Estimate when the arc length reaches |a_goal| and set |arc_test| to...@>=
8268
8269   tmp = (v02 + 2) / 4;
8270   if ( a_goal<=arc1 ) {
8271     tmp2 = halfp(v0);
8272     return 
8273       (halfp(mp_solve_rising_cubic(mp, tmp2, arc1-tmp2-tmp, tmp, a_goal))- two);
8274   } else { 
8275     tmp2 = halfp(v2);
8276     return ((half_unit - two) +
8277       halfp(mp_solve_rising_cubic(mp, tmp, arc-arc1-tmp-tmp2, tmp2, a_goal-arc1)));
8278   }
8279 }
8280
8281 @ Here is the |solve_rising_cubic| routine that finds the time~$t$ when
8282 $$ B(0, a, a+b, a+b+c; t) = x. $$
8283 This routine is based on |crossing_point| but is simplified by the
8284 assumptions that $B(a,b,c;t)\ge0$ for $0\le t\le1$ and that |0<=x<=a+b+c|.
8285 If rounding error causes this condition to be violated slightly, we just ignore
8286 it and proceed with binary search.  This finds a time when the function value
8287 reaches |x| and the slope is positive.
8288
8289 @<Declare subroutines needed by |arc_test|@>=
8290 scaled mp_solve_rising_cubic (MP mp,scaled a, scaled b,  scaled c, scaled x) {
8291   scaled ab, bc, ac; /* bisection results */
8292   integer t; /* $2^k+q$ where unscaled answer is in $[q2^{-k},(q+1)2^{-k})$ */
8293   integer xx; /* temporary for updating |x| */
8294   if ( (a<0) || (c<0) ) mp_confusion(mp, "rising?");
8295 @:this can't happen rising?}{\quad rising?@>
8296   if ( x<=0 ) {
8297         return 0;
8298   } else if ( x >= a+b+c ) {
8299     return unity;
8300   } else { 
8301     t = 1;
8302     @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than
8303       |el_gordo div 3|@>;
8304     do {  
8305       t+=t;
8306       @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>;
8307       xx = x - a - ab - ac;
8308       if ( xx < -x ) { x+=x; b=ab; c=ac;  }
8309       else { x = x + xx;  a=ac; b=mp->bc; t = t+1; };
8310     } while (t < unity);
8311     return (t - unity);
8312   }
8313 }
8314
8315 @ @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>=
8316 ab = half(a+b);
8317 bc = half(b+c);
8318 ac = half(ab+bc)
8319
8320 @ @d one_third_el_gordo 05252525252 /* upper bound on |a|, |b|, and |c| */
8321
8322 @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than...@>=
8323 while ((a>one_third_el_gordo)||(b>one_third_el_gordo)||(c>one_third_el_gordo)) { 
8324   a = halfp(a);
8325   b = half(b);
8326   c = halfp(c);
8327   x = halfp(x);
8328 }
8329
8330 @ It is convenient to have a simpler interface to |arc_test| that requires no
8331 unnecessary arguments and ensures that each $({\it dx},{\it dy})$ pair has
8332 length less than |fraction_four|.
8333
8334 @d arc_tol   16  /* quit when change in arc length estimate reaches this */
8335
8336 @c scaled mp_do_arc_test (MP mp,scaled dx0, scaled dy0, scaled dx1, 
8337                           scaled dy1, scaled dx2, scaled dy2, scaled a_goal) {
8338   scaled v0,v1,v2; /* length of each $({\it dx},{\it dy})$ pair */
8339   scaled v02; /* twice the norm of the quadratic at $t={1\over2}$ */
8340   v0 = mp_pyth_add(mp, dx0,dy0);
8341   v1 = mp_pyth_add(mp, dx1,dy1);
8342   v2 = mp_pyth_add(mp, dx2,dy2);
8343   if ( (v0>=fraction_four) || (v1>=fraction_four) || (v2>=fraction_four) ) { 
8344     mp->arith_error = true;
8345     if ( a_goal==el_gordo )  return el_gordo;
8346     else return (-two);
8347   } else { 
8348     v02 = mp_pyth_add(mp, dx1+half(dx0+dx2), dy1+half(dy0+dy2));
8349     return (mp_arc_test(mp, dx0,dy0, dx1,dy1, dx2,dy2,
8350                                  v0, v02, v2, a_goal, arc_tol));
8351   }
8352 }
8353
8354 @ Now it is easy to find the arc length of an entire path.
8355
8356 @c scaled mp_get_arc_length (MP mp,pointer h) {
8357   pointer p,q; /* for traversing the path */
8358   scaled a,a_tot; /* current and total arc lengths */
8359   a_tot = 0;
8360   p = h;
8361   while ( right_type(p)!=endpoint ){ 
8362     q = link(p);
8363     a = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8364       left_x(q)-right_x(p), left_y(q)-right_y(p),
8365       x_coord(q)-left_x(q), y_coord(q)-left_y(q), el_gordo);
8366     a_tot = mp_slow_add(mp, a, a_tot);
8367     if ( q==h ) break;  else p=q;
8368   }
8369   check_arith;
8370   return a_tot;
8371 }
8372
8373 @ The inverse operation of finding the time on a path~|h| when the arc length
8374 reaches some value |arc0| can also be accomplished via |do_arc_test|.  Some care
8375 is required to handle very large times or negative times on cyclic paths.  For
8376 non-cyclic paths, |arc0| values that are negative or too large cause
8377 |get_arc_time| to return 0 or the length of path~|h|.
8378
8379 If |arc0| is greater than the arc length of a cyclic path~|h|, the result is a
8380 time value greater than the length of the path.  Since it could be much greater,
8381 we must be prepared to compute the arc length of path~|h| and divide this into
8382 |arc0| to find how many multiples of the length of path~|h| to add.
8383
8384 @c scaled mp_get_arc_time (MP mp,pointer h, scaled  arc0) {
8385   pointer p,q; /* for traversing the path */
8386   scaled t_tot; /* accumulator for the result */
8387   scaled t; /* the result of |do_arc_test| */
8388   scaled arc; /* portion of |arc0| not used up so far */
8389   integer n; /* number of extra times to go around the cycle */
8390   if ( arc0<0 ) {
8391     @<Deal with a negative |arc0| value and |return|@>;
8392   }
8393   if ( arc0==el_gordo ) decr(arc0);
8394   t_tot = 0;
8395   arc = arc0;
8396   p = h;
8397   while ( (right_type(p)!=endpoint) && (arc>0) ) {
8398     q = link(p);
8399     t = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8400       left_x(q)-right_x(p), left_y(q)-right_y(p),
8401       x_coord(q)-left_x(q), y_coord(q)-left_y(q), arc);
8402     @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>;
8403     if ( q==h ) {
8404       @<Update |t_tot| and |arc| to avoid going around the cyclic
8405         path too many times but set |arith_error:=true| and |goto done| on
8406         overflow@>;
8407     }
8408     p = q;
8409   }
8410   check_arith;
8411   return t_tot;
8412 }
8413
8414 @ @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>=
8415 if ( t<0 ) { t_tot = t_tot + t + two;  arc = 0;  }
8416 else { t_tot = t_tot + unity;  arc = arc - t;  }
8417
8418 @ @<Deal with a negative |arc0| value and |return|@>=
8419
8420   if ( left_type(h)==endpoint ) {
8421     t_tot=0;
8422   } else { 
8423     p = mp_htap_ypoc(mp, h);
8424     t_tot = -mp_get_arc_time(mp, p, -arc0);
8425     mp_toss_knot_list(mp, p);
8426   }
8427   check_arith;
8428   return t_tot;
8429 }
8430
8431 @ @<Update |t_tot| and |arc| to avoid going around the cyclic...@>=
8432 if ( arc>0 ) { 
8433   n = arc / (arc0 - arc);
8434   arc = arc - n*(arc0 - arc);
8435   if ( t_tot > el_gordo / (n+1) ) { 
8436     mp->arith_error = true;
8437     t_tot = el_gordo;
8438     break;
8439   }
8440   t_tot = (n + 1)*t_tot;
8441 }
8442
8443 @* \[20] Data structures for pens.
8444 A Pen in \MP\ can be either elliptical or polygonal.  Elliptical pens result
8445 in \ps\ \&{stroke} commands, while anything drawn with a polygonal pen is
8446 @:stroke}{\&{stroke} command@>
8447 converted into an area fill as described in the next part of this program.
8448 The mathematics behind this process is based on simple aspects of the theory
8449 of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge Stolfi
8450 [``A kinematic framework for computational geometry,'' Proc.\ IEEE Symp.\
8451 Foundations of Computer Science {\bf 24} (1983), 100--111].
8452
8453 Polygonal pens are created from paths via \MP's \&{makepen} primitive.
8454 @:makepen_}{\&{makepen} primitive@>
8455 This path representation is almost sufficient for our purposes except that
8456 a pen path should always be a convex polygon with the vertices in
8457 counter-clockwise order.
8458 Since we will need to scan pen polygons both forward and backward, a pen
8459 should be represented as a doubly linked ring of knot nodes.  There is
8460 room for the extra back pointer because we do not need the
8461 |left_type| or |right_type| fields.  In fact, we don't need the |left_x|,
8462 |left_y|, |right_x|, or |right_y| fields either but we leave these alone
8463 so that certain procedures can operate on both pens and paths.  In particular,
8464 pens can be copied using |copy_path| and recycled using |toss_knot_list|.
8465
8466 @d knil info
8467   /* this replaces the |left_type| and |right_type| fields in a pen knot */
8468
8469 @ The |make_pen| procedure turns a path into a pen by initializing
8470 the |knil| pointers and making sure the knots form a convex polygon.
8471 Thus each cubic in the given path becomes a straight line and the control
8472 points are ignored.  If the path is not cyclic, the ends are connected by a
8473 straight line.
8474
8475 @d copy_pen(A) mp_make_pen(mp, mp_copy_path(mp, (A)),false)
8476
8477 @c @<Declare a function called |convex_hull|@>;
8478 pointer mp_make_pen (MP mp,pointer h, boolean need_hull) {
8479   pointer p,q; /* two consecutive knots */
8480   q=h;
8481   do {  
8482     p=q; q=link(q);
8483     knil(q)=p;
8484   } while (q!=h);
8485   if ( need_hull ){ 
8486     h=mp_convex_hull(mp, h);
8487     @<Make sure |h| isn't confused with an elliptical pen@>;
8488   }
8489   return h;
8490 }
8491
8492 @ The only information required about an elliptical pen is the overall
8493 transformation that has been applied to the original \&{pencircle}.
8494 @:pencircle_}{\&{pencircle} primitive@>
8495 Since it suffices to keep track of how the three points $(0,0)$, $(1,0)$,
8496 and $(0,1)$ are transformed, an elliptical pen can be stored in a single
8497 knot node and transformed as if it were a path.
8498
8499 @d pen_is_elliptical(A) ((A)==link((A)))
8500
8501 @c pointer mp_get_pen_circle (MP mp,scaled diam) {
8502   pointer h; /* the knot node to return */
8503   h=mp_get_node(mp, knot_node_size);
8504   link(h)=h; knil(h)=h;
8505   originator(h)=program_code;
8506   x_coord(h)=0; y_coord(h)=0;
8507   left_x(h)=diam; left_y(h)=0;
8508   right_x(h)=0; right_y(h)=diam;
8509   return h;
8510 }
8511
8512 @ If the polygon being returned by |make_pen| has only one vertex, it will
8513 be interpreted as an elliptical pen.  This is no problem since a degenerate
8514 polygon can equally well be thought of as a degenerate ellipse.  We need only
8515 initialize the |left_x|, |left_y|, |right_x|, and |right_y| fields.
8516
8517 @<Make sure |h| isn't confused with an elliptical pen@>=
8518 if ( pen_is_elliptical( h) ){ 
8519   left_x(h)=x_coord(h); left_y(h)=y_coord(h);
8520   right_x(h)=x_coord(h); right_y(h)=y_coord(h);
8521 }
8522
8523 @ We have to cheat a little here but most operations on pens only use
8524 the first three words in each knot node.
8525 @^data structure assumptions@>
8526
8527 @<Initialize a pen at |test_pen| so that it fits in nine words@>=
8528 x_coord(test_pen)=-half_unit;
8529 y_coord(test_pen)=0;
8530 x_coord(test_pen+3)=half_unit;
8531 y_coord(test_pen+3)=0;
8532 x_coord(test_pen+6)=0;
8533 y_coord(test_pen+6)=unity;
8534 link(test_pen)=test_pen+3;
8535 link(test_pen+3)=test_pen+6;
8536 link(test_pen+6)=test_pen;
8537 knil(test_pen)=test_pen+6;
8538 knil(test_pen+3)=test_pen;
8539 knil(test_pen+6)=test_pen+3
8540
8541 @ Printing a polygonal pen is very much like printing a path
8542
8543 @<Declare subroutines for printing expressions@>=
8544 void mp_pr_pen (MP mp,pointer h) {
8545   pointer p,q; /* for list traversal */
8546   if ( pen_is_elliptical(h) ) {
8547     @<Print the elliptical pen |h|@>;
8548   } else { 
8549     p=h;
8550     do {  
8551       mp_print_two(mp, x_coord(p),y_coord(p));
8552       mp_print_nl(mp, " .. ");
8553       @<Advance |p| making sure the links are OK and |return| if there is
8554         a problem@>;
8555      } while (p!=h);
8556      mp_print(mp, "cycle");
8557   }
8558 }
8559
8560 @ @<Advance |p| making sure the links are OK and |return| if there is...@>=
8561 q=link(p);
8562 if ( (q==null) || (knil(q)!=p) ) { 
8563   mp_print_nl(mp, "???"); return; /* this won't happen */
8564 @.???@>
8565 }
8566 p=q
8567
8568 @ @<Print the elliptical pen |h|@>=
8569
8570 mp_print(mp, "pencircle transformed (");
8571 mp_print_scaled(mp, x_coord(h));
8572 mp_print_char(mp, ',');
8573 mp_print_scaled(mp, y_coord(h));
8574 mp_print_char(mp, ',');
8575 mp_print_scaled(mp, left_x(h)-x_coord(h));
8576 mp_print_char(mp, ',');
8577 mp_print_scaled(mp, right_x(h)-x_coord(h));
8578 mp_print_char(mp, ',');
8579 mp_print_scaled(mp, left_y(h)-y_coord(h));
8580 mp_print_char(mp, ',');
8581 mp_print_scaled(mp, right_y(h)-y_coord(h));
8582 mp_print_char(mp, ')');
8583 }
8584
8585 @ Here us another version of |pr_pen| that prints the pen as a diagnostic
8586 message.
8587
8588 @<Declare subroutines for printing expressions@>=
8589 void mp_print_pen (MP mp,pointer h, char *s, boolean nuline) { 
8590   mp_print_diagnostic(mp, "Pen",s,nuline); mp_print_ln(mp);
8591 @.Pen at line...@>
8592   mp_pr_pen(mp, h);
8593   mp_end_diagnostic(mp, true);
8594 }
8595
8596 @ Making a polygonal pen into a path involves restoring the |left_type| and
8597 |right_type| fields and setting the control points so as to make a polygonal
8598 path.
8599
8600 @c 
8601 void mp_make_path (MP mp,pointer h) {
8602   pointer p; /* for traversing the knot list */
8603   small_number k; /* a loop counter */
8604   @<Other local variables in |make_path|@>;
8605   if ( pen_is_elliptical(h) ) {
8606     @<Make the elliptical pen |h| into a path@>;
8607   } else { 
8608     p=h;
8609     do {  
8610       left_type(p)=explicit;
8611       right_type(p)=explicit;
8612       @<copy the coordinates of knot |p| into its control points@>;
8613        p=link(p);
8614     } while (p!=h);
8615   }
8616 }
8617
8618 @ @<copy the coordinates of knot |p| into its control points@>=
8619 left_x(p)=x_coord(p);
8620 left_y(p)=y_coord(p);
8621 right_x(p)=x_coord(p);
8622 right_y(p)=y_coord(p)
8623
8624 @ We need an eight knot path to get a good approximation to an ellipse.
8625
8626 @<Make the elliptical pen |h| into a path@>=
8627
8628   @<Extract the transformation parameters from the elliptical pen~|h|@>;
8629   p=h;
8630   for (k=0;k<=7;k++ ) { 
8631     @<Initialize |p| as the |k|th knot of a circle of unit diameter,
8632       transforming it appropriately@>;
8633     if ( k==7 ) link(p)=h;  else link(p)=mp_get_node(mp, knot_node_size);
8634     p=link(p);
8635   }
8636 }
8637
8638 @ @<Extract the transformation parameters from the elliptical pen~|h|@>=
8639 center_x=x_coord(h);
8640 center_y=y_coord(h);
8641 width_x=left_x(h)-center_x;
8642 width_y=left_y(h)-center_y;
8643 height_x=right_x(h)-center_x;
8644 height_y=right_y(h)-center_y
8645
8646 @ @<Other local variables in |make_path|@>=
8647 scaled center_x,center_y; /* translation parameters for an elliptical pen */
8648 scaled width_x,width_y; /* the effect of a unit change in $x$ */
8649 scaled height_x,height_y; /* the effect of a unit change in $y$ */
8650 scaled dx,dy; /* the vector from knot |p| to its right control point */
8651 integer kk;
8652   /* |k| advanced $270^\circ$ around the ring (cf. $\sin\theta=\cos(\theta+270)$) */
8653
8654 @ The only tricky thing here are the tables |half_cos| and |d_cos| used to
8655 find the point $k/8$ of the way around the circle and the direction vector
8656 to use there.
8657
8658 @<Initialize |p| as the |k|th knot of a circle of unit diameter,...@>=
8659 kk=(k+6)% 8;
8660 x_coord(p)=center_x+mp_take_fraction(mp, mp->half_cos[k],width_x)
8661            +mp_take_fraction(mp, mp->half_cos[kk],height_x);
8662 y_coord(p)=center_y+mp_take_fraction(mp, mp->half_cos[k],width_y)
8663            +mp_take_fraction(mp, mp->half_cos[kk],height_y);
8664 dx=-mp_take_fraction(mp, mp->d_cos[kk],width_x)
8665    +mp_take_fraction(mp, mp->d_cos[k],height_x);
8666 dy=-mp_take_fraction(mp, mp->d_cos[kk],width_y)
8667    +mp_take_fraction(mp, mp->d_cos[k],height_y);
8668 right_x(p)=x_coord(p)+dx;
8669 right_y(p)=y_coord(p)+dy;
8670 left_x(p)=x_coord(p)-dx;
8671 left_y(p)=y_coord(p)-dy;
8672 left_type(p)=explicit;
8673 right_type(p)=explicit;
8674 originator(p)=program_code
8675
8676 @ @<Glob...@>=
8677 fraction half_cos[8]; /* ${1\over2}\cos(45k)$ */
8678 fraction d_cos[8]; /* a magic constant times $\cos(45k)$ */
8679
8680 @ The magic constant for |d_cos| is the distance between $({1\over2},0)$ and
8681 $({1\over4}\sqrt2,{1\over4}\sqrt2)$ times the result of the |velocity|
8682 function for $\theta=\phi=22.5^\circ$.  This comes out to be
8683 $$ d = {\sqrt{2-\sqrt2}\over 3+3\cos22.5^\circ}
8684   \approx 0.132608244919772.
8685 $$
8686
8687 @<Set init...@>=
8688 mp->half_cos[0]=fraction_half;
8689 mp->half_cos[1]=94906266; /* $2^{26}\sqrt2\approx94906265.62$ */
8690 mp->half_cos[2]=0;
8691 mp->d_cos[0]=35596755; /* $2^{28}d\approx35596754.69$ */
8692 mp->d_cos[1]=25170707; /* $2^{27}\sqrt2\,d\approx25170706.63$ */
8693 mp->d_cos[2]=0;
8694 for (k=3;k<= 4;k++ ) { 
8695   mp->half_cos[k]=-mp->half_cos[4-k];
8696   mp->d_cos[k]=-mp->d_cos[4-k];
8697 }
8698 for (k=5;k<= 7;k++ ) { 
8699   mp->half_cos[k]=mp->half_cos[8-k];
8700   mp->d_cos[k]=mp->d_cos[8-k];
8701 }
8702
8703 @ The |convex_hull| function forces a pen polygon to be convex when it is
8704 returned by |make_pen| and after any subsequent transformation where rounding
8705 error might allow the convexity to be lost.
8706 The convex hull algorithm used here is described by F.~P. Preparata and
8707 M.~I. Shamos [{\sl Computational Geometry}, Springer-Verlag, 1985].
8708
8709 @<Declare a function called |convex_hull|@>=
8710 @<Declare a procedure called |move_knot|@>;
8711 pointer mp_convex_hull (MP mp,pointer h) { /* Make a polygonal pen convex */
8712   pointer l,r; /* the leftmost and rightmost knots */
8713   pointer p,q; /* knots being scanned */
8714   pointer s; /* the starting point for an upcoming scan */
8715   scaled dx,dy; /* a temporary pointer */
8716   if ( pen_is_elliptical(h) ) {
8717      return h;
8718   } else { 
8719     @<Set |l| to the leftmost knot in polygon~|h|@>;
8720     @<Set |r| to the rightmost knot in polygon~|h|@>;
8721     if ( l!=r ) { 
8722       s=link(r);
8723       @<Find any knots on the path from |l| to |r| above the |l|-|r| line and
8724         move them past~|r|@>;
8725       @<Find any knots on the path from |s| to |l| below the |l|-|r| line and
8726         move them past~|l|@>;
8727       @<Sort the path from |l| to |r| by increasing $x$@>;
8728       @<Sort the path from |r| to |l| by decreasing $x$@>;
8729     }
8730     if ( l!=link(l) ) {
8731       @<Do a Gramm scan and remove vertices where there is no left turn@>;
8732     }
8733     return l;
8734   }
8735 }
8736
8737 @ All comparisons are done primarily on $x$ and secondarily on $y$.
8738
8739 @<Set |l| to the leftmost knot in polygon~|h|@>=
8740 l=h;
8741 p=link(h);
8742 while ( p!=h ) { 
8743   if ( x_coord(p)<=x_coord(l) )
8744     if ( (x_coord(p)<x_coord(l)) || (y_coord(p)<y_coord(l)) )
8745       l=p;
8746   p=link(p);
8747 }
8748
8749 @ @<Set |r| to the rightmost knot in polygon~|h|@>=
8750 r=h;
8751 p=link(h);
8752 while ( p!=h ) { 
8753   if ( x_coord(p)>=x_coord(r) )
8754     if ( (x_coord(p)>x_coord(r)) || (y_coord(p)>y_coord(r)) )
8755       r=p;
8756   p=link(p);
8757 }
8758
8759 @ @<Find any knots on the path from |l| to |r| above the |l|-|r| line...@>=
8760 dx=x_coord(r)-x_coord(l);
8761 dy=y_coord(r)-y_coord(l);
8762 p=link(l);
8763 while ( p!=r ) { 
8764   q=link(p);
8765   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))>0 )
8766     mp_move_knot(mp, p, r);
8767   p=q;
8768 }
8769
8770 @ The |move_knot| procedure removes |p| from a doubly linked list and inserts
8771 it after |q|.
8772
8773 @ @<Declare a procedure called |move_knot|@>=
8774 void mp_move_knot (MP mp,pointer p, pointer q) { 
8775   link(knil(p))=link(p);
8776   knil(link(p))=knil(p);
8777   knil(p)=q;
8778   link(p)=link(q);
8779   link(q)=p;
8780   knil(link(p))=p;
8781 }
8782
8783 @ @<Find any knots on the path from |s| to |l| below the |l|-|r| line...@>=
8784 p=s;
8785 while ( p!=l ) { 
8786   q=link(p);
8787   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))<0 )
8788     mp_move_knot(mp, p,l);
8789   p=q;
8790 }
8791
8792 @ The list is likely to be in order already so we just do linear insertions.
8793 Secondary comparisons on $y$ ensure that the sort is consistent with the
8794 choice of |l| and |r|.
8795
8796 @<Sort the path from |l| to |r| by increasing $x$@>=
8797 p=link(l);
8798 while ( p!=r ) { 
8799   q=knil(p);
8800   while ( x_coord(q)>x_coord(p) ) q=knil(q);
8801   while ( x_coord(q)==x_coord(p) ) {
8802     if ( y_coord(q)>y_coord(p) ) q=knil(q); else break;
8803   }
8804   if ( q==knil(p) ) p=link(p);
8805   else { p=link(p); mp_move_knot(mp, knil(p),q); };
8806 }
8807
8808 @ @<Sort the path from |r| to |l| by decreasing $x$@>=
8809 p=link(r);
8810 while ( p!=l ){ 
8811   q=knil(p);
8812   while ( x_coord(q)<x_coord(p) ) q=knil(q);
8813   while ( x_coord(q)==x_coord(p) ) {
8814     if ( y_coord(q)<y_coord(p) ) q=knil(q); else break;
8815   }
8816   if ( q==knil(p) ) p=link(p);
8817   else { p=link(p); mp_move_knot(mp, knil(p),q); };
8818 }
8819
8820 @ The condition involving |ab_vs_cd| tests if there is not a left turn
8821 at knot |q|.  There usually will be a left turn so we streamline the case
8822 where the |then| clause is not executed.
8823
8824 @<Do a Gramm scan and remove vertices where there...@>=
8825
8826 p=l; q=link(l);
8827 while (1) { 
8828   dx=x_coord(q)-x_coord(p);
8829   dy=y_coord(q)-y_coord(p);
8830   p=q; q=link(q);
8831   if ( p==l ) break;
8832   if ( p!=r )
8833     if ( mp_ab_vs_cd(mp, dx,y_coord(q)-y_coord(p),dy,x_coord(q)-x_coord(p))<=0 ) {
8834       @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>;
8835     }
8836   }
8837 }
8838
8839 @ @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>=
8840
8841 s=knil(p);
8842 mp_free_node(mp, p,knot_node_size);
8843 link(s)=q; knil(q)=s;
8844 if ( s==l ) p=s;
8845 else { p=knil(s); q=s; };
8846 }
8847
8848 @ The |find_offset| procedure sets global variables |(cur_x,cur_y)| to the
8849 offset associated with the given direction |(x,y)|.  If two different offsets
8850 apply, it chooses one of them.
8851
8852 @c 
8853 void mp_find_offset (MP mp,scaled x, scaled y, pointer h) {
8854   pointer p,q; /* consecutive knots */
8855   scaled wx,wy,hx,hy;
8856   /* the transformation matrix for an elliptical pen */
8857   fraction xx,yy; /* untransformed offset for an elliptical pen */
8858   fraction d; /* a temporary register */
8859   if ( pen_is_elliptical(h) ) {
8860     @<Find the offset for |(x,y)| on the elliptical pen~|h|@>
8861   } else { 
8862     q=h;
8863     do {  
8864       p=q; q=link(q);
8865     } while (! mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)>=0);
8866     do {  
8867       p=q; q=link(q);
8868     } while (! mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)<=0);
8869     mp->cur_x=x_coord(p);
8870     mp->cur_y=y_coord(p);
8871   }
8872 }
8873
8874 @ @<Glob...@>=
8875 scaled cur_x;
8876 scaled cur_y; /* all-purpose return value registers */
8877
8878 @ @<Find the offset for |(x,y)| on the elliptical pen~|h|@>=
8879 if ( (x==0) && (y==0) ) {
8880   mp->cur_x=x_coord(h); mp->cur_y=y_coord(h);  
8881 } else { 
8882   @<Find the non-constant part of the transformation for |h|@>;
8883   while ( (abs(x)<fraction_half) && (abs(y)<fraction_half) ){ 
8884     x+=x; y+=y;  
8885   };
8886   @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the
8887     untransformed version of |(x,y)|@>;
8888   mp->cur_x=x_coord(h)+mp_take_fraction(mp, xx,wx)+mp_take_fraction(mp, yy,hx);
8889   mp->cur_y=y_coord(h)+mp_take_fraction(mp, xx,wy)+mp_take_fraction(mp, yy,hy);
8890 }
8891
8892 @ @<Find the non-constant part of the transformation for |h|@>=
8893 wx=left_x(h)-x_coord(h);
8894 wy=left_y(h)-y_coord(h);
8895 hx=right_x(h)-x_coord(h);
8896 hy=right_y(h)-y_coord(h)
8897
8898 @ @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the...@>=
8899 yy=-(mp_take_fraction(mp, x,hy)+mp_take_fraction(mp, y,-hx));
8900 xx=mp_take_fraction(mp, x,-wy)+mp_take_fraction(mp, y,wx);
8901 d=mp_pyth_add(mp, xx,yy);
8902 if ( d>0 ) { 
8903   xx=half(mp_make_fraction(mp, xx,d));
8904   yy=half(mp_make_fraction(mp, yy,d));
8905 }
8906
8907 @ Finding the bounding box of a pen is easy except if the pen is elliptical.
8908 But we can handle that case by just calling |find_offset| twice.  The answer
8909 is stored in the global variables |minx|, |maxx|, |miny|, and |maxy|.
8910
8911 @c 
8912 void mp_pen_bbox (MP mp,pointer h) {
8913   pointer p; /* for scanning the knot list */
8914   if ( pen_is_elliptical(h) ) {
8915     @<Find the bounding box of an elliptical pen@>;
8916   } else { 
8917     minx=x_coord(h); maxx=minx;
8918     miny=y_coord(h); maxy=miny;
8919     p=link(h);
8920     while ( p!=h ) {
8921       if ( x_coord(p)<minx ) minx=x_coord(p);
8922       if ( y_coord(p)<miny ) miny=y_coord(p);
8923       if ( x_coord(p)>maxx ) maxx=x_coord(p);
8924       if ( y_coord(p)>maxy ) maxy=y_coord(p);
8925       p=link(p);
8926     }
8927   }
8928 }
8929
8930 @ @<Find the bounding box of an elliptical pen@>=
8931
8932 mp_find_offset(mp, 0,fraction_one,h);
8933 maxx=mp->cur_x;
8934 minx=2*x_coord(h)-mp->cur_x;
8935 mp_find_offset(mp, -fraction_one,0,h);
8936 maxy=mp->cur_y;
8937 miny=2*y_coord(h)-mp->cur_y;
8938 }
8939
8940 @* \[21] Edge structures.
8941 Now we come to \MP's internal scheme for representing pictures.
8942 The representation is very different from \MF's edge structures
8943 because \MP\ pictures contain \ps\ graphics objects instead of pixel
8944 images.  However, the basic idea is somewhat similar in that shapes
8945 are represented via their boundaries.
8946
8947 The main purpose of edge structures is to keep track of graphical objects
8948 until it is time to translate them into \ps.  Since \MP\ does not need to
8949 know anything about an edge structure other than how to translate it into
8950 \ps\ and how to find its bounding box, edge structures can be just linked
8951 lists of graphical objects.  \MP\ has no easy way to determine whether
8952 two such objects overlap, but it suffices to draw the first one first and
8953 let the second one overwrite it if necessary.
8954
8955 @ Let's consider the types of graphical objects one at a time.
8956 First of all, a filled contour is represented by a eight-word node.  The first
8957 word contains |type| and |link| fields, and the next six words contain a
8958 pointer to a cyclic path and the value to use for \ps' \&{currentrgbcolor}
8959 parameter.  If a pen is used for filling |pen_p|, |ljoin_val| and |miterlim_val|
8960 give the relevant information.
8961
8962 @d path_p(A) link((A)+1)
8963   /* a pointer to the path that needs filling */
8964 @d pen_p(A) info((A)+1)
8965   /* a pointer to the pen to fill or stroke with */
8966 @d color_model(A) type((A)+2) /*  the color model  */
8967 @d obj_red_loc(A) ((A)+3)  /* the first of three locations for the color */
8968 @d obj_cyan_loc obj_red_loc  /* the first of four locations for the color */
8969 @d obj_grey_loc obj_red_loc  /* the location for the color */
8970 @d red_val(A) mp->mem[(A)+3].sc
8971   /* the red component of the color in the range $0\ldots1$ */
8972 @d cyan_val red_val
8973 @d grey_val red_val
8974 @d green_val(A) mp->mem[(A)+4].sc
8975   /* the green component of the color in the range $0\ldots1$ */
8976 @d magenta_val green_val
8977 @d blue_val(A) mp->mem[(A)+5].sc
8978   /* the blue component of the color in the range $0\ldots1$ */
8979 @d yellow_val blue_val
8980 @d black_val(A) mp->mem[(A)+6].sc
8981   /* the blue component of the color in the range $0\ldots1$ */
8982 @d ljoin_val(A) name_type((A))  /* the value of \&{linejoin} */
8983 @:linejoin_}{\&{linejoin} primitive@>
8984 @d miterlim_val(A) mp->mem[(A)+7].sc  /* the value of \&{miterlimit} */
8985 @:miterlimit_}{\&{miterlimit} primitive@>
8986 @d obj_color_part(A) mp->mem[(A)+3-red_part].sc
8987   /* interpret an object pointer that has been offset by |red_part..blue_part| */
8988 @d pre_script(A) mp->mem[(A)+8].hh.lh
8989 @d post_script(A) mp->mem[(A)+8].hh.rh
8990 @d fill_node_size 9
8991 @d fill_code 1
8992
8993 @c 
8994 pointer mp_new_fill_node (MP mp,pointer p) {
8995   /* make a fill node for cyclic path |p| and color black */
8996   pointer t; /* the new node */
8997   t=mp_get_node(mp, fill_node_size);
8998   type(t)=fill_code;
8999   path_p(t)=p;
9000   pen_p(t)=null; /* |null| means don't use a pen */
9001   red_val(t)=0;
9002   green_val(t)=0;
9003   blue_val(t)=0;
9004   black_val(t)=0;
9005   color_model(t)=uninitialized_model;
9006   pre_script(t)=null;
9007   post_script(t)=null;
9008   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9009   return t;
9010 }
9011
9012 @ @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>=
9013 if ( mp->internal[linejoin]>unity ) ljoin_val(t)=2;
9014 else if ( mp->internal[linejoin]>0 ) ljoin_val(t)=1;
9015 else ljoin_val(t)=0;
9016 if ( mp->internal[miterlimit]<unity )
9017   miterlim_val(t)=unity;
9018 else
9019   miterlim_val(t)=mp->internal[miterlimit]
9020
9021 @ A stroked path is represented by an eight-word node that is like a filled
9022 contour node except that it contains the current \&{linecap} value, a scale
9023 factor for the dash pattern, and a pointer that is non-null if the stroke
9024 is to be dashed.  The purpose of the scale factor is to allow a picture to
9025 be transformed without touching the picture that |dash_p| points to.
9026
9027 @d dash_p(A) link((A)+9)
9028   /* a pointer to the edge structure that gives the dash pattern */
9029 @d lcap_val(A) type((A)+9)
9030   /* the value of \&{linecap} */
9031 @:linecap_}{\&{linecap} primitive@>
9032 @d dash_scale(A) mp->mem[(A)+10].sc /* dash lengths are scaled by this factor */
9033 @d stroked_node_size 11
9034 @d stroked_code 2
9035
9036 @c 
9037 pointer mp_new_stroked_node (MP mp,pointer p) {
9038   /* make a stroked node for path |p| with |pen_p(p)| temporarily |null| */
9039   pointer t; /* the new node */
9040   t=mp_get_node(mp, stroked_node_size);
9041   type(t)=stroked_code;
9042   path_p(t)=p; pen_p(t)=null;
9043   dash_p(t)=null;
9044   dash_scale(t)=unity;
9045   red_val(t)=0;
9046   green_val(t)=0;
9047   blue_val(t)=0;
9048   black_val(t)=0;
9049   color_model(t)=uninitialized_model;
9050   pre_script(t)=null;
9051   post_script(t)=null;
9052   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9053   if ( mp->internal[linecap]>unity ) lcap_val(t)=2;
9054   else if ( mp->internal[linecap]>0 ) lcap_val(t)=1;
9055   else lcap_val(t)=0;
9056   return t;
9057 }
9058
9059 @ When a dashed line is computed in a transformed coordinate system, the dash
9060 lengths get scaled like the pen shape and we need to compensate for this.  Since
9061 there is no unique scale factor for an arbitrary transformation, we use the
9062 the square root of the determinant.  The properties of the determinant make it
9063 easier to maintain the |dash_scale|.  The computation is fairly straight-forward
9064 except for the initialization of the scale factor |s|.  The factor of 64 is
9065 needed because |square_rt| scales its result by $2^8$ while we need $2^{14}$
9066 to counteract the effect of |take_fraction|.
9067
9068 @<Declare subroutines needed by |print_edges|@>=
9069 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) {
9070   scaled maxabs; /* $max(|a|,|b|,|c|,|d|)$ */
9071   integer s; /* amount by which the result of |square_rt| needs to be scaled */
9072   @<Initialize |maxabs|@>;
9073   s=64;
9074   while ( (maxabs<fraction_one) && (s>1) ){ 
9075     a+=a; b+=b; c+=c; d+=d;
9076     maxabs+=maxabs; s=halfp(s);
9077   }
9078   return s*mp_square_rt(mp, abs(mp_take_fraction(mp, a,d)-mp_take_fraction(mp, b,c)));
9079 }
9080 @#
9081 scaled mp_get_pen_scale (MP mp,pointer p) { 
9082   return mp_sqrt_det(mp, 
9083     left_x(p)-x_coord(p), right_x(p)-x_coord(p),
9084     left_y(p)-y_coord(p), right_y(p)-y_coord(p));
9085 }
9086
9087 @ @<Initialize |maxabs|@>=
9088 maxabs=abs(a);
9089 if ( abs(b)>maxabs ) maxabs=abs(b);
9090 if ( abs(c)>maxabs ) maxabs=abs(c);
9091 if ( abs(d)>maxabs ) maxabs=abs(d)
9092
9093 @ When a picture contains text, this is represented by a fourteen-word node
9094 where the color information and |type| and |link| fields are augmented by
9095 additional fields that describe the text and  how it is transformed.
9096 The |path_p| and |pen_p| pointers are replaced by a number that identifies
9097 the font and a string number that gives the text to be displayed.
9098 The |width|, |height|, and |depth| fields
9099 give the dimensions of the text at its design size, and the remaining six
9100 words give a transformation to be applied to the text.  The |new_text_node|
9101 function initializes everything to default values so that the text comes out
9102 black with its reference point at the origin.
9103
9104 @d text_p(A) link((A)+1)  /* a string pointer for the text to display */
9105 @d font_n(A) info((A)+1)  /* the font number */
9106 @d width_val(A) mp->mem[(A)+7].sc  /* unscaled width of the text */
9107 @d height_val(A) mp->mem[(A)+9].sc  /* unscaled height of the text */
9108 @d depth_val(A) mp->mem[(A)+10].sc  /* unscaled depth of the text */
9109 @d text_tx_loc(A) ((A)+11)
9110   /* the first of six locations for transformation parameters */
9111 @d tx_val(A) mp->mem[(A)+11].sc  /* $x$ shift amount */
9112 @d ty_val(A) mp->mem[(A)+12].sc  /* $y$ shift amount */
9113 @d txx_val(A) mp->mem[(A)+13].sc  /* |txx| transformation parameter */
9114 @d txy_val(A) mp->mem[(A)+14].sc  /* |txy| transformation parameter */
9115 @d tyx_val(A) mp->mem[(A)+15].sc  /* |tyx| transformation parameter */
9116 @d tyy_val(A) mp->mem[(A)+16].sc  /* |tyy| transformation parameter */
9117 @d text_trans_part(A) mp->mem[(A)+11-x_part].sc
9118     /* interpret a text node ponter that has been offset by |x_part..yy_part| */
9119 @d text_node_size 17
9120 @d text_code 3
9121
9122 @c @<Declare text measuring subroutines@>;
9123 pointer mp_new_text_node (MP mp,char *f,str_number s) {
9124   /* make a text node for font |f| and text string |s| */
9125   pointer t; /* the new node */
9126   t=mp_get_node(mp, text_node_size);
9127   type(t)=text_code;
9128   text_p(t)=s;
9129   font_n(t)=mp_find_font(mp, f); /* this identifies the font */
9130   red_val(t)=0;
9131   green_val(t)=0;
9132   blue_val(t)=0;
9133   black_val(t)=0;
9134   color_model(t)=uninitialized_model;
9135   pre_script(t)=null;
9136   post_script(t)=null;
9137   tx_val(t)=0; ty_val(t)=0;
9138   txx_val(t)=unity; txy_val(t)=0;
9139   tyx_val(t)=0; tyy_val(t)=unity;
9140   mp_set_text_box(mp, t); /* this finds the bounding box */
9141   return t;
9142 }
9143
9144 @ The last two types of graphical objects that can occur in an edge structure
9145 are clipping paths and \&{setbounds} paths.  These are slightly more difficult
9146 @:set_bounds_}{\&{setbounds} primitive@>
9147 to implement because we must keep track of exactly what is being clipped or
9148 bounded when pictures get merged together.  For this reason, each clipping or
9149 \&{setbounds} operation is represented by a pair of nodes:  first comes a
9150 two-word node whose |path_p| gives the relevant path, then there is the list
9151 of objects to clip or bound followed by a two-word node whose second word is
9152 unused.
9153
9154 Using at least two words for each graphical object node allows them all to be
9155 allocated and deallocated similarly with a global array |gr_object_size| to
9156 give the size in words for each object type.
9157
9158 @d start_clip_size 2
9159 @d start_bounds_size 2
9160 @d stop_clip_size 2 /* the second word is not used here */
9161 @d stop_bounds_size 2 /* the second word is not used here */
9162 @#
9163 @d stop_type(A) ((A)+2)
9164   /* matching |type| for |start_clip_code| or |start_bounds_code| */
9165 @d has_color(A) (type((A))<mp_start_clip_code)
9166   /* does a graphical object have color fields? */
9167 @d has_pen(A) (type((A))<text_code)
9168   /* does a graphical object have a |pen_p| field? */
9169 @d is_start_or_stop(A) (type((A))>=mp_start_clip_code)
9170 @d is_stop(A) (type((A))>=mp_stop_clip_code)
9171
9172 @<Types...@>=
9173 enum {
9174  mp_start_clip_code=4, /* |type| of a node that starts clipping */
9175  mp_start_bounds_code, /* |type| of a node that gives a \&{setbounds} path */
9176  mp_stop_clip_code, /* |type| of a node that stops clipping */
9177  mp_stop_bounds_code /* |type| of a node that stops \&{setbounds} */
9178 };
9179
9180 @ @c 
9181 pointer mp_new_bounds_node (MP mp,pointer p, small_number  c) {
9182   /* make a node of type |c| where |p| is the clipping or \&{setbounds} path */
9183   pointer t; /* the new node */
9184   t=mp_get_node(mp, mp->gr_object_size[c]);
9185   type(t)=c;
9186   path_p(t)=p;
9187   return t;
9188 };
9189
9190 @ We need an array to keep track of the sizes of graphical objects.
9191
9192 @<Glob...@>=
9193 small_number gr_object_size[mp_stop_bounds_code+1];
9194
9195 @ @<Set init...@>=
9196 mp->gr_object_size[fill_code]=fill_node_size;
9197 mp->gr_object_size[stroked_code]=stroked_node_size;
9198 mp->gr_object_size[text_code]=text_node_size;
9199 mp->gr_object_size[mp_start_clip_code]=start_clip_size;
9200 mp->gr_object_size[mp_stop_clip_code]=stop_clip_size;
9201 mp->gr_object_size[mp_start_bounds_code]=start_bounds_size;
9202 mp->gr_object_size[mp_stop_bounds_code]=stop_bounds_size;
9203
9204 @ All the essential information in an edge structure is encoded as a linked list
9205 of graphical objects as we have just seen, but it is helpful to add some
9206 redundant information.  A single edge structure might be used as a dash pattern
9207 many times, and it would be nice to avoid scanning the same structure
9208 repeatedly.  Thus, an edge structure known to be a suitable dash pattern
9209 has a header that gives a list of dashes in a sorted order designed for rapid
9210 translation into \ps.
9211
9212 Each dash is represented by a three-word node containing the initial and final
9213 $x$~coordinates as well as the usual |link| field.  The |link| fields points to
9214 the dash node with the next higher $x$-coordinates and the final link points
9215 to a special location called |null_dash|.  (There should be no overlap between
9216 dashes).  Since the $y$~coordinate of the dash pattern is needed to determine
9217 the period of repetition, this needs to be stored in the edge header along
9218 with a pointer to the list of dash nodes.
9219
9220 @d start_x(A) mp->mem[(A)+1].sc  /* the starting $x$~coordinate in a dash node */
9221 @d stop_x(A) mp->mem[(A)+2].sc  /* the ending $x$~coordinate in a dash node */
9222 @d dash_node_size 3
9223 @d dash_list link
9224   /* in an edge header this points to the first dash node */
9225 @d dash_y(A) mp->mem[(A)+1].sc  /* $y$ value for the dash list in an edge header */
9226
9227 @ It is also convenient for an edge header to contain the bounding
9228 box information needed by the \&{llcorner} and \&{urcorner} operators
9229 so that this does not have to be recomputed unnecessarily.  This is done by
9230 adding fields for the $x$~and $y$ extremes as well as a pointer that indicates
9231 how far the bounding box computation has gotten.  Thus if the user asks for
9232 the bounding box and then adds some more text to the picture before asking
9233 for more bounding box information, the second computation need only look at
9234 the additional text.
9235
9236 When the bounding box has not been computed, the |bblast| pointer points
9237 to a dummy link at the head of the graphical object list while the |minx_val|
9238 and |miny_val| fields contain |el_gordo| and the |maxx_val| and |maxy_val|
9239 fields contain |-el_gordo|.
9240
9241 Since the bounding box of pictures containing objects of type
9242 |mp_start_bounds_code| depends on the value of \&{truecorners}, the bounding box
9243 @:true_corners_}{\&{truecorners} primitive@>
9244 data might not be valid for all values of this parameter.  Hence, the |bbtype|
9245 field is needed to keep track of this.
9246
9247 @d minx_val(A) mp->mem[(A)+2].sc
9248 @d miny_val(A) mp->mem[(A)+3].sc
9249 @d maxx_val(A) mp->mem[(A)+4].sc
9250 @d maxy_val(A) mp->mem[(A)+5].sc
9251 @d bblast(A) link((A)+6)  /* last item considered in bounding box computation */
9252 @d bbtype(A) info((A)+6)  /* tells how bounding box data depends on \&{truecorners} */
9253 @d dummy_loc(A) ((A)+7)  /* where the object list begins in an edge header */
9254 @d no_bounds 0
9255   /* |bbtype| value when bounding box data is valid for all \&{truecorners} values */
9256 @d bounds_set 1
9257   /* |bbtype| value when bounding box data is for \&{truecorners}${}\le 0$ */
9258 @d bounds_unset 2
9259   /* |bbtype| value when bounding box data is for \&{truecorners}${}>0$ */
9260
9261 @c 
9262 void mp_init_bbox (MP mp,pointer h) {
9263   /* Initialize the bounding box information in edge structure |h| */
9264   bblast(h)=dummy_loc(h);
9265   bbtype(h)=no_bounds;
9266   minx_val(h)=el_gordo;
9267   miny_val(h)=el_gordo;
9268   maxx_val(h)=-el_gordo;
9269   maxy_val(h)=-el_gordo;
9270 }
9271
9272 @ The only other entries in an edge header are a reference count in the first
9273 word and a pointer to the tail of the object list in the last word.
9274
9275 @d obj_tail(A) info((A)+7)  /* points to the last entry in the object list */
9276 @d edge_header_size 8
9277
9278 @c 
9279 void mp_init_edges (MP mp,pointer h) {
9280   /* initialize an edge header to null values */
9281   dash_list(h)=null_dash;
9282   obj_tail(h)=dummy_loc(h);
9283   link(dummy_loc(h))=null;
9284   ref_count(h)=null;
9285   mp_init_bbox(mp, h);
9286 }
9287
9288 @ Here is how edge structures are deleted.  The process can be recursive because
9289 of the need to dereference edge structures that are used as dash patterns.
9290 @^recursion@>
9291
9292 @d add_edge_ref(A) incr(ref_count((A)))
9293 @d delete_edge_ref(A) { if ( ref_count((A))==null ) mp_toss_edges(mp, (A));
9294   else decr(ref_count((A))); }
9295
9296 @<Declare the recycling subroutines@>=
9297 void mp_flush_dash_list (MP mp,pointer h);
9298 pointer mp_toss_gr_object (MP mp,pointer p) ;
9299 void mp_toss_edges (MP mp,pointer h) ;
9300
9301 @ @c void mp_toss_edges (MP mp,pointer h) {
9302   pointer p,q;  /* pointers that scan the list being recycled */
9303   pointer r; /* an edge structure that object |p| refers to */
9304   mp_flush_dash_list(mp, h);
9305   q=link(dummy_loc(h));
9306   while ( (q!=null) ) { 
9307     p=q; q=link(q);
9308     r=mp_toss_gr_object(mp, p);
9309     if ( r!=null ) delete_edge_ref(r);
9310   }
9311   mp_free_node(mp, h,edge_header_size);
9312 }
9313 void mp_flush_dash_list (MP mp,pointer h) {
9314   pointer p,q;  /* pointers that scan the list being recycled */
9315   q=dash_list(h);
9316   while ( q!=null_dash ) { 
9317     p=q; q=link(q);
9318     mp_free_node(mp, p,dash_node_size);
9319   }
9320   dash_list(h)=null_dash;
9321 }
9322 pointer mp_toss_gr_object (MP mp,pointer p) {
9323   /* returns an edge structure that needs to be dereferenced */
9324   pointer e; /* the edge structure to return */
9325   e=null;
9326   @<Prepare to recycle graphical object |p|@>;
9327   mp_free_node(mp, p,mp->gr_object_size[type(p)]);
9328   return e;
9329 }
9330
9331 @ @<Prepare to recycle graphical object |p|@>=
9332 switch (type(p)) {
9333 case fill_code: 
9334   mp_toss_knot_list(mp, path_p(p));
9335   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9336   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9337   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9338   break;
9339 case stroked_code: 
9340   mp_toss_knot_list(mp, path_p(p));
9341   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9342   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9343   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9344   e=dash_p(p);
9345   break;
9346 case text_code: 
9347   delete_str_ref(text_p(p));
9348   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9349   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9350   break;
9351 case mp_start_clip_code:
9352 case mp_start_bounds_code: 
9353   mp_toss_knot_list(mp, path_p(p));
9354   break;
9355 case mp_stop_clip_code:
9356 case mp_stop_bounds_code: 
9357   break;
9358 } /* there are no other cases */
9359
9360 @ If we use |add_edge_ref| to ``copy'' edge structures, the real copying needs
9361 to be done before making a significant change to an edge structure.  Much of
9362 the work is done in a separate routine |copy_objects| that copies a list of
9363 graphical objects into a new edge header.
9364
9365 @c @<Declare a function called |copy_objects|@>;
9366 pointer mp_private_edges (MP mp,pointer h) {
9367   /* make a private copy of the edge structure headed by |h| */
9368   pointer hh;  /* the edge header for the new copy */
9369   pointer p,pp;  /* pointers for copying the dash list */
9370   if ( ref_count(h)==null ) {
9371     return h;
9372   } else { 
9373     decr(ref_count(h));
9374     hh=mp_copy_objects(mp, link(dummy_loc(h)),null);
9375     @<Copy the dash list from |h| to |hh|@>;
9376     @<Copy the bounding box information from |h| to |hh| and make |bblast(hh)|
9377       point into the new object list@>;
9378     return hh;
9379   }
9380 }
9381
9382 @ Here we use the fact that |dash_list(hh)=link(hh)|.
9383 @^data structure assumptions@>
9384
9385 @<Copy the dash list from |h| to |hh|@>=
9386 pp=hh; p=dash_list(h);
9387 while ( (p!=null_dash) ) { 
9388   link(pp)=mp_get_node(mp, dash_node_size);
9389   pp=link(pp);
9390   start_x(pp)=start_x(p);
9391   stop_x(pp)=stop_x(p);
9392   p=link(p);
9393 }
9394 link(pp)=null_dash;
9395 dash_y(hh)=dash_y(h)
9396
9397 @ @<Copy the bounding box information from |h| to |hh|...@>=
9398 minx_val(hh)=minx_val(h);
9399 miny_val(hh)=miny_val(h);
9400 maxx_val(hh)=maxx_val(h);
9401 maxy_val(hh)=maxy_val(h);
9402 bbtype(hh)=bbtype(h);
9403 p=dummy_loc(h); pp=dummy_loc(hh);
9404 while ((p!=bblast(h)) ) { 
9405   if ( p==null ) mp_confusion(mp, "bblast");
9406 @:this can't happen bblast}{\quad bblast@>
9407   p=link(p); pp=link(pp);
9408 }
9409 bblast(hh)=pp
9410
9411 @ Here is the promised routine for copying graphical objects into a new edge
9412 structure.  It starts copying at object~|p| and stops just before object~|q|.
9413 If |q| is null, it copies the entire sublist headed at |p|.  The resulting edge
9414 structure requires further initialization by |init_bbox|.
9415
9416 @<Declare a function called |copy_objects|@>=
9417 pointer mp_copy_objects (MP mp, pointer p, pointer q) {
9418   pointer hh;  /* the new edge header */
9419   pointer pp;  /* the last newly copied object */
9420   small_number k;  /* temporary register */
9421   hh=mp_get_node(mp, edge_header_size);
9422   dash_list(hh)=null_dash;
9423   ref_count(hh)=null;
9424   pp=dummy_loc(hh);
9425   while ( (p!=q) ) {
9426     @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>;
9427   }
9428   obj_tail(hh)=pp;
9429   link(pp)=null;
9430   return hh;
9431 }
9432
9433 @ @<Make |link(pp)| point to a copy of object |p|, and update |p| and |pp|@>=
9434 { k=mp->gr_object_size[type(p)];
9435   link(pp)=mp_get_node(mp, k);
9436   pp=link(pp);
9437   while ( (k>0) ) { decr(k); mp->mem[pp+k]=mp->mem[p+k];  };
9438   @<Fix anything in graphical object |pp| that should differ from the
9439     corresponding field in |p|@>;
9440   p=link(p);
9441 }
9442
9443 @ @<Fix anything in graphical object |pp| that should differ from the...@>=
9444 switch (type(p)) {
9445 case mp_start_clip_code:
9446 case mp_start_bounds_code: 
9447   path_p(pp)=mp_copy_path(mp, path_p(p));
9448   break;
9449 case fill_code: 
9450   path_p(pp)=mp_copy_path(mp, path_p(p));
9451   if ( pen_p(p)!=null ) pen_p(pp)=copy_pen(pen_p(p));
9452   break;
9453 case stroked_code: 
9454   path_p(pp)=mp_copy_path(mp, path_p(p));
9455   pen_p(pp)=copy_pen(pen_p(p));
9456   if ( dash_p(p)!=null ) add_edge_ref(dash_p(pp));
9457   break;
9458 case text_code: 
9459   add_str_ref(text_p(pp));
9460   break;
9461 case mp_stop_clip_code:
9462 case mp_stop_bounds_code: 
9463   break;
9464 }  /* there are no other cases */
9465
9466 @ Here is one way to find an acceptable value for the second argument to
9467 |copy_objects|.  Given a non-null graphical object list, |skip_1component|
9468 skips past one picture component, where a ``picture component'' is a single
9469 graphical object, or a start bounds or start clip object and everything up
9470 through the matching stop bounds or stop clip object.  The macro version avoids
9471 procedure call overhead and error handling: |skip_component(p)(e)| advances |p|
9472 unless |p| points to a stop bounds or stop clip node, in which case it executes
9473 |e| instead.
9474
9475 @d skip_component(A)
9476     if ( ! is_start_or_stop((A)) ) (A)=link((A));
9477     else if ( ! is_stop((A)) ) (A)=mp_skip_1component(mp, (A));
9478     else 
9479
9480 @c 
9481 pointer mp_skip_1component (MP mp,pointer p) {
9482   integer lev; /* current nesting level */
9483   lev=0;
9484   do {  
9485    if ( is_start_or_stop(p) ) {
9486      if ( is_stop(p) ) decr(lev);  else incr(lev);
9487    }
9488    p=link(p);
9489   } while (lev!=0);
9490   return p;
9491 }
9492
9493 @ Here is a diagnostic routine for printing an edge structure in symbolic form.
9494
9495 @<Declare subroutines for printing expressions@>=
9496 @<Declare subroutines needed by |print_edges|@>;
9497 void mp_print_edges (MP mp,pointer h, char *s, boolean nuline) {
9498   pointer p;  /* a graphical object to be printed */
9499   pointer hh,pp;  /* temporary pointers */
9500   scaled scf;  /* a scale factor for the dash pattern */
9501   boolean ok_to_dash;  /* |false| for polygonal pen strokes */
9502   mp_print_diagnostic(mp, "Edge structure",s,nuline);
9503   p=dummy_loc(h);
9504   while ( link(p)!=null ) { 
9505     p=link(p);
9506     mp_print_ln(mp);
9507     switch (type(p)) {
9508       @<Cases for printing graphical object node |p|@>;
9509     default: 
9510           mp_print(mp, "[unknown object type!]");
9511           break;
9512     }
9513   }
9514   mp_print_nl(mp, "End edges");
9515   if ( p!=obj_tail(h) ) mp_print(mp, "?");
9516 @.End edges?@>
9517   mp_end_diagnostic(mp, true);
9518 }
9519
9520 @ @<Cases for printing graphical object node |p|@>=
9521 case fill_code: 
9522   mp_print(mp, "Filled contour ");
9523   mp_print_obj_color(mp, p);
9524   mp_print_char(mp, ':'); mp_print_ln(mp);
9525   mp_pr_path(mp, path_p(p)); mp_print_ln(mp);
9526   if ( (pen_p(p)!=null) ) {
9527     @<Print join type for graphical object |p|@>;
9528     mp_print(mp, " with pen"); mp_print_ln(mp);
9529     mp_pr_pen(mp, pen_p(p));
9530   }
9531   break;
9532
9533 @ @<Print join type for graphical object |p|@>=
9534 switch (ljoin_val(p)) {
9535 case 0:
9536   mp_print(mp, "mitered joins limited ");
9537   mp_print_scaled(mp, miterlim_val(p));
9538   break;
9539 case 1:
9540   mp_print(mp, "round joins");
9541   break;
9542 case 2:
9543   mp_print(mp, "beveled joins");
9544   break;
9545 default: 
9546   mp_print(mp, "?? joins");
9547 @.??@>
9548   break;
9549 }
9550
9551 @ For stroked nodes, we need to print |lcap_val(p)| as well.
9552
9553 @<Print join and cap types for stroked node |p|@>=
9554 switch (lcap_val(p)) {
9555 case 0:mp_print(mp, "butt"); break;
9556 case 1:mp_print(mp, "round"); break;
9557 case 2:mp_print(mp, "square"); break;
9558 default: mp_print(mp, "??"); break;
9559 @.??@>
9560 }
9561 mp_print(mp, " ends, ");
9562 @<Print join type for graphical object |p|@>
9563
9564 @ Here is a routine that prints the color of a graphical object if it isn't
9565 black (the default color).
9566
9567 @<Declare subroutines needed by |print_edges|@>=
9568 @<Declare a procedure called |print_compact_node|@>;
9569 void mp_print_obj_color (MP mp,pointer p) { 
9570   if ( color_model(p)==grey_model ) {
9571     if ( grey_val(p)>0 ) { 
9572       mp_print(mp, "greyed ");
9573       mp_print_compact_node(mp, obj_grey_loc(p),1);
9574     };
9575   } else if ( color_model(p)==cmyk_model ) {
9576     if ( (cyan_val(p)>0) || (magenta_val(p)>0) || 
9577          (yellow_val(p)>0) || (black_val(p)>0) ) { 
9578       mp_print(mp, "processcolored ");
9579       mp_print_compact_node(mp, obj_cyan_loc(p),4);
9580     };
9581   } else if ( color_model(p)==rgb_model ) {
9582     if ( (red_val(p)>0) || (green_val(p)>0) || (blue_val(p)>0) ) { 
9583       mp_print(mp, "colored "); 
9584       mp_print_compact_node(mp, obj_red_loc(p),3);
9585     };
9586   }
9587 }
9588
9589 @ We also need a procedure for printing consecutive scaled values as if they
9590 were a known big node.
9591
9592 @<Declare a procedure called |print_compact_node|@>=
9593 void mp_print_compact_node (MP mp,pointer p, small_number k) {
9594   pointer q;  /* last location to print */
9595   q=p+k-1;
9596   mp_print_char(mp, '(');
9597   while ( p<=q ){ 
9598     mp_print_scaled(mp, mp->mem[p].sc);
9599     if ( p<q ) mp_print_char(mp, ',');
9600     incr(p);
9601   }
9602   mp_print_char(mp, ')');
9603 }
9604
9605 @ @<Cases for printing graphical object node |p|@>=
9606 case stroked_code: 
9607   mp_print(mp, "Filled pen stroke ");
9608   mp_print_obj_color(mp, p);
9609   mp_print_char(mp, ':'); mp_print_ln(mp);
9610   mp_pr_path(mp, path_p(p));
9611   if ( dash_p(p)!=null ) { 
9612     mp_print_nl(mp, "dashed (");
9613     @<Finish printing the dash pattern that |p| refers to@>;
9614   }
9615   mp_print_ln(mp);
9616   @<Print join and cap types for stroked node |p|@>;
9617   mp_print(mp, " with pen"); mp_print_ln(mp);
9618   if ( pen_p(p)==null ) mp_print(mp, "???"); /* shouldn't happen */
9619 @.???@>
9620   else mp_pr_pen(mp, pen_p(p));
9621   break;
9622
9623 @ Normally, the  |dash_list| field in an edge header is set to |null_dash|
9624 when it is not known to define a suitable dash pattern.  This is disallowed
9625 here because the |dash_p| field should never point to such an edge header.
9626 Note that memory is allocated for |start_x(null_dash)| and we are free to
9627 give it any convenient value.
9628
9629 @<Finish printing the dash pattern that |p| refers to@>=
9630 ok_to_dash=pen_is_elliptical(pen_p(p));
9631 if ( ! ok_to_dash ) scf=unity; else scf=dash_scale(p);
9632 hh=dash_p(p);
9633 pp=dash_list(hh);
9634 if ( (pp==null_dash) || (dash_y(hh)<0) ) {
9635   mp_print(mp, " ??");
9636 } else { start_x(null_dash)=start_x(pp)+dash_y(hh);
9637   while ( pp!=null_dash ) { 
9638     mp_print(mp, "on ");
9639     mp_print_scaled(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf));
9640     mp_print(mp, " off ");
9641     mp_print_scaled(mp, mp_take_scaled(mp, start_x(link(pp))-stop_x(pp),scf));
9642     pp = link(pp);
9643     if ( pp!=null_dash ) mp_print_char(mp, ' ');
9644   }
9645   mp_print(mp, ") shifted ");
9646   mp_print_scaled(mp, -mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
9647   if ( ! ok_to_dash || (dash_y(hh)==0) ) mp_print(mp, " (this will be ignored)");
9648 }
9649
9650 @ @<Declare subroutines needed by |print_edges|@>=
9651 scaled mp_dash_offset (MP mp,pointer h) {
9652   scaled x;  /* the answer */
9653   if ( (dash_list(h)==null_dash) || (dash_y(h)<0) ) mp_confusion(mp, "dash0");
9654 @:this can't happen dash0}{\quad dash0@>
9655   if ( dash_y(h)==0 ) {
9656     x=0; 
9657   } else { 
9658     x=-(start_x(dash_list(h)) % dash_y(h));
9659     if ( x<0 ) x=x+dash_y(h);
9660   }
9661   return x;
9662 }
9663
9664 @ @<Cases for printing graphical object node |p|@>=
9665 case text_code: 
9666   mp_print_char(mp, '"'); mp_print_str(mp,text_p(p));
9667   mp_print(mp, "\" infont \""); mp_print(mp, mp->font_name[font_n(p)]);
9668   mp_print_char(mp, '"'); mp_print_ln(mp);
9669   mp_print_obj_color(mp, p);
9670   mp_print(mp, "transformed ");
9671   mp_print_compact_node(mp, text_tx_loc(p),6);
9672   break;
9673
9674 @ @<Cases for printing graphical object node |p|@>=
9675 case mp_start_clip_code: 
9676   mp_print(mp, "clipping path:");
9677   mp_print_ln(mp);
9678   mp_pr_path(mp, path_p(p));
9679   break;
9680 case mp_stop_clip_code: 
9681   mp_print(mp, "stop clipping");
9682   break;
9683
9684 @ @<Cases for printing graphical object node |p|@>=
9685 case mp_start_bounds_code: 
9686   mp_print(mp, "setbounds path:");
9687   mp_print_ln(mp);
9688   mp_pr_path(mp, path_p(p));
9689   break;
9690 case mp_stop_bounds_code: 
9691   mp_print(mp, "end of setbounds");
9692   break;
9693
9694 @ To initialize the |dash_list| field in an edge header~|h|, we need a
9695 subroutine that scans an edge structure and tries to interpret it as a dash
9696 pattern.  This can only be done when there are no filled regions or clipping
9697 paths and all the pen strokes have the same color.  The first step is to let
9698 $y_0$ be the initial $y$~coordinate of the first pen stroke.  Then we implicitly
9699 project all the pen stroke paths onto the line $y=y_0$ and require that there
9700 be no retracing.  If the resulting paths cover a range of $x$~coordinates of
9701 length $\Delta x$, we set |dash_y(h)| to the length of the dash pattern by
9702 finding the maximum of $\Delta x$ and the absolute value of~$y_0$.
9703
9704 @c @<Declare a procedure called |x_retrace_error|@>;
9705 pointer mp_make_dashes (MP mp,pointer h) { /* returns |h| or |null| */
9706   pointer p;  /* this scans the stroked nodes in the object list */
9707   pointer p0;  /* if not |null| this points to the first stroked node */
9708   pointer pp,qq,rr;  /* pointers into |path_p(p)| */
9709   pointer d,dd;  /* pointers used to create the dash list */
9710   @<Other local variables in |make_dashes|@>;
9711   scaled y0=0;  /* the initial $y$ coordinate */
9712   if ( dash_list(h)!=null_dash ) 
9713         return h;
9714   p0=null;
9715   p=link(dummy_loc(h));
9716   while ( p!=null ) { 
9717     if ( type(p)!=stroked_code ) {
9718       @<Compain that the edge structure contains a node of the wrong type
9719         and |goto not_found|@>;
9720     }
9721     pp=path_p(p);
9722     if ( p0==null ){ p0=p; y0=y_coord(pp);  };
9723     @<Make |d| point to a new dash node created from stroke |p| and path |pp|
9724       or |goto not_found| if there is an error@>;
9725     @<Insert |d| into the dash list and |goto not_found| if there is an error@>;
9726     p=link(p);
9727   }
9728   if ( dash_list(h)==null_dash ) 
9729     goto NOT_FOUND; /* No error message */
9730   @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>;
9731   @<Set |dash_y(h)| and merge the first and last dashes if necessary@>;
9732   return h;
9733 NOT_FOUND: 
9734   @<Flush the dash list, recycle |h| and return |null|@>;
9735 };
9736
9737 @ @<Compain that the edge structure contains a node of the wrong type...@>=
9738
9739 print_err("Picture is too complicated to use as a dash pattern");
9740 help3("When you say `dashed p', picture p should not contain any")
9741   ("text, filled regions, or clipping paths.  This time it did")
9742   ("so I'll just make it a solid line instead.");
9743 mp_put_get_error(mp);
9744 goto NOT_FOUND;
9745 }
9746
9747 @ A similar error occurs when monotonicity fails.
9748
9749 @<Declare a procedure called |x_retrace_error|@>=
9750 void mp_x_retrace_error (MP mp) { 
9751 print_err("Picture is too complicated to use as a dash pattern");
9752 help3("When you say `dashed p', every path in p should be monotone")
9753   ("in x and there must be no overlapping.  This failed")
9754   ("so I'll just make it a solid line instead.");
9755 mp_put_get_error(mp);
9756 }
9757
9758 @ We stash |p| in |info(d)| if |dash_p(p)<>0| so that subsequent processing can
9759 handle the case where the pen stroke |p| is itself dashed.
9760
9761 @<Make |d| point to a new dash node created from stroke |p| and path...@>=
9762 @<Make sure |p| and |p0| are the same color and |goto not_found| if there is
9763   an error@>;
9764 rr=pp;
9765 if ( link(pp)!=pp ) {
9766   do {  
9767     qq=rr; rr=link(rr);
9768     @<Check for retracing between knots |qq| and |rr| and |goto not_found|
9769       if there is a problem@>;
9770   } while (right_type(rr)!=endpoint);
9771 }
9772 d=mp_get_node(mp, dash_node_size);
9773 if ( dash_p(p)==0 ) info(d)=0;  else info(d)=p;
9774 if ( x_coord(pp)<x_coord(rr) ) { 
9775   start_x(d)=x_coord(pp);
9776   stop_x(d)=x_coord(rr);
9777 } else { 
9778   start_x(d)=x_coord(rr);
9779   stop_x(d)=x_coord(pp);
9780 }
9781
9782 @ We also need to check for the case where the segment from |qq| to |rr| is
9783 monotone in $x$ but is reversed relative to the path from |pp| to |qq|.
9784
9785 @<Check for retracing between knots |qq| and |rr| and |goto not_found|...@>=
9786 x0=x_coord(qq);
9787 x1=right_x(qq);
9788 x2=left_x(rr);
9789 x3=x_coord(rr);
9790 if ( (x0>x1) || (x1>x2) || (x2>x3) ) {
9791   if ( (x0<x1) || (x1<x2) || (x2<x3) ) {
9792     if ( mp_ab_vs_cd(mp, x2-x1,x2-x1,x1-x0,x3-x2)>0 ) {
9793       mp_x_retrace_error(mp); goto NOT_FOUND;
9794     }
9795   }
9796 }
9797 if ( (x_coord(pp)>x0) || (x0>x3) ) {
9798   if ( (x_coord(pp)<x0) || (x0<x3) ) {
9799     mp_x_retrace_error(mp); goto NOT_FOUND;
9800   }
9801 }
9802
9803 @ @<Other local variables in |make_dashes|@>=
9804   scaled x0,x1,x2,x3;  /* $x$ coordinates of the segment from |qq| to |rr| */
9805
9806 @ @<Make sure |p| and |p0| are the same color and |goto not_found|...@>=
9807 if ( (red_val(p)!=red_val(p0)) || (black_val(p)!=black_val(p0)) ||
9808   (green_val(p)!=green_val(p0)) || (blue_val(p)!=blue_val(p0)) ) {
9809   print_err("Picture is too complicated to use as a dash pattern");
9810   help3("When you say `dashed p', everything in picture p should")
9811     ("be the same color.  I can\'t handle your color changes")
9812     ("so I'll just make it a solid line instead.");
9813   mp_put_get_error(mp);
9814   goto NOT_FOUND;
9815 }
9816
9817 @ @<Insert |d| into the dash list and |goto not_found| if there is an error@>=
9818 start_x(null_dash)=stop_x(d);
9819 dd=h; /* this makes |link(dd)=dash_list(h)| */
9820 while ( start_x(link(dd))<stop_x(d) )
9821   dd=link(dd);
9822 if ( dd!=h ) {
9823   if ( (stop_x(dd)>start_x(d)) )
9824     { mp_x_retrace_error(mp); goto NOT_FOUND;  };
9825 }
9826 link(d)=link(dd);
9827 link(dd)=d
9828
9829 @ @<Set |dash_y(h)| and merge the first and last dashes if necessary@>=
9830 d=dash_list(h);
9831 while ( (link(d)!=null_dash) )
9832   d=link(d);
9833 dd=dash_list(h);
9834 dash_y(h)=stop_x(d)-start_x(dd);
9835 if ( abs(y0)>dash_y(h) ) {
9836   dash_y(h)=abs(y0);
9837 } else if ( d!=dd ) { 
9838   dash_list(h)=link(dd);
9839   stop_x(d)=stop_x(dd)+dash_y(h);
9840   mp_free_node(mp, dd,dash_node_size);
9841 }
9842
9843 @ We get here when the argument is a null picture or when there is an error.
9844 Recovering from an error involves making |dash_list(h)| empty to indicate
9845 that |h| is not known to be a valid dash pattern.  We also dereference |h|
9846 since it is not being used for the return value.
9847
9848 @<Flush the dash list, recycle |h| and return |null|@>=
9849 mp_flush_dash_list(mp, h);
9850 delete_edge_ref(h);
9851 return null
9852
9853 @ Having carefully saved the dashed stroked nodes in the
9854 corresponding dash nodes, we must be prepared to break up these dashes into
9855 smaller dashes.
9856
9857 @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>=
9858 d=h;  /* now |link(d)=dash_list(h)| */
9859 while ( link(d)!=null_dash ) {
9860   ds=info(link(d));
9861   if ( ds==null ) { 
9862     d=link(d);
9863   } else {
9864     hh=dash_p(ds);
9865     hsf=dash_scale(ds);
9866     if ( (hh==null) ) mp_confusion(mp, "dash1");
9867 @:this can't happen dash0}{\quad dash1@>
9868     if ( dash_y(hh)==0 ) {
9869       d=link(d);
9870     } else { 
9871       if ( dash_list(hh)==null ) mp_confusion(mp, "dash1");
9872 @:this can't happen dash0}{\quad dash1@>
9873       @<Replace |link(d)| by a dashed version as determined by edge header
9874           |hh| and scale factor |ds|@>;
9875     }
9876   }
9877 }
9878
9879 @ @<Other local variables in |make_dashes|@>=
9880 pointer dln;  /* |link(d)| */
9881 pointer hh;  /* an edge header that tells how to break up |dln| */
9882 scaled hsf;  /* the dash pattern from |hh| gets scaled by this */
9883 pointer ds;  /* the stroked node from which |hh| and |hsf| are derived */
9884 scaled xoff;  /* added to $x$ values in |dash_list(hh)| to match |dln| */
9885
9886 @ @<Replace |link(d)| by a dashed version as determined by edge header...@>=
9887 dln=link(d);
9888 dd=dash_list(hh);
9889 xoff=start_x(dln)-mp_take_scaled(mp, hsf,start_x(dd))-
9890         mp_take_scaled(mp, hsf,mp_dash_offset(mp, hh));
9891 start_x(null_dash)=mp_take_scaled(mp, hsf,start_x(dd))
9892                    +mp_take_scaled(mp, hsf,dash_y(hh));
9893 stop_x(null_dash)=start_x(null_dash);
9894 @<Advance |dd| until finding the first dash that overlaps |dln| when
9895   offset by |xoff|@>;
9896 while ( start_x(dln)<=stop_x(dln) ) {
9897   @<If |dd| has `fallen off the end', back up to the beginning and fix |xoff|@>;
9898   @<Insert a dash between |d| and |dln| for the overlap with the offset version
9899     of |dd|@>;
9900   dd=link(dd);
9901   start_x(dln)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
9902 }
9903 link(d)=link(dln);
9904 mp_free_node(mp, dln,dash_node_size)
9905
9906 @ The name of this module is a bit of a lie because we actually just find the
9907 first |dd| where |take_scaled (hsf, stop_x(dd))| is large enough to make an
9908 overlap possible.  It could be that the unoffset version of dash |dln| falls
9909 in the gap between |dd| and its predecessor.
9910
9911 @<Advance |dd| until finding the first dash that overlaps |dln| when...@>=
9912 while ( xoff+mp_take_scaled(mp, hsf,stop_x(dd))<start_x(dln) ) {
9913   dd=link(dd);
9914 }
9915
9916 @ @<If |dd| has `fallen off the end', back up to the beginning and fix...@>=
9917 if ( dd==null_dash ) { 
9918   dd=dash_list(hh);
9919   xoff=xoff+mp_take_scaled(mp, hsf,dash_y(hh));
9920 }
9921
9922 @ At this point we already know that
9923 |start_x(dln)<=xoff+take_scaled(hsf,stop_x(dd))|.
9924
9925 @<Insert a dash between |d| and |dln| for the overlap with the offset...@>=
9926 if ( xoff+mp_take_scaled(mp, hsf,start_x(dd))<=stop_x(dln) ) {
9927   link(d)=mp_get_node(mp, dash_node_size);
9928   d=link(d);
9929   link(d)=dln;
9930   if ( start_x(dln)>xoff+mp_take_scaled(mp, hsf,start_x(dd)))
9931     start_x(d)=start_x(dln);
9932   else 
9933     start_x(d)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
9934   if ( stop_x(dln)<xoff+mp_take_scaled(mp, hsf,stop_x(dd)) ) 
9935     stop_x(d)=stop_x(dln);
9936   else 
9937     stop_x(d)=xoff+mp_take_scaled(mp, hsf,stop_x(dd));
9938 }
9939
9940 @ The next major task is to update the bounding box information in an edge
9941 header~|h|. This is done via a procedure |adjust_bbox| that enlarges an edge
9942 header's bounding box to accommodate the box computed by |path_bbox| or
9943 |pen_bbox|. (This is stored in global variables |minx|, |miny|, |maxx|, and
9944 |maxy|.)
9945
9946 @c void mp_adjust_bbox (MP mp,pointer h) { 
9947   if ( minx<minx_val(h) ) minx_val(h)=minx;
9948   if ( miny<miny_val(h) ) miny_val(h)=miny;
9949   if ( maxx>maxx_val(h) ) maxx_val(h)=maxx;
9950   if ( maxy>maxy_val(h) ) maxy_val(h)=maxy;
9951 }
9952
9953 @ Here is a special routine for updating the bounding box information in
9954 edge header~|h| to account for the squared-off ends of a non-cyclic path~|p|
9955 that is to be stroked with the pen~|pp|.
9956
9957 @c void mp_box_ends (MP mp, pointer p, pointer pp, pointer h) {
9958   pointer q;  /* a knot node adjacent to knot |p| */
9959   fraction dx,dy;  /* a unit vector in the direction out of the path at~|p| */
9960   scaled d;  /* a factor for adjusting the length of |(dx,dy)| */
9961   scaled z;  /* a coordinate being tested against the bounding box */
9962   scaled xx,yy;  /* the extreme pen vertex in the |(dx,dy)| direction */
9963   integer i; /* a loop counter */
9964   if ( right_type(p)!=endpoint ) { 
9965     q=link(p);
9966     while (1) { 
9967       @<Make |(dx,dy)| the final direction for the path segment from
9968         |q| to~|p|; set~|d|@>;
9969       d=mp_pyth_add(mp, dx,dy);
9970       if ( d>0 ) { 
9971          @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>;
9972          for (i=1;i<= 2;i++) { 
9973            @<Use |(dx,dy)| to generate a vertex of the square end cap and
9974              update the bounding box to accommodate it@>;
9975            dx=-dx; dy=-dy; 
9976         }
9977       }
9978       if ( right_type(p)==endpoint ) {
9979          return;
9980       } else {
9981         @<Advance |p| to the end of the path and make |q| the previous knot@>;
9982       } 
9983     }
9984   }
9985 }
9986
9987 @ @<Make |(dx,dy)| the final direction for the path segment from...@>=
9988 if ( q==link(p) ) { 
9989   dx=x_coord(p)-right_x(p);
9990   dy=y_coord(p)-right_y(p);
9991   if ( (dx==0)&&(dy==0) ) {
9992     dx=x_coord(p)-left_x(q);
9993     dy=y_coord(p)-left_y(q);
9994   }
9995 } else { 
9996   dx=x_coord(p)-left_x(p);
9997   dy=y_coord(p)-left_y(p);
9998   if ( (dx==0)&&(dy==0) ) {
9999     dx=x_coord(p)-right_x(q);
10000     dy=y_coord(p)-right_y(q);
10001   }
10002 }
10003 dx=x_coord(p)-x_coord(q);
10004 dy=y_coord(p)-y_coord(q)
10005
10006 @ @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>=
10007 dx=mp_make_fraction(mp, dx,d);
10008 dy=mp_make_fraction(mp, dy,d);
10009 mp_find_offset(mp, -dy,dx,pp);
10010 xx=mp->cur_x; yy=mp->cur_y
10011
10012 @ @<Use |(dx,dy)| to generate a vertex of the square end cap and...@>=
10013 mp_find_offset(mp, dx,dy,pp);
10014 d=mp_take_fraction(mp, xx-mp->cur_x,dx)+mp_take_fraction(mp, yy-mp->cur_y,dy);
10015 if ( ((d<0)&&(i==1)) || ((d>0)&&(i==2))) 
10016   mp_confusion(mp, "box_ends");
10017 @:this can't happen box ends}{\quad\\{box\_ends}@>
10018 z=x_coord(p)+mp->cur_x+mp_take_fraction(mp, d,dx);
10019 if ( z<minx_val(h) ) minx_val(h)=z;
10020 if ( z>maxx_val(h) ) maxx_val(h)=z;
10021 z=y_coord(p)+mp->cur_y+mp_take_fraction(mp, d,dy);
10022 if ( z<miny_val(h) ) miny_val(h)=z;
10023 if ( z>maxy_val(h) ) maxy_val(h)=z
10024
10025 @ @<Advance |p| to the end of the path and make |q| the previous knot@>=
10026 do {  
10027   q=p;
10028   p=link(p);
10029 } while (right_type(p)!=endpoint)
10030
10031 @ The major difficulty in finding the bounding box of an edge structure is the
10032 effect of clipping paths.  We treat them conservatively by only clipping to the
10033 clipping path's bounding box, but this still
10034 requires recursive calls to |set_bbox| in order to find the bounding box of
10035 @^recursion@>
10036 the objects to be clipped.  Such calls are distinguished by the fact that the
10037 boolean parameter |top_level| is false.
10038
10039 @c void mp_set_bbox (MP mp,pointer h, boolean top_level) {
10040   pointer p;  /* a graphical object being considered */
10041   scaled sminx,sminy,smaxx,smaxy;
10042   /* for saving the bounding box during recursive calls */
10043   scaled x0,x1,y0,y1;  /* temporary registers */
10044   integer lev;  /* nesting level for |mp_start_bounds_code| nodes */
10045   @<Wipe out any existing bounding box information if |bbtype(h)| is
10046   incompatible with |internal[true_corners]|@>;
10047   while ( link(bblast(h))!=null ) { 
10048     p=link(bblast(h));
10049     bblast(h)=p;
10050     switch (type(p)) {
10051     case mp_stop_clip_code: 
10052       if ( top_level ) mp_confusion(mp, "bbox");  else return;
10053 @:this can't happen bbox}{\quad bbox@>
10054       break;
10055     @<Other cases for updating the bounding box based on the type of object |p|@>;
10056     } /* all cases are enumerated above */
10057   }
10058   if ( ! top_level ) mp_confusion(mp, "bbox");
10059 }
10060
10061 @ @<Wipe out any existing bounding box information if |bbtype(h)| is...@>=
10062 switch (bbtype(h)) {
10063 case no_bounds: 
10064   break;
10065 case bounds_set: 
10066   if ( mp->internal[true_corners]>0 ) mp_init_bbox(mp, h);
10067   break;
10068 case bounds_unset: 
10069   if ( mp->internal[true_corners]<=0 ) mp_init_bbox(mp, h);
10070   break;
10071 } /* there are no other cases */
10072
10073 @ @<Other cases for updating the bounding box...@>=
10074 case fill_code: 
10075   mp_path_bbox(mp, path_p(p));
10076   if ( pen_p(p)!=null ) { 
10077     x0=minx; y0=miny;
10078     x1=maxx; y1=maxy;
10079     mp_pen_bbox(mp, pen_p(p));
10080     minx=minx+x0;
10081     miny=miny+y0;
10082     maxx=maxx+x1;
10083     maxy=maxy+y1;
10084   }
10085   mp_adjust_bbox(mp, h);
10086   break;
10087
10088 @ @<Other cases for updating the bounding box...@>=
10089 case mp_start_bounds_code: 
10090   if ( mp->internal[true_corners]>0 ) {
10091     bbtype(h)=bounds_unset;
10092   } else { 
10093     bbtype(h)=bounds_set;
10094     mp_path_bbox(mp, path_p(p));
10095     mp_adjust_bbox(mp, h);
10096     @<Scan to the matching |mp_stop_bounds_code| node and update |p| and
10097       |bblast(h)|@>;
10098   }
10099   break;
10100 case mp_stop_bounds_code: 
10101   if ( mp->internal[true_corners]<=0 ) mp_confusion(mp, "bbox2");
10102 @:this can't happen bbox2}{\quad bbox2@>
10103   break;
10104
10105 @ @<Scan to the matching |mp_stop_bounds_code| node and update |p| and...@>=
10106 lev=1;
10107 while ( lev!=0 ) { 
10108   if ( link(p)==null ) mp_confusion(mp, "bbox2");
10109 @:this can't happen bbox2}{\quad bbox2@>
10110   p=link(p);
10111   if ( type(p)==mp_start_bounds_code ) incr(lev);
10112   else if ( type(p)==mp_stop_bounds_code ) decr(lev);
10113 }
10114 bblast(h)=p
10115
10116 @ It saves a lot of grief here to be slightly conservative and not account for
10117 omitted parts of dashed lines.  We also don't worry about the material omitted
10118 when using butt end caps.  The basic computation is for round end caps and
10119 |box_ends| augments it for square end caps.
10120
10121 @<Other cases for updating the bounding box...@>=
10122 case stroked_code: 
10123   mp_path_bbox(mp, path_p(p));
10124   x0=minx; y0=miny;
10125   x1=maxx; y1=maxy;
10126   mp_pen_bbox(mp, pen_p(p));
10127   minx=minx+x0;
10128   miny=miny+y0;
10129   maxx=maxx+x1;
10130   maxy=maxy+y1;
10131   mp_adjust_bbox(mp, h);
10132   if ( (left_type(path_p(p))==endpoint)&&(lcap_val(p)==2) )
10133     mp_box_ends(mp, path_p(p), pen_p(p), h);
10134   break;
10135
10136 @ The height width and depth information stored in a text node determines a
10137 rectangle that needs to be transformed according to the transformation
10138 parameters stored in the text node.
10139
10140 @<Other cases for updating the bounding box...@>=
10141 case text_code: 
10142   x1=mp_take_scaled(mp, txx_val(p),width_val(p));
10143   y0=mp_take_scaled(mp, txy_val(p),-depth_val(p));
10144   y1=mp_take_scaled(mp, txy_val(p),height_val(p));
10145   minx=tx_val(p);
10146   maxx=minx;
10147   if ( y0<y1 ) { minx=minx+y0; maxx=maxx+y1;  }
10148   else         { minx=minx+y1; maxx=maxx+y0;  }
10149   if ( x1<0 ) minx=minx+x1;  else maxx=maxx+x1;
10150   x1=mp_take_scaled(mp, tyx_val(p),width_val(p));
10151   y0=mp_take_scaled(mp, tyy_val(p),-depth_val(p));
10152   y1=mp_take_scaled(mp, tyy_val(p),height_val(p));
10153   miny=ty_val(p);
10154   maxy=miny;
10155   if ( y0<y1 ) { miny=miny+y0; maxy=maxy+y1;  }
10156   else         { miny=miny+y1; maxy=maxy+y0;  }
10157   if ( x1<0 ) miny=miny+x1;  else maxy=maxy+x1;
10158   mp_adjust_bbox(mp, h);
10159   break;
10160
10161 @ This case involves a recursive call that advances |bblast(h)| to the node of
10162 type |mp_stop_clip_code| that matches |p|.
10163
10164 @<Other cases for updating the bounding box...@>=
10165 case mp_start_clip_code: 
10166   mp_path_bbox(mp, path_p(p));
10167   x0=minx; y0=miny;
10168   x1=maxx; y1=maxy;
10169   sminx=minx_val(h); sminy=miny_val(h);
10170   smaxx=maxx_val(h); smaxy=maxy_val(h);
10171   @<Reinitialize the bounding box in header |h| and call |set_bbox| recursively
10172     starting at |link(p)|@>;
10173   @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,
10174     |y0|, |y1|@>;
10175   minx=sminx; miny=sminy;
10176   maxx=smaxx; maxy=smaxy;
10177   mp_adjust_bbox(mp, h);
10178   break;
10179
10180 @ @<Reinitialize the bounding box in header |h| and call |set_bbox|...@>=
10181 minx_val(h)=el_gordo;
10182 miny_val(h)=el_gordo;
10183 maxx_val(h)=-el_gordo;
10184 maxy_val(h)=-el_gordo;
10185 mp_set_bbox(mp, h,false)
10186
10187 @ @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,...@>=
10188 if ( minx_val(h)<x0 ) minx_val(h)=x0;
10189 if ( miny_val(h)<y0 ) miny_val(h)=y0;
10190 if ( maxx_val(h)>x1 ) maxx_val(h)=x1;
10191 if ( maxy_val(h)>y1 ) maxy_val(h)=y1
10192
10193 @* \[22] Finding an envelope.
10194 When \MP\ has a path and a polygonal pen, it needs to express the desired
10195 shape in terms of things \ps\ can understand.  The present task is to compute
10196 a new path that describes the region to be filled.  It is convenient to
10197 define this as a two step process where the first step is determining what
10198 offset to use for each segment of the path.
10199
10200 @ Given a pointer |c| to a cyclic path,
10201 and a pointer~|h| to the first knot of a pen polygon,
10202 the |offset_prep| routine changes the path into cubics that are
10203 associated with particular pen offsets. Thus if the cubic between |p|
10204 and~|q| is associated with the |k|th offset and the cubic between |q| and~|r|
10205 has offset |l| then |info(q)=zero_off+l-k|. (The constant |zero_off| is added
10206 to because |l-k| could be negative.)
10207
10208 After overwriting the type information with offset differences, we no longer
10209 have a true path so we refer to the knot list returned by |offset_prep| as an
10210 ``envelope spec.''
10211 @^envelope spec@>
10212 Since an envelope spec only determines relative changes in pen offsets,
10213 |offset_prep| sets a global variable |spec_offset| to the relative change from
10214 |h| to the first offset.
10215
10216 @d zero_off 16384 /* added to offset changes to make them positive */
10217
10218 @<Glob...@>=
10219 integer spec_offset; /* number of pen edges between |h| and the initial offset */
10220
10221 @ @c @<Declare subroutines needed by |offset_prep|@>;
10222 pointer mp_offset_prep (MP mp,pointer c, pointer h) {
10223   halfword n; /* the number of vertices in the pen polygon */
10224   pointer p,q,r,w, ww; /* for list manipulation */
10225   integer k_needed; /* amount to be added to |info(p)| when it is computed */
10226   pointer w0; /* a pointer to pen offset to use just before |p| */
10227   scaled dxin,dyin; /* the direction into knot |p| */
10228   integer turn_amt; /* change in pen offsets for the current cubic */
10229   @<Other local variables for |offset_prep|@>;
10230   dx0=0; dy0=0;
10231   @<Initialize the pen size~|n|@>;
10232   @<Initialize the incoming direction and pen offset at |c|@>;
10233   p=c; k_needed=0;
10234   do {  
10235     q=link(p);
10236     @<Split the cubic between |p| and |q|, if necessary, into cubics
10237       associated with single offsets, after which |q| should
10238       point to the end of the final such cubic@>;
10239     @<Advance |p| to node |q|, removing any ``dead'' cubics that
10240       might have been introduced by the splitting process@>;
10241   } while (q!=c);
10242   @<Fix the offset change in |info(c)| and set the return value of
10243     |offset_prep|@>;
10244 }
10245
10246 @ We shall want to keep track of where certain knots on the cyclic path
10247 wind up in the envelope spec.  It doesn't suffice just to keep pointers to
10248 knot nodes because some nodes are deleted while removing dead cubics.  Thus
10249 |offset_prep| updates the following pointers
10250
10251 @<Glob...@>=
10252 pointer spec_p1;
10253 pointer spec_p2; /* pointers to distinguished knots */
10254
10255 @ @<Set init...@>=
10256 mp->spec_p1=null; mp->spec_p2=null;
10257
10258 @ @<Initialize the pen size~|n|@>=
10259 n=0; p=h;
10260 do {  
10261   incr(n);
10262   p=link(p);
10263 } while (p!=h)
10264
10265 @ Since the true incoming direction isn't known yet, we just pick a direction
10266 consistent with the pen offset~|h|.  If this is wrong, it can be corrected
10267 later.
10268
10269 @<Initialize the incoming direction and pen offset at |c|@>=
10270 dxin=x_coord(link(h))-x_coord(knil(h));
10271 dyin=y_coord(link(h))-y_coord(knil(h));
10272 if ( (dxin==0)&&(dyin==0) ) {
10273   dxin=y_coord(knil(h))-y_coord(h);
10274   dyin=x_coord(h)-x_coord(knil(h));
10275 }
10276 w0=h
10277
10278 @ We must be careful not to remove the only cubic in a cycle.
10279
10280 But we must also be careful for another reason. If the user-supplied
10281 path starts with a set of degenerate cubics, these should not be removed
10282 because at this point we cannot do so cleanly. The relevant bug is
10283 tracker id 267, bugs 52c, reported by Boguslav.
10284
10285 @<Advance |p| to node |q|, removing any ``dead'' cubics...@>=
10286 do {  r=link(p);
10287 if ( x_coord(p)==right_x(p) ) if ( y_coord(p)==right_y(p) )
10288  if ( x_coord(p)==left_x(r) ) if ( y_coord(p)==left_y(r) )
10289   if ( x_coord(p)==x_coord(r) ) if ( y_coord(p)==y_coord(r) )
10290     if ( r!=p ) if ( ((r!=q) || (originator(r)!=metapost_user)) ) {
10291       @<Remove the cubic following |p| and update the data structures
10292         to merge |r| into |p|@>;
10293 }
10294 p=r;
10295 } while (p!=q)
10296
10297 @ @<Remove the cubic following |p| and update the data structures...@>=
10298 { k_needed=info(p)-zero_off;
10299   if ( r==q ) { 
10300     q=p;
10301   } else { 
10302     info(p)=k_needed+info(r);
10303     k_needed=0;
10304   };
10305   if ( r==c ) { info(p)=info(c); c=p; };
10306   if ( r==mp->spec_p1 ) mp->spec_p1=p;
10307   if ( r==mp->spec_p2 ) mp->spec_p2=p;
10308   r=p; mp_remove_cubic(mp, p);
10309 }
10310
10311 @ Not setting the |info| field of the newly created knot allows the splitting
10312 routine to work for paths.
10313
10314 @<Declare subroutines needed by |offset_prep|@>=
10315 void mp_split_cubic (MP mp,pointer p, fraction t) { /* splits the cubic after |p| */
10316   scaled v; /* an intermediate value */
10317   pointer q,r; /* for list manipulation */
10318   q=link(p); r=mp_get_node(mp, knot_node_size); link(p)=r; link(r)=q;
10319   originator(r)=program_code;
10320   left_type(r)=explicit; right_type(r)=explicit;
10321   v=t_of_the_way(right_x(p),left_x(q));
10322   right_x(p)=t_of_the_way(x_coord(p),right_x(p));
10323   left_x(q)=t_of_the_way(left_x(q),x_coord(q));
10324   left_x(r)=t_of_the_way(right_x(p),v);
10325   right_x(r)=t_of_the_way(v,left_x(q));
10326   x_coord(r)=t_of_the_way(left_x(r),right_x(r));
10327   v=t_of_the_way(right_y(p),left_y(q));
10328   right_y(p)=t_of_the_way(y_coord(p),right_y(p));
10329   left_y(q)=t_of_the_way(left_y(q),y_coord(q));
10330   left_y(r)=t_of_the_way(right_y(p),v);
10331   right_y(r)=t_of_the_way(v,left_y(q));
10332   y_coord(r)=t_of_the_way(left_y(r),right_y(r));
10333 }
10334
10335 @ This does not set |info(p)| or |right_type(p)|.
10336
10337 @<Declare subroutines needed by |offset_prep|@>=
10338 void mp_remove_cubic (MP mp,pointer p) { /* removes the dead cubic following~|p| */
10339   pointer q; /* the node that disappears */
10340   q=link(p); link(p)=link(q);
10341   right_x(p)=right_x(q); right_y(p)=right_y(q);
10342   mp_free_node(mp, q,knot_node_size);
10343 }
10344
10345 @ Let $d\prec d'$ mean that the counter-clockwise angle from $d$ to~$d'$ is
10346 strictly between zero and $180^\circ$.  Then we can define $d\preceq d'$ to
10347 mean that the angle could be zero or $180^\circ$. If $w_k=(u_k,v_k)$ is the
10348 $k$th pen offset, the $k$th pen edge direction is defined by the formula
10349 $$d_k=(u\k-u_k,\,v\k-v_k).$$
10350 When listed by increasing $k$, these directions occur in counter-clockwise
10351 order so that $d_k\preceq d\k$ for all~$k$.
10352 The goal of |offset_prep| is to find an offset index~|k| to associate with
10353 each cubic, such that the direction $d(t)$ of the cubic satisfies
10354 $$d_{k-1}\preceq d(t)\preceq d_k\qquad\hbox{for $0\le t\le 1$.}\eqno(*)$$
10355 We may have to split a cubic into many pieces before each
10356 piece corresponds to a unique offset.
10357
10358 @<Split the cubic between |p| and |q|, if necessary, into cubics...@>=
10359 info(p)=zero_off+k_needed;
10360 k_needed=0;
10361 @<Prepare for derivative computations;
10362   |goto not_found| if the current cubic is dead@>;
10363 @<Find the initial direction |(dx,dy)|@>;
10364 @<Update |info(p)| and find the offset $w_k$ such that
10365   $d_{k-1}\preceq(\\{dx},\\{dy})\prec d_k$; also advance |w0| for
10366   the direction change at |p|@>;
10367 @<Find the final direction |(dxin,dyin)|@>;
10368 @<Decide on the net change in pen offsets and set |turn_amt|@>;
10369 @<Complete the offset splitting process@>;
10370 w0=mp_pen_walk(mp, w0,turn_amt);
10371 NOT_FOUND: do_nothing
10372
10373 @ @<Declare subroutines needed by |offset_prep|@>=
10374 pointer mp_pen_walk (MP mp,pointer w, integer k) {
10375   /* walk |k| steps around a pen from |w| */
10376   while ( k>0 ) { w=link(w); decr(k);  };
10377   while ( k<0 ) { w=knil(w); incr(k);  };
10378   return w;
10379 }
10380
10381 @ The direction of a cubic $B(z_0,z_1,z_2,z_3;t)=\bigl(x(t),y(t)\bigr)$ can be
10382 calculated from the quadratic polynomials
10383 ${1\over3}x'(t)=B(x_1-x_0,x_2-x_1,x_3-x_2;t)$ and
10384 ${1\over3}y'(t)=B(y_1-y_0,y_2-y_1,y_3-y_2;t)$.
10385 Since we may be calculating directions from several cubics
10386 split from the current one, it is desirable to do these calculations
10387 without losing too much precision. ``Scaled up'' values of the
10388 derivatives, which will be less tainted by accumulated errors than
10389 derivatives found from the cubics themselves, are maintained in
10390 local variables |x0|, |x1|, and |x2|, representing $X_0=2^l(x_1-x_0)$,
10391 $X_1=2^l(x_2-x_1)$, and $X_2=2^l(x_3-x_2)$; similarly |y0|, |y1|, and~|y2|
10392 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)$.
10393
10394 @<Other local variables for |offset_prep|@>=
10395 integer x0,x1,x2,y0,y1,y2; /* representatives of derivatives */
10396 integer t0,t1,t2; /* coefficients of polynomial for slope testing */
10397 integer du,dv,dx,dy; /* for directions of the pen and the curve */
10398 integer dx0,dy0; /* initial direction for the first cubic in the curve */
10399 integer mp_max_coef; /* used while scaling */
10400 integer x0a,x1a,x2a,y0a,y1a,y2a; /* intermediate values */
10401 fraction t; /* where the derivative passes through zero */
10402 fraction s; /* a temporary value */
10403
10404 @ @<Prepare for derivative computations...@>=
10405 x0=right_x(p)-x_coord(p);
10406 x2=x_coord(q)-left_x(q);
10407 x1=left_x(q)-right_x(p);
10408 y0=right_y(p)-y_coord(p); y2=y_coord(q)-left_y(q);
10409 y1=left_y(q)-right_y(p);
10410 mp_max_coef=abs(x0);
10411 if ( abs(x1)>mp_max_coef ) mp_max_coef=abs(x1);
10412 if ( abs(x2)>mp_max_coef ) mp_max_coef=abs(x2);
10413 if ( abs(y0)>mp_max_coef ) mp_max_coef=abs(y0);
10414 if ( abs(y1)>mp_max_coef ) mp_max_coef=abs(y1);
10415 if ( abs(y2)>mp_max_coef ) mp_max_coef=abs(y2);
10416 if ( mp_max_coef==0 ) goto NOT_FOUND;
10417 while ( mp_max_coef<fraction_half ) {
10418   mp_max_coef+=mp_max_coef;
10419   x0+=x0; x1+=x1; x2+=x2;
10420   y0+=y0; y1+=y1; y2+=y2;
10421 }
10422
10423 @ Let us first solve a special case of the problem: Suppose we
10424 know an index~$k$ such that either (i)~$d(t)\succeq d_{k-1}$ for all~$t$
10425 and $d(0)\prec d_k$, or (ii)~$d(t)\preceq d_k$ for all~$t$ and
10426 $d(0)\succ d_{k-1}$.
10427 Then, in a sense, we're halfway done, since one of the two relations
10428 in $(*)$ is satisfied, and the other couldn't be satisfied for
10429 any other value of~|k|.
10430
10431 Actually, the conditions can be relaxed somewhat since a relation such as
10432 $d(t)\succeq d_{k-1}$ restricts $d(t)$ to a half plane when all that really
10433 matters is whether $d(t)$ crosses the ray in the $d_{k-1}$ direction from
10434 the origin.  The condition for case~(i) becomes $d_{k-1}\preceq d(0)\prec d_k$
10435 and $d(t)$ never crosses the $d_{k-1}$ ray in the clockwise direction.
10436 Case~(ii) is similar except $d(t)$ cannot cross the $d_k$ ray in the
10437 counterclockwise direction.
10438
10439 The |fin_offset_prep| subroutine solves the stated subproblem.
10440 It has a parameter called |rise| that is |1| in
10441 case~(i), |-1| in case~(ii). Parameters |x0| through |y2| represent
10442 the derivative of the cubic following |p|.
10443 The |w| parameter should point to offset~$w_k$ and |info(p)| should already
10444 be set properly.  The |turn_amt| parameter gives the absolute value of the
10445 overall net change in pen offsets.
10446
10447 @<Declare subroutines needed by |offset_prep|@>=
10448 void mp_fin_offset_prep (MP mp,pointer p, pointer w, integer 
10449   x0,integer x1, integer x2, integer y0, integer y1, integer y2, 
10450   integer rise, integer turn_amt)  {
10451   pointer ww; /* for list manipulation */
10452   scaled du,dv; /* for slope calculation */
10453   integer t0,t1,t2; /* test coefficients */
10454   fraction t; /* place where the derivative passes a critical slope */
10455   fraction s; /* slope or reciprocal slope */
10456   integer v; /* intermediate value for updating |x0..y2| */
10457   pointer q; /* original |link(p)| */
10458   q=link(p);
10459   while (1)  { 
10460     if ( rise>0 ) ww=link(w); /* a pointer to $w\k$ */
10461     else  ww=knil(w); /* a pointer to $w_{k-1}$ */
10462     @<Compute test coefficients |(t0,t1,t2)|
10463       for $d(t)$ versus $d_k$ or $d_{k-1}$@>;
10464     t=mp_crossing_point(mp, t0,t1,t2);
10465     if ( t>=fraction_one ) {
10466       if ( turn_amt>0 ) t=fraction_one;  else return;
10467     }
10468     @<Split the cubic at $t$,
10469       and split off another cubic if the derivative crosses back@>;
10470     w=ww;
10471   }
10472 }
10473
10474 @ We want $B(\\{t0},\\{t1},\\{t2};t)$ to be the dot product of $d(t)$ with a
10475 $-90^\circ$ rotation of the vector from |w| to |ww|.  This makes the resulting
10476 function cross from positive to negative when $d_{k-1}\preceq d(t)\preceq d_k$
10477 begins to fail.
10478
10479 @<Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...@>=
10480 du=x_coord(ww)-x_coord(w); dv=y_coord(ww)-y_coord(w);
10481 if ( abs(du)>=abs(dv) ) {
10482   s=mp_make_fraction(mp, dv,du);
10483   t0=mp_take_fraction(mp, x0,s)-y0;
10484   t1=mp_take_fraction(mp, x1,s)-y1;
10485   t2=mp_take_fraction(mp, x2,s)-y2;
10486   if ( du<0 ) { negate(t0); negate(t1); negate(t2);  }
10487 } else { 
10488   s=mp_make_fraction(mp, du,dv);
10489   t0=x0-mp_take_fraction(mp, y0,s);
10490   t1=x1-mp_take_fraction(mp, y1,s);
10491   t2=x2-mp_take_fraction(mp, y2,s);
10492   if ( dv<0 ) { negate(t0); negate(t1); negate(t2);  }
10493 }
10494 if ( t0<0 ) t0=0 /* should be positive without rounding error */
10495
10496 @ The curve has crossed $d_k$ or $d_{k-1}$; its initial segment satisfies
10497 $(*)$, and it might cross again, yielding another solution of $(*)$.
10498
10499 @<Split the cubic at $t$, and split off another...@>=
10500
10501 mp_split_cubic(mp, p,t); p=link(p); info(p)=zero_off+rise;
10502 decr(turn_amt);
10503 v=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10504 x0=t_of_the_way(v,x1);
10505 v=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10506 y0=t_of_the_way(v,y1);
10507 if ( turn_amt<0 ) {
10508   t1=t_of_the_way(t1,t2);
10509   if ( t1>0 ) t1=0; /* without rounding error, |t1| would be |<=0| */
10510   t=mp_crossing_point(mp, 0,-t1,-t2);
10511   if ( t>fraction_one ) t=fraction_one;
10512   incr(turn_amt);
10513   if ( (t==fraction_one)&&(link(p)!=q) ) {
10514     info(link(p))=info(link(p))-rise;
10515   } else { 
10516     mp_split_cubic(mp, p,t); info(link(p))=zero_off-rise;
10517     v=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10518     x2=t_of_the_way(x1,v);
10519     v=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10520     y2=t_of_the_way(y1,v);
10521   }
10522 }
10523 }
10524
10525 @ Now we must consider the general problem of |offset_prep|, when
10526 nothing is known about a given cubic. We start by finding its
10527 direction in the vicinity of |t=0|.
10528
10529 If $z'(t)=0$, the given cubic is numerically unstable but |offset_prep|
10530 has not yet introduced any more numerical errors.  Thus we can compute
10531 the true initial direction for the given cubic, even if it is almost
10532 degenerate.
10533
10534 @<Find the initial direction |(dx,dy)|@>=
10535 dx=x0; dy=y0;
10536 if ( dx==0 ) if ( dy==0 ) { 
10537   dx=x1; dy=y1;
10538   if ( dx==0 ) if ( dy==0 ) { 
10539     dx=x2; dy=y2;
10540   }
10541 }
10542 if ( p==c ) { dx0=dx; dy0=dy;  }
10543
10544 @ @<Find the final direction |(dxin,dyin)|@>=
10545 dxin=x2; dyin=y2;
10546 if ( dxin==0 ) if ( dyin==0 ) {
10547   dxin=x1; dyin=y1;
10548   if ( dxin==0 ) if ( dyin==0 ) {
10549     dxin=x0; dyin=y0;
10550   }
10551 }
10552
10553 @ The next step is to bracket the initial direction between consecutive
10554 edges of the pen polygon.  We must be careful to turn clockwise only if
10555 this makes the turn less than $180^\circ$. (A $180^\circ$ turn must be
10556 counter-clockwise in order to make \&{doublepath} envelopes come out
10557 @:double_path_}{\&{doublepath} primitive@>
10558 right.) This code depends on |w0| being the offset for |(dxin,dyin)|.
10559
10560 @<Update |info(p)| and find the offset $w_k$ such that...@>=
10561 turn_amt=mp_get_turn_amt(mp, w0, dx, dy, mp_ab_vs_cd(mp, dy,dxin,dx,dyin)>=0);
10562 w=mp_pen_walk(mp, w0, turn_amt);
10563 w0=w;
10564 info(p)=info(p)+turn_amt
10565
10566 @ Decide how many pen offsets to go away from |w| in order to find the offset
10567 for |(dx,dy)|, going counterclockwise if |ccw| is |true|.  This assumes that
10568 |w| is the offset for some direction $(x',y')$ from which the angle to |(dx,dy)|
10569 in the sense determined by |ccw| is less than or equal to $180^\circ$.
10570
10571 If the pen polygon has only two edges, they could both be parallel
10572 to |(dx,dy)|.  In this case, we must be careful to stop after crossing the first
10573 such edge in order to avoid an infinite loop.
10574
10575 @<Declare subroutines needed by |offset_prep|@>=
10576 integer mp_get_turn_amt (MP mp,pointer w, scaled  dx,
10577                          scaled dy, boolean  ccw) {
10578   pointer ww; /* a neighbor of knot~|w| */
10579   integer s; /* turn amount so far */
10580   integer t; /* |ab_vs_cd| result */
10581   s=0;
10582   if ( ccw ) { 
10583     ww=link(w);
10584     do {  
10585       t=mp_ab_vs_cd(mp, dy,x_coord(ww)-x_coord(w),
10586                         dx,y_coord(ww)-y_coord(w));
10587       if ( t<0 ) break;
10588       incr(s);
10589       w=ww; ww=link(ww);
10590     } while (t>0);
10591   } else { 
10592     ww=knil(w);
10593     while ( mp_ab_vs_cd(mp, dy,x_coord(w)-x_coord(ww),
10594                             dx,y_coord(w)-y_coord(ww))<0 ) { 
10595       decr(s);
10596       w=ww; ww=knil(ww);
10597     }
10598   }
10599   return s;
10600 }
10601
10602 @ When we're all done, the final offset is |w0| and the final curve direction
10603 is |(dxin,dyin)|.  With this knowledge of the incoming direction at |c|, we
10604 can correct |info(c)| which was erroneously based on an incoming offset
10605 of~|h|.
10606
10607 @d fix_by(A) info(c)=info(c)+(A)
10608
10609 @<Fix the offset change in |info(c)| and set the return value of...@>=
10610 mp->spec_offset=info(c)-zero_off;
10611 if ( link(c)==c ) {
10612   info(c)=zero_off+n;
10613 } else { 
10614   fix_by(k_needed);
10615   while ( w0!=h ) { fix_by(1); w0=link(w0);  };
10616   while ( info(c)<=zero_off-n ) fix_by(n);
10617   while ( info(c)>zero_off ) fix_by(-n);
10618   if ( (info(c)!=zero_off)&&(mp_ab_vs_cd(mp, dy0,dxin,dx0,dyin)>=0) ) fix_by(n);
10619 }
10620 return c
10621
10622 @ Finally we want to reduce the general problem to situations that
10623 |fin_offset_prep| can handle. We split the cubic into at most three parts
10624 with respect to $d_{k-1}$, and apply |fin_offset_prep| to each part.
10625
10626 @<Complete the offset splitting process@>=
10627 ww=knil(w);
10628 @<Compute test coeff...@>;
10629 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set
10630   |t:=fraction_one+1|@>;
10631 if ( t>fraction_one ) {
10632   mp_fin_offset_prep(mp, p,w,x0,x1,x2,y0,y1,y2,1,turn_amt);
10633 } else {
10634   mp_split_cubic(mp, p,t); r=link(p);
10635   x1a=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10636   x2a=t_of_the_way(x1a,x1);
10637   y1a=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10638   y2a=t_of_the_way(y1a,y1);
10639   mp_fin_offset_prep(mp, p,w,x0,x1a,x2a,y0,y1a,y2a,1,0); x0=x2a; y0=y2a;
10640   info(r)=zero_off-1;
10641   if ( turn_amt>=0 ) {
10642     t1=t_of_the_way(t1,t2);
10643     if ( t1>0 ) t1=0;
10644     t=mp_crossing_point(mp, 0,-t1,-t2);
10645     if ( t>fraction_one ) t=fraction_one;
10646     @<Split off another rising cubic for |fin_offset_prep|@>;
10647     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,0);
10648   } else {
10649     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,-1-turn_amt);
10650   }
10651 }
10652
10653 @ @<Split off another rising cubic for |fin_offset_prep|@>=
10654 mp_split_cubic(mp, r,t); info(link(r))=zero_off+1;
10655 x1a=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10656 x0a=t_of_the_way(x1,x1a);
10657 y1a=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10658 y0a=t_of_the_way(y1,y1a);
10659 mp_fin_offset_prep(mp, link(r),w,x0a,x1a,x2,y0a,y1a,y2,1,turn_amt);
10660 x2=x0a; y2=y0a
10661
10662 @ At this point, the direction of the incoming pen edge is |(-du,-dv)|.
10663 When the component of $d(t)$ perpendicular to |(-du,-dv)| crosses zero, we
10664 need to decide whether the directions are parallel or antiparallel.  We
10665 can test this by finding the dot product of $d(t)$ and |(-du,-dv)|, but this
10666 should be avoided when the value of |turn_amt| already determines the
10667 answer.  If |t2<0|, there is one crossing and it is antiparallel only if
10668 |turn_amt>=0|.  If |turn_amt<0|, there should always be at least one
10669 crossing and the first crossing cannot be antiparallel.
10670
10671 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set...@>=
10672 t=mp_crossing_point(mp, t0,t1,t2);
10673 if ( turn_amt>=0 ) {
10674   if ( t2<0 ) {
10675     t=fraction_one+1;
10676   } else { 
10677     u0=t_of_the_way(x0,x1);
10678     u1=t_of_the_way(x1,x2);
10679     ss=mp_take_fraction(mp, -du,t_of_the_way(u0,u1));
10680     v0=t_of_the_way(y0,y1);
10681     v1=t_of_the_way(y1,y2);
10682     ss=ss+mp_take_fraction(mp, -dv,t_of_the_way(v0,v1));
10683     if ( ss<0 ) t=fraction_one+1;
10684   }
10685 } else if ( t>fraction_one ) {
10686   t=fraction_one;
10687 }
10688
10689 @ @<Other local variables for |offset_prep|@>=
10690 integer u0,u1,v0,v1; /* intermediate values for $d(t)$ calculation */
10691 integer ss = 0; /* the part of the dot product computed so far */
10692 int d_sign; /* sign of overall change in direction for this cubic */
10693
10694 @ If the cubic almost has a cusp, it is a numerically ill-conditioned
10695 problem to decide which way it loops around but that's OK as long we're
10696 consistent.  To make \&{doublepath} envelopes work properly, reversing
10697 the path should always change the sign of |turn_amt|.
10698
10699 @<Decide on the net change in pen offsets and set |turn_amt|@>=
10700 d_sign=mp_ab_vs_cd(mp, dx,dyin, dxin,dy);
10701 if ( d_sign==0 ) {
10702   if ( dx==0 ) {
10703     if ( dy>0 ) d_sign=1;  else d_sign=-1;
10704   } else if ( dx>0 ) { 
10705     d_sign=1;  
10706   } else { 
10707     d_sign=-1; 
10708   }
10709 }
10710 @<Make |ss| negative if and only if the total change in direction is
10711   more than $180^\circ$@>;
10712 turn_amt=mp_get_turn_amt(mp, w, dxin, dyin, d_sign>0);
10713 if ( ss<0 ) turn_amt=turn_amt-d_sign*n
10714
10715 @ In order to be invariant under path reversal, the result of this computation
10716 should not change when |x0|, |y0|, $\ldots$ are all negated and |(x0,y0)| is
10717 then swapped with |(x2,y2)|.  We make use of the identities
10718 |take_fraction(-a,-b)=take_fraction(a,b)| and
10719 |t_of_the_way(-a,-b)=-(t_of_the_way(a,b))|.
10720
10721 @<Make |ss| negative if and only if the total change in direction is...@>=
10722 t0=half(mp_take_fraction(mp, x0,y2))-half(mp_take_fraction(mp, x2,y0));
10723 t1=half(mp_take_fraction(mp, x1,y0+y2))-half(mp_take_fraction(mp, y1,x0+x2));
10724 if ( t0==0 ) t0=d_sign; /* path reversal always negates |d_sign| */
10725 if ( t0>0 ) {
10726   t=mp_crossing_point(mp, t0,t1,-t0);
10727   u0=t_of_the_way(x0,x1);
10728   u1=t_of_the_way(x1,x2);
10729   v0=t_of_the_way(y0,y1);
10730   v1=t_of_the_way(y1,y2);
10731 } else { 
10732   t=mp_crossing_point(mp, -t0,t1,t0);
10733   u0=t_of_the_way(x2,x1);
10734   u1=t_of_the_way(x1,x0);
10735   v0=t_of_the_way(y2,y1);
10736   v1=t_of_the_way(y1,y0);
10737 }
10738 s=mp_take_fraction(mp, x0+x2,t_of_the_way(u0,u1))+
10739   mp_take_fraction(mp, y0+y2,t_of_the_way(v0,v1))
10740
10741 @ Here's a routine that prints an envelope spec in symbolic form.  It assumes
10742 that the |cur_pen| has not been walked around to the first offset.
10743
10744 @c 
10745 void mp_print_spec (MP mp,pointer cur_spec, pointer cur_pen, char *s) {
10746   pointer p,q; /* list traversal */
10747   pointer w; /* the current pen offset */
10748   mp_print_diagnostic(mp, "Envelope spec",s,true);
10749   p=cur_spec; w=mp_pen_walk(mp, cur_pen,mp->spec_offset);
10750   mp_print_ln(mp);
10751   mp_print_two(mp, x_coord(cur_spec),y_coord(cur_spec));
10752   mp_print(mp, " % beginning with offset ");
10753   mp_print_two(mp, x_coord(w),y_coord(w));
10754   do { 
10755     do {  
10756       q=link(p);
10757       @<Print the cubic between |p| and |q|@>;
10758       p=q;
10759     } while (! ((p==cur_spec) || (info(p)!=zero_off)));
10760     if ( info(p)!=zero_off ) {
10761       @<Update |w| as indicated by |info(p)| and print an explanation@>;
10762     }
10763   } while (p!=cur_spec);
10764   mp_print_nl(mp, " & cycle");
10765   mp_end_diagnostic(mp, true);
10766 }
10767
10768 @ @<Update |w| as indicated by |info(p)| and print an explanation@>=
10769
10770   w=mp_pen_walk(mp, w,info(p)-zero_off);
10771   mp_print(mp, " % ");
10772   if ( info(p)>zero_off ) mp_print(mp, "counter");
10773   mp_print(mp, "clockwise to offset ");
10774   mp_print_two(mp, x_coord(w),y_coord(w));
10775 }
10776
10777 @ @<Print the cubic between |p| and |q|@>=
10778
10779   mp_print_nl(mp, "   ..controls ");
10780   mp_print_two(mp, right_x(p),right_y(p));
10781   mp_print(mp, " and ");
10782   mp_print_two(mp, left_x(q),left_y(q));
10783   mp_print_nl(mp, " ..");
10784   mp_print_two(mp, x_coord(q),y_coord(q));
10785 }
10786
10787 @ Once we have an envelope spec, the remaining task to construct the actual
10788 envelope by offsetting each cubic as determined by the |info| fields in
10789 the knots.  First we use |offset_prep| to convert the |c| into an envelope
10790 spec. Then we add the offsets so that |c| becomes a cyclic path that represents
10791 the envelope.
10792
10793 The |ljoin| and |miterlim| parameters control the treatment of points where the
10794 pen offset changes, and |lcap| controls the endpoints of a \&{doublepath}.
10795 The endpoints are easily located because |c| is given in undoubled form
10796 and then doubled in this procedure.  We use |spec_p1| and |spec_p2| to keep
10797 track of the endpoints and treat them like very sharp corners.
10798 Butt end caps are treated like beveled joins; round end caps are treated like
10799 round joins; and square end caps are achieved by setting |join_type:=3|.
10800
10801 None of these parameters apply to inside joins where the convolution tracing
10802 has retrograde lines.  In such cases we use a simple connect-the-endpoints
10803 approach that is achieved by setting |join_type:=2|.
10804
10805 @c @<Declare a function called |insert_knot|@>;
10806 pointer mp_make_envelope (MP mp,pointer c, pointer h, small_number ljoin,
10807   small_number lcap, scaled miterlim) {
10808   pointer p,q,r,q0; /* for manipulating the path */
10809   int join_type=0; /* codes |0..3| for mitered, round, beveled, or square */
10810   pointer w,w0; /* the pen knot for the current offset */
10811   scaled qx,qy; /* unshifted coordinates of |q| */
10812   halfword k,k0; /* controls pen edge insertion */
10813   @<Other local variables for |make_envelope|@>;
10814   dxin=0; dyin=0; dxout=0; dyout=0;
10815   mp->spec_p1=null; mp->spec_p2=null;
10816   @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>;
10817   @<Use |offset_prep| to compute the envelope spec then walk |h| around to
10818     the initial offset@>;
10819   w=h;
10820   p=c;
10821   do {  
10822     q=link(p); q0=q;
10823     qx=x_coord(q); qy=y_coord(q);
10824     k=info(q);
10825     k0=k; w0=w;
10826     if ( k!=zero_off ) {
10827       @<Set |join_type| to indicate how to handle offset changes at~|q|@>;
10828     }
10829     @<Add offset |w| to the cubic from |p| to |q|@>;
10830     while ( k!=zero_off ) { 
10831       @<Step |w| and move |k| one step closer to |zero_off|@>;
10832       if ( (join_type==1)||(k==zero_off) )
10833          q=mp_insert_knot(mp, q,qx+x_coord(w),qy+y_coord(w));
10834     };
10835     if ( q!=link(p) ) {
10836       @<Set |p=link(p)| and add knots between |p| and |q| as
10837         required by |join_type|@>;
10838     }
10839     p=q;
10840   } while (q0!=c);
10841   return c;
10842 }
10843
10844 @ @<Use |offset_prep| to compute the envelope spec then walk |h| around to...@>=
10845 c=mp_offset_prep(mp, c,h);
10846 if ( mp->internal[tracing_specs]>0 ) 
10847   mp_print_spec(mp, c,h,"");
10848 h=mp_pen_walk(mp, h,mp->spec_offset)
10849
10850 @ Mitered and squared-off joins depend on path directions that are difficult to
10851 compute for degenerate cubics.  The envelope spec computed by |offset_prep| can
10852 have degenerate cubics only if the entire cycle collapses to a single
10853 degenerate cubic.  Setting |join_type:=2| in this case makes the computed
10854 envelope degenerate as well.
10855
10856 @<Set |join_type| to indicate how to handle offset changes at~|q|@>=
10857 if ( k<zero_off ) {
10858   join_type=2;
10859 } else {
10860   if ( (q!=mp->spec_p1)&&(q!=mp->spec_p2) ) join_type=ljoin;
10861   else if ( lcap==2 ) join_type=3;
10862   else join_type=2-lcap;
10863   if ( (join_type==0)||(join_type==3) ) {
10864     @<Set the incoming and outgoing directions at |q|; in case of
10865       degeneracy set |join_type:=2|@>;
10866     if ( join_type==0 ) {
10867       @<If |miterlim| is less than the secant of half the angle at |q|
10868         then set |join_type:=2|@>;
10869     }
10870   }
10871 }
10872
10873 @ @<If |miterlim| is less than the secant of half the angle at |q|...@>=
10874
10875   tmp=mp_take_fraction(mp, miterlim,fraction_half+
10876       half(mp_take_fraction(mp, dxin,dxout)+mp_take_fraction(mp, dyin,dyout)));
10877   if ( tmp<unity )
10878     if ( mp_take_scaled(mp, miterlim,tmp)<unity ) join_type=2;
10879 }
10880
10881 @ @<Other local variables for |make_envelope|@>=
10882 fraction dxin,dyin,dxout,dyout; /* directions at |q| when square or mitered */
10883 scaled tmp; /* a temporary value */
10884
10885 @ The coordinates of |p| have already been shifted unless |p| is the first
10886 knot in which case they get shifted at the very end.
10887
10888 @<Add offset |w| to the cubic from |p| to |q|@>=
10889 right_x(p)=right_x(p)+x_coord(w);
10890 right_y(p)=right_y(p)+y_coord(w);
10891 left_x(q)=left_x(q)+x_coord(w);
10892 left_y(q)=left_y(q)+y_coord(w);
10893 x_coord(q)=x_coord(q)+x_coord(w);
10894 y_coord(q)=y_coord(q)+y_coord(w);
10895 left_type(q)=explicit;
10896 right_type(q)=explicit
10897
10898 @ @<Step |w| and move |k| one step closer to |zero_off|@>=
10899 if ( k>zero_off ){ w=link(w); decr(k);  }
10900 else { w=knil(w); incr(k);  }
10901
10902 @ The cubic from |q| to the new knot at |(x,y)| becomes a line segment and
10903 the |right_x| and |right_y| fields of |r| are set from |q|.  This is done in
10904 case the cubic containing these control points is ``yet to be examined.''
10905
10906 @<Declare a function called |insert_knot|@>=
10907 pointer mp_insert_knot (MP mp,pointer q, scaled x, scaled y) {
10908   /* returns the inserted knot */
10909   pointer r; /* the new knot */
10910   r=mp_get_node(mp, knot_node_size);
10911   link(r)=link(q); link(q)=r;
10912   right_x(r)=right_x(q);
10913   right_y(r)=right_y(q);
10914   x_coord(r)=x;
10915   y_coord(r)=y;
10916   right_x(q)=x_coord(q);
10917   right_y(q)=y_coord(q);
10918   left_x(r)=x_coord(r);
10919   left_y(r)=y_coord(r);
10920   left_type(r)=explicit;
10921   right_type(r)=explicit;
10922   originator(r)=program_code;
10923   return r;
10924 }
10925
10926 @ After setting |p:=link(p)|, either |join_type=1| or |q=link(p)|.
10927
10928 @<Set |p=link(p)| and add knots between |p| and |q| as...@>=
10929
10930   p=link(p);
10931   if ( (join_type==0)||(join_type==3) ) {
10932     if ( join_type==0 ) {
10933       @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>
10934     } else {
10935       @<Make |r| the last of two knots inserted between |p| and |q| to form a
10936         squared join@>;
10937     }
10938     if ( r!=null ) { 
10939       right_x(r)=x_coord(r);
10940       right_y(r)=y_coord(r);
10941     }
10942   }
10943 }
10944
10945 @ For very small angles, adding a knot is unnecessary and would cause numerical
10946 problems, so we just set |r:=null| in that case.
10947
10948 @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>=
10949
10950   det=mp_take_fraction(mp, dyout,dxin)-mp_take_fraction(mp, dxout,dyin);
10951   if ( abs(det)<26844 ) { 
10952      r=null; /* sine $<10^{-4}$ */
10953   } else { 
10954     tmp=mp_take_fraction(mp, x_coord(q)-x_coord(p),dyout)-
10955         mp_take_fraction(mp, y_coord(q)-y_coord(p),dxout);
10956     tmp=mp_make_fraction(mp, tmp,det);
10957     r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
10958       y_coord(p)+mp_take_fraction(mp, tmp,dyin));
10959   }
10960 }
10961
10962 @ @<Other local variables for |make_envelope|@>=
10963 fraction det; /* a determinant used for mitered join calculations */
10964
10965 @ @<Make |r| the last of two knots inserted between |p| and |q| to form a...@>=
10966
10967   ht_x=y_coord(w)-y_coord(w0);
10968   ht_y=x_coord(w0)-x_coord(w);
10969   while ( (abs(ht_x)<fraction_half)&&(abs(ht_y)<fraction_half) ) { 
10970     ht_x+=ht_x; ht_y+=ht_y;
10971   }
10972   @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range dot
10973     product with |(ht_x,ht_y)|@>;
10974   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxin,ht_x)+
10975                                   mp_take_fraction(mp, dyin,ht_y));
10976   r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
10977                          y_coord(p)+mp_take_fraction(mp, tmp,dyin));
10978   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxout,ht_x)+
10979                                   mp_take_fraction(mp, dyout,ht_y));
10980   r=mp_insert_knot(mp, r,x_coord(q)+mp_take_fraction(mp, tmp,dxout),
10981                          y_coord(q)+mp_take_fraction(mp, tmp,dyout));
10982 }
10983
10984 @ @<Other local variables for |make_envelope|@>=
10985 fraction ht_x,ht_y; /* perpendicular to the segment from |p| to |q| */
10986 scaled max_ht; /* maximum height of the pen polygon above the |w0|-|w| line */
10987 halfword kk; /* keeps track of the pen vertices being scanned */
10988 pointer ww; /* the pen vertex being tested */
10989
10990 @ The dot product of the vector from |w0| to |ww| with |(ht_x,ht_y)| ranges
10991 from zero to |max_ht|.
10992
10993 @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range...@>=
10994 max_ht=0;
10995 kk=zero_off;
10996 ww=w;
10997 while (1)  { 
10998   @<Step |ww| and move |kk| one step closer to |k0|@>;
10999   if ( kk==k0 ) break;
11000   tmp=mp_take_fraction(mp, x_coord(ww)-x_coord(w0),ht_x)+
11001       mp_take_fraction(mp, y_coord(ww)-y_coord(w0),ht_y);
11002   if ( tmp>max_ht ) max_ht=tmp;
11003 }
11004
11005
11006 @ @<Step |ww| and move |kk| one step closer to |k0|@>=
11007 if ( kk>k0 ) { ww=link(ww); decr(kk);  }
11008 else { ww=knil(ww); incr(kk);  }
11009
11010 @ @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>=
11011 if ( left_type(c)==endpoint ) { 
11012   mp->spec_p1=mp_htap_ypoc(mp, c);
11013   mp->spec_p2=mp->path_tail;
11014   originator(mp->spec_p1)=program_code;
11015   link(mp->spec_p2)=link(mp->spec_p1);
11016   link(mp->spec_p1)=c;
11017   mp_remove_cubic(mp, mp->spec_p1);
11018   c=mp->spec_p1;
11019   if ( c!=link(c) ) {
11020     originator(mp->spec_p2)=program_code;
11021     mp_remove_cubic(mp, mp->spec_p2);
11022   } else {
11023     @<Make |c| look like a cycle of length one@>;
11024   }
11025 }
11026
11027 @ @<Make |c| look like a cycle of length one@>=
11028
11029   left_type(c)=explicit; right_type(c)=explicit;
11030   left_x(c)=x_coord(c); left_y(c)=y_coord(c);
11031   right_x(c)=x_coord(c); right_y(c)=y_coord(c);
11032 }
11033
11034 @ In degenerate situations we might have to look at the knot preceding~|q|.
11035 That knot is |p| but if |p<>c|, its coordinates have already been offset by |w|.
11036
11037 @<Set the incoming and outgoing directions at |q|; in case of...@>=
11038 dxin=x_coord(q)-left_x(q);
11039 dyin=y_coord(q)-left_y(q);
11040 if ( (dxin==0)&&(dyin==0) ) {
11041   dxin=x_coord(q)-right_x(p);
11042   dyin=y_coord(q)-right_y(p);
11043   if ( (dxin==0)&&(dyin==0) ) {
11044     dxin=x_coord(q)-x_coord(p);
11045     dyin=y_coord(q)-y_coord(p);
11046     if ( p!=c ) { /* the coordinates of |p| have been offset by |w| */
11047       dxin=dxin+x_coord(w);
11048       dyin=dyin+y_coord(w);
11049     }
11050   }
11051 }
11052 tmp=mp_pyth_add(mp, dxin,dyin);
11053 if ( tmp==0 ) {
11054   join_type=2;
11055 } else { 
11056   dxin=mp_make_fraction(mp, dxin,tmp);
11057   dyin=mp_make_fraction(mp, dyin,tmp);
11058   @<Set the outgoing direction at |q|@>;
11059 }
11060
11061 @ If |q=c| then the coordinates of |r| and the control points between |q|
11062 and~|r| have already been offset by |h|.
11063
11064 @<Set the outgoing direction at |q|@>=
11065 dxout=right_x(q)-x_coord(q);
11066 dyout=right_y(q)-y_coord(q);
11067 if ( (dxout==0)&&(dyout==0) ) {
11068   r=link(q);
11069   dxout=left_x(r)-x_coord(q);
11070   dyout=left_y(r)-y_coord(q);
11071   if ( (dxout==0)&&(dyout==0) ) {
11072     dxout=x_coord(r)-x_coord(q);
11073     dyout=y_coord(r)-y_coord(q);
11074   }
11075 }
11076 if ( q==c ) {
11077   dxout=dxout-x_coord(h);
11078   dyout=dyout-y_coord(h);
11079 }
11080 tmp=mp_pyth_add(mp, dxout,dyout);
11081 if ( tmp==0 ) mp_confusion(mp, "degenerate spec");
11082 @:this can't happen degerate spec}{\quad degenerate spec@>
11083 dxout=mp_make_fraction(mp, dxout,tmp);
11084 dyout=mp_make_fraction(mp, dyout,tmp)
11085
11086 @* \[23] Direction and intersection times.
11087 A path of length $n$ is defined parametrically by functions $x(t)$ and
11088 $y(t)$, for |0<=t<=n|; we can regard $t$ as the ``time'' at which the path
11089 reaches the point $\bigl(x(t),y(t)\bigr)$.  In this section of the program
11090 we shall consider operations that determine special times associated with
11091 given paths: the first time that a path travels in a given direction, and
11092 a pair of times at which two paths cross each other.
11093
11094 @ Let's start with the easier task. The function |find_direction_time| is
11095 given a direction |(x,y)| and a path starting at~|h|. If the path never
11096 travels in direction |(x,y)|, the direction time will be~|-1|; otherwise
11097 it will be nonnegative.
11098
11099 Certain anomalous cases can arise: If |(x,y)=(0,0)|, so that the given
11100 direction is undefined, the direction time will be~0. If $\bigl(x'(t),
11101 y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be
11102 assumed to match any given direction at time~|t|.
11103
11104 The routine solves this problem in nondegenerate cases by rotating the path
11105 and the given direction so that |(x,y)=(1,0)|; i.e., the main task will be
11106 to find when a given path first travels ``due east.''
11107
11108 @c 
11109 scaled mp_find_direction_time (MP mp,scaled x, scaled y, pointer h) {
11110   scaled max; /* $\max\bigl(\vert x\vert,\vert y\vert\bigr)$ */
11111   pointer p,q; /* for list traversal */
11112   scaled n; /* the direction time at knot |p| */
11113   scaled tt; /* the direction time within a cubic */
11114   @<Other local variables for |find_direction_time|@>;
11115   @<Normalize the given direction for better accuracy;
11116     but |return| with zero result if it's zero@>;
11117   n=0; p=h; phi=0;
11118   while (1) { 
11119     if ( right_type(p)==endpoint ) break;
11120     q=link(p);
11121     @<Rotate the cubic between |p| and |q|; then
11122       |goto found| if the rotated cubic travels due east at some time |tt|;
11123       but |break| if an entire cyclic path has been traversed@>;
11124     p=q; n=n+unity;
11125   }
11126   return (-unity);
11127 FOUND: 
11128   return (n+tt);
11129 }
11130
11131 @ @<Normalize the given direction for better accuracy...@>=
11132 if ( abs(x)<abs(y) ) { 
11133   x=mp_make_fraction(mp, x,abs(y));
11134   if ( y>0 ) y=fraction_one; else y=-fraction_one;
11135 } else if ( x==0 ) { 
11136   return 0;
11137 } else  { 
11138   y=mp_make_fraction(mp, y,abs(x));
11139   if ( x>0 ) x=fraction_one; else x=-fraction_one;
11140 }
11141
11142 @ Since we're interested in the tangent directions, we work with the
11143 derivative $${\textstyle1\over3}B'(x_0,x_1,x_2,x_3;t)=
11144 B(x_1-x_0,x_2-x_1,x_3-x_2;t)$$ instead of
11145 $B(x_0,x_1,x_2,x_3;t)$ itself. The derived coefficients are also scaled up
11146 in order to achieve better accuracy.
11147
11148 The given path may turn abruptly at a knot, and it might pass the critical
11149 tangent direction at such a time. Therefore we remember the direction |phi|
11150 in which the previous rotated cubic was traveling. (The value of |phi| will be
11151 undefined on the first cubic, i.e., when |n=0|.)
11152
11153 @<Rotate the cubic between |p| and |q|; then...@>=
11154 tt=0;
11155 @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples of the control
11156   points of the rotated derivatives@>;
11157 if ( y1==0 ) if ( x1>=0 ) goto FOUND;
11158 if ( n>0 ) { 
11159   @<Exit to |found| if an eastward direction occurs at knot |p|@>;
11160   if ( p==h ) break;
11161   };
11162 if ( (x3!=0)||(y3!=0) ) phi=mp_n_arg(mp, x3,y3);
11163 @<Exit to |found| if the curve whose derivatives are specified by
11164   |x1,x2,x3,y1,y2,y3| travels eastward at some time~|tt|@>
11165
11166 @ @<Other local variables for |find_direction_time|@>=
11167 scaled x1,x2,x3,y1,y2,y3;  /* multiples of rotated derivatives */
11168 angle theta,phi; /* angles of exit and entry at a knot */
11169 fraction t; /* temp storage */
11170
11171 @ @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples...@>=
11172 x1=right_x(p)-x_coord(p); x2=left_x(q)-right_x(p);
11173 x3=x_coord(q)-left_x(q);
11174 y1=right_y(p)-y_coord(p); y2=left_y(q)-right_y(p);
11175 y3=y_coord(q)-left_y(q);
11176 max=abs(x1);
11177 if ( abs(x2)>max ) max=abs(x2);
11178 if ( abs(x3)>max ) max=abs(x3);
11179 if ( abs(y1)>max ) max=abs(y1);
11180 if ( abs(y2)>max ) max=abs(y2);
11181 if ( abs(y3)>max ) max=abs(y3);
11182 if ( max==0 ) goto FOUND;
11183 while ( max<fraction_half ){ 
11184   max+=max; x1+=x1; x2+=x2; x3+=x3;
11185   y1+=y1; y2+=y2; y3+=y3;
11186 }
11187 t=x1; x1=mp_take_fraction(mp, x1,x)+mp_take_fraction(mp, y1,y);
11188 y1=mp_take_fraction(mp, y1,x)-mp_take_fraction(mp, t,y);
11189 t=x2; x2=mp_take_fraction(mp, x2,x)+mp_take_fraction(mp, y2,y);
11190 y2=mp_take_fraction(mp, y2,x)-mp_take_fraction(mp, t,y);
11191 t=x3; x3=mp_take_fraction(mp, x3,x)+mp_take_fraction(mp, y3,y);
11192 y3=mp_take_fraction(mp, y3,x)-mp_take_fraction(mp, t,y)
11193
11194 @ @<Exit to |found| if an eastward direction occurs at knot |p|@>=
11195 theta=mp_n_arg(mp, x1,y1);
11196 if ( theta>=0 ) if ( phi<=0 ) if ( phi>=theta-one_eighty_deg ) goto FOUND;
11197 if ( theta<=0 ) if ( phi>=0 ) if ( phi<=theta+one_eighty_deg ) goto FOUND
11198
11199 @ In this step we want to use the |crossing_point| routine to find the
11200 roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$.
11201 Several complications arise: If the quadratic equation has a double root,
11202 the curve never crosses zero, and |crossing_point| will find nothing;
11203 this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic
11204 equation has simple roots, or only one root, we may have to negate it
11205 so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root.
11206 And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is
11207 identically zero.
11208
11209 @ @<Exit to |found| if the curve whose derivatives are specified by...@>=
11210 if ( x1<0 ) if ( x2<0 ) if ( x3<0 ) goto DONE;
11211 if ( mp_ab_vs_cd(mp, y1,y3,y2,y2)==0 ) {
11212   @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11213     either |goto found| or |goto done|@>;
11214 }
11215 if ( y1<=0 ) {
11216   if ( y1<0 ) { y1=-y1; y2=-y2; y3=-y3; }
11217   else if ( y2>0 ){ y2=-y2; y3=-y3; };
11218 }
11219 @<Check the places where $B(y_1,y_2,y_3;t)=0$ to see if
11220   $B(x_1,x_2,x_3;t)\ge0$@>;
11221 DONE:
11222
11223 @ The quadratic polynomial $B(y_1,y_2,y_3;t)$ begins |>=0| and has at most
11224 two roots, because we know that it isn't identically zero.
11225
11226 It must be admitted that the |crossing_point| routine is not perfectly accurate;
11227 rounding errors might cause it to find a root when $y_1y_3>y_2^2$, or to
11228 miss the roots when $y_1y_3<y_2^2$. The rotation process is itself
11229 subject to rounding errors. Yet this code optimistically tries to
11230 do the right thing.
11231
11232 @d we_found_it { tt=(t+04000) / 010000; goto FOUND; }
11233
11234 @<Check the places where $B(y_1,y_2,y_3;t)=0$...@>=
11235 t=mp_crossing_point(mp, y1,y2,y3);
11236 if ( t>fraction_one ) goto DONE;
11237 y2=t_of_the_way(y2,y3);
11238 x1=t_of_the_way(x1,x2);
11239 x2=t_of_the_way(x2,x3);
11240 x1=t_of_the_way(x1,x2);
11241 if ( x1>=0 ) we_found_it;
11242 if ( y2>0 ) y2=0;
11243 tt=t; t=mp_crossing_point(mp, 0,-y2,-y3);
11244 if ( t>fraction_one ) goto DONE;
11245 x1=t_of_the_way(x1,x2);
11246 x2=t_of_the_way(x2,x3);
11247 if ( t_of_the_way(x1,x2)>=0 ) { 
11248   t=t_of_the_way(tt,fraction_one); we_found_it;
11249 }
11250
11251 @ @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11252     either |goto found| or |goto done|@>=
11253
11254   if ( mp_ab_vs_cd(mp, y1,y2,0,0)<0 ) {
11255     t=mp_make_fraction(mp, y1,y1-y2);
11256     x1=t_of_the_way(x1,x2);
11257     x2=t_of_the_way(x2,x3);
11258     if ( t_of_the_way(x1,x2)>=0 ) we_found_it;
11259   } else if ( y3==0 ) {
11260     if ( y1==0 ) {
11261       @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|@>;
11262     } else if ( x3>=0 ) {
11263       tt=unity; goto FOUND;
11264     }
11265   }
11266   goto DONE;
11267 }
11268
11269 @ At this point we know that the derivative of |y(t)| is identically zero,
11270 and that |x1<0|; but either |x2>=0| or |x3>=0|, so there's some hope of
11271 traveling east.
11272
11273 @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|...@>=
11274
11275   t=mp_crossing_point(mp, -x1,-x2,-x3);
11276   if ( t<=fraction_one ) we_found_it;
11277   if ( mp_ab_vs_cd(mp, x1,x3,x2,x2)<=0 ) { 
11278     t=mp_make_fraction(mp, x1,x1-x2); we_found_it;
11279   }
11280 }
11281
11282 @ The intersection of two cubics can be found by an interesting variant
11283 of the general bisection scheme described in the introduction to
11284 |crossing_point|.\
11285 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)$,
11286 we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$,
11287 if an intersection exists. First we find the smallest rectangle that
11288 encloses the points $\{w_0,w_1,w_2,w_3\}$ and check that it overlaps
11289 the smallest rectangle that encloses
11290 $\{z_0,z_1,z_2,z_3\}$; if not, the cubics certainly don't intersect.
11291 But if the rectangles do overlap, we bisect the intervals, getting
11292 new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first
11293 tries for an intersection between $w'$ and~$z'$, then (if unsuccessful)
11294 between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$,
11295 finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful
11296 levels of bisection we will have determined the intersection times $t_1$
11297 and~$t_2$ to $l$~bits of accuracy.
11298
11299 \def\submin{_{\rm min}} \def\submax{_{\rm max}}
11300 As before, it is better to work with the numbers $W_k=2^l(w_k-w_{k-1})$
11301 and $Z_k=2^l(z_k-z_{k-1})$ rather than the coefficients $w_k$ and $z_k$
11302 themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$,
11303 to determine when the enclosing rectangles overlap. Here's why:
11304 The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$,
11305 and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$,
11306 if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin=
11307 \min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates
11308 overlap if and only if $u\submin\L x\submax$ and
11309 $x\submin\L u\submax$. Letting
11310 $$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\;
11311   U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$
11312 we have $u\submin=2^lu_0+U\submin$, etc.; the condition for overlap
11313 reduces to
11314 $$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$
11315 Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly,
11316 the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The
11317 coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases,
11318 because of the overlap condition; i.e., we know that $X\submin$,
11319 $X\submax$, and their relatives are bounded, hence $X\submax-
11320 U\submin$ and $X\submin-U\submax$ are bounded.
11321
11322 @ Incidentally, if the given cubics intersect more than once, the process
11323 just sketched will not necessarily find the lexicographically smallest pair
11324 $(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled
11325 order''; i.e., if $t_1=(.a_1a_2\ldots a_{16})_2$ and
11326 $t_2=(.b_1b_2\ldots b_{16})_2$, then we will minimize
11327 $a_1b_1a_2b_2\ldots a_{16}b_{16}$, not
11328 $a_1a_2\ldots a_{16}b_1b_2\ldots b_{16}$.
11329 Shuffled order agrees with lexicographic order if all pairs of solutions
11330 $(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff
11331 $t_2<t_2'$; but in general, lexicographic order can be quite different,
11332 and the bisection algorithm would be substantially less efficient if it were
11333 constrained by lexicographic order.
11334
11335 For example, suppose that an overlap has been found for $l=3$ and
11336 $(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by
11337 either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4.
11338 Then there is probably an intersection in one of the subintervals
11339 $(.1011,.011x)$; but lexicographic order would require us to explore
11340 $(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't
11341 want to store all of the subdivision data for the second path, so the
11342 subdivisions would have to be regenerated many times. Such inefficiencies
11343 would be associated with every `1' in the binary representation of~$t_1$.
11344
11345 @ The subdivision process introduces rounding errors, hence we need to
11346 make a more liberal test for overlap. It is not hard to show that the
11347 computed values of $U_i$ differ from the truth by at most~$l$, on
11348 level~$l$, hence $U\submin$ and $U\submax$ will be at most $3l$ in error.
11349 If $\beta$ is an upper bound on the absolute error in the computed
11350 components of $\Delta=(|delx|,|dely|)$ on level~$l$, we will replace
11351 the test `$X\submin-U\submax\L|delx|$' by the more liberal test
11352 `$X\submin-U\submax\L|delx|+|tol|$', where $|tol|=6l+\beta$.
11353
11354 More accuracy is obtained if we try the algorithm first with |tol=0|;
11355 the more liberal tolerance is used only if an exact approach fails.
11356 It is convenient to do this double-take by letting `3' in the preceding
11357 paragraph be a parameter, which is first 0, then 3.
11358
11359 @<Glob...@>=
11360 unsigned int tol_step; /* either 0 or 3, usually */
11361
11362 @ We shall use an explicit stack to implement the recursive bisection
11363 method described above. The |bisect_stack| array will contain numerous 5-word
11364 packets like $(U_1,U_2,U_3,U\submin,U\submax)$, as well as 20-word packets
11365 comprising the 5-word packets for $U$, $V$, $X$, and~$Y$.
11366
11367 The following macros define the allocation of stack positions to
11368 the quantities needed for bisection-intersection.
11369
11370 @d stack_1(A) mp->bisect_stack[(A)] /* $U_1$, $V_1$, $X_1$, or $Y_1$ */
11371 @d stack_2(A) mp->bisect_stack[(A)+1] /* $U_2$, $V_2$, $X_2$, or $Y_2$ */
11372 @d stack_3(A) mp->bisect_stack[(A)+2] /* $U_3$, $V_3$, $X_3$, or $Y_3$ */
11373 @d stack_min(A) mp->bisect_stack[(A)+3]
11374   /* $U\submin$, $V\submin$, $X\submin$, or $Y\submin$ */
11375 @d stack_max(A) mp->bisect_stack[(A)+4]
11376   /* $U\submax$, $V\submax$, $X\submax$, or $Y\submax$ */
11377 @d int_packets 20 /* number of words to represent $U_k$, $V_k$, $X_k$, and $Y_k$ */
11378 @#
11379 @d u_packet(A) ((A)-5)
11380 @d v_packet(A) ((A)-10)
11381 @d x_packet(A) ((A)-15)
11382 @d y_packet(A) ((A)-20)
11383 @d l_packets (mp->bisect_ptr-int_packets)
11384 @d r_packets mp->bisect_ptr
11385 @d ul_packet u_packet(l_packets) /* base of $U'_k$ variables */
11386 @d vl_packet v_packet(l_packets) /* base of $V'_k$ variables */
11387 @d xl_packet x_packet(l_packets) /* base of $X'_k$ variables */
11388 @d yl_packet y_packet(l_packets) /* base of $Y'_k$ variables */
11389 @d ur_packet u_packet(r_packets) /* base of $U''_k$ variables */
11390 @d vr_packet v_packet(r_packets) /* base of $V''_k$ variables */
11391 @d xr_packet x_packet(r_packets) /* base of $X''_k$ variables */
11392 @d yr_packet y_packet(r_packets) /* base of $Y''_k$ variables */
11393 @#
11394 @d u1l stack_1(ul_packet) /* $U'_1$ */
11395 @d u2l stack_2(ul_packet) /* $U'_2$ */
11396 @d u3l stack_3(ul_packet) /* $U'_3$ */
11397 @d v1l stack_1(vl_packet) /* $V'_1$ */
11398 @d v2l stack_2(vl_packet) /* $V'_2$ */
11399 @d v3l stack_3(vl_packet) /* $V'_3$ */
11400 @d x1l stack_1(xl_packet) /* $X'_1$ */
11401 @d x2l stack_2(xl_packet) /* $X'_2$ */
11402 @d x3l stack_3(xl_packet) /* $X'_3$ */
11403 @d y1l stack_1(yl_packet) /* $Y'_1$ */
11404 @d y2l stack_2(yl_packet) /* $Y'_2$ */
11405 @d y3l stack_3(yl_packet) /* $Y'_3$ */
11406 @d u1r stack_1(ur_packet) /* $U''_1$ */
11407 @d u2r stack_2(ur_packet) /* $U''_2$ */
11408 @d u3r stack_3(ur_packet) /* $U''_3$ */
11409 @d v1r stack_1(vr_packet) /* $V''_1$ */
11410 @d v2r stack_2(vr_packet) /* $V''_2$ */
11411 @d v3r stack_3(vr_packet) /* $V''_3$ */
11412 @d x1r stack_1(xr_packet) /* $X''_1$ */
11413 @d x2r stack_2(xr_packet) /* $X''_2$ */
11414 @d x3r stack_3(xr_packet) /* $X''_3$ */
11415 @d y1r stack_1(yr_packet) /* $Y''_1$ */
11416 @d y2r stack_2(yr_packet) /* $Y''_2$ */
11417 @d y3r stack_3(yr_packet) /* $Y''_3$ */
11418 @#
11419 @d stack_dx mp->bisect_stack[mp->bisect_ptr] /* stacked value of |delx| */
11420 @d stack_dy mp->bisect_stack[mp->bisect_ptr+1] /* stacked value of |dely| */
11421 @d stack_tol mp->bisect_stack[mp->bisect_ptr+2] /* stacked value of |tol| */
11422 @d stack_uv mp->bisect_stack[mp->bisect_ptr+3] /* stacked value of |uv| */
11423 @d stack_xy mp->bisect_stack[mp->bisect_ptr+4] /* stacked value of |xy| */
11424 @d int_increment (int_packets+int_packets+5) /* number of stack words per level */
11425
11426 @<Glob...@>=
11427 integer *bisect_stack;
11428 unsigned int bisect_ptr;
11429
11430 @ @<Allocate or initialize ...@>=
11431 mp->bisect_stack = xmalloc((bistack_size+1),sizeof(integer));
11432
11433 @ @<Dealloc variables@>=
11434 xfree(mp->bisect_stack);
11435
11436 @ @<Check the ``constant''...@>=
11437 if ( int_packets+17*int_increment>bistack_size ) mp->bad=19;
11438
11439 @ Computation of the min and max is a tedious but fairly fast sequence of
11440 instructions; exactly four comparisons are made in each branch.
11441
11442 @d set_min_max(A) 
11443   if ( stack_1((A))<0 ) {
11444     if ( stack_3((A))>=0 ) {
11445       if ( stack_2((A))<0 ) stack_min((A))=stack_1((A))+stack_2((A));
11446       else stack_min((A))=stack_1((A));
11447       stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11448       if ( stack_max((A))<0 ) stack_max((A))=0;
11449     } else { 
11450       stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11451       if ( stack_min((A))>stack_1((A)) ) stack_min((A))=stack_1((A));
11452       stack_max((A))=stack_1((A))+stack_2((A));
11453       if ( stack_max((A))<0 ) stack_max((A))=0;
11454     }
11455   } else if ( stack_3((A))<=0 ) {
11456     if ( stack_2((A))>0 ) stack_max((A))=stack_1((A))+stack_2((A));
11457     else stack_max((A))=stack_1((A));
11458     stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11459     if ( stack_min((A))>0 ) stack_min((A))=0;
11460   } else  { 
11461     stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11462     if ( stack_max((A))<stack_1((A)) ) stack_max((A))=stack_1((A));
11463     stack_min((A))=stack_1((A))+stack_2((A));
11464     if ( stack_min((A))>0 ) stack_min((A))=0;
11465   }
11466
11467 @ It's convenient to keep the current values of $l$, $t_1$, and $t_2$ in
11468 the integer form $2^l+2^lt_1$ and $2^l+2^lt_2$. The |cubic_intersection|
11469 routine uses global variables |cur_t| and |cur_tt| for this purpose;
11470 after successful completion, |cur_t| and |cur_tt| will contain |unity|
11471 plus the |scaled| values of $t_1$ and~$t_2$.
11472
11473 The values of |cur_t| and |cur_tt| will be set to zero if |cubic_intersection|
11474 finds no intersection. The routine gives up and gives an approximate answer
11475 if it has backtracked
11476 more than 5000 times (otherwise there are cases where several minutes
11477 of fruitless computation would be possible).
11478
11479 @d max_patience 5000
11480
11481 @<Glob...@>=
11482 integer cur_t;integer cur_tt; /* controls and results of |cubic_intersection| */
11483 integer time_to_go; /* this many backtracks before giving up */
11484 integer max_t; /* maximum of $2^{l+1}$ so far achieved */
11485
11486 @ The given cubics $B(w_0,w_1,w_2,w_3;t)$ and
11487 $B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes |(p,link(p))|
11488 and |(pp,link(pp))|, respectively.
11489
11490 @c void mp_cubic_intersection (MP mp,pointer p, pointer pp) {
11491   pointer q,qq; /* |link(p)|, |link(pp)| */
11492   mp->time_to_go=max_patience; mp->max_t=2;
11493   @<Initialize for intersections at level zero@>;
11494 CONTINUE:
11495   while (1) { 
11496     if ( mp->delx-mp->tol<=stack_max(x_packet(mp->xy))-stack_min(u_packet(mp->uv)))
11497     if ( mp->delx+mp->tol>=stack_min(x_packet(mp->xy))-stack_max(u_packet(mp->uv)))
11498     if ( mp->dely-mp->tol<=stack_max(y_packet(mp->xy))-stack_min(v_packet(mp->uv)))
11499     if ( mp->dely+mp->tol>=stack_min(y_packet(mp->xy))-stack_max(v_packet(mp->uv))) 
11500     { 
11501       if ( mp->cur_t>=mp->max_t ){ 
11502         if ( mp->max_t==two ) { /* we've done 17 bisections */ 
11503            mp->cur_t=halfp(mp->cur_t+1); mp->cur_tt=halfp(mp->cur_tt+1); return;
11504         }
11505         mp->max_t+=mp->max_t; mp->appr_t=mp->cur_t; mp->appr_tt=mp->cur_tt;
11506       }
11507       @<Subdivide for a new level of intersection@>;
11508       goto CONTINUE;
11509     }
11510     if ( mp->time_to_go>0 ) {
11511       decr(mp->time_to_go);
11512     } else { 
11513       while ( mp->appr_t<unity ) { 
11514         mp->appr_t+=mp->appr_t; mp->appr_tt+=mp->appr_tt;
11515       }
11516       mp->cur_t=mp->appr_t; mp->cur_tt=mp->appr_tt; return;
11517     }
11518     @<Advance to the next pair |(cur_t,cur_tt)|@>;
11519   }
11520 }
11521
11522 @ The following variables are global, although they are used only by
11523 |cubic_intersection|, because it is necessary on some machines to
11524 split |cubic_intersection| up into two procedures.
11525
11526 @<Glob...@>=
11527 integer delx;integer dely; /* the components of $\Delta=2^l(w_0-z_0)$ */
11528 integer tol; /* bound on the uncertainly in the overlap test */
11529 unsigned int uv;
11530 unsigned int xy; /* pointers to the current packets of interest */
11531 integer three_l; /* |tol_step| times the bisection level */
11532 integer appr_t;integer appr_tt; /* best approximations known to the answers */
11533
11534 @ We shall assume that the coordinates are sufficiently non-extreme that
11535 integer overflow will not occur.
11536
11537 @<Initialize for intersections at level zero@>=
11538 q=link(p); qq=link(pp); mp->bisect_ptr=int_packets;
11539 u1r=right_x(p)-x_coord(p); u2r=left_x(q)-right_x(p);
11540 u3r=x_coord(q)-left_x(q); set_min_max(ur_packet);
11541 v1r=right_y(p)-y_coord(p); v2r=left_y(q)-right_y(p);
11542 v3r=y_coord(q)-left_y(q); set_min_max(vr_packet);
11543 x1r=right_x(pp)-x_coord(pp); x2r=left_x(qq)-right_x(pp);
11544 x3r=x_coord(qq)-left_x(qq); set_min_max(xr_packet);
11545 y1r=right_y(pp)-y_coord(pp); y2r=left_y(qq)-right_y(pp);
11546 y3r=y_coord(qq)-left_y(qq); set_min_max(yr_packet);
11547 mp->delx=x_coord(p)-x_coord(pp); mp->dely=y_coord(p)-y_coord(pp);
11548 mp->tol=0; mp->uv=r_packets; mp->xy=r_packets; 
11549 mp->three_l=0; mp->cur_t=1; mp->cur_tt=1
11550
11551 @ @<Subdivide for a new level of intersection@>=
11552 stack_dx=mp->delx; stack_dy=mp->dely; stack_tol=mp->tol; 
11553 stack_uv=mp->uv; stack_xy=mp->xy;
11554 mp->bisect_ptr=mp->bisect_ptr+int_increment;
11555 mp->cur_t+=mp->cur_t; mp->cur_tt+=mp->cur_tt;
11556 u1l=stack_1(u_packet(mp->uv)); u3r=stack_3(u_packet(mp->uv));
11557 u2l=half(u1l+stack_2(u_packet(mp->uv)));
11558 u2r=half(u3r+stack_2(u_packet(mp->uv)));
11559 u3l=half(u2l+u2r); u1r=u3l;
11560 set_min_max(ul_packet); set_min_max(ur_packet);
11561 v1l=stack_1(v_packet(mp->uv)); v3r=stack_3(v_packet(mp->uv));
11562 v2l=half(v1l+stack_2(v_packet(mp->uv)));
11563 v2r=half(v3r+stack_2(v_packet(mp->uv)));
11564 v3l=half(v2l+v2r); v1r=v3l;
11565 set_min_max(vl_packet); set_min_max(vr_packet);
11566 x1l=stack_1(x_packet(mp->xy)); x3r=stack_3(x_packet(mp->xy));
11567 x2l=half(x1l+stack_2(x_packet(mp->xy)));
11568 x2r=half(x3r+stack_2(x_packet(mp->xy)));
11569 x3l=half(x2l+x2r); x1r=x3l;
11570 set_min_max(xl_packet); set_min_max(xr_packet);
11571 y1l=stack_1(y_packet(mp->xy)); y3r=stack_3(y_packet(mp->xy));
11572 y2l=half(y1l+stack_2(y_packet(mp->xy)));
11573 y2r=half(y3r+stack_2(y_packet(mp->xy)));
11574 y3l=half(y2l+y2r); y1r=y3l;
11575 set_min_max(yl_packet); set_min_max(yr_packet);
11576 mp->uv=l_packets; mp->xy=l_packets;
11577 mp->delx+=mp->delx; mp->dely+=mp->dely;
11578 mp->tol=mp->tol-mp->three_l+mp->tol_step; 
11579 mp->tol+=mp->tol; mp->three_l=mp->three_l+mp->tol_step
11580
11581 @ @<Advance to the next pair |(cur_t,cur_tt)|@>=
11582 NOT_FOUND: 
11583 if ( odd(mp->cur_tt) ) {
11584   if ( odd(mp->cur_t) ) {
11585      @<Descend to the previous level and |goto not_found|@>;
11586   } else { 
11587     incr(mp->cur_t);
11588     mp->delx=mp->delx+stack_1(u_packet(mp->uv))+stack_2(u_packet(mp->uv))
11589       +stack_3(u_packet(mp->uv));
11590     mp->dely=mp->dely+stack_1(v_packet(mp->uv))+stack_2(v_packet(mp->uv))
11591       +stack_3(v_packet(mp->uv));
11592     mp->uv=mp->uv+int_packets; /* switch from |l_packet| to |r_packet| */
11593     decr(mp->cur_tt); mp->xy=mp->xy-int_packets; 
11594          /* switch from |r_packet| to |l_packet| */
11595     mp->delx=mp->delx+stack_1(x_packet(mp->xy))+stack_2(x_packet(mp->xy))
11596       +stack_3(x_packet(mp->xy));
11597     mp->dely=mp->dely+stack_1(y_packet(mp->xy))+stack_2(y_packet(mp->xy))
11598       +stack_3(y_packet(mp->xy));
11599   }
11600 } else { 
11601   incr(mp->cur_tt); mp->tol=mp->tol+mp->three_l;
11602   mp->delx=mp->delx-stack_1(x_packet(mp->xy))-stack_2(x_packet(mp->xy))
11603     -stack_3(x_packet(mp->xy));
11604   mp->dely=mp->dely-stack_1(y_packet(mp->xy))-stack_2(y_packet(mp->xy))
11605     -stack_3(y_packet(mp->xy));
11606   mp->xy=mp->xy+int_packets; /* switch from |l_packet| to |r_packet| */
11607 }
11608
11609 @ @<Descend to the previous level...@>=
11610
11611   mp->cur_t=halfp(mp->cur_t); mp->cur_tt=halfp(mp->cur_tt);
11612   if ( mp->cur_t==0 ) return;
11613   mp->bisect_ptr=mp->bisect_ptr-int_increment; 
11614   mp->three_l=mp->three_l-mp->tol_step;
11615   mp->delx=stack_dx; mp->dely=stack_dy; mp->tol=stack_tol; 
11616   mp->uv=stack_uv; mp->xy=stack_xy;
11617   goto NOT_FOUND;
11618 }
11619
11620 @ The |path_intersection| procedure is much simpler.
11621 It invokes |cubic_intersection| in lexicographic order until finding a
11622 pair of cubics that intersect. The final intersection times are placed in
11623 |cur_t| and~|cur_tt|.
11624
11625 @c void mp_path_intersection (MP mp,pointer h, pointer hh) {
11626   pointer p,pp; /* link registers that traverse the given paths */
11627   integer n,nn; /* integer parts of intersection times, minus |unity| */
11628   @<Change one-point paths into dead cycles@>;
11629   mp->tol_step=0;
11630   do {  
11631     n=-unity; p=h;
11632     do {  
11633       if ( right_type(p)!=endpoint ) { 
11634         nn=-unity; pp=hh;
11635         do {  
11636           if ( right_type(pp)!=endpoint )  { 
11637             mp_cubic_intersection(mp, p,pp);
11638             if ( mp->cur_t>0 ) { 
11639               mp->cur_t=mp->cur_t+n; mp->cur_tt=mp->cur_tt+nn; 
11640               return;
11641             }
11642           }
11643           nn=nn+unity; pp=link(pp);
11644         } while (pp!=hh);
11645       }
11646       n=n+unity; p=link(p);
11647     } while (p!=h);
11648     mp->tol_step=mp->tol_step+3;
11649   } while (mp->tol_step<=3);
11650   mp->cur_t=-unity; mp->cur_tt=-unity;
11651 }
11652
11653 @ @<Change one-point paths...@>=
11654 if ( right_type(h)==endpoint ) {
11655   right_x(h)=x_coord(h); left_x(h)=x_coord(h);
11656   right_y(h)=y_coord(h); left_y(h)=y_coord(h); right_type(h)=explicit;
11657 }
11658 if ( right_type(hh)==endpoint ) {
11659   right_x(hh)=x_coord(hh); left_x(hh)=x_coord(hh);
11660   right_y(hh)=y_coord(hh); left_y(hh)=y_coord(hh); right_type(hh)=explicit;
11661 }
11662
11663 @* \[24] Dynamic linear equations.
11664 \MP\ users define variables implicitly by stating equations that should be
11665 satisfied; the computer is supposed to be smart enough to solve those equations.
11666 And indeed, the computer tries valiantly to do so, by distinguishing five
11667 different types of numeric values:
11668
11669 \smallskip\hang
11670 |type(p)=mp_known| is the nice case, when |value(p)| is the |scaled| value
11671 of the variable whose address is~|p|.
11672
11673 \smallskip\hang
11674 |type(p)=mp_dependent| means that |value(p)| is not present, but |dep_list(p)|
11675 points to a {\sl dependency list\/} that expresses the value of variable~|p|
11676 as a |scaled| number plus a sum of independent variables with |fraction|
11677 coefficients.
11678
11679 \smallskip\hang
11680 |type(p)=mp_independent| means that |value(p)=64s+m|, where |s>0| is a ``serial
11681 number'' reflecting the time this variable was first used in an equation;
11682 also |0<=m<64|, and each dependent variable
11683 that refers to this one is actually referring to the future value of
11684 this variable times~$2^m$. (Usually |m=0|, but higher degrees of
11685 scaling are sometimes needed to keep the coefficients in dependency lists
11686 from getting too large. The value of~|m| will always be even.)
11687
11688 \smallskip\hang
11689 |type(p)=mp_numeric_type| means that variable |p| hasn't appeared in an
11690 equation before, but it has been explicitly declared to be numeric.
11691
11692 \smallskip\hang
11693 |type(p)=undefined| means that variable |p| hasn't appeared before.
11694
11695 \smallskip\noindent
11696 We have actually discussed these five types in the reverse order of their
11697 history during a computation: Once |known|, a variable never again
11698 becomes |dependent|; once |dependent|, it almost never again becomes
11699 |mp_independent|; once |mp_independent|, it never again becomes |mp_numeric_type|;
11700 and once |mp_numeric_type|, it never again becomes |undefined| (except
11701 of course when the user specifically decides to scrap the old value
11702 and start again). A backward step may, however, take place: Sometimes
11703 a |dependent| variable becomes |mp_independent| again, when one of the
11704 independent variables it depends on is reverting to |undefined|.
11705
11706
11707 The next patch detects overflow of independent-variable serial
11708 numbers. Diagnosed and patched by Thorsten Dahlheimer.
11709
11710 @d s_scale 64 /* the serial numbers are multiplied by this factor */
11711 @d max_indep_vars 0177777777 /* $2^{25}-1$ */
11712 @d max_serial_no 017777777700 /* |max_indep_vars*s_scale| */
11713 @d new_indep(A)  /* create a new independent variable */
11714   { if ( mp->serial_no==max_serial_no )
11715     mp_fatal_error(mp, "variable instance identifiers exhausted");
11716   type((A))=mp_independent; mp->serial_no=mp->serial_no+s_scale;
11717   value((A))=mp->serial_no;
11718   }
11719
11720 @<Glob...@>=
11721 integer serial_no; /* the most recent serial number, times |s_scale| */
11722
11723 @ @<Make variable |q+s| newly independent@>=new_indep(q+s)
11724
11725 @ But how are dependency lists represented? It's simple: The linear combination
11726 $\alpha_1v_1+\cdots+\alpha_kv_k+\beta$ appears in |k+1| value nodes. If
11727 |q=dep_list(p)| points to this list, and if |k>0|, then |value(q)=
11728 @t$\alpha_1$@>| (which is a |fraction|); |info(q)| points to the location
11729 of $\alpha_1$; and |link(p)| points to the dependency list
11730 $\alpha_2v_2+\cdots+\alpha_kv_k+\beta$. On the other hand if |k=0|,
11731 then |value(q)=@t$\beta$@>| (which is |scaled|) and |info(q)=null|.
11732 The independent variables $v_1$, \dots,~$v_k$ have been sorted so that
11733 they appear in decreasing order of their |value| fields (i.e., of
11734 their serial numbers). \ (It is convenient to use decreasing order,
11735 since |value(null)=0|. If the independent variables were not sorted by
11736 serial number but by some other criterion, such as their location in |mem|,
11737 the equation-solving mechanism would be too system-dependent, because
11738 the ordering can affect the computed results.)
11739
11740 The |link| field in the node that contains the constant term $\beta$ is
11741 called the {\sl final link\/} of the dependency list. \MP\ maintains
11742 a doubly-linked master list of all dependency lists, in terms of a permanently
11743 allocated node
11744 in |mem| called |dep_head|. If there are no dependencies, we have
11745 |link(dep_head)=dep_head| and |prev_dep(dep_head)=dep_head|;
11746 otherwise |link(dep_head)| points to the first dependent variable, say~|p|,
11747 and |prev_dep(p)=dep_head|. We have |type(p)=mp_dependent|, and |dep_list(p)|
11748 points to its dependency list. If the final link of that dependency list
11749 occurs in location~|q|, then |link(q)| points to the next dependent
11750 variable (say~|r|); and we have |prev_dep(r)=q|, etc.
11751
11752 @d dep_list(A) link(value_loc((A)))
11753   /* half of the |value| field in a |dependent| variable */
11754 @d prev_dep(A) info(value_loc((A)))
11755   /* the other half; makes a doubly linked list */
11756 @d dep_node_size 2 /* the number of words per dependency node */
11757
11758 @<Initialize table entries...@>= mp->serial_no=0;
11759 link(dep_head)=dep_head; prev_dep(dep_head)=dep_head;
11760 info(dep_head)=null; dep_list(dep_head)=null;
11761
11762 @ Actually the description above contains a little white lie. There's
11763 another kind of variable called |mp_proto_dependent|, which is
11764 just like a |dependent| one except that the $\alpha$ coefficients
11765 in its dependency list are |scaled| instead of being fractions.
11766 Proto-dependency lists are mixed with dependency lists in the
11767 nodes reachable from |dep_head|.
11768
11769 @ Here is a procedure that prints a dependency list in symbolic form.
11770 The second parameter should be either |dependent| or |mp_proto_dependent|,
11771 to indicate the scaling of the coefficients.
11772
11773 @<Declare subroutines for printing expressions@>=
11774 void mp_print_dependency (MP mp,pointer p, small_number t) {
11775   integer v; /* a coefficient */
11776   pointer pp,q; /* for list manipulation */
11777   pp=p;
11778   while (1) { 
11779     v=abs(value(p)); q=info(p);
11780     if ( q==null ) { /* the constant term */
11781       if ( (v!=0)||(p==pp) ) {
11782          if ( value(p)>0 ) if ( p!=pp ) mp_print_char(mp, '+');
11783          mp_print_scaled(mp, value(p));
11784       }
11785       return;
11786     }
11787     @<Print the coefficient, unless it's $\pm1.0$@>;
11788     if ( type(q)!=mp_independent ) mp_confusion(mp, "dep");
11789 @:this can't happen dep}{\quad dep@>
11790     mp_print_variable_name(mp, q); v=value(q) % s_scale;
11791     while ( v>0 ) { mp_print(mp, "*4"); v=v-2; }
11792     p=link(p);
11793   }
11794 }
11795
11796 @ @<Print the coefficient, unless it's $\pm1.0$@>=
11797 if ( value(p)<0 ) mp_print_char(mp, '-');
11798 else if ( p!=pp ) mp_print_char(mp, '+');
11799 if ( t==mp_dependent ) v=mp_round_fraction(mp, v);
11800 if ( v!=unity ) mp_print_scaled(mp, v)
11801
11802 @ The maximum absolute value of a coefficient in a given dependency list
11803 is returned by the following simple function.
11804
11805 @c fraction mp_max_coef (MP mp,pointer p) {
11806   fraction x; /* the maximum so far */
11807   x=0;
11808   while ( info(p)!=null ) {
11809     if ( abs(value(p))>x ) x=abs(value(p));
11810     p=link(p);
11811   }
11812   return x;
11813 }
11814
11815 @ One of the main operations needed on dependency lists is to add a multiple
11816 of one list to the other; we call this |p_plus_fq|, where |p| and~|q| point
11817 to dependency lists and |f| is a fraction.
11818
11819 If the coefficient of any independent variable becomes |coef_bound| or
11820 more, in absolute value, this procedure changes the type of that variable
11821 to `|independent_needing_fix|', and sets the global variable |fix_needed|
11822 to~|true|. The value of $|coef_bound|=\mu$ is chosen so that
11823 $\mu^2+\mu<8$; this means that the numbers we deal with won't
11824 get too large. (Instead of the ``optimum'' $\mu=(\sqrt{33}-1)/2\approx
11825 2.3723$, the safer value 7/3 is taken as the threshold.)
11826
11827 The changes mentioned in the preceding paragraph are actually done only if
11828 the global variable |watch_coefs| is |true|. But it usually is; in fact,
11829 it is |false| only when \MP\ is making a dependency list that will soon
11830 be equated to zero.
11831
11832 Several procedures that act on dependency lists, including |p_plus_fq|,
11833 set the global variable |dep_final| to the final (constant term) node of
11834 the dependency list that they produce.
11835
11836 @d coef_bound 04525252525 /* |fraction| approximation to 7/3 */
11837 @d independent_needing_fix 0
11838
11839 @<Glob...@>=
11840 boolean fix_needed; /* does at least one |independent| variable need scaling? */
11841 boolean watch_coefs; /* should we scale coefficients that exceed |coef_bound|? */
11842 pointer dep_final; /* location of the constant term and final link */
11843
11844 @ @<Set init...@>=
11845 mp->fix_needed=false; mp->watch_coefs=true;
11846
11847 @ The |p_plus_fq| procedure has a fourth parameter, |t|, that should be
11848 set to |mp_proto_dependent| if |p| is a proto-dependency list. In this
11849 case |f| will be |scaled|, not a |fraction|. Similarly, the fifth parameter~|tt|
11850 should be |mp_proto_dependent| if |q| is a proto-dependency list.
11851
11852 List |q| is unchanged by the operation; but list |p| is totally destroyed.
11853
11854 The final link of the dependency list or proto-dependency list returned
11855 by |p_plus_fq| is the same as the original final link of~|p|. Indeed, the
11856 constant term of the result will be located in the same |mem| location
11857 as the original constant term of~|p|.
11858
11859 Coefficients of the result are assumed to be zero if they are less than
11860 a certain threshold. This compensates for inevitable rounding errors,
11861 and tends to make more variables `|known|'. The threshold is approximately
11862 $10^{-5}$ in the case of normal dependency lists, $10^{-4}$ for
11863 proto-dependencies.
11864
11865 @d fraction_threshold 2685 /* a |fraction| coefficient less than this is zeroed */
11866 @d half_fraction_threshold 1342 /* half of |fraction_threshold| */
11867 @d scaled_threshold 8 /* a |scaled| coefficient less than this is zeroed */
11868 @d half_scaled_threshold 4 /* half of |scaled_threshold| */
11869
11870 @<Declare basic dependency-list subroutines@>=
11871 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
11872                       pointer q, small_number t, small_number tt) ;
11873
11874 @ @c
11875 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
11876                       pointer q, small_number t, small_number tt) {
11877   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
11878   pointer r,s; /* for list manipulation */
11879   integer mp_threshold; /* defines a neighborhood of zero */
11880   integer v; /* temporary register */
11881   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
11882   else mp_threshold=scaled_threshold;
11883   r=temp_head; pp=info(p); qq=info(q);
11884   while (1) {
11885     if ( pp==qq ) {
11886       if ( pp==null ) {
11887        break;
11888       } else {
11889         @<Contribute a term from |p|, plus |f| times the
11890           corresponding term from |q|@>
11891       }
11892     } else if ( value(pp)<value(qq) ) {
11893       @<Contribute a term from |q|, multiplied by~|f|@>
11894     } else { 
11895      link(r)=p; r=p; p=link(p); pp=info(p);
11896     }
11897   }
11898   if ( t==mp_dependent )
11899     value(p)=mp_slow_add(mp, value(p),mp_take_fraction(mp, value(q),f));
11900   else  
11901     value(p)=mp_slow_add(mp, value(p),mp_take_scaled(mp, value(q),f));
11902   link(r)=p; mp->dep_final=p; 
11903   return link(temp_head);
11904 }
11905
11906 @ @<Contribute a term from |p|, plus |f|...@>=
11907
11908   if ( tt==mp_dependent ) v=value(p)+mp_take_fraction(mp, f,value(q));
11909   else v=value(p)+mp_take_scaled(mp, f,value(q));
11910   value(p)=v; s=p; p=link(p);
11911   if ( abs(v)<mp_threshold ) {
11912     mp_free_node(mp, s,dep_node_size);
11913   } else {
11914     if ( (abs(v)>=coef_bound)  && mp->watch_coefs ) { 
11915       type(qq)=independent_needing_fix; mp->fix_needed=true;
11916     }
11917     link(r)=s; r=s;
11918   };
11919   pp=info(p); q=link(q); qq=info(q);
11920 }
11921
11922 @ @<Contribute a term from |q|, multiplied by~|f|@>=
11923
11924   if ( tt==mp_dependent ) v=mp_take_fraction(mp, f,value(q));
11925   else v=mp_take_scaled(mp, f,value(q));
11926   if ( abs(v)>halfp(mp_threshold) ) { 
11927     s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=v;
11928     if ( (abs(v)>=coef_bound) && mp->watch_coefs ) { 
11929       type(qq)=independent_needing_fix; mp->fix_needed=true;
11930     }
11931     link(r)=s; r=s;
11932   }
11933   q=link(q); qq=info(q);
11934 }
11935
11936 @ It is convenient to have another subroutine for the special case
11937 of |p_plus_fq| when |f=1.0|. In this routine lists |p| and |q| are
11938 both of the same type~|t| (either |dependent| or |mp_proto_dependent|).
11939
11940 @c pointer mp_p_plus_q (MP mp,pointer p, pointer q, small_number t) {
11941   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
11942   pointer r,s; /* for list manipulation */
11943   integer mp_threshold; /* defines a neighborhood of zero */
11944   integer v; /* temporary register */
11945   if ( t==mp_dependent ) mp_threshold=fraction_threshold;
11946   else mp_threshold=scaled_threshold;
11947   r=temp_head; pp=info(p); qq=info(q);
11948   while (1) {
11949     if ( pp==qq ) {
11950       if ( pp==null ) {
11951         break;
11952       } else {
11953         @<Contribute a term from |p|, plus the
11954           corresponding term from |q|@>
11955       }
11956     } else if ( value(pp)<value(qq) ) {
11957       s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=value(q);
11958       q=link(q); qq=info(q); link(r)=s; r=s;
11959     } else { 
11960       link(r)=p; r=p; p=link(p); pp=info(p);
11961     }
11962   }
11963   value(p)=mp_slow_add(mp, value(p),value(q));
11964   link(r)=p; mp->dep_final=p; 
11965   return link(temp_head);
11966 }
11967
11968 @ @<Contribute a term from |p|, plus the...@>=
11969
11970   v=value(p)+value(q);
11971   value(p)=v; s=p; p=link(p); pp=info(p);
11972   if ( abs(v)<mp_threshold ) {
11973     mp_free_node(mp, s,dep_node_size);
11974   } else { 
11975     if ( (abs(v)>=coef_bound ) && mp->watch_coefs ) {
11976       type(qq)=independent_needing_fix; mp->fix_needed=true;
11977     }
11978     link(r)=s; r=s;
11979   }
11980   q=link(q); qq=info(q);
11981 }
11982
11983 @ A somewhat simpler routine will multiply a dependency list
11984 by a given constant~|v|. The constant is either a |fraction| less than
11985 |fraction_one|, or it is |scaled|. In the latter case we might be forced to
11986 convert a dependency list to a proto-dependency list.
11987 Parameters |t0| and |t1| are the list types before and after;
11988 they should agree unless |t0=mp_dependent| and |t1=mp_proto_dependent|
11989 and |v_is_scaled=true|.
11990
11991 @c pointer mp_p_times_v (MP mp,pointer p, integer v, small_number t0,
11992                          small_number t1, boolean v_is_scaled) {
11993   pointer r,s; /* for list manipulation */
11994   integer w; /* tentative coefficient */
11995   integer mp_threshold;
11996   boolean scaling_down;
11997   if ( t0!=t1 ) scaling_down=true; else scaling_down=! v_is_scaled;
11998   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
11999   else mp_threshold=half_scaled_threshold;
12000   r=temp_head;
12001   while ( info(p)!=null ) {    
12002     if ( scaling_down ) w=mp_take_fraction(mp, v,value(p));
12003     else w=mp_take_scaled(mp, v,value(p));
12004     if ( abs(w)<=mp_threshold ) { 
12005       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12006     } else {
12007       if ( abs(w)>=coef_bound ) { 
12008         mp->fix_needed=true; type(info(p))=independent_needing_fix;
12009       }
12010       link(r)=p; r=p; value(p)=w; p=link(p);
12011     }
12012   }
12013   link(r)=p;
12014   if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
12015   else value(p)=mp_take_fraction(mp, value(p),v);
12016   return link(temp_head);
12017 };
12018
12019 @ Similarly, we sometimes need to divide a dependency list
12020 by a given |scaled| constant.
12021
12022 @<Declare basic dependency-list subroutines@>=
12023 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12024   t0, small_number t1) ;
12025
12026 @ @c
12027 pointer mp_p_over_v (MP mp,pointer p, scaled v, small_number 
12028   t0, small_number t1) {
12029   pointer r,s; /* for list manipulation */
12030   integer w; /* tentative coefficient */
12031   integer mp_threshold;
12032   boolean scaling_down;
12033   if ( t0!=t1 ) scaling_down=true; else scaling_down=false;
12034   if ( t1==mp_dependent ) mp_threshold=half_fraction_threshold;
12035   else mp_threshold=half_scaled_threshold;
12036   r=temp_head;
12037   while ( info( p)!=null ) {
12038     if ( scaling_down ) {
12039       if ( abs(v)<02000000 ) w=mp_make_scaled(mp, value(p),v*010000);
12040       else w=mp_make_scaled(mp, mp_round_fraction(mp, value(p)),v);
12041     } else {
12042       w=mp_make_scaled(mp, value(p),v);
12043     }
12044     if ( abs(w)<=mp_threshold ) {
12045       s=link(p); mp_free_node(mp, p,dep_node_size); p=s;
12046     } else { 
12047       if ( abs(w)>=coef_bound ) {
12048          mp->fix_needed=true; type(info(p))=independent_needing_fix;
12049       }
12050       link(r)=p; r=p; value(p)=w; p=link(p);
12051     }
12052   }
12053   link(r)=p; value(p)=mp_make_scaled(mp, value(p),v);
12054   return link(temp_head);
12055 };
12056
12057 @ Here's another utility routine for dependency lists. When an independent
12058 variable becomes dependent, we want to remove it from all existing
12059 dependencies. The |p_with_x_becoming_q| function computes the
12060 dependency list of~|p| after variable~|x| has been replaced by~|q|.
12061
12062 This procedure has basically the same calling conventions as |p_plus_fq|:
12063 List~|q| is unchanged; list~|p| is destroyed; the constant node and the
12064 final link are inherited from~|p|; and the fourth parameter tells whether
12065 or not |p| is |mp_proto_dependent|. However, the global variable |dep_final|
12066 is not altered if |x| does not occur in list~|p|.
12067
12068 @c pointer mp_p_with_x_becoming_q (MP mp,pointer p,
12069            pointer x, pointer q, small_number t) {
12070   pointer r,s; /* for list manipulation */
12071   integer v; /* coefficient of |x| */
12072   integer sx; /* serial number of |x| */
12073   s=p; r=temp_head; sx=value(x);
12074   while ( value(info(s))>sx ) { r=s; s=link(s); };
12075   if ( info(s)!=x ) { 
12076     return p;
12077   } else { 
12078     link(temp_head)=p; link(r)=link(s); v=value(s);
12079     mp_free_node(mp, s,dep_node_size);
12080     return mp_p_plus_fq(mp, link(temp_head),v,q,t,mp_dependent);
12081   }
12082 }
12083
12084 @ Here's a simple procedure that reports an error when a variable
12085 has just received a known value that's out of the required range.
12086
12087 @<Declare basic dependency-list subroutines@>=
12088 void mp_val_too_big (MP mp,scaled x) ;
12089
12090 @ @c void mp_val_too_big (MP mp,scaled x) { 
12091   if ( mp->internal[warning_check]>0 ) { 
12092     print_err("Value is too large ("); mp_print_scaled(mp, x); mp_print_char(mp, ')');
12093 @.Value is too large@>
12094     help4("The equation I just processed has given some variable")
12095       ("a value of 4096 or more. Continue and I'll try to cope")
12096       ("with that big value; but it might be dangerous.")
12097       ("(Set warningcheck:=0 to suppress this message.)");
12098     mp_error(mp);
12099   }
12100 }
12101
12102 @ When a dependent variable becomes known, the following routine
12103 removes its dependency list. Here |p| points to the variable, and
12104 |q| points to the dependency list (which is one node long).
12105
12106 @<Declare basic dependency-list subroutines@>=
12107 void mp_make_known (MP mp,pointer p, pointer q) ;
12108
12109 @ @c void mp_make_known (MP mp,pointer p, pointer q) {
12110   int t; /* the previous type */
12111   prev_dep(link(q))=prev_dep(p);
12112   link(prev_dep(p))=link(q); t=type(p);
12113   type(p)=mp_known; value(p)=value(q); mp_free_node(mp, q,dep_node_size);
12114   if ( abs(value(p))>=fraction_one ) mp_val_too_big(mp, value(p));
12115   if (( mp->internal[tracing_equations]>0) && mp_interesting(mp, p) ) {
12116     mp_begin_diagnostic(mp); mp_print_nl(mp, "#### ");
12117 @:]]]\#\#\#\#_}{\.{\#\#\#\#}@>
12118     mp_print_variable_name(mp, p); 
12119     mp_print_char(mp, '='); mp_print_scaled(mp, value(p));
12120     mp_end_diagnostic(mp, false);
12121   }
12122   if (( mp->cur_exp==p ) && mp->cur_type==t ) {
12123     mp->cur_type=mp_known; mp->cur_exp=value(p);
12124     mp_free_node(mp, p,value_node_size);
12125   }
12126 }
12127
12128 @ The |fix_dependencies| routine is called into action when |fix_needed|
12129 has been triggered. The program keeps a list~|s| of independent variables
12130 whose coefficients must be divided by~4.
12131
12132 In unusual cases, this fixup process might reduce one or more coefficients
12133 to zero, so that a variable will become known more or less by default.
12134
12135 @<Declare basic dependency-list subroutines@>=
12136 void mp_fix_dependencies (MP mp);
12137
12138 @ @c void mp_fix_dependencies (MP mp) {
12139   pointer p,q,r,s,t; /* list manipulation registers */
12140   pointer x; /* an independent variable */
12141   r=link(dep_head); s=null;
12142   while ( r!=dep_head ){ 
12143     t=r;
12144     @<Run through the dependency list for variable |t|, fixing
12145       all nodes, and ending with final link~|q|@>;
12146     r=link(q);
12147     if ( q==dep_list(t) ) mp_make_known(mp, t,q);
12148   }
12149   while ( s!=null ) { 
12150     p=link(s); x=info(s); free_avail(s); s=p;
12151     type(x)=mp_independent; value(x)=value(x)+2;
12152   }
12153   mp->fix_needed=false;
12154 }
12155
12156 @ @d independent_being_fixed 1 /* this variable already appears in |s| */
12157
12158 @<Run through the dependency list for variable |t|...@>=
12159 r=value_loc(t); /* |link(r)=dep_list(t)| */
12160 while (1) { 
12161   q=link(r); x=info(q);
12162   if ( x==null ) break;
12163   if ( type(x)<=independent_being_fixed ) {
12164     if ( type(x)<independent_being_fixed ) {
12165       p=mp_get_avail(mp); link(p)=s; s=p;
12166       info(s)=x; type(x)=independent_being_fixed;
12167     }
12168     value(q)=value(q) / 4;
12169     if ( value(q)==0 ) {
12170       link(r)=link(q); mp_free_node(mp, q,dep_node_size); q=r;
12171     }
12172   }
12173   r=q;
12174 }
12175
12176
12177 @ The |new_dep| routine installs a dependency list~|p| into the value node~|q|,
12178 linking it into the list of all known dependencies. We assume that
12179 |dep_final| points to the final node of list~|p|.
12180
12181 @c void mp_new_dep (MP mp,pointer q, pointer p) {
12182   pointer r; /* what used to be the first dependency */
12183   dep_list(q)=p; prev_dep(q)=dep_head;
12184   r=link(dep_head); link(mp->dep_final)=r; prev_dep(r)=mp->dep_final;
12185   link(dep_head)=q;
12186 }
12187
12188 @ Here is one of the ways a dependency list gets started.
12189 The |const_dependency| routine produces a list that has nothing but
12190 a constant term.
12191
12192 @c pointer mp_const_dependency (MP mp, scaled v) {
12193   mp->dep_final=mp_get_node(mp, dep_node_size);
12194   value(mp->dep_final)=v; info(mp->dep_final)=null;
12195   return mp->dep_final;
12196 }
12197
12198 @ And here's a more interesting way to start a dependency list from scratch:
12199 The parameter to |single_dependency| is the location of an
12200 independent variable~|x|, and the result is the simple dependency list
12201 `|x+0|'.
12202
12203 In the unlikely event that the given independent variable has been doubled so
12204 often that we can't refer to it with a nonzero coefficient,
12205 |single_dependency| returns the simple list `0'.  This case can be
12206 recognized by testing that the returned list pointer is equal to
12207 |dep_final|.
12208
12209 @c pointer mp_single_dependency (MP mp,pointer p) {
12210   pointer q; /* the new dependency list */
12211   integer m; /* the number of doublings */
12212   m=value(p) % s_scale;
12213   if ( m>28 ) {
12214     return mp_const_dependency(mp, 0);
12215   } else { 
12216     q=mp_get_node(mp, dep_node_size);
12217     value(q)=two_to_the(28-m); info(q)=p;
12218     link(q)=mp_const_dependency(mp, 0);
12219     return q;
12220   }
12221 }
12222
12223 @ We sometimes need to make an exact copy of a dependency list.
12224
12225 @c pointer mp_copy_dep_list (MP mp,pointer p) {
12226   pointer q; /* the new dependency list */
12227   q=mp_get_node(mp, dep_node_size); mp->dep_final=q;
12228   while (1) { 
12229     info(mp->dep_final)=info(p); value(mp->dep_final)=value(p);
12230     if ( info(mp->dep_final)==null ) break;
12231     link(mp->dep_final)=mp_get_node(mp, dep_node_size);
12232     mp->dep_final=link(mp->dep_final); p=link(p);
12233   }
12234   return q;
12235 }
12236
12237 @ But how do variables normally become known? Ah, now we get to the heart of the
12238 equation-solving mechanism. The |linear_eq| procedure is given a |dependent|
12239 or |mp_proto_dependent| list,~|p|, in which at least one independent variable
12240 appears. It equates this list to zero, by choosing an independent variable
12241 with the largest coefficient and making it dependent on the others. The
12242 newly dependent variable is eliminated from all current dependencies,
12243 thereby possibly making other dependent variables known.
12244
12245 The given list |p| is, of course, totally destroyed by all this processing.
12246
12247 @c void mp_linear_eq (MP mp, pointer p, small_number t) {
12248   pointer q,r,s; /* for link manipulation */
12249   pointer x; /* the variable that loses its independence */
12250   integer n; /* the number of times |x| had been halved */
12251   integer v; /* the coefficient of |x| in list |p| */
12252   pointer prev_r; /* lags one step behind |r| */
12253   pointer final_node; /* the constant term of the new dependency list */
12254   integer w; /* a tentative coefficient */
12255    @<Find a node |q| in list |p| whose coefficient |v| is largest@>;
12256   x=info(q); n=value(x) % s_scale;
12257   @<Divide list |p| by |-v|, removing node |q|@>;
12258   if ( mp->internal[tracing_equations]>0 ) {
12259     @<Display the new dependency@>;
12260   }
12261   @<Simplify all existing dependencies by substituting for |x|@>;
12262   @<Change variable |x| from |independent| to |dependent| or |known|@>;
12263   if ( mp->fix_needed ) mp_fix_dependencies(mp);
12264 }
12265
12266 @ @<Find a node |q| in list |p| whose coefficient |v| is largest@>=
12267 q=p; r=link(p); v=value(q);
12268 while ( info(r)!=null ) { 
12269   if ( abs(value(r))>abs(v) ) { q=r; v=value(r); };
12270   r=link(r);
12271 }
12272
12273 @ Here we want to change the coefficients from |scaled| to |fraction|,
12274 except in the constant term. In the common case of a trivial equation
12275 like `\.{x=3.14}', we will have |v=-fraction_one|, |q=p|, and |t=mp_dependent|.
12276
12277 @<Divide list |p| by |-v|, removing node |q|@>=
12278 s=temp_head; link(s)=p; r=p;
12279 do { 
12280   if ( r==q ) {
12281     link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12282   } else  { 
12283     w=mp_make_fraction(mp, value(r),v);
12284     if ( abs(w)<=half_fraction_threshold ) {
12285       link(s)=link(r); mp_free_node(mp, r,dep_node_size);
12286     } else { 
12287       value(r)=-w; s=r;
12288     }
12289   }
12290   r=link(s);
12291 } while (info(r)!=null);
12292 if ( t==mp_proto_dependent ) {
12293   value(r)=-mp_make_scaled(mp, value(r),v);
12294 } else if ( v!=-fraction_one ) {
12295   value(r)=-mp_make_fraction(mp, value(r),v);
12296 }
12297 final_node=r; p=link(temp_head)
12298
12299 @ @<Display the new dependency@>=
12300 if ( mp_interesting(mp, x) ) {
12301   mp_begin_diagnostic(mp); mp_print_nl(mp, "## "); 
12302   mp_print_variable_name(mp, x);
12303 @:]]]\#\#_}{\.{\#\#}@>
12304   w=n;
12305   while ( w>0 ) { mp_print(mp, "*4"); w=w-2;  };
12306   mp_print_char(mp, '='); mp_print_dependency(mp, p,mp_dependent); 
12307   mp_end_diagnostic(mp, false);
12308 }
12309
12310 @ @<Simplify all existing dependencies by substituting for |x|@>=
12311 prev_r=dep_head; r=link(dep_head);
12312 while ( r!=dep_head ) {
12313   s=dep_list(r); q=mp_p_with_x_becoming_q(mp, s,x,p,type(r));
12314   if ( info(q)==null ) {
12315     mp_make_known(mp, r,q);
12316   } else { 
12317     dep_list(r)=q;
12318     do {  q=link(q); } while (info(q)!=null);
12319     prev_r=q;
12320   }
12321   r=link(prev_r);
12322 }
12323
12324 @ @<Change variable |x| from |independent| to |dependent| or |known|@>=
12325 if ( n>0 ) @<Divide list |p| by $2^n$@>;
12326 if ( info(p)==null ) {
12327   type(x)=mp_known;
12328   value(x)=value(p);
12329   if ( abs(value(x))>=fraction_one ) mp_val_too_big(mp, value(x));
12330   mp_free_node(mp, p,dep_node_size);
12331   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) {
12332     mp->cur_exp=value(x); mp->cur_type=mp_known;
12333     mp_free_node(mp, x,value_node_size);
12334   }
12335 } else { 
12336   type(x)=mp_dependent; mp->dep_final=final_node; mp_new_dep(mp, x,p);
12337   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) mp->cur_type=mp_dependent;
12338 }
12339
12340 @ @<Divide list |p| by $2^n$@>=
12341
12342   s=temp_head; link(temp_head)=p; r=p;
12343   do {  
12344     if ( n>30 ) w=0;
12345     else w=value(r) / two_to_the(n);
12346     if ( (abs(w)<=half_fraction_threshold)&&(info(r)!=null) ) {
12347       link(s)=link(r);
12348       mp_free_node(mp, r,dep_node_size);
12349     } else { 
12350       value(r)=w; s=r;
12351     }
12352     r=link(s);
12353   } while (info(s)!=null);
12354   p=link(temp_head);
12355 }
12356
12357 @ The |check_mem| procedure, which is used only when \MP\ is being
12358 debugged, makes sure that the current dependency lists are well formed.
12359
12360 @<Check the list of linear dependencies@>=
12361 q=dep_head; p=link(q);
12362 while ( p!=dep_head ) {
12363   if ( prev_dep(p)!=q ) {
12364     mp_print_nl(mp, "Bad PREVDEP at "); mp_print_int(mp, p);
12365 @.Bad PREVDEP...@>
12366   }
12367   p=dep_list(p);
12368   while (1) {
12369     r=info(p); q=p; p=link(q);
12370     if ( r==null ) break;
12371     if ( value(info(p))>=value(r) ) {
12372       mp_print_nl(mp, "Out of order at "); mp_print_int(mp, p);
12373 @.Out of order...@>
12374     }
12375   }
12376 }
12377
12378 @* \[25] Dynamic nonlinear equations.
12379 Variables of numeric type are maintained by the general scheme of
12380 independent, dependent, and known values that we have just studied;
12381 and the components of pair and transform variables are handled in the
12382 same way. But \MP\ also has five other types of values: \&{boolean},
12383 \&{string}, \&{pen}, \&{path}, and \&{picture}; what about them?
12384
12385 Equations are allowed between nonlinear quantities, but only in a
12386 simple form. Two variables that haven't yet been assigned values are
12387 either equal to each other, or they're not.
12388
12389 Before a boolean variable has received a value, its type is |mp_unknown_boolean|;
12390 similarly, there are variables whose type is |mp_unknown_string|, |mp_unknown_pen|,
12391 |mp_unknown_path|, and |mp_unknown_picture|. In such cases the value is either
12392 |null| (which means that no other variables are equivalent to this one), or
12393 it points to another variable of the same undefined type. The pointers in the
12394 latter case form a cycle of nodes, which we shall call a ``ring.''
12395 Rings of undefined variables may include capsules, which arise as
12396 intermediate results within expressions or as \&{expr} parameters to macros.
12397
12398 When one member of a ring receives a value, the same value is given to
12399 all the other members. In the case of paths and pictures, this implies
12400 making separate copies of a potentially large data structure; users should
12401 restrain their enthusiasm for such generality, unless they have lots and
12402 lots of memory space.
12403
12404 @ The following procedure is called when a capsule node is being
12405 added to a ring (e.g., when an unknown variable is mentioned in an expression).
12406
12407 @c pointer mp_new_ring_entry (MP mp,pointer p) {
12408   pointer q; /* the new capsule node */
12409   q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
12410   type(q)=type(p);
12411   if ( value(p)==null ) value(q)=p; else value(q)=value(p);
12412   value(p)=q;
12413   return q;
12414 }
12415
12416 @ Conversely, we might delete a capsule or a variable before it becomes known.
12417 The following procedure simply detaches a quantity from its ring,
12418 without recycling the storage.
12419
12420 @<Declare the recycling subroutines@>=
12421 void mp_ring_delete (MP mp,pointer p) {
12422   pointer q; 
12423   q=value(p);
12424   if ( q!=null ) if ( q!=p ){ 
12425     while ( value(q)!=p ) q=value(q);
12426     value(q)=value(p);
12427   }
12428 }
12429
12430 @ Eventually there might be an equation that assigns values to all of the
12431 variables in a ring. The |nonlinear_eq| subroutine does the necessary
12432 propagation of values.
12433
12434 If the parameter |flush_p| is |true|, node |p| itself needn't receive a
12435 value, it will soon be recycled.
12436
12437 @c void mp_nonlinear_eq (MP mp,integer v, pointer p, boolean flush_p) {
12438   small_number t; /* the type of ring |p| */
12439   pointer q,r; /* link manipulation registers */
12440   t=type(p)-unknown_tag; q=value(p);
12441   if ( flush_p ) type(p)=mp_vacuous; else p=q;
12442   do {  
12443     r=value(q); type(q)=t;
12444     switch (t) {
12445     case mp_boolean_type: value(q)=v; break;
12446     case mp_string_type: value(q)=v; add_str_ref(v); break;
12447     case mp_pen_type: value(q)=copy_pen(v); break;
12448     case mp_path_type: value(q)=mp_copy_path(mp, v); break;
12449     case mp_picture_type: value(q)=v; add_edge_ref(v); break;
12450     } /* there ain't no more cases */
12451     q=r;
12452   } while (q!=p);
12453 }
12454
12455 @ If two members of rings are equated, and if they have the same type,
12456 the |ring_merge| procedure is called on to make them equivalent.
12457
12458 @c void mp_ring_merge (MP mp,pointer p, pointer q) {
12459   pointer r; /* traverses one list */
12460   r=value(p);
12461   while ( r!=p ) {
12462     if ( r==q ) {
12463       @<Exclaim about a redundant equation@>;
12464       return;
12465     };
12466     r=value(r);
12467   }
12468   r=value(p); value(p)=value(q); value(q)=r;
12469 }
12470
12471 @ @<Exclaim about a redundant equation@>=
12472
12473   print_err("Redundant equation");
12474 @.Redundant equation@>
12475   help2("I already knew that this equation was true.")
12476    ("But perhaps no harm has been done; let's continue.");
12477   mp_put_get_error(mp);
12478 }
12479
12480 @* \[26] Introduction to the syntactic routines.
12481 Let's pause a moment now and try to look at the Big Picture.
12482 The \MP\ program consists of three main parts: syntactic routines,
12483 semantic routines, and output routines. The chief purpose of the
12484 syntactic routines is to deliver the user's input to the semantic routines,
12485 while parsing expressions and locating operators and operands. The
12486 semantic routines act as an interpreter responding to these operators,
12487 which may be regarded as commands. And the output routines are
12488 periodically called on to produce compact font descriptions that can be
12489 used for typesetting or for making interim proof drawings. We have
12490 discussed the basic data structures and many of the details of semantic
12491 operations, so we are good and ready to plunge into the part of \MP\ that
12492 actually controls the activities.
12493
12494 Our current goal is to come to grips with the |get_next| procedure,
12495 which is the keystone of \MP's input mechanism. Each call of |get_next|
12496 sets the value of three variables |cur_cmd|, |cur_mod|, and |cur_sym|,
12497 representing the next input token.
12498 $$\vbox{\halign{#\hfil\cr
12499   \hbox{|cur_cmd| denotes a command code from the long list of codes
12500    given earlier;}\cr
12501   \hbox{|cur_mod| denotes a modifier of the command code;}\cr
12502   \hbox{|cur_sym| is the hash address of the symbolic token that was
12503    just scanned,}\cr
12504   \hbox{\qquad or zero in the case of a numeric or string
12505    or capsule token.}\cr}}$$
12506 Underlying this external behavior of |get_next| is all the machinery
12507 necessary to convert from character files to tokens. At a given time we
12508 may be only partially finished with the reading of several files (for
12509 which \&{input} was specified), and partially finished with the expansion
12510 of some user-defined macros and/or some macro parameters, and partially
12511 finished reading some text that the user has inserted online,
12512 and so on. When reading a character file, the characters must be
12513 converted to tokens; comments and blank spaces must
12514 be removed, numeric and string tokens must be evaluated.
12515
12516 To handle these situations, which might all be present simultaneously,
12517 \MP\ uses various stacks that hold information about the incomplete
12518 activities, and there is a finite state control for each level of the
12519 input mechanism. These stacks record the current state of an implicitly
12520 recursive process, but the |get_next| procedure is not recursive.
12521
12522 @<Glob...@>=
12523 eight_bits cur_cmd; /* current command set by |get_next| */
12524 integer cur_mod; /* operand of current command */
12525 halfword cur_sym; /* hash address of current symbol */
12526
12527 @ The |print_cmd_mod| routine prints a symbolic interpretation of a
12528 command code and its modifier.
12529 It consists of a rather tedious sequence of print
12530 commands, and most of it is essentially an inverse to the |primitive|
12531 routine that enters a \MP\ primitive into |hash| and |eqtb|. Therefore almost
12532 all of this procedure appears elsewhere in the program, together with the
12533 corresponding |primitive| calls.
12534
12535 @<Declare the procedure called |print_cmd_mod|@>=
12536 void mp_print_cmd_mod (MP mp,integer c, integer m) { 
12537  switch (c) {
12538   @<Cases of |print_cmd_mod| for symbolic printing of primitives@>
12539   default: mp_print(mp, "[unknown command code!]"); break;
12540   }
12541 }
12542
12543 @ Here is a procedure that displays a given command in braces, in the
12544 user's transcript file.
12545
12546 @d show_cur_cmd_mod mp_show_cmd_mod(mp, mp->cur_cmd,mp->cur_mod)
12547
12548 @c 
12549 void mp_show_cmd_mod (MP mp,integer c, integer m) { 
12550   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
12551   mp_print_cmd_mod(mp, c,m); mp_print_char(mp, '}');
12552   mp_end_diagnostic(mp, false);
12553 }
12554
12555 @* \[27] Input stacks and states.
12556 The state of \MP's input mechanism appears in the input stack, whose
12557 entries are records with five fields, called |index|, |start|, |loc|,
12558 |limit|, and |name|. The top element of this stack is maintained in a
12559 global variable for which no subscripting needs to be done; the other
12560 elements of the stack appear in an array. Hence the stack is declared thus:
12561
12562 @<Types...@>=
12563 typedef struct {
12564   quarterword index_field;
12565   halfword start_field, loc_field, limit_field, name_field;
12566 } in_state_record;
12567
12568 @ @<Glob...@>=
12569 in_state_record *input_stack;
12570 integer input_ptr; /* first unused location of |input_stack| */
12571 integer max_in_stack; /* largest value of |input_ptr| when pushing */
12572 in_state_record cur_input; /* the ``top'' input state */
12573 int stack_size; /* maximum number of simultaneous input sources */
12574
12575 @ @<Allocate or initialize ...@>=
12576 mp->stack_size = 300;
12577 mp->input_stack = xmalloc((mp->stack_size+1),sizeof(in_state_record));
12578
12579 @ @<Dealloc variables@>=
12580 xfree(mp->input_stack);
12581
12582 @ We've already defined the special variable |loc==cur_input.loc_field|
12583 in our discussion of basic input-output routines. The other components of
12584 |cur_input| are defined in the same way:
12585
12586 @d index mp->cur_input.index_field /* reference for buffer information */
12587 @d start mp->cur_input.start_field /* starting position in |buffer| */
12588 @d limit mp->cur_input.limit_field /* end of current line in |buffer| */
12589 @d name mp->cur_input.name_field /* name of the current file */
12590
12591 @ Let's look more closely now at the five control variables
12592 (|index|,~|start|,~|loc|,~|limit|,~|name|),
12593 assuming that \MP\ is reading a line of characters that have been input
12594 from some file or from the user's terminal. There is an array called
12595 |buffer| that acts as a stack of all lines of characters that are
12596 currently being read from files, including all lines on subsidiary
12597 levels of the input stack that are not yet completed. \MP\ will return to
12598 the other lines when it is finished with the present input file.
12599
12600 (Incidentally, on a machine with byte-oriented addressing, it would be
12601 appropriate to combine |buffer| with the |str_pool| array,
12602 letting the buffer entries grow downward from the top of the string pool
12603 and checking that these two tables don't bump into each other.)
12604
12605 The line we are currently working on begins in position |start| of the
12606 buffer; the next character we are about to read is |buffer[loc]|; and
12607 |limit| is the location of the last character present. We always have
12608 |loc<=limit|. For convenience, |buffer[limit]| has been set to |"%"|, so
12609 that the end of a line is easily sensed.
12610
12611 The |name| variable is a string number that designates the name of
12612 the current file, if we are reading an ordinary text file.  Special codes
12613 |is_term..max_spec_src| indicate other sources of input text.
12614
12615 @d is_term 0 /* |name| value when reading from the terminal for normal input */
12616 @d is_read 1 /* |name| value when executing a \&{readstring} or \&{readfrom} */
12617 @d is_scantok 2 /* |name| value when reading text generated by \&{scantokens} */
12618 @d max_spec_src is_scantok
12619
12620 @ Additional information about the current line is available via the
12621 |index| variable, which counts how many lines of characters are present
12622 in the buffer below the current level. We have |index=0| when reading
12623 from the terminal and prompting the user for each line; then if the user types,
12624 e.g., `\.{input figs}', we will have |index=1| while reading
12625 the file \.{figs.mp}. However, it does not follow that |index| is the
12626 same as the input stack pointer, since many of the levels on the input
12627 stack may come from token lists and some |index| values may correspond
12628 to \.{MPX} files that are not currently on the stack.
12629
12630 The global variable |in_open| is equal to the highest |index| value counting
12631 \.{MPX} files but excluding token-list input levels.  Thus, the number of
12632 partially read lines in the buffer is |in_open+1| and we have |in_open>=index|
12633 when we are not reading a token list.
12634
12635 If we are not currently reading from the terminal,
12636 we are reading from the file variable |input_file[index]|. We use
12637 the notation |terminal_input| as a convenient abbreviation for |name=is_term|,
12638 and |cur_file| as an abbreviation for |input_file[index]|.
12639
12640 When \MP\ is not reading from the terminal, the global variable |line| contains
12641 the line number in the current file, for use in error messages. More precisely,
12642 |line| is a macro for |line_stack[index]| and the |line_stack| array gives
12643 the line number for each file in the |input_file| array.
12644
12645 When an \.{MPX} file is opened the file name is stored in the |mpx_name|
12646 array so that the name doesn't get lost when the file is temporarily removed
12647 from the input stack.
12648 Thus when |input_file[k]| is an \.{MPX} file, its name is |mpx_name[k]|
12649 and it contains translated \TeX\ pictures for |input_file[k-1]|.
12650 Since this is not an \.{MPX} file, we have
12651 $$ \hbox{|mpx_name[k-1]<=absent|}. $$
12652 This |name| field is set to |finished| when |input_file[k]| is completely
12653 read.
12654
12655 If more information about the input state is needed, it can be
12656 included in small arrays like those shown here. For example,
12657 the current page or segment number in the input file might be put
12658 into a variable |page|, that is really a macro for the current entry
12659 in `\ignorespaces|page_stack:array[0..max_in_open] of integer|\unskip'
12660 by analogy with |line_stack|.
12661 @^system dependencies@>
12662
12663 @d terminal_input (name==is_term) /* are we reading from the terminal? */
12664 @d cur_file mp->input_file[index] /* the current |FILE *| variable */
12665 @d line mp->line_stack[index] /* current line number in the current source file */
12666 @d in_name mp->iname_stack[index] /* a string used to construct \.{MPX} file names */
12667 @d in_area mp->iarea_stack[index] /* another string for naming \.{MPX} files */
12668 @d absent 1 /* |name_field| value for unused |mpx_in_stack| entries */
12669 @d mpx_reading (mp->mpx_name[index]>absent)
12670   /* when reading a file, is it an \.{MPX} file? */
12671 @d finished 0
12672   /* |name_field| value when the corresponding \.{MPX} file is finished */
12673
12674 @<Glob...@>=
12675 integer in_open; /* the number of lines in the buffer, less one */
12676 unsigned int open_parens; /* the number of open text files */
12677 FILE  * *input_file ;
12678 integer *line_stack ; /* the line number for each file */
12679 char *  *iname_stack; /* used for naming \.{MPX} files */
12680 char *  *iarea_stack; /* used for naming \.{MPX} files */
12681 halfword*mpx_name  ;
12682
12683 @ @<Allocate or ...@>=
12684 mp->input_file  = xmalloc((mp->max_in_open+1),sizeof(FILE *));
12685 mp->line_stack  = xmalloc((mp->max_in_open+1),sizeof(integer));
12686 mp->iname_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12687 mp->iarea_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
12688 mp->mpx_name    = xmalloc((mp->max_in_open+1),sizeof(halfword));
12689 {
12690   int k;
12691   for (k=0;k<=mp->max_in_open;k++) {
12692     mp->iname_stack[k] =NULL;
12693     mp->iarea_stack[k] =NULL;
12694   }
12695 }
12696
12697 @ @<Dealloc variables@>=
12698 {
12699   int l;
12700   for (l=0;l<=mp->max_in_open;l++) {
12701     xfree(mp->iname_stack[l]);
12702     xfree(mp->iarea_stack[l]);
12703   }
12704 }
12705 xfree(mp->input_file);
12706 xfree(mp->line_stack);
12707 xfree(mp->iname_stack);
12708 xfree(mp->iarea_stack);
12709 xfree(mp->mpx_name);
12710
12711
12712 @ However, all this discussion about input state really applies only to the
12713 case that we are inputting from a file. There is another important case,
12714 namely when we are currently getting input from a token list. In this case
12715 |index>max_in_open|, and the conventions about the other state variables
12716 are different:
12717
12718 \yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
12719 the node that will be read next. If |loc=null|, the token list has been
12720 fully read.
12721
12722 \yskip\hang|start| points to the first node of the token list; this node
12723 may or may not contain a reference count, depending on the type of token
12724 list involved.
12725
12726 \yskip\hang|token_type|, which takes the place of |index| in the
12727 discussion above, is a code number that explains what kind of token list
12728 is being scanned.
12729
12730 \yskip\hang|name| points to the |eqtb| address of the control sequence
12731 being expanded, if the current token list is a macro not defined by
12732 \&{vardef}. Macros defined by \&{vardef} have |name=null|; their name
12733 can be deduced by looking at their first two parameters.
12734
12735 \yskip\hang|param_start|, which takes the place of |limit|, tells where
12736 the parameters of the current macro or loop text begin in the |param_stack|.
12737
12738 \yskip\noindent The |token_type| can take several values, depending on
12739 where the current token list came from:
12740
12741 \yskip
12742 \indent|forever_text|, if the token list being scanned is the body of
12743 a \&{forever} loop;
12744
12745 \indent|loop_text|, if the token list being scanned is the body of
12746 a \&{for} or \&{forsuffixes} loop;
12747
12748 \indent|parameter|, if a \&{text} or \&{suffix} parameter is being scanned;
12749
12750 \indent|backed_up|, if the token list being scanned has been inserted as
12751 `to be read again'.
12752
12753 \indent|inserted|, if the token list being scanned has been inserted as
12754 part of error recovery;
12755
12756 \indent|macro|, if the expansion of a user-defined symbolic token is being
12757 scanned.
12758
12759 \yskip\noindent
12760 The token list begins with a reference count if and only if |token_type=
12761 macro|.
12762 @^reference counts@>
12763
12764 @d token_type index /* type of current token list */
12765 @d token_state (index>(int)mp->max_in_open) /* are we scanning a token list? */
12766 @d file_state (index<=(int)mp->max_in_open) /* are we scanning a file line? */
12767 @d param_start limit /* base of macro parameters in |param_stack| */
12768 @d forever_text (mp->max_in_open+1) /* |token_type| code for loop texts */
12769 @d loop_text (mp->max_in_open+2) /* |token_type| code for loop texts */
12770 @d parameter (mp->max_in_open+3) /* |token_type| code for parameter texts */
12771 @d backed_up (mp->max_in_open+4) /* |token_type| code for texts to be reread */
12772 @d inserted (mp->max_in_open+5) /* |token_type| code for inserted texts */
12773 @d macro (mp->max_in_open+6) /* |token_type| code for macro replacement texts */
12774
12775 @ The |param_stack| is an auxiliary array used to hold pointers to the token
12776 lists for parameters at the current level and subsidiary levels of input.
12777 This stack grows at a different rate from the others.
12778
12779 @<Glob...@>=
12780 pointer *param_stack;  /* token list pointers for parameters */
12781 integer param_ptr; /* first unused entry in |param_stack| */
12782 integer max_param_stack;  /* largest value of |param_ptr| */
12783
12784 @ @<Allocate or initialize ...@>=
12785 mp->param_stack = xmalloc((mp->param_size+1),sizeof(pointer));
12786
12787 @ @<Dealloc variables@>=
12788 xfree(mp->param_stack);
12789
12790 @ Notice that the |line| isn't valid when |token_state| is true because it
12791 depends on |index|.  If we really need to know the line number for the
12792 topmost file in the index stack we use the following function.  If a page
12793 number or other information is needed, this routine should be modified to
12794 compute it as well.
12795 @^system dependencies@>
12796
12797 @<Declare a function called |true_line|@>=
12798 integer mp_true_line (MP mp) {
12799   int k; /* an index into the input stack */
12800   if ( file_state && (name>max_spec_src) ) {
12801      return line;
12802   } else { 
12803     k=mp->input_ptr;
12804     while ((k>0) &&
12805            ((mp->input_stack[(k-1)].index_field>mp->max_in_open)||
12806             (mp->input_stack[(k-1)].name_field<=max_spec_src))) {
12807       decr(k);
12808     }
12809     return mp->line_stack[(k-1)];
12810   }
12811   return 0; 
12812 }
12813
12814 @ Thus, the ``current input state'' can be very complicated indeed; there
12815 can be many levels and each level can arise in a variety of ways. The
12816 |show_context| procedure, which is used by \MP's error-reporting routine to
12817 print out the current input state on all levels down to the most recent
12818 line of characters from an input file, illustrates most of these conventions.
12819 The global variable |file_ptr| contains the lowest level that was
12820 displayed by this procedure.
12821
12822 @<Glob...@>=
12823 integer file_ptr; /* shallowest level shown by |show_context| */
12824
12825 @ The status at each level is indicated by printing two lines, where the first
12826 line indicates what was read so far and the second line shows what remains
12827 to be read. The context is cropped, if necessary, so that the first line
12828 contains at most |half_error_line| characters, and the second contains
12829 at most |error_line|. Non-current input levels whose |token_type| is
12830 `|backed_up|' are shown only if they have not been fully read.
12831
12832 @c void mp_show_context (MP mp) { /* prints where the scanner is */
12833   int old_setting; /* saved |selector| setting */
12834   @<Local variables for formatting calculations@>
12835   mp->file_ptr=mp->input_ptr; mp->input_stack[mp->file_ptr]=mp->cur_input;
12836   /* store current state */
12837   while (1) { 
12838     mp->cur_input=mp->input_stack[mp->file_ptr]; /* enter into the context */
12839     @<Display the current context@>;
12840     if ( file_state )
12841       if ( (name>max_spec_src) || (mp->file_ptr==0) ) break;
12842     decr(mp->file_ptr);
12843   }
12844   mp->cur_input=mp->input_stack[mp->input_ptr]; /* restore original state */
12845 }
12846
12847 @ @<Display the current context@>=
12848 if ( (mp->file_ptr==mp->input_ptr) || file_state ||
12849    (token_type!=backed_up) || (loc!=null) ) {
12850     /* we omit backed-up token lists that have already been read */
12851   mp->tally=0; /* get ready to count characters */
12852   old_setting=mp->selector;
12853   if ( file_state ) {
12854     @<Print location of current line@>;
12855     @<Pseudoprint the line@>;
12856   } else { 
12857     @<Print type of token list@>;
12858     @<Pseudoprint the token list@>;
12859   }
12860   mp->selector=old_setting; /* stop pseudoprinting */
12861   @<Print two lines using the tricky pseudoprinted information@>;
12862 }
12863
12864 @ This routine should be changed, if necessary, to give the best possible
12865 indication of where the current line resides in the input file.
12866 For example, on some systems it is best to print both a page and line number.
12867 @^system dependencies@>
12868
12869 @<Print location of current line@>=
12870 if ( name>max_spec_src ) {
12871   mp_print_nl(mp, "l."); mp_print_int(mp, mp_true_line(mp));
12872 } else if ( terminal_input ) {
12873   if ( mp->file_ptr==0 ) mp_print_nl(mp, "<*>");
12874   else mp_print_nl(mp, "<insert>");
12875 } else if ( name==is_scantok ) {
12876   mp_print_nl(mp, "<scantokens>");
12877 } else {
12878   mp_print_nl(mp, "<read>");
12879 }
12880 mp_print_char(mp, ' ')
12881
12882 @ Can't use case statement here because the |token_type| is not
12883 a constant expression.
12884
12885 @<Print type of token list@>=
12886 {
12887   if(token_type==forever_text) {
12888     mp_print_nl(mp, "<forever> ");
12889   } else if (token_type==loop_text) {
12890     @<Print the current loop value@>;
12891   } else if (token_type==parameter) {
12892     mp_print_nl(mp, "<argument> "); 
12893   } else if (token_type==backed_up) { 
12894     if ( loc==null ) mp_print_nl(mp, "<recently read> ");
12895     else mp_print_nl(mp, "<to be read again> ");
12896   } else if (token_type==inserted) {
12897     mp_print_nl(mp, "<inserted text> ");
12898   } else if (token_type==macro) {
12899     mp_print_ln(mp);
12900     if ( name!=null ) mp_print_text(name);
12901     else @<Print the name of a \&{vardef}'d macro@>;
12902     mp_print(mp, "->");
12903   } else {
12904     mp_print_nl(mp, "?");/* this should never happen */
12905 @.?\relax@>
12906   }
12907 }
12908
12909 @ The parameter that corresponds to a loop text is either a token list
12910 (in the case of \&{forsuffixes}) or a ``capsule'' (in the case of \&{for}).
12911 We'll discuss capsules later; for now, all we need to know is that
12912 the |link| field in a capsule parameter is |void| and that
12913 |print_exp(p,0)| displays the value of capsule~|p| in abbreviated form.
12914
12915 @d diov (null+1) /* a null pointer different from |null| */
12916
12917 @<Print the current loop value@>=
12918 { mp_print_nl(mp, "<for("); p=mp->param_stack[param_start];
12919   if ( p!=null ) {
12920     if ( link(p)==diov ) mp_print_exp(mp, p,0); /* we're in a \&{for} loop */
12921     else mp_show_token_list(mp, p,null,20,mp->tally);
12922   }
12923   mp_print(mp, ")> ");
12924 }
12925
12926 @ The first two parameters of a macro defined by \&{vardef} will be token
12927 lists representing the macro's prefix and ``at point.'' By putting these
12928 together, we get the macro's full name.
12929
12930 @<Print the name of a \&{vardef}'d macro@>=
12931 { p=mp->param_stack[param_start];
12932   if ( p==null ) {
12933     mp_show_token_list(mp, mp->param_stack[param_start+1],null,20,mp->tally);
12934   } else { 
12935     q=p;
12936     while ( link(q)!=null ) q=link(q);
12937     link(q)=mp->param_stack[param_start+1];
12938     mp_show_token_list(mp, p,null,20,mp->tally);
12939     link(q)=null;
12940   }
12941 }
12942
12943 @ Now it is necessary to explain a little trick. We don't want to store a long
12944 string that corresponds to a token list, because that string might take up
12945 lots of memory; and we are printing during a time when an error message is
12946 being given, so we dare not do anything that might overflow one of \MP's
12947 tables. So `pseudoprinting' is the answer: We enter a mode of printing
12948 that stores characters into a buffer of length |error_line|, where character
12949 $k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
12950 |k<trick_count|, otherwise character |k| is dropped. Initially we set
12951 |tally:=0| and |trick_count:=1000000|; then when we reach the
12952 point where transition from line 1 to line 2 should occur, we
12953 set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
12954 tally+1+error_line-half_error_line)|. At the end of the
12955 pseudoprinting, the values of |first_count|, |tally|, and
12956 |trick_count| give us all the information we need to print the two lines,
12957 and all of the necessary text is in |trick_buf|.
12958
12959 Namely, let |l| be the length of the descriptive information that appears
12960 on the first line. The length of the context information gathered for that
12961 line is |k=first_count|, and the length of the context information
12962 gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
12963 where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
12964 descriptive information on line~1, and set |n:=l+k|; here |n| is the
12965 length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
12966 and print `\.{...}' followed by
12967 $$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
12968 where subscripts of |trick_buf| are circular modulo |error_line|. The
12969 second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
12970 unless |n+m>error_line|; in the latter case, further cropping is done.
12971 This is easier to program than to explain.
12972
12973 @<Local variables for formatting...@>=
12974 int i; /* index into |buffer| */
12975 integer l; /* length of descriptive information on line 1 */
12976 integer m; /* context information gathered for line 2 */
12977 int n; /* length of line 1 */
12978 integer p; /* starting or ending place in |trick_buf| */
12979 integer q; /* temporary index */
12980
12981 @ The following code tells the print routines to gather
12982 the desired information.
12983
12984 @d begin_pseudoprint { 
12985   l=mp->tally; mp->tally=0; mp->selector=pseudo;
12986   mp->trick_count=1000000;
12987 }
12988 @d set_trick_count {
12989   mp->first_count=mp->tally;
12990   mp->trick_count=mp->tally+1+mp->error_line-mp->half_error_line;
12991   if ( mp->trick_count<mp->error_line ) mp->trick_count=mp->error_line;
12992 }
12993
12994 @ And the following code uses the information after it has been gathered.
12995
12996 @<Print two lines using the tricky pseudoprinted information@>=
12997 if ( mp->trick_count==1000000 ) set_trick_count;
12998   /* |set_trick_count| must be performed */
12999 if ( mp->tally<mp->trick_count ) m=mp->tally-mp->first_count;
13000 else m=mp->trick_count-mp->first_count; /* context on line 2 */
13001 if ( l+mp->first_count<=mp->half_error_line ) {
13002   p=0; n=l+mp->first_count;
13003 } else  { 
13004   mp_print(mp, "..."); p=l+mp->first_count-mp->half_error_line+3;
13005   n=mp->half_error_line;
13006 }
13007 for (q=p;q<=mp->first_count-1;q++) {
13008   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13009 }
13010 mp_print_ln(mp);
13011 for (q=1;q<=n;q++) {
13012   mp_print_char(mp, ' '); /* print |n| spaces to begin line~2 */
13013 }
13014 if ( m+n<=mp->error_line ) p=mp->first_count+m; 
13015 else p=mp->first_count+(mp->error_line-n-3);
13016 for (q=mp->first_count;q<=p-1;q++) {
13017   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13018 }
13019 if ( m+n>mp->error_line ) mp_print(mp, "...")
13020
13021 @ But the trick is distracting us from our current goal, which is to
13022 understand the input state. So let's concentrate on the data structures that
13023 are being pseudoprinted as we finish up the |show_context| procedure.
13024
13025 @<Pseudoprint the line@>=
13026 begin_pseudoprint;
13027 if ( limit>0 ) {
13028   for (i=start;i<=limit-1;i++) {
13029     if ( i==loc ) set_trick_count;
13030     mp_print_str(mp, mp->buffer[i]);
13031   }
13032 }
13033
13034 @ @<Pseudoprint the token list@>=
13035 begin_pseudoprint;
13036 if ( token_type!=macro ) mp_show_token_list(mp, start,loc,100000,0);
13037 else mp_show_macro(mp, start,loc,100000)
13038
13039 @ Here is the missing piece of |show_token_list| that is activated when the
13040 token beginning line~2 is about to be shown:
13041
13042 @<Do magic computation@>=set_trick_count
13043
13044 @* \[28] Maintaining the input stacks.
13045 The following subroutines change the input status in commonly needed ways.
13046
13047 First comes |push_input|, which stores the current state and creates a
13048 new level (having, initially, the same properties as the old).
13049
13050 @d push_input  { /* enter a new input level, save the old */
13051   if ( mp->input_ptr>mp->max_in_stack ) {
13052     mp->max_in_stack=mp->input_ptr;
13053     if ( mp->input_ptr==mp->stack_size ) {
13054       int l = (mp->stack_size+(mp->stack_size>>2));
13055       XREALLOC(mp->input_stack, l, in_state_record);
13056       mp->stack_size = l;
13057     }         
13058   }
13059   mp->input_stack[mp->input_ptr]=mp->cur_input; /* stack the record */
13060   incr(mp->input_ptr);
13061 }
13062
13063 @ And of course what goes up must come down.
13064
13065 @d pop_input { /* leave an input level, re-enter the old */
13066     decr(mp->input_ptr); mp->cur_input=mp->input_stack[mp->input_ptr];
13067   }
13068
13069 @ Here is a procedure that starts a new level of token-list input, given
13070 a token list |p| and its type |t|. If |t=macro|, the calling routine should
13071 set |name|, reset~|loc|, and increase the macro's reference count.
13072
13073 @d back_list(A) mp_begin_token_list(mp, (A),backed_up) /* backs up a simple token list */
13074
13075 @c void mp_begin_token_list (MP mp,pointer p, quarterword t)  { 
13076   push_input; start=p; token_type=t;
13077   param_start=mp->param_ptr; loc=p;
13078 }
13079
13080 @ When a token list has been fully scanned, the following computations
13081 should be done as we leave that level of input.
13082 @^inner loop@>
13083
13084 @c void mp_end_token_list (MP mp) { /* leave a token-list input level */
13085   pointer p; /* temporary register */
13086   if ( token_type>=backed_up ) { /* token list to be deleted */
13087     if ( token_type<=inserted ) { 
13088       mp_flush_token_list(mp, start); goto DONE;
13089     } else {
13090       mp_delete_mac_ref(mp, start); /* update reference count */
13091     }
13092   }
13093   while ( mp->param_ptr>param_start ) { /* parameters must be flushed */
13094     decr(mp->param_ptr);
13095     p=mp->param_stack[mp->param_ptr];
13096     if ( p!=null ) {
13097       if ( link(p)==diov ) { /* it's an \&{expr} parameter */
13098         mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
13099       } else {
13100         mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
13101       }
13102     }
13103   }
13104 DONE: 
13105   pop_input; check_interrupt;
13106 }
13107
13108 @ The contents of |cur_cmd,cur_mod,cur_sym| are placed into an equivalent
13109 token by the |cur_tok| routine.
13110 @^inner loop@>
13111
13112 @c @<Declare the procedure called |make_exp_copy|@>;
13113 pointer mp_cur_tok (MP mp) {
13114   pointer p; /* a new token node */
13115   small_number save_type; /* |cur_type| to be restored */
13116   integer save_exp; /* |cur_exp| to be restored */
13117   if ( mp->cur_sym==0 ) {
13118     if ( mp->cur_cmd==capsule_token ) {
13119       save_type=mp->cur_type; save_exp=mp->cur_exp;
13120       mp_make_exp_copy(mp, mp->cur_mod); p=mp_stash_cur_exp(mp); link(p)=null;
13121       mp->cur_type=save_type; mp->cur_exp=save_exp;
13122     } else { 
13123       p=mp_get_node(mp, token_node_size);
13124       value(p)=mp->cur_mod; name_type(p)=mp_token;
13125       if ( mp->cur_cmd==numeric_token ) type(p)=mp_known;
13126       else type(p)=mp_string_type;
13127     }
13128   } else { 
13129     fast_get_avail(p); info(p)=mp->cur_sym;
13130   }
13131   return p;
13132 }
13133
13134 @ Sometimes \MP\ has read too far and wants to ``unscan'' what it has
13135 seen. The |back_input| procedure takes care of this by putting the token
13136 just scanned back into the input stream, ready to be read again.
13137 If |cur_sym<>0|, the values of |cur_cmd| and |cur_mod| are irrelevant.
13138
13139 @<Declarations@>= 
13140 void mp_back_input (MP mp);
13141
13142 @ @c void mp_back_input (MP mp) {/* undoes one token of input */
13143   pointer p; /* a token list of length one */
13144   p=mp_cur_tok(mp);
13145   while ( token_state &&(loc==null) ) 
13146     mp_end_token_list(mp); /* conserve stack space */
13147   back_list(p);
13148 }
13149
13150 @ The |back_error| routine is used when we want to restore or replace an
13151 offending token just before issuing an error message.  We disable interrupts
13152 during the call of |back_input| so that the help message won't be lost.
13153
13154 @<Declarations@>=
13155 void mp_error (MP mp);
13156 void mp_back_error (MP mp);
13157
13158 @ @c void mp_back_error (MP mp) { /* back up one token and call |error| */
13159   mp->OK_to_interrupt=false; 
13160   mp_back_input(mp); 
13161   mp->OK_to_interrupt=true; mp_error(mp);
13162 }
13163 void mp_ins_error (MP mp) { /* back up one inserted token and call |error| */
13164   mp->OK_to_interrupt=false; 
13165   mp_back_input(mp); token_type=inserted;
13166   mp->OK_to_interrupt=true; mp_error(mp);
13167 }
13168
13169 @ The |begin_file_reading| procedure starts a new level of input for lines
13170 of characters to be read from a file, or as an insertion from the
13171 terminal. It does not take care of opening the file, nor does it set |loc|
13172 or |limit| or |line|.
13173 @^system dependencies@>
13174
13175 @c void mp_begin_file_reading (MP mp) { 
13176   if ( mp->in_open==mp->max_in_open ) 
13177     mp_overflow(mp, "text input levels",mp->max_in_open);
13178 @:MetaPost capacity exceeded text input levels}{\quad text input levels@>
13179   if ( mp->first==mp->buf_size ) 
13180     mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13181   incr(mp->in_open); push_input; index=mp->in_open;
13182   mp->mpx_name[index]=absent;
13183   start=mp->first;
13184   name=is_term; /* |terminal_input| is now |true| */
13185 }
13186
13187 @ Conversely, the variables must be downdated when such a level of input
13188 is finished.  Any associated \.{MPX} file must also be closed and popped
13189 off the file stack.
13190
13191 @c void mp_end_file_reading (MP mp) { 
13192   if ( mp->in_open>index ) {
13193     if ( (mp->mpx_name[mp->in_open]==absent)||(name<=max_spec_src) ) {
13194       mp_confusion(mp, "endinput");
13195 @:this can't happen endinput}{\quad endinput@>
13196     } else { 
13197       fclose(mp->input_file[mp->in_open]); /* close an \.{MPX} file */
13198       delete_str_ref(mp->mpx_name[mp->in_open]);
13199       decr(mp->in_open);
13200     }
13201   }
13202   mp->first=start;
13203   if ( index!=mp->in_open ) mp_confusion(mp, "endinput");
13204   if ( name>max_spec_src ) {
13205     fclose(cur_file);
13206     delete_str_ref(name);
13207     xfree(in_name); in_name=NULL;
13208     xfree(in_area); in_area=NULL;
13209   }
13210   pop_input; decr(mp->in_open);
13211 }
13212
13213 @ Here is a function that tries to resume input from an \.{MPX} file already
13214 associated with the current input file.  It returns |false| if this doesn't
13215 work.
13216
13217 @c boolean mp_begin_mpx_reading (MP mp) { 
13218   if ( mp->in_open!=index+1 ) {
13219      return false;
13220   } else { 
13221     if ( mp->mpx_name[mp->in_open]<=absent ) mp_confusion(mp, "mpx");
13222 @:this can't happen mpx}{\quad mpx@>
13223     if ( mp->first==mp->buf_size ) 
13224       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
13225     push_input; index=mp->in_open;
13226     start=mp->first;
13227     name=mp->mpx_name[mp->in_open]; add_str_ref(name);
13228     @<Put an empty line in the input buffer@>;
13229     return true;
13230   }
13231 }
13232
13233 @ This procedure temporarily stops reading an \.{MPX} file.
13234
13235 @c void mp_end_mpx_reading (MP mp) { 
13236   if ( mp->in_open!=index ) mp_confusion(mp, "mpx");
13237 @:this can't happen mpx}{\quad mpx@>
13238   if ( loc<limit ) {
13239     @<Complain that we are not at the end of a line in the \.{MPX} file@>;
13240   }
13241   mp->first=start;
13242   pop_input;
13243 }
13244
13245 @ Here we enforce a restriction that simplifies the input stacks considerably.
13246 This should not inconvenience the user because \.{MPX} files are generated
13247 by an auxiliary program called \.{DVItoMP}.
13248
13249 @ @<Complain that we are not at the end of a line in the \.{MPX} file@>=
13250
13251 print_err("`mpxbreak' must be at the end of a line");
13252 help4("This file contains picture expressions for btex...etex")
13253   ("blocks.  Such files are normally generated automatically")
13254   ("but this one seems to be messed up.  I'm going to ignore")
13255   ("the rest of this line.");
13256 mp_error(mp);
13257 }
13258
13259 @ In order to keep the stack from overflowing during a long sequence of
13260 inserted `\.{show}' commands, the following routine removes completed
13261 error-inserted lines from memory.
13262
13263 @c void mp_clear_for_error_prompt (MP mp) { 
13264   while ( file_state && terminal_input &&
13265     (mp->input_ptr>0)&&(loc==limit) ) mp_end_file_reading(mp);
13266   mp_print_ln(mp); clear_terminal;
13267 }
13268
13269 @ To get \MP's whole input mechanism going, we perform the following
13270 actions.
13271
13272 @<Initialize the input routines@>=
13273 { mp->input_ptr=0; mp->max_in_stack=0;
13274   mp->in_open=0; mp->open_parens=0; mp->max_buf_stack=0;
13275   mp->param_ptr=0; mp->max_param_stack=0;
13276   mp->first=1;
13277   start=1; index=0; line=0; name=is_term;
13278   mp->mpx_name[0]=absent;
13279   mp->force_eof=false;
13280   if ( ! mp_init_terminal(mp) ) exit(EXIT_FAILURE);
13281   limit=mp->last; mp->first=mp->last+1; 
13282   /* |init_terminal| has set |loc| and |last| */
13283 }
13284
13285 @* \[29] Getting the next token.
13286 The heart of \MP's input mechanism is the |get_next| procedure, which
13287 we shall develop in the next few sections of the program. Perhaps we
13288 shouldn't actually call it the ``heart,'' however; it really acts as \MP's
13289 eyes and mouth, reading the source files and gobbling them up. And it also
13290 helps \MP\ to regurgitate stored token lists that are to be processed again.
13291
13292 The main duty of |get_next| is to input one token and to set |cur_cmd|
13293 and |cur_mod| to that token's command code and modifier. Furthermore, if
13294 the input token is a symbolic token, that token's |hash| address
13295 is stored in |cur_sym|; otherwise |cur_sym| is set to zero.
13296
13297 Underlying this simple description is a certain amount of complexity
13298 because of all the cases that need to be handled.
13299 However, the inner loop of |get_next| is reasonably short and fast.
13300
13301 @ Before getting into |get_next|, we need to consider a mechanism by which
13302 \MP\ helps keep errors from propagating too far. Whenever the program goes
13303 into a mode where it keeps calling |get_next| repeatedly until a certain
13304 condition is met, it sets |scanner_status| to some value other than |normal|.
13305 Then if an input file ends, or if an `\&{outer}' symbol appears,
13306 an appropriate error recovery will be possible.
13307
13308 The global variable |warning_info| helps in this error recovery by providing
13309 additional information. For example, |warning_info| might indicate the
13310 name of a macro whose replacement text is being scanned.
13311
13312 @d normal 0 /* |scanner_status| at ``quiet times'' */
13313 @d skipping 1 /* |scanner_status| when false conditional text is being skipped */
13314 @d flushing 2 /* |scanner_status| when junk after a statement is being ignored */
13315 @d absorbing 3 /* |scanner_status| when a \&{text} parameter is being scanned */
13316 @d var_defining 4 /* |scanner_status| when a \&{vardef} is being scanned */
13317 @d op_defining 5 /* |scanner_status| when a macro \&{def} is being scanned */
13318 @d loop_defining 6 /* |scanner_status| when a \&{for} loop is being scanned */
13319 @d tex_flushing 7 /* |scanner_status| when skipping \TeX\ material */
13320
13321 @<Glob...@>=
13322 integer scanner_status; /* are we scanning at high speed? */
13323 integer warning_info; /* if so, what else do we need to know,
13324     in case an error occurs? */
13325
13326 @ @<Initialize the input routines@>=
13327 mp->scanner_status=normal;
13328
13329 @ The following subroutine
13330 is called when an `\&{outer}' symbolic token has been scanned or
13331 when the end of a file has been reached. These two cases are distinguished
13332 by |cur_sym|, which is zero at the end of a file.
13333
13334 @c boolean mp_check_outer_validity (MP mp) {
13335   pointer p; /* points to inserted token list */
13336   if ( mp->scanner_status==normal ) {
13337     return true;
13338   } else if ( mp->scanner_status==tex_flushing ) {
13339     @<Check if the file has ended while flushing \TeX\ material and set the
13340       result value for |check_outer_validity|@>;
13341   } else { 
13342     mp->deletions_allowed=false;
13343     @<Back up an outer symbolic token so that it can be reread@>;
13344     if ( mp->scanner_status>skipping ) {
13345       @<Tell the user what has run away and try to recover@>;
13346     } else { 
13347       print_err("Incomplete if; all text was ignored after line ");
13348 @.Incomplete if...@>
13349       mp_print_int(mp, mp->warning_info);
13350       help3("A forbidden `outer' token occurred in skipped text.")
13351         ("This kind of error happens when you say `if...' and forget")
13352         ("the matching `fi'. I've inserted a `fi'; this might work.");
13353       if ( mp->cur_sym==0 ) 
13354         mp->help_line[2]="The file ended while I was skipping conditional text.";
13355       mp->cur_sym=frozen_fi; mp_ins_error(mp);
13356     }
13357     mp->deletions_allowed=true; 
13358         return false;
13359   }
13360 }
13361
13362 @ @<Check if the file has ended while flushing \TeX\ material and set...@>=
13363 if ( mp->cur_sym!=0 ) { 
13364    return true;
13365 } else { 
13366   mp->deletions_allowed=false;
13367   print_err("TeX mode didn't end; all text was ignored after line ");
13368   mp_print_int(mp, mp->warning_info);
13369   help2("The file ended while I was looking for the `etex' to")
13370     ("finish this TeX material.  I've inserted `etex' now.");
13371   mp->cur_sym = frozen_etex;
13372   mp_ins_error(mp);
13373   mp->deletions_allowed=true;
13374   return false;
13375 }
13376
13377 @ @<Back up an outer symbolic token so that it can be reread@>=
13378 if ( mp->cur_sym!=0 ) {
13379   p=mp_get_avail(mp); info(p)=mp->cur_sym;
13380   back_list(p); /* prepare to read the symbolic token again */
13381 }
13382
13383 @ @<Tell the user what has run away...@>=
13384
13385   mp_runaway(mp); /* print the definition-so-far */
13386   if ( mp->cur_sym==0 ) {
13387     print_err("File ended");
13388 @.File ended while scanning...@>
13389   } else { 
13390     print_err("Forbidden token found");
13391 @.Forbidden token found...@>
13392   }
13393   mp_print(mp, " while scanning ");
13394   help4("I suspect you have forgotten an `enddef',")
13395     ("causing me to read past where you wanted me to stop.")
13396     ("I'll try to recover; but if the error is serious,")
13397     ("you'd better type `E' or `X' now and fix your file.");
13398   switch (mp->scanner_status) {
13399     @<Complete the error message,
13400       and set |cur_sym| to a token that might help recover from the error@>
13401   } /* there are no other cases */
13402   mp_ins_error(mp);
13403 }
13404
13405 @ As we consider various kinds of errors, it is also appropriate to
13406 change the first line of the help message just given; |help_line[3]|
13407 points to the string that might be changed.
13408
13409 @<Complete the error message,...@>=
13410 case flushing: 
13411   mp_print(mp, "to the end of the statement");
13412   mp->help_line[3]="A previous error seems to have propagated,";
13413   mp->cur_sym=frozen_semicolon;
13414   break;
13415 case absorbing: 
13416   mp_print(mp, "a text argument");
13417   mp->help_line[3]="It seems that a right delimiter was left out,";
13418   if ( mp->warning_info==0 ) {
13419     mp->cur_sym=frozen_end_group;
13420   } else { 
13421     mp->cur_sym=frozen_right_delimiter;
13422     equiv(frozen_right_delimiter)=mp->warning_info;
13423   }
13424   break;
13425 case var_defining:
13426 case op_defining: 
13427   mp_print(mp, "the definition of ");
13428   if ( mp->scanner_status==op_defining ) 
13429      mp_print_text(mp->warning_info);
13430   else 
13431      mp_print_variable_name(mp, mp->warning_info);
13432   mp->cur_sym=frozen_end_def;
13433   break;
13434 case loop_defining: 
13435   mp_print(mp, "the text of a "); 
13436   mp_print_text(mp->warning_info);
13437   mp_print(mp, " loop");
13438   mp->help_line[3]="I suspect you have forgotten an `endfor',";
13439   mp->cur_sym=frozen_end_for;
13440   break;
13441
13442 @ The |runaway| procedure displays the first part of the text that occurred
13443 when \MP\ began its special |scanner_status|, if that text has been saved.
13444
13445 @<Declare the procedure called |runaway|@>=
13446 void mp_runaway (MP mp) { 
13447   if ( mp->scanner_status>flushing ) { 
13448      mp_print_nl(mp, "Runaway ");
13449          switch (mp->scanner_status) { 
13450          case absorbing: mp_print(mp, "text?"); break;
13451          case var_defining: 
13452      case op_defining: mp_print(mp,"definition?"); break;
13453      case loop_defining: mp_print(mp, "loop?"); break;
13454      } /* there are no other cases */
13455      mp_print_ln(mp); 
13456      mp_show_token_list(mp, link(hold_head),null,mp->error_line-10,0);
13457   }
13458 }
13459
13460 @ We need to mention a procedure that may be called by |get_next|.
13461
13462 @<Declarations@>= 
13463 void mp_firm_up_the_line (MP mp);
13464
13465 @ And now we're ready to take the plunge into |get_next| itself.
13466 Note that the behavior depends on the |scanner_status| because percent signs
13467 and double quotes need to be passed over when skipping TeX material.
13468
13469 @c 
13470 void mp_get_next (MP mp) {
13471   /* sets |cur_cmd|, |cur_mod|, |cur_sym| to next token */
13472 @^inner loop@>
13473   /*restart*/ /* go here to get the next input token */
13474   /*exit*/ /* go here when the next input token has been got */
13475   /*|common_ending|*/ /* go here to finish getting a symbolic token */
13476   /*found*/ /* go here when the end of a symbolic token has been found */
13477   /*switch*/ /* go here to branch on the class of an input character */
13478   /*|start_numeric_token|,|start_decimal_token|,|fin_numeric_token|,|done|*/
13479     /* go here at crucial stages when scanning a number */
13480   int k; /* an index into |buffer| */
13481   ASCII_code c; /* the current character in the buffer */
13482   ASCII_code class; /* its class number */
13483   integer n,f; /* registers for decimal-to-binary conversion */
13484 RESTART: 
13485   mp->cur_sym=0;
13486   if ( file_state ) {
13487     @<Input from external file; |goto restart| if no input found,
13488     or |return| if a non-symbolic token is found@>;
13489   } else {
13490     @<Input from token list; |goto restart| if end of list or
13491       if a parameter needs to be expanded,
13492       or |return| if a non-symbolic token is found@>;
13493   }
13494 COMMON_ENDING: 
13495   @<Finish getting the symbolic token in |cur_sym|;
13496    |goto restart| if it is illegal@>;
13497 }
13498
13499 @ When a symbolic token is declared to be `\&{outer}', its command code
13500 is increased by |outer_tag|.
13501 @^inner loop@>
13502
13503 @<Finish getting the symbolic token in |cur_sym|...@>=
13504 mp->cur_cmd=eq_type(mp->cur_sym); mp->cur_mod=equiv(mp->cur_sym);
13505 if ( mp->cur_cmd>=outer_tag ) {
13506   if ( mp_check_outer_validity(mp) ) 
13507     mp->cur_cmd=mp->cur_cmd-outer_tag;
13508   else 
13509     goto RESTART;
13510 }
13511
13512 @ A percent sign appears in |buffer[limit]|; this makes it unnecessary
13513 to have a special test for end-of-line.
13514 @^inner loop@>
13515
13516 @<Input from external file;...@>=
13517
13518 SWITCH: 
13519   c=mp->buffer[loc]; incr(loc); class=mp->char_class[c];
13520   switch (class) {
13521   case digit_class: goto START_NUMERIC_TOKEN; break;
13522   case period_class: 
13523     class=mp->char_class[mp->buffer[loc]];
13524     if ( class>period_class ) {
13525       goto SWITCH;
13526     } else if ( class<period_class ) { /* |class=digit_class| */
13527       n=0; goto START_DECIMAL_TOKEN;
13528     }
13529 @:. }{\..\ token@>
13530     break;
13531   case space_class: goto SWITCH; break;
13532   case percent_class: 
13533     if ( mp->scanner_status==tex_flushing ) {
13534       if ( loc<limit ) goto SWITCH;
13535     }
13536     @<Move to next line of file, or |goto restart| if there is no next line@>;
13537     check_interrupt;
13538     goto SWITCH;
13539     break;
13540   case string_class: 
13541     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13542     else @<Get a string token and |return|@>;
13543     break;
13544   case isolated_classes: 
13545     k=loc-1; goto FOUND; break;
13546   case invalid_class: 
13547     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13548     else @<Decry the invalid character and |goto restart|@>;
13549     break;
13550   default: break; /* letters, etc. */
13551   }
13552   k=loc-1;
13553   while ( mp->char_class[mp->buffer[loc]]==class ) incr(loc);
13554   goto FOUND;
13555 START_NUMERIC_TOKEN:
13556   @<Get the integer part |n| of a numeric token;
13557     set |f:=0| and |goto fin_numeric_token| if there is no decimal point@>;
13558 START_DECIMAL_TOKEN:
13559   @<Get the fraction part |f| of a numeric token@>;
13560 FIN_NUMERIC_TOKEN:
13561   @<Pack the numeric and fraction parts of a numeric token
13562     and |return|@>;
13563 FOUND: 
13564   mp->cur_sym=mp_id_lookup(mp, k,loc-k);
13565 }
13566
13567 @ We go to |restart| instead of to |SWITCH|, because |state| might equal
13568 |token_list| after the error has been dealt with
13569 (cf.\ |clear_for_error_prompt|).
13570
13571 @<Decry the invalid...@>=
13572
13573   print_err("Text line contains an invalid character");
13574 @.Text line contains...@>
13575   help2("A funny symbol that I can\'t read has just been input.")
13576     ("Continue, and I'll forget that it ever happened.");
13577   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13578   goto RESTART;
13579 }
13580
13581 @ @<Get a string token and |return|@>=
13582
13583   if ( mp->buffer[loc]=='"' ) {
13584     mp->cur_mod=rts("");
13585   } else { 
13586     k=loc; mp->buffer[limit+1]='"';
13587     do {  
13588      incr(loc);
13589     } while (mp->buffer[loc]!='"');
13590     if ( loc>limit ) {
13591       @<Decry the missing string delimiter and |goto restart|@>;
13592     }
13593     if ( loc==k+1 ) {
13594       mp->cur_mod=mp->buffer[k];
13595     } else { 
13596       str_room(loc-k);
13597       do {  
13598         append_char(mp->buffer[k]); incr(k);
13599       } while (k!=loc);
13600       mp->cur_mod=mp_make_string(mp);
13601     }
13602   }
13603   incr(loc); mp->cur_cmd=string_token; 
13604   return;
13605 }
13606
13607 @ We go to |restart| after this error message, not to |SWITCH|,
13608 because the |clear_for_error_prompt| routine might have reinstated
13609 |token_state| after |error| has finished.
13610
13611 @<Decry the missing string delimiter and |goto restart|@>=
13612
13613   loc=limit; /* the next character to be read on this line will be |"%"| */
13614   print_err("Incomplete string token has been flushed");
13615 @.Incomplete string token...@>
13616   help3("Strings should finish on the same line as they began.")
13617     ("I've deleted the partial string; you might want to")
13618     ("insert another by typing, e.g., `I\"new string\"'.");
13619   mp->deletions_allowed=false; mp_error(mp);
13620   mp->deletions_allowed=true; 
13621   goto RESTART;
13622 }
13623
13624 @ @<Get the integer part |n| of a numeric token...@>=
13625 n=c-'0';
13626 while ( mp->char_class[mp->buffer[loc]]==digit_class ) {
13627   if ( n<32768 ) n=10*n+mp->buffer[loc]-'0';
13628   incr(loc);
13629 }
13630 if ( mp->buffer[loc]=='.' ) 
13631   if ( mp->char_class[mp->buffer[loc+1]]==digit_class ) 
13632     goto DONE;
13633 f=0; 
13634 goto FIN_NUMERIC_TOKEN;
13635 DONE: incr(loc)
13636
13637 @ @<Get the fraction part |f| of a numeric token@>=
13638 k=0;
13639 do { 
13640   if ( k<17 ) { /* digits for |k>=17| cannot affect the result */
13641     mp->dig[k]=mp->buffer[loc]-'0'; incr(k);
13642   }
13643   incr(loc);
13644 } while (mp->char_class[mp->buffer[loc]]==digit_class);
13645 f=mp_round_decimals(mp, k);
13646 if ( f==unity ) {
13647   incr(n); f=0;
13648 }
13649
13650 @ @<Pack the numeric and fraction parts of a numeric token and |return|@>=
13651 if ( n<32768 ) {
13652   @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>;
13653 } else if ( mp->scanner_status!=tex_flushing ) {
13654   print_err("Enormous number has been reduced");
13655 @.Enormous number...@>
13656   help2("I can\'t handle numbers bigger than 32767.99998;")
13657     ("so I've changed your constant to that maximum amount.");
13658   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13659   mp->cur_mod=el_gordo;
13660 }
13661 mp->cur_cmd=numeric_token; return
13662
13663 @ @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>=
13664
13665   mp->cur_mod=n*unity+f;
13666   if ( mp->cur_mod>=fraction_one ) {
13667     if ( (mp->internal[warning_check]>0) &&
13668          (mp->scanner_status!=tex_flushing) ) {
13669       print_err("Number is too large (");
13670       mp_print_scaled(mp, mp->cur_mod);
13671       mp_print_char(mp, ')');
13672       help3("It is at least 4096. Continue and I'll try to cope")
13673       ("with that big value; but it might be dangerous.")
13674       ("(Set warningcheck:=0 to suppress this message.)");
13675       mp_error(mp);
13676     }
13677   }
13678 }
13679
13680 @ Let's consider now what happens when |get_next| is looking at a token list.
13681 @^inner loop@>
13682
13683 @<Input from token list;...@>=
13684 if ( loc>=mp->hi_mem_min ) { /* one-word token */
13685   mp->cur_sym=info(loc); loc=link(loc); /* move to next */
13686   if ( mp->cur_sym>=expr_base ) {
13687     if ( mp->cur_sym>=suffix_base ) {
13688       @<Insert a suffix or text parameter and |goto restart|@>;
13689     } else { 
13690       mp->cur_cmd=capsule_token;
13691       mp->cur_mod=mp->param_stack[param_start+mp->cur_sym-(expr_base)];
13692       mp->cur_sym=0; return;
13693     }
13694   }
13695 } else if ( loc>null ) {
13696   @<Get a stored numeric or string or capsule token and |return|@>
13697 } else { /* we are done with this token list */
13698   mp_end_token_list(mp); goto RESTART; /* resume previous level */
13699 }
13700
13701 @ @<Insert a suffix or text parameter...@>=
13702
13703   if ( mp->cur_sym>=text_base ) mp->cur_sym=mp->cur_sym-mp->param_size;
13704   /* |param_size=text_base-suffix_base| */
13705   mp_begin_token_list(mp,
13706                       mp->param_stack[param_start+mp->cur_sym-(suffix_base)],
13707                       parameter);
13708   goto RESTART;
13709 }
13710
13711 @ @<Get a stored numeric or string or capsule token...@>=
13712
13713   if ( name_type(loc)==mp_token ) {
13714     mp->cur_mod=value(loc);
13715     if ( type(loc)==mp_known ) {
13716       mp->cur_cmd=numeric_token;
13717     } else { 
13718       mp->cur_cmd=string_token; add_str_ref(mp->cur_mod);
13719     }
13720   } else { 
13721     mp->cur_mod=loc; mp->cur_cmd=capsule_token;
13722   };
13723   loc=link(loc); return;
13724 }
13725
13726 @ All of the easy branches of |get_next| have now been taken care of.
13727 There is one more branch.
13728
13729 @<Move to next line of file, or |goto restart|...@>=
13730 if ( name>max_spec_src ) {
13731   @<Read next line of file into |buffer|, or
13732     |goto restart| if the file has ended@>;
13733 } else { 
13734   if ( mp->input_ptr>0 ) {
13735      /* text was inserted during error recovery or by \&{scantokens} */
13736     mp_end_file_reading(mp); goto RESTART; /* resume previous level */
13737   }
13738   if ( mp->selector<log_only || mp->selector>=write_file) mp_open_log_file(mp);
13739   if ( mp->interaction>mp_nonstop_mode ) {
13740     if ( limit==start ) /* previous line was empty */
13741       mp_print_nl(mp, "(Please type a command or say `end')");
13742 @.Please type...@>
13743     mp_print_ln(mp); mp->first=start;
13744     prompt_input("*"); /* input on-line into |buffer| */
13745 @.*\relax@>
13746     limit=mp->last; mp->buffer[limit]='%';
13747     mp->first=limit+1; loc=start;
13748   } else {
13749     mp_fatal_error(mp, "*** (job aborted, no legal end found)");
13750 @.job aborted@>
13751     /* nonstop mode, which is intended for overnight batch processing,
13752     never waits for on-line input */
13753   }
13754 }
13755
13756 @ The global variable |force_eof| is normally |false|; it is set |true|
13757 by an \&{endinput} command.
13758
13759 @<Glob...@>=
13760 boolean force_eof; /* should the next \&{input} be aborted early? */
13761
13762 @ We must decrement |loc| in order to leave the buffer in a valid state
13763 when an error condition causes us to |goto restart| without calling
13764 |end_file_reading|.
13765
13766 @<Read next line of file into |buffer|, or
13767   |goto restart| if the file has ended@>=
13768
13769   incr(line); mp->first=start;
13770   if ( ! mp->force_eof ) {
13771     if ( mp_input_ln(mp, cur_file,true) ) /* not end of file */
13772       mp_firm_up_the_line(mp); /* this sets |limit| */
13773     else 
13774       mp->force_eof=true;
13775   };
13776   if ( mp->force_eof ) {
13777     mp->force_eof=false;
13778     decr(loc);
13779     if ( mpx_reading ) {
13780       @<Complain that the \.{MPX} file ended unexpectly; then set
13781         |cur_sym:=frozen_mpx_break| and |goto comon_ending|@>;
13782     } else { 
13783       mp_print_char(mp, ')'); decr(mp->open_parens);
13784       update_terminal; /* show user that file has been read */
13785       mp_end_file_reading(mp); /* resume previous level */
13786       if ( mp_check_outer_validity(mp) ) goto  RESTART;  
13787       else goto RESTART;
13788     }
13789   }
13790   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; /* ready to read */
13791 }
13792
13793 @ We should never actually come to the end of an \.{MPX} file because such
13794 files should have an \&{mpxbreak} after the translation of the last
13795 \&{btex}$\,\ldots\,$\&{etex} block.
13796
13797 @<Complain that the \.{MPX} file ended unexpectly; then set...@>=
13798
13799   mp->mpx_name[index]=finished;
13800   print_err("mpx file ended unexpectedly");
13801   help4("The file had too few picture expressions for btex...etex")
13802     ("blocks.  Such files are normally generated automatically")
13803     ("but this one got messed up.  You might want to insert a")
13804     ("picture expression now.");
13805   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13806   mp->cur_sym=frozen_mpx_break; goto COMMON_ENDING;
13807 }
13808
13809 @ Sometimes we want to make it look as though we have just read a blank line
13810 without really doing so.
13811
13812 @<Put an empty line in the input buffer@>=
13813 mp->last=mp->first; limit=mp->last; /* simulate |input_ln| and |firm_up_the_line| */
13814 mp->buffer[limit]='%'; mp->first=limit+1; loc=start
13815
13816 @ If the user has set the |pausing| parameter to some positive value,
13817 and if nonstop mode has not been selected, each line of input is displayed
13818 on the terminal and the transcript file, followed by `\.{=>}'.
13819 \MP\ waits for a response. If the response is null (i.e., if nothing is
13820 typed except perhaps a few blank spaces), the original
13821 line is accepted as it stands; otherwise the line typed is
13822 used instead of the line in the file.
13823
13824 @c void mp_firm_up_the_line (MP mp) {
13825   size_t k; /* an index into |buffer| */
13826   limit=mp->last;
13827   if ( mp->internal[pausing]>0 ) if ( mp->interaction>mp_nonstop_mode ) {
13828     wake_up_terminal; mp_print_ln(mp);
13829     if ( start<limit ) {
13830       for (k=(size_t)start;k<=(size_t)(limit-1);k++) {
13831         mp_print_str(mp, mp->buffer[k]);
13832       } 
13833     }
13834     mp->first=limit; prompt_input("=>"); /* wait for user response */
13835 @.=>@>
13836     if ( mp->last>mp->first ) {
13837       for (k=mp->first;k<=mp->last-1;k++) { /* move line down in buffer */
13838         mp->buffer[k+start-mp->first]=mp->buffer[k];
13839       }
13840       limit=start+mp->last-mp->first;
13841     }
13842   }
13843 }
13844
13845 @* \[30] Dealing with \TeX\ material.
13846 The \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}$\,\ldots\,$\&{etex}
13847 features need to be implemented at a low level in the scanning process
13848 so that \MP\ can stay in synch with the a preprocessor that treats
13849 blocks of \TeX\ material as they occur in the input file without trying
13850 to expand \MP\ macros.  Thus we need a special version of |get_next|
13851 that does not expand macros and such but does handle \&{btex},
13852 \&{verbatimtex}, etc.
13853
13854 The special version of |get_next| is called |get_t_next|.  It works by flushing
13855 \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}\allowbreak
13856 $\,\ldots\,$\&{etex} blocks, switching to the \.{MPX} file when it sees
13857 \&{btex}, and switching back when it sees \&{mpxbreak}.
13858
13859 @d btex_code 0
13860 @d verbatim_code 1
13861
13862 @ @<Put each...@>=
13863 mp_primitive(mp, "btex",start_tex,btex_code);
13864 @:btex_}{\&{btex} primitive@>
13865 mp_primitive(mp, "verbatimtex",start_tex,verbatim_code);
13866 @:verbatimtex_}{\&{verbatimtex} primitive@>
13867 mp_primitive(mp, "etex",etex_marker,0); mp->eqtb[frozen_etex]=mp->eqtb[mp->cur_sym];
13868 @:etex_}{\&{etex} primitive@>
13869 mp_primitive(mp, "mpxbreak",mpx_break,0); mp->eqtb[frozen_mpx_break]=mp->eqtb[mp->cur_sym];
13870 @:mpx_break_}{\&{mpxbreak} primitive@>
13871
13872 @ @<Cases of |print_cmd...@>=
13873 case start_tex: if ( m==btex_code ) mp_print(mp, "btex");
13874   else mp_print(mp, "verbatimtex"); break;
13875 case etex_marker: mp_print(mp, "etex"); break;
13876 case mpx_break: mp_print(mp, "mpxbreak"); break;
13877
13878 @ Actually, |get_t_next| is a macro that avoids procedure overhead except
13879 in the unusual case where \&{btex}, \&{verbatimtex}, \&{etex}, or \&{mpxbreak}
13880 is encountered.
13881
13882 @d get_t_next {mp_get_next(mp); if ( mp->cur_cmd<=max_pre_command ) mp_t_next(mp); }
13883
13884 @<Declarations@>=
13885 void mp_start_mpx_input (MP mp);
13886
13887 @ @c 
13888 void mp_t_next (MP mp) {
13889   int old_status; /* saves the |scanner_status| */
13890   integer old_info; /* saves the |warning_info| */
13891   while ( mp->cur_cmd<=max_pre_command ) {
13892     if ( mp->cur_cmd==mpx_break ) {
13893       if ( ! file_state || (mp->mpx_name[index]==absent) ) {
13894         @<Complain about a misplaced \&{mpxbreak}@>;
13895       } else { 
13896         mp_end_mpx_reading(mp); 
13897         goto TEX_FLUSH;
13898       }
13899     } else if ( mp->cur_cmd==start_tex ) {
13900       if ( token_state || (name<=max_spec_src) ) {
13901         @<Complain that we are not reading a file@>;
13902       } else if ( mpx_reading ) {
13903         @<Complain that \.{MPX} files cannot contain \TeX\ material@>;
13904       } else if ( (mp->cur_mod!=verbatim_code)&&
13905                   (mp->mpx_name[index]!=finished) ) {
13906         if ( ! mp_begin_mpx_reading(mp) ) mp_start_mpx_input(mp);
13907       } else {
13908         goto TEX_FLUSH;
13909       }
13910     } else {
13911        @<Complain about a misplaced \&{etex}@>;
13912     }
13913     goto COMMON_ENDING;
13914   TEX_FLUSH: 
13915     @<Flush the \TeX\ material@>;
13916   COMMON_ENDING: 
13917     mp_get_next(mp);
13918   }
13919 }
13920
13921 @ We could be in the middle of an operation such as skipping false conditional
13922 text when \TeX\ material is encountered, so we must be careful to save the
13923 |scanner_status|.
13924
13925 @<Flush the \TeX\ material@>=
13926 old_status=mp->scanner_status;
13927 old_info=mp->warning_info;
13928 mp->scanner_status=tex_flushing;
13929 mp->warning_info=line;
13930 do {  mp_get_next(mp); } while (mp->cur_cmd!=etex_marker);
13931 mp->scanner_status=old_status;
13932 mp->warning_info=old_info
13933
13934 @ @<Complain that \.{MPX} files cannot contain \TeX\ material@>=
13935 { print_err("An mpx file cannot contain btex or verbatimtex blocks");
13936 help4("This file contains picture expressions for btex...etex")
13937   ("blocks.  Such files are normally generated automatically")
13938   ("but this one seems to be messed up.  I'll just keep going")
13939   ("and hope for the best.");
13940 mp_error(mp);
13941 }
13942
13943 @ @<Complain that we are not reading a file@>=
13944 { print_err("You can only use `btex' or `verbatimtex' in a file");
13945 help3("I'll have to ignore this preprocessor command because it")
13946   ("only works when there is a file to preprocess.  You might")
13947   ("want to delete everything up to the next `etex`.");
13948 mp_error(mp);
13949 }
13950
13951 @ @<Complain about a misplaced \&{mpxbreak}@>=
13952 { print_err("Misplaced mpxbreak");
13953 help2("I'll ignore this preprocessor command because it")
13954   ("doesn't belong here");
13955 mp_error(mp);
13956 }
13957
13958 @ @<Complain about a misplaced \&{etex}@>=
13959 { print_err("Extra etex will be ignored");
13960 help1("There is no btex or verbatimtex for this to match");
13961 mp_error(mp);
13962 }
13963
13964 @* \[31] Scanning macro definitions.
13965 \MP\ has a variety of ways to tuck tokens away into token lists for later
13966 use: Macros can be defined with \&{def}, \&{vardef}, \&{primarydef}, etc.;
13967 repeatable code can be defined with \&{for}, \&{forever}, \&{forsuffixes}.
13968 All such operations are handled by the routines in this part of the program.
13969
13970 The modifier part of each command code is zero for the ``ending delimiters''
13971 like \&{enddef} and \&{endfor}.
13972
13973 @d start_def 1 /* command modifier for \&{def} */
13974 @d var_def 2 /* command modifier for \&{vardef} */
13975 @d end_def 0 /* command modifier for \&{enddef} */
13976 @d start_forever 1 /* command modifier for \&{forever} */
13977 @d end_for 0 /* command modifier for \&{endfor} */
13978
13979 @<Put each...@>=
13980 mp_primitive(mp, "def",macro_def,start_def);
13981 @:def_}{\&{def} primitive@>
13982 mp_primitive(mp, "vardef",macro_def,var_def);
13983 @:var_def_}{\&{vardef} primitive@>
13984 mp_primitive(mp, "primarydef",macro_def,secondary_primary_macro);
13985 @:primary_def_}{\&{primarydef} primitive@>
13986 mp_primitive(mp, "secondarydef",macro_def,tertiary_secondary_macro);
13987 @:secondary_def_}{\&{secondarydef} primitive@>
13988 mp_primitive(mp, "tertiarydef",macro_def,expression_tertiary_macro);
13989 @:tertiary_def_}{\&{tertiarydef} primitive@>
13990 mp_primitive(mp, "enddef",macro_def,end_def); mp->eqtb[frozen_end_def]=mp->eqtb[mp->cur_sym];
13991 @:end_def_}{\&{enddef} primitive@>
13992 @#
13993 mp_primitive(mp, "for",iteration,expr_base);
13994 @:for_}{\&{for} primitive@>
13995 mp_primitive(mp, "forsuffixes",iteration,suffix_base);
13996 @:for_suffixes_}{\&{forsuffixes} primitive@>
13997 mp_primitive(mp, "forever",iteration,start_forever);
13998 @:forever_}{\&{forever} primitive@>
13999 mp_primitive(mp, "endfor",iteration,end_for); mp->eqtb[frozen_end_for]=mp->eqtb[mp->cur_sym];
14000 @:end_for_}{\&{endfor} primitive@>
14001
14002 @ @<Cases of |print_cmd...@>=
14003 case macro_def:
14004   if ( m<=var_def ) {
14005     if ( m==start_def ) mp_print(mp, "def");
14006     else if ( m<start_def ) mp_print(mp, "enddef");
14007     else mp_print(mp, "vardef");
14008   } else if ( m==secondary_primary_macro ) { 
14009     mp_print(mp, "primarydef");
14010   } else if ( m==tertiary_secondary_macro ) { 
14011     mp_print(mp, "secondarydef");
14012   } else { 
14013     mp_print(mp, "tertiarydef");
14014   }
14015   break;
14016 case iteration: 
14017   if ( m<=start_forever ) {
14018     if ( m==start_forever ) mp_print(mp, "forever"); 
14019     else mp_print(mp, "endfor");
14020   } else if ( m==expr_base ) {
14021     mp_print(mp, "for"); 
14022   } else { 
14023     mp_print(mp, "forsuffixes");
14024   }
14025   break;
14026
14027 @ Different macro-absorbing operations have different syntaxes, but they
14028 also have a lot in common. There is a list of special symbols that are to
14029 be replaced by parameter tokens; there is a special command code that
14030 ends the definition; the quotation conventions are identical.  Therefore
14031 it makes sense to have most of the work done by a single subroutine. That
14032 subroutine is called |scan_toks|.
14033
14034 The first parameter to |scan_toks| is the command code that will
14035 terminate scanning (either |macro_def|, |loop_repeat|, or |iteration|).
14036
14037 The second parameter, |subst_list|, points to a (possibly empty) list
14038 of two-word nodes whose |info| and |value| fields specify symbol tokens
14039 before and after replacement. The list will be returned to free storage
14040 by |scan_toks|.
14041
14042 The third parameter is simply appended to the token list that is built.
14043 And the final parameter tells how many of the special operations
14044 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#} are to be replaced by suffix parameters.
14045 When such parameters are present, they are called \.{(SUFFIX0)},
14046 \.{(SUFFIX1)}, and \.{(SUFFIX2)}.
14047
14048 @c pointer mp_scan_toks (MP mp,command_code terminator, pointer 
14049   subst_list, pointer tail_end, small_number suffix_count) {
14050   pointer p; /* tail of the token list being built */
14051   pointer q; /* temporary for link management */
14052   integer balance; /* left delimiters minus right delimiters */
14053   p=hold_head; balance=1; link(hold_head)=null;
14054   while (1) { 
14055     get_t_next;
14056     if ( mp->cur_sym>0 ) {
14057       @<Substitute for |cur_sym|, if it's on the |subst_list|@>;
14058       if ( mp->cur_cmd==terminator ) {
14059         @<Adjust the balance; |break| if it's zero@>;
14060       } else if ( mp->cur_cmd==macro_special ) {
14061         @<Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}@>;
14062       }
14063     }
14064     link(p)=mp_cur_tok(mp); p=link(p);
14065   }
14066   link(p)=tail_end; mp_flush_node_list(mp, subst_list);
14067   return link(hold_head);
14068 }
14069
14070 @ @<Substitute for |cur_sym|...@>=
14071
14072   q=subst_list;
14073   while ( q!=null ) {
14074     if ( info(q)==mp->cur_sym ) {
14075       mp->cur_sym=value(q); mp->cur_cmd=relax; break;
14076     }
14077     q=link(q);
14078   }
14079 }
14080
14081 @ @<Adjust the balance; |break| if it's zero@>=
14082 if ( mp->cur_mod>0 ) {
14083   incr(balance);
14084 } else { 
14085   decr(balance);
14086   if ( balance==0 )
14087     break;
14088 }
14089
14090 @ Four commands are intended to be used only within macro texts: \&{quote},
14091 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#}. They are variants of a single command
14092 code called |macro_special|.
14093
14094 @d quote 0 /* |macro_special| modifier for \&{quote} */
14095 @d macro_prefix 1 /* |macro_special| modifier for \.{\#\AT!} */
14096 @d macro_at 2 /* |macro_special| modifier for \.{\AT!} */
14097 @d macro_suffix 3 /* |macro_special| modifier for \.{\AT!\#} */
14098
14099 @<Put each...@>=
14100 mp_primitive(mp, "quote",macro_special,quote);
14101 @:quote_}{\&{quote} primitive@>
14102 mp_primitive(mp, "#@@",macro_special,macro_prefix);
14103 @:]]]\#\AT!_}{\.{\#\AT!} primitive@>
14104 mp_primitive(mp, "@@",macro_special,macro_at);
14105 @:]]]\AT!_}{\.{\AT!} primitive@>
14106 mp_primitive(mp, "@@#",macro_special,macro_suffix);
14107 @:]]]\AT!\#_}{\.{\AT!\#} primitive@>
14108
14109 @ @<Cases of |print_cmd...@>=
14110 case macro_special: 
14111   switch (m) {
14112   case macro_prefix: mp_print(mp, "#@@"); break;
14113   case macro_at: mp_print_char(mp, '@@'); break;
14114   case macro_suffix: mp_print(mp, "@@#"); break;
14115   default: mp_print(mp, "quote"); break;
14116   }
14117   break;
14118
14119 @ @<Handle quoted...@>=
14120
14121   if ( mp->cur_mod==quote ) { get_t_next; } 
14122   else if ( mp->cur_mod<=suffix_count ) 
14123     mp->cur_sym=suffix_base-1+mp->cur_mod;
14124 }
14125
14126 @ Here is a routine that's used whenever a token will be redefined. If
14127 the user's token is unredefinable, the `|frozen_inaccessible|' token is
14128 substituted; the latter is redefinable but essentially impossible to use,
14129 hence \MP's tables won't get fouled up.
14130
14131 @c void mp_get_symbol (MP mp) { /* sets |cur_sym| to a safe symbol */
14132 RESTART: 
14133   get_t_next;
14134   if ( (mp->cur_sym==0)||(mp->cur_sym>frozen_inaccessible) ) {
14135     print_err("Missing symbolic token inserted");
14136 @.Missing symbolic token...@>
14137     help3("Sorry: You can\'t redefine a number, string, or expr.")
14138       ("I've inserted an inaccessible symbol so that your")
14139       ("definition will be completed without mixing me up too badly.");
14140     if ( mp->cur_sym>0 )
14141       mp->help_line[2]="Sorry: You can\'t redefine my error-recovery tokens.";
14142     else if ( mp->cur_cmd==string_token ) 
14143       delete_str_ref(mp->cur_mod);
14144     mp->cur_sym=frozen_inaccessible; mp_ins_error(mp); goto RESTART;
14145   }
14146 }
14147
14148 @ Before we actually redefine a symbolic token, we need to clear away its
14149 former value, if it was a variable. The following stronger version of
14150 |get_symbol| does that.
14151
14152 @c void mp_get_clear_symbol (MP mp) { 
14153   mp_get_symbol(mp); mp_clear_symbol(mp, mp->cur_sym,false);
14154 }
14155
14156 @ Here's another little subroutine; it checks that an equals sign
14157 or assignment sign comes along at the proper place in a macro definition.
14158
14159 @c void mp_check_equals (MP mp) { 
14160   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
14161      mp_missing_err(mp, "=");
14162 @.Missing `='@>
14163     help5("The next thing in this `def' should have been `=',")
14164       ("because I've already looked at the definition heading.")
14165       ("But don't worry; I'll pretend that an equals sign")
14166       ("was present. Everything from here to `enddef'")
14167       ("will be the replacement text of this macro.");
14168     mp_back_error(mp);
14169   }
14170 }
14171
14172 @ A \&{primarydef}, \&{secondarydef}, or \&{tertiarydef} is rather easily
14173 handled now that we have |scan_toks|.  In this case there are
14174 two parameters, which will be \.{EXPR0} and \.{EXPR1} (i.e.,
14175 |expr_base| and |expr_base+1|).
14176
14177 @c void mp_make_op_def (MP mp) {
14178   command_code m; /* the type of definition */
14179   pointer p,q,r; /* for list manipulation */
14180   m=mp->cur_mod;
14181   mp_get_symbol(mp); q=mp_get_node(mp, token_node_size);
14182   info(q)=mp->cur_sym; value(q)=expr_base;
14183   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym;
14184   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
14185   info(p)=mp->cur_sym; value(p)=expr_base+1; link(p)=q;
14186   get_t_next; mp_check_equals(mp);
14187   mp->scanner_status=op_defining; q=mp_get_avail(mp); ref_count(q)=null;
14188   r=mp_get_avail(mp); link(q)=r; info(r)=general_macro;
14189   link(r)=mp_scan_toks(mp, macro_def,p,null,0);
14190   mp->scanner_status=normal; eq_type(mp->warning_info)=m;
14191   equiv(mp->warning_info)=q; mp_get_x_next(mp);
14192 }
14193
14194 @ Parameters to macros are introduced by the keywords \&{expr},
14195 \&{suffix}, \&{text}, \&{primary}, \&{secondary}, and \&{tertiary}.
14196
14197 @<Put each...@>=
14198 mp_primitive(mp, "expr",param_type,expr_base);
14199 @:expr_}{\&{expr} primitive@>
14200 mp_primitive(mp, "suffix",param_type,suffix_base);
14201 @:suffix_}{\&{suffix} primitive@>
14202 mp_primitive(mp, "text",param_type,text_base);
14203 @:text_}{\&{text} primitive@>
14204 mp_primitive(mp, "primary",param_type,primary_macro);
14205 @:primary_}{\&{primary} primitive@>
14206 mp_primitive(mp, "secondary",param_type,secondary_macro);
14207 @:secondary_}{\&{secondary} primitive@>
14208 mp_primitive(mp, "tertiary",param_type,tertiary_macro);
14209 @:tertiary_}{\&{tertiary} primitive@>
14210
14211 @ @<Cases of |print_cmd...@>=
14212 case param_type:
14213   if ( m>=expr_base ) {
14214     if ( m==expr_base ) mp_print(mp, "expr");
14215     else if ( m==suffix_base ) mp_print(mp, "suffix");
14216     else mp_print(mp, "text");
14217   } else if ( m<secondary_macro ) {
14218     mp_print(mp, "primary");
14219   } else if ( m==secondary_macro ) {
14220     mp_print(mp, "secondary");
14221   } else {
14222     mp_print(mp, "tertiary");
14223   }
14224   break;
14225
14226 @ Let's turn next to the more complex processing associated with \&{def}
14227 and \&{vardef}. When the following procedure is called, |cur_mod|
14228 should be either |start_def| or |var_def|.
14229
14230 @c @<Declare the procedure called |check_delimiter|@>;
14231 @<Declare the function called |scan_declared_variable|@>;
14232 void mp_scan_def (MP mp) {
14233   int m; /* the type of definition */
14234   int n; /* the number of special suffix parameters */
14235   int k; /* the total number of parameters */
14236   int c; /* the kind of macro we're defining */
14237   pointer r; /* parameter-substitution list */
14238   pointer q; /* tail of the macro token list */
14239   pointer p; /* temporary storage */
14240   halfword base; /* |expr_base|, |suffix_base|, or |text_base| */
14241   pointer l_delim,r_delim; /* matching delimiters */
14242   m=mp->cur_mod; c=general_macro; link(hold_head)=null;
14243   q=mp_get_avail(mp); ref_count(q)=null; r=null;
14244   @<Scan the token or variable to be defined;
14245     set |n|, |scanner_status|, and |warning_info|@>;
14246   k=n;
14247   if ( mp->cur_cmd==left_delimiter ) {
14248     @<Absorb delimited parameters, putting them into lists |q| and |r|@>;
14249   }
14250   if ( mp->cur_cmd==param_type ) {
14251     @<Absorb undelimited parameters, putting them into list |r|@>;
14252   }
14253   mp_check_equals(mp);
14254   p=mp_get_avail(mp); info(p)=c; link(q)=p;
14255   @<Attach the replacement text to the tail of node |p|@>;
14256   mp->scanner_status=normal; mp_get_x_next(mp);
14257 }
14258
14259 @ We don't put `|frozen_end_group|' into the replacement text of
14260 a \&{vardef}, because the user may want to redefine `\.{endgroup}'.
14261
14262 @<Attach the replacement text to the tail of node |p|@>=
14263 if ( m==start_def ) {
14264   link(p)=mp_scan_toks(mp, macro_def,r,null,n);
14265 } else { 
14266   q=mp_get_avail(mp); info(q)=mp->bg_loc; link(p)=q;
14267   p=mp_get_avail(mp); info(p)=mp->eg_loc;
14268   link(q)=mp_scan_toks(mp, macro_def,r,p,n);
14269 }
14270 if ( mp->warning_info==bad_vardef ) 
14271   mp_flush_token_list(mp, value(bad_vardef))
14272
14273 @ @<Glob...@>=
14274 int bg_loc;
14275 int eg_loc; /* hash addresses of `\.{begingroup}' and `\.{endgroup}' */
14276
14277 @ @<Scan the token or variable to be defined;...@>=
14278 if ( m==start_def ) {
14279   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym; get_t_next;
14280   mp->scanner_status=op_defining; n=0;
14281   eq_type(mp->warning_info)=defined_macro; equiv(mp->warning_info)=q;
14282 } else { 
14283   p=mp_scan_declared_variable(mp);
14284   mp_flush_variable(mp, equiv(info(p)),link(p),true);
14285   mp->warning_info=mp_find_variable(mp, p); mp_flush_list(mp, p);
14286   if ( mp->warning_info==null ) @<Change to `\.{a bad variable}'@>;
14287   mp->scanner_status=var_defining; n=2;
14288   if ( mp->cur_cmd==macro_special ) if ( mp->cur_mod==macro_suffix ) {/* \.{\AT!\#} */
14289     n=3; get_t_next;
14290   }
14291   type(mp->warning_info)=mp_unsuffixed_macro-2+n; value(mp->warning_info)=q;
14292 } /* |mp_suffixed_macro=mp_unsuffixed_macro+1| */
14293
14294 @ @<Change to `\.{a bad variable}'@>=
14295
14296   print_err("This variable already starts with a macro");
14297 @.This variable already...@>
14298   help2("After `vardef a' you can\'t say `vardef a.b'.")
14299     ("So I'll have to discard this definition.");
14300   mp_error(mp); mp->warning_info=bad_vardef;
14301 }
14302
14303 @ @<Initialize table entries...@>=
14304 name_type(bad_vardef)=mp_root; link(bad_vardef)=frozen_bad_vardef;
14305 equiv(frozen_bad_vardef)=bad_vardef; eq_type(frozen_bad_vardef)=tag_token;
14306
14307 @ @<Absorb delimited parameters, putting them into lists |q| and |r|@>=
14308 do {  
14309   l_delim=mp->cur_sym; r_delim=mp->cur_mod; get_t_next;
14310   if ( (mp->cur_cmd==param_type)&&(mp->cur_mod>=expr_base) ) {
14311    base=mp->cur_mod;
14312   } else { 
14313     print_err("Missing parameter type; `expr' will be assumed");
14314 @.Missing parameter type@>
14315     help1("You should've had `expr' or `suffix' or `text' here.");
14316     mp_back_error(mp); base=expr_base;
14317   }
14318   @<Absorb parameter tokens for type |base|@>;
14319   mp_check_delimiter(mp, l_delim,r_delim);
14320   get_t_next;
14321 } while (mp->cur_cmd==left_delimiter)
14322
14323 @ @<Absorb parameter tokens for type |base|@>=
14324 do { 
14325   link(q)=mp_get_avail(mp); q=link(q); info(q)=base+k;
14326   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size); 
14327   value(p)=base+k; info(p)=mp->cur_sym;
14328   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14329 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14330   incr(k); link(p)=r; r=p; get_t_next;
14331 } while (mp->cur_cmd==comma)
14332
14333 @ @<Absorb undelimited parameters, putting them into list |r|@>=
14334
14335   p=mp_get_node(mp, token_node_size);
14336   if ( mp->cur_mod<expr_base ) {
14337     c=mp->cur_mod; value(p)=expr_base+k;
14338   } else { 
14339     value(p)=mp->cur_mod+k;
14340     if ( mp->cur_mod==expr_base ) c=expr_macro;
14341     else if ( mp->cur_mod==suffix_base ) c=suffix_macro;
14342     else c=text_macro;
14343   }
14344   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14345   incr(k); mp_get_symbol(mp); info(p)=mp->cur_sym; link(p)=r; r=p; get_t_next;
14346   if ( c==expr_macro ) if ( mp->cur_cmd==of_token ) {
14347     c=of_macro; p=mp_get_node(mp, token_node_size);
14348     if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14349     value(p)=expr_base+k; mp_get_symbol(mp); info(p)=mp->cur_sym;
14350     link(p)=r; r=p; get_t_next;
14351   }
14352 }
14353
14354 @* \[32] Expanding the next token.
14355 Only a few command codes |<min_command| can possibly be returned by
14356 |get_t_next|; in increasing order, they are
14357 |if_test|, |fi_or_else|, |input|, |iteration|, |repeat_loop|,
14358 |exit_test|, |relax|, |scan_tokens|, |expand_after|, and |defined_macro|.
14359
14360 \MP\ usually gets the next token of input by saying |get_x_next|. This is
14361 like |get_t_next| except that it keeps getting more tokens until
14362 finding |cur_cmd>=min_command|. In other words, |get_x_next| expands
14363 macros and removes conditionals or iterations or input instructions that
14364 might be present.
14365
14366 It follows that |get_x_next| might invoke itself recursively. In fact,
14367 there is massive recursion, since macro expansion can involve the
14368 scanning of arbitrarily complex expressions, which in turn involve
14369 macro expansion and conditionals, etc.
14370 @^recursion@>
14371
14372 Therefore it's necessary to declare a whole bunch of |forward|
14373 procedures at this point, and to insert some other procedures
14374 that will be invoked by |get_x_next|.
14375
14376 @<Declarations@>= 
14377 void mp_scan_primary (MP mp);
14378 void mp_scan_secondary (MP mp);
14379 void mp_scan_tertiary (MP mp);
14380 void mp_scan_expression (MP mp);
14381 void mp_scan_suffix (MP mp);
14382 @<Declare the procedure called |macro_call|@>;
14383 void mp_get_boolean (MP mp);
14384 void mp_pass_text (MP mp);
14385 void mp_conditional (MP mp);
14386 void mp_start_input (MP mp);
14387 void mp_begin_iteration (MP mp);
14388 void mp_resume_iteration (MP mp);
14389 void mp_stop_iteration (MP mp);
14390
14391 @ An auxiliary subroutine called |expand| is used by |get_x_next|
14392 when it has to do exotic expansion commands.
14393
14394 @c void mp_expand (MP mp) {
14395   pointer p; /* for list manipulation */
14396   size_t k; /* something that we hope is |<=buf_size| */
14397   pool_pointer j; /* index into |str_pool| */
14398   if ( mp->internal[tracing_commands]>unity ) 
14399     if ( mp->cur_cmd!=defined_macro )
14400       show_cur_cmd_mod;
14401   switch (mp->cur_cmd)  {
14402   case if_test:
14403     mp_conditional(mp); /* this procedure is discussed in Part 36 below */
14404     break;
14405   case fi_or_else:
14406     @<Terminate the current conditional and skip to \&{fi}@>;
14407     break;
14408   case input:
14409     @<Initiate or terminate input from a file@>;
14410     break;
14411   case iteration:
14412     if ( mp->cur_mod==end_for ) {
14413       @<Scold the user for having an extra \&{endfor}@>;
14414     } else {
14415       mp_begin_iteration(mp); /* this procedure is discussed in Part 37 below */
14416     }
14417     break;
14418   case repeat_loop: 
14419     @<Repeat a loop@>;
14420     break;
14421   case exit_test: 
14422     @<Exit a loop if the proper time has come@>;
14423     break;
14424   case relax: 
14425     break;
14426   case expand_after: 
14427     @<Expand the token after the next token@>;
14428     break;
14429   case scan_tokens: 
14430     @<Put a string into the input buffer@>;
14431     break;
14432   case defined_macro:
14433    mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14434    break;
14435   }; /* there are no other cases */
14436 };
14437
14438 @ @<Scold the user...@>=
14439
14440   print_err("Extra `endfor'");
14441 @.Extra `endfor'@>
14442   help2("I'm not currently working on a for loop,")
14443     ("so I had better not try to end anything.");
14444   mp_error(mp);
14445 }
14446
14447 @ The processing of \&{input} involves the |start_input| subroutine,
14448 which will be declared later; the processing of \&{endinput} is trivial.
14449
14450 @<Put each...@>=
14451 mp_primitive(mp, "input",input,0);
14452 @:input_}{\&{input} primitive@>
14453 mp_primitive(mp, "endinput",input,1);
14454 @:end_input_}{\&{endinput} primitive@>
14455
14456 @ @<Cases of |print_cmd_mod|...@>=
14457 case input: 
14458   if ( m==0 ) mp_print(mp, "input");
14459   else mp_print(mp, "endinput");
14460   break;
14461
14462 @ @<Initiate or terminate input...@>=
14463 if ( mp->cur_mod>0 ) mp->force_eof=true;
14464 else mp_start_input(mp)
14465
14466 @ We'll discuss the complicated parts of loop operations later. For now
14467 it suffices to know that there's a global variable called |loop_ptr|
14468 that will be |null| if no loop is in progress.
14469
14470 @<Repeat a loop@>=
14471 { while ( token_state &&(loc==null) ) 
14472     mp_end_token_list(mp); /* conserve stack space */
14473   if ( mp->loop_ptr==null ) {
14474     print_err("Lost loop");
14475 @.Lost loop@>
14476     help2("I'm confused; after exiting from a loop, I still seem")
14477       ("to want to repeat it. I'll try to forget the problem.");
14478     mp_error(mp);
14479   } else {
14480     mp_resume_iteration(mp); /* this procedure is in Part 37 below */
14481   }
14482 }
14483
14484 @ @<Exit a loop if the proper time has come@>=
14485 { mp_get_boolean(mp);
14486   if ( mp->internal[tracing_commands]>unity ) 
14487     mp_show_cmd_mod(mp, nullary,mp->cur_exp);
14488   if ( mp->cur_exp==true_code ) {
14489     if ( mp->loop_ptr==null ) {
14490       print_err("No loop is in progress");
14491 @.No loop is in progress@>
14492       help1("Why say `exitif' when there's nothing to exit from?");
14493       if ( mp->cur_cmd==semicolon ) mp_error(mp); else mp_back_error(mp);
14494     } else {
14495      @<Exit prematurely from an iteration@>;
14496     }
14497   } else if ( mp->cur_cmd!=semicolon ) {
14498     mp_missing_err(mp, ";");
14499 @.Missing `;'@>
14500     help2("After `exitif <boolean exp>' I expect to see a semicolon.")
14501     ("I shall pretend that one was there."); mp_back_error(mp);
14502   }
14503 }
14504
14505 @ Here we use the fact that |forever_text| is the only |token_type| that
14506 is less than |loop_text|.
14507
14508 @<Exit prematurely...@>=
14509 { p=null;
14510   do {  
14511     if ( file_state ) {
14512       mp_end_file_reading(mp);
14513     } else { 
14514       if ( token_type<=loop_text ) p=start;
14515       mp_end_token_list(mp);
14516     }
14517   } while (p==null);
14518   if ( p!=info(mp->loop_ptr) ) mp_fatal_error(mp, "*** (loop confusion)");
14519 @.loop confusion@>
14520   mp_stop_iteration(mp); /* this procedure is in Part 34 below */
14521 }
14522
14523 @ @<Expand the token after the next token@>=
14524 { get_t_next;
14525   p=mp_cur_tok(mp); get_t_next;
14526   if ( mp->cur_cmd<min_command ) mp_expand(mp); 
14527   else mp_back_input(mp);
14528   back_list(p);
14529 }
14530
14531 @ @<Put a string into the input buffer@>=
14532 { mp_get_x_next(mp); mp_scan_primary(mp);
14533   if ( mp->cur_type!=mp_string_type ) {
14534     mp_disp_err(mp, null,"Not a string");
14535 @.Not a string@>
14536     help2("I'm going to flush this expression, since")
14537        ("scantokens should be followed by a known string.");
14538     mp_put_get_flush_error(mp, 0);
14539   } else { 
14540     mp_back_input(mp);
14541     if ( length(mp->cur_exp)>0 )
14542        @<Pretend we're reading a new one-line file@>;
14543   }
14544 }
14545
14546 @ @<Pretend we're reading a new one-line file@>=
14547 { mp_begin_file_reading(mp); name=is_scantok;
14548   k=mp->first+length(mp->cur_exp);
14549   if ( k>=mp->max_buf_stack ) {
14550     while ( k>=mp->buf_size ) {
14551       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
14552     }
14553     mp->max_buf_stack=k+1;
14554   }
14555   j=mp->str_start[mp->cur_exp]; limit=k;
14556   while ( mp->first<(size_t)limit ) {
14557     mp->buffer[mp->first]=mp->str_pool[j]; incr(j); incr(mp->first);
14558   }
14559   mp->buffer[limit]='%'; mp->first=limit+1; loc=start; 
14560   mp_flush_cur_exp(mp, 0);
14561 }
14562
14563 @ Here finally is |get_x_next|.
14564
14565 The expression scanning routines to be considered later
14566 communicate via the global quantities |cur_type| and |cur_exp|;
14567 we must be very careful to save and restore these quantities while
14568 macros are being expanded.
14569 @^inner loop@>
14570
14571 @<Declarations@>=
14572 void mp_get_x_next (MP mp);
14573
14574 @ @c void mp_get_x_next (MP mp) {
14575   pointer save_exp; /* a capsule to save |cur_type| and |cur_exp| */
14576   get_t_next;
14577   if ( mp->cur_cmd<min_command ) {
14578     save_exp=mp_stash_cur_exp(mp);
14579     do {  
14580       if ( mp->cur_cmd==defined_macro ) 
14581         mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14582       else 
14583         mp_expand(mp);
14584       get_t_next;
14585      } while (mp->cur_cmd<min_command);
14586      mp_unstash_cur_exp(mp, save_exp); /* that restores |cur_type| and |cur_exp| */
14587   }
14588 }
14589
14590 @ Now let's consider the |macro_call| procedure, which is used to start up
14591 all user-defined macros. Since the arguments to a macro might be expressions,
14592 |macro_call| is recursive.
14593 @^recursion@>
14594
14595 The first parameter to |macro_call| points to the reference count of the
14596 token list that defines the macro. The second parameter contains any
14597 arguments that have already been parsed (see below).  The third parameter
14598 points to the symbolic token that names the macro. If the third parameter
14599 is |null|, the macro was defined by \&{vardef}, so its name can be
14600 reconstructed from the prefix and ``at'' arguments found within the
14601 second parameter.
14602
14603 What is this second parameter? It's simply a linked list of one-word items,
14604 whose |info| fields point to the arguments. In other words, if |arg_list=null|,
14605 no arguments have been scanned yet; otherwise |info(arg_list)| points to
14606 the first scanned argument, and |link(arg_list)| points to the list of
14607 further arguments (if any).
14608
14609 Arguments of type \&{expr} are so-called capsules, which we will
14610 discuss later when we concentrate on expressions; they can be
14611 recognized easily because their |link| field is |void|. Arguments of type
14612 \&{suffix} and \&{text} are token lists without reference counts.
14613
14614 @ After argument scanning is complete, the arguments are moved to the
14615 |param_stack|. (They can't be put on that stack any sooner, because
14616 the stack is growing and shrinking in unpredictable ways as more arguments
14617 are being acquired.)  Then the macro body is fed to the scanner; i.e.,
14618 the replacement text of the macro is placed at the top of the \MP's
14619 input stack, so that |get_t_next| will proceed to read it next.
14620
14621 @<Declare the procedure called |macro_call|@>=
14622 @<Declare the procedure called |print_macro_name|@>;
14623 @<Declare the procedure called |print_arg|@>;
14624 @<Declare the procedure called |scan_text_arg|@>;
14625 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14626                     pointer macro_name) ;
14627
14628 @ @c
14629 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14630                     pointer macro_name) {
14631   /* invokes a user-defined control sequence */
14632   pointer r; /* current node in the macro's token list */
14633   pointer p,q; /* for list manipulation */
14634   integer n; /* the number of arguments */
14635   pointer tail = 0; /* tail of the argument list */
14636   pointer l_delim=0,r_delim=0; /* a delimiter pair */
14637   r=link(def_ref); add_mac_ref(def_ref);
14638   if ( arg_list==null ) {
14639     n=0;
14640   } else {
14641    @<Determine the number |n| of arguments already supplied,
14642     and set |tail| to the tail of |arg_list|@>;
14643   }
14644   if ( mp->internal[tracing_macros]>0 ) {
14645     @<Show the text of the macro being expanded, and the existing arguments@>;
14646   }
14647   @<Scan the remaining arguments, if any; set |r| to the first token
14648     of the replacement text@>;
14649   @<Feed the arguments and replacement text to the scanner@>;
14650 }
14651
14652 @ @<Show the text of the macro...@>=
14653 mp_begin_diagnostic(mp); mp_print_ln(mp); 
14654 mp_print_macro_name(mp, arg_list,macro_name);
14655 if ( n==3 ) mp_print(mp, "@@#"); /* indicate a suffixed macro */
14656 mp_show_macro(mp, def_ref,null,100000);
14657 if ( arg_list!=null ) {
14658   n=0; p=arg_list;
14659   do {  
14660     q=info(p);
14661     mp_print_arg(mp, q,n,0);
14662     incr(n); p=link(p);
14663   } while (p!=null);
14664 }
14665 mp_end_diagnostic(mp, false)
14666
14667
14668 @ @<Declare the procedure called |print_macro_name|@>=
14669 void mp_print_macro_name (MP mp,pointer a, pointer n);
14670
14671 @ @c
14672 void mp_print_macro_name (MP mp,pointer a, pointer n) {
14673   pointer p,q; /* they traverse the first part of |a| */
14674   if ( n!=null ) {
14675     mp_print_text(n);
14676   } else  { 
14677     p=info(a);
14678     if ( p==null ) {
14679       mp_print_text(info(info(link(a))));
14680     } else { 
14681       q=p;
14682       while ( link(q)!=null ) q=link(q);
14683       link(q)=info(link(a));
14684       mp_show_token_list(mp, p,null,1000,0);
14685       link(q)=null;
14686     }
14687   }
14688 }
14689
14690 @ @<Declare the procedure called |print_arg|@>=
14691 void mp_print_arg (MP mp,pointer q, integer n, pointer b) ;
14692
14693 @ @c
14694 void mp_print_arg (MP mp,pointer q, integer n, pointer b) {
14695   if ( link(q)==diov ) mp_print_nl(mp, "(EXPR");
14696   else if ( (b<text_base)&&(b!=text_macro) ) mp_print_nl(mp, "(SUFFIX");
14697   else mp_print_nl(mp, "(TEXT");
14698   mp_print_int(mp, n); mp_print(mp, ")<-");
14699   if ( link(q)==diov ) mp_print_exp(mp, q,1);
14700   else mp_show_token_list(mp, q,null,1000,0);
14701 }
14702
14703 @ @<Determine the number |n| of arguments already supplied...@>=
14704 {  
14705   n=1; tail=arg_list;
14706   while ( link(tail)!=null ) { 
14707     incr(n); tail=link(tail);
14708   }
14709 }
14710
14711 @ @<Scan the remaining arguments, if any; set |r|...@>=
14712 mp->cur_cmd=comma+1; /* anything |<>comma| will do */
14713 while ( info(r)>=expr_base ) { 
14714   @<Scan the delimited argument represented by |info(r)|@>;
14715   r=link(r);
14716 };
14717 if ( mp->cur_cmd==comma ) {
14718   print_err("Too many arguments to ");
14719 @.Too many arguments...@>
14720   mp_print_macro_name(mp, arg_list,macro_name); mp_print_char(mp, ';');
14721   mp_print_nl(mp, "  Missing `"); mp_print_text(r_delim);
14722 @.Missing `)'...@>
14723   mp_print(mp, "' has been inserted");
14724   help3("I'm going to assume that the comma I just read was a")
14725    ("right delimiter, and then I'll begin expanding the macro.")
14726    ("You might want to delete some tokens before continuing.");
14727   mp_error(mp);
14728 }
14729 if ( info(r)!=general_macro ) {
14730   @<Scan undelimited argument(s)@>;
14731 }
14732 r=link(r)
14733
14734 @ At this point, the reader will find it advisable to review the explanation
14735 of token list format that was presented earlier, paying special attention to
14736 the conventions that apply only at the beginning of a macro's token list.
14737
14738 On the other hand, the reader will have to take the expression-parsing
14739 aspects of the following program on faith; we will explain |cur_type|
14740 and |cur_exp| later. (Several things in this program depend on each other,
14741 and it's necessary to jump into the circle somewhere.)
14742
14743 @<Scan the delimited argument represented by |info(r)|@>=
14744 if ( mp->cur_cmd!=comma ) {
14745   mp_get_x_next(mp);
14746   if ( mp->cur_cmd!=left_delimiter ) {
14747     print_err("Missing argument to ");
14748 @.Missing argument...@>
14749     mp_print_macro_name(mp, arg_list,macro_name);
14750     help3("That macro has more parameters than you thought.")
14751      ("I'll continue by pretending that each missing argument")
14752      ("is either zero or null.");
14753     if ( info(r)>=suffix_base ) {
14754       mp->cur_exp=null; mp->cur_type=mp_token_list;
14755     } else { 
14756       mp->cur_exp=0; mp->cur_type=mp_known;
14757     }
14758     mp_back_error(mp); mp->cur_cmd=right_delimiter; 
14759     goto FOUND;
14760   }
14761   l_delim=mp->cur_sym; r_delim=mp->cur_mod;
14762 }
14763 @<Scan the argument represented by |info(r)|@>;
14764 if ( mp->cur_cmd!=comma ) 
14765   @<Check that the proper right delimiter was present@>;
14766 FOUND:  
14767 @<Append the current expression to |arg_list|@>
14768
14769 @ @<Check that the proper right delim...@>=
14770 if ( (mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
14771   if ( info(link(r))>=expr_base ) {
14772     mp_missing_err(mp, ",");
14773 @.Missing `,'@>
14774     help3("I've finished reading a macro argument and am about to")
14775       ("read another; the arguments weren't delimited correctly.")
14776        ("You might want to delete some tokens before continuing.");
14777     mp_back_error(mp); mp->cur_cmd=comma;
14778   } else { 
14779     mp_missing_err(mp, str(text(r_delim)));
14780 @.Missing `)'@>
14781     help2("I've gotten to the end of the macro parameter list.")
14782        ("You might want to delete some tokens before continuing.");
14783     mp_back_error(mp);
14784   }
14785 }
14786
14787 @ A \&{suffix} or \&{text} parameter will be have been scanned as
14788 a token list pointed to by |cur_exp|, in which case we will have
14789 |cur_type=token_list|.
14790
14791 @<Append the current expression to |arg_list|@>=
14792
14793   p=mp_get_avail(mp);
14794   if ( mp->cur_type==mp_token_list ) info(p)=mp->cur_exp;
14795   else info(p)=mp_stash_cur_exp(mp);
14796   if ( mp->internal[tracing_macros]>0 ) {
14797     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,info(r)); 
14798     mp_end_diagnostic(mp, false);
14799   }
14800   if ( arg_list==null ) arg_list=p;
14801   else link(tail)=p;
14802   tail=p; incr(n);
14803 }
14804
14805 @ @<Scan the argument represented by |info(r)|@>=
14806 if ( info(r)>=text_base ) {
14807   mp_scan_text_arg(mp, l_delim,r_delim);
14808 } else { 
14809   mp_get_x_next(mp);
14810   if ( info(r)>=suffix_base ) mp_scan_suffix(mp);
14811   else mp_scan_expression(mp);
14812 }
14813
14814 @ The parameters to |scan_text_arg| are either a pair of delimiters
14815 or zero; the latter case is for undelimited text arguments, which
14816 end with the first semicolon or \&{endgroup} or \&{end} that is not
14817 contained in a group.
14818
14819 @<Declare the procedure called |scan_text_arg|@>=
14820 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) ;
14821
14822 @ @c
14823 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) {
14824   integer balance; /* excess of |l_delim| over |r_delim| */
14825   pointer p; /* list tail */
14826   mp->warning_info=l_delim; mp->scanner_status=absorbing;
14827   p=hold_head; balance=1; link(hold_head)=null;
14828   while (1)  { 
14829     get_t_next;
14830     if ( l_delim==0 ) {
14831       @<Adjust the balance for an undelimited argument; |break| if done@>;
14832     } else {
14833           @<Adjust the balance for a delimited argument; |break| if done@>;
14834     }
14835     link(p)=mp_cur_tok(mp); p=link(p);
14836   }
14837   mp->cur_exp=link(hold_head); mp->cur_type=mp_token_list;
14838   mp->scanner_status=normal;
14839 };
14840
14841 @ @<Adjust the balance for a delimited argument...@>=
14842 if ( mp->cur_cmd==right_delimiter ) { 
14843   if ( mp->cur_mod==l_delim ) { 
14844     decr(balance);
14845     if ( balance==0 ) break;
14846   }
14847 } else if ( mp->cur_cmd==left_delimiter ) {
14848   if ( mp->cur_mod==r_delim ) incr(balance);
14849 }
14850
14851 @ @<Adjust the balance for an undelimited...@>=
14852 if ( end_of_statement ) { /* |cur_cmd=semicolon|, |end_group|, or |stop| */
14853   if ( balance==1 ) { break; }
14854   else  { if ( mp->cur_cmd==end_group ) decr(balance); }
14855 } else if ( mp->cur_cmd==begin_group ) { 
14856   incr(balance); 
14857 }
14858
14859 @ @<Scan undelimited argument(s)@>=
14860
14861   if ( info(r)<text_macro ) {
14862     mp_get_x_next(mp);
14863     if ( info(r)!=suffix_macro ) {
14864       if ( (mp->cur_cmd==equals)||(mp->cur_cmd==assignment) ) mp_get_x_next(mp);
14865     }
14866   }
14867   switch (info(r)) {
14868   case primary_macro:mp_scan_primary(mp); break;
14869   case secondary_macro:mp_scan_secondary(mp); break;
14870   case tertiary_macro:mp_scan_tertiary(mp); break;
14871   case expr_macro:mp_scan_expression(mp); break;
14872   case of_macro:
14873     @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>;
14874     break;
14875   case suffix_macro:
14876     @<Scan a suffix with optional delimiters@>;
14877     break;
14878   case text_macro:mp_scan_text_arg(mp, 0,0); break;
14879   } /* there are no other cases */
14880   mp_back_input(mp); 
14881   @<Append the current expression to |arg_list|@>;
14882 }
14883
14884 @ @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>=
14885
14886   mp_scan_expression(mp); p=mp_get_avail(mp); info(p)=mp_stash_cur_exp(mp);
14887   if ( mp->internal[tracing_macros]>0 ) { 
14888     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,0); 
14889     mp_end_diagnostic(mp, false);
14890   }
14891   if ( arg_list==null ) arg_list=p; else link(tail)=p;
14892   tail=p;incr(n);
14893   if ( mp->cur_cmd!=of_token ) {
14894     mp_missing_err(mp, "of"); mp_print(mp, " for ");
14895 @.Missing `of'@>
14896     mp_print_macro_name(mp, arg_list,macro_name);
14897     help1("I've got the first argument; will look now for the other.");
14898     mp_back_error(mp);
14899   }
14900   mp_get_x_next(mp); mp_scan_primary(mp);
14901 }
14902
14903 @ @<Scan a suffix with optional delimiters@>=
14904
14905   if ( mp->cur_cmd!=left_delimiter ) {
14906     l_delim=null;
14907   } else { 
14908     l_delim=mp->cur_sym; r_delim=mp->cur_mod; mp_get_x_next(mp);
14909   };
14910   mp_scan_suffix(mp);
14911   if ( l_delim!=null ) {
14912     if ((mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
14913       mp_missing_err(mp, str(text(r_delim)));
14914 @.Missing `)'@>
14915       help2("I've gotten to the end of the macro parameter list.")
14916          ("You might want to delete some tokens before continuing.");
14917       mp_back_error(mp);
14918     }
14919     mp_get_x_next(mp);
14920   }
14921 }
14922
14923 @ Before we put a new token list on the input stack, it is wise to clean off
14924 all token lists that have recently been depleted. Then a user macro that ends
14925 with a call to itself will not require unbounded stack space.
14926
14927 @<Feed the arguments and replacement text to the scanner@>=
14928 while ( token_state &&(loc==null) ) mp_end_token_list(mp); /* conserve stack space */
14929 if ( mp->param_ptr+n>mp->max_param_stack ) {
14930   mp->max_param_stack=mp->param_ptr+n;
14931   if ( mp->max_param_stack>mp->param_size )
14932     mp_overflow(mp, "parameter stack size",mp->param_size);
14933 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14934 }
14935 mp_begin_token_list(mp, def_ref,macro); name=macro_name; loc=r;
14936 if ( n>0 ) {
14937   p=arg_list;
14938   do {  
14939    mp->param_stack[mp->param_ptr]=info(p); incr(mp->param_ptr); p=link(p);
14940   } while (p!=null);
14941   mp_flush_list(mp, arg_list);
14942 }
14943
14944 @ It's sometimes necessary to put a single argument onto |param_stack|.
14945 The |stack_argument| subroutine does this.
14946
14947 @c void mp_stack_argument (MP mp,pointer p) { 
14948   if ( mp->param_ptr==mp->max_param_stack ) {
14949     incr(mp->max_param_stack);
14950     if ( mp->max_param_stack>mp->param_size )
14951       mp_overflow(mp, "parameter stack size",mp->param_size);
14952 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14953   }
14954   mp->param_stack[mp->param_ptr]=p; incr(mp->param_ptr);
14955 }
14956
14957 @* \[33] Conditional processing.
14958 Let's consider now the way \&{if} commands are handled.
14959
14960 Conditions can be inside conditions, and this nesting has a stack
14961 that is independent of other stacks.
14962 Four global variables represent the top of the condition stack:
14963 |cond_ptr| points to pushed-down entries, if~any; |cur_if| tells whether
14964 we are processing \&{if} or \&{elseif}; |if_limit| specifies
14965 the largest code of a |fi_or_else| command that is syntactically legal;
14966 and |if_line| is the line number at which the current conditional began.
14967
14968 If no conditions are currently in progress, the condition stack has the
14969 special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
14970 Otherwise |cond_ptr| points to a two-word node; the |type|, |name_type|, and
14971 |link| fields of the first word contain |if_limit|, |cur_if|, and
14972 |cond_ptr| at the next level, and the second word contains the
14973 corresponding |if_line|.
14974
14975 @d if_node_size 2 /* number of words in stack entry for conditionals */
14976 @d if_line_field(A) mp->mem[(A)+1].cint
14977 @d if_code 1 /* code for \&{if} being evaluated */
14978 @d fi_code 2 /* code for \&{fi} */
14979 @d else_code 3 /* code for \&{else} */
14980 @d else_if_code 4 /* code for \&{elseif} */
14981
14982 @<Glob...@>=
14983 pointer cond_ptr; /* top of the condition stack */
14984 integer if_limit; /* upper bound on |fi_or_else| codes */
14985 small_number cur_if; /* type of conditional being worked on */
14986 integer if_line; /* line where that conditional began */
14987
14988 @ @<Set init...@>=
14989 mp->cond_ptr=null; mp->if_limit=normal; mp->cur_if=0; mp->if_line=0;
14990
14991 @ @<Put each...@>=
14992 mp_primitive(mp, "if",if_test,if_code);
14993 @:if_}{\&{if} primitive@>
14994 mp_primitive(mp, "fi",fi_or_else,fi_code); mp->eqtb[frozen_fi]=mp->eqtb[mp->cur_sym];
14995 @:fi_}{\&{fi} primitive@>
14996 mp_primitive(mp, "else",fi_or_else,else_code);
14997 @:else_}{\&{else} primitive@>
14998 mp_primitive(mp, "elseif",fi_or_else,else_if_code);
14999 @:else_if_}{\&{elseif} primitive@>
15000
15001 @ @<Cases of |print_cmd_mod|...@>=
15002 case if_test:
15003 case fi_or_else: 
15004   switch (m) {
15005   case if_code:mp_print(mp, "if"); break;
15006   case fi_code:mp_print(mp, "fi");  break;
15007   case else_code:mp_print(mp, "else"); break;
15008   default: mp_print(mp, "elseif"); break;
15009   }
15010   break;
15011
15012 @ Here is a procedure that ignores text until coming to an \&{elseif},
15013 \&{else}, or \&{fi} at level zero of $\&{if}\ldots\&{fi}$
15014 nesting. After it has acted, |cur_mod| will indicate the token that
15015 was found.
15016
15017 \MP's smallest two command codes are |if_test| and |fi_or_else|; this
15018 makes the skipping process a bit simpler.
15019
15020 @c 
15021 void mp_pass_text (MP mp) {
15022   integer l = 0;
15023   mp->scanner_status=skipping;
15024   mp->warning_info=mp_true_line(mp);
15025   while (1)  { 
15026     get_t_next;
15027     if ( mp->cur_cmd<=fi_or_else ) {
15028       if ( mp->cur_cmd<fi_or_else ) {
15029         incr(l);
15030       } else { 
15031         if ( l==0 ) break;
15032         if ( mp->cur_mod==fi_code ) decr(l);
15033       }
15034     } else {
15035       @<Decrease the string reference count,
15036        if the current token is a string@>;
15037     }
15038   }
15039   mp->scanner_status=normal;
15040 }
15041
15042 @ @<Decrease the string reference count...@>=
15043 if ( mp->cur_cmd==string_token ) { delete_str_ref(mp->cur_mod); }
15044
15045 @ When we begin to process a new \&{if}, we set |if_limit:=if_code|; then
15046 if \&{elseif} or \&{else} or \&{fi} occurs before the current \&{if}
15047 condition has been evaluated, a colon will be inserted.
15048 A construction like `\.{if fi}' would otherwise get \MP\ confused.
15049
15050 @<Push the condition stack@>=
15051 { p=mp_get_node(mp, if_node_size); link(p)=mp->cond_ptr; type(p)=mp->if_limit;
15052   name_type(p)=mp->cur_if; if_line_field(p)=mp->if_line;
15053   mp->cond_ptr=p; mp->if_limit=if_code; mp->if_line=mp_true_line(mp); 
15054   mp->cur_if=if_code;
15055 }
15056
15057 @ @<Pop the condition stack@>=
15058 { p=mp->cond_ptr; mp->if_line=if_line_field(p);
15059   mp->cur_if=name_type(p); mp->if_limit=type(p); mp->cond_ptr=link(p);
15060   mp_free_node(mp, p,if_node_size);
15061 }
15062
15063 @ Here's a procedure that changes the |if_limit| code corresponding to
15064 a given value of |cond_ptr|.
15065
15066 @c void mp_change_if_limit (MP mp,small_number l, pointer p) {
15067   pointer q;
15068   if ( p==mp->cond_ptr ) {
15069     mp->if_limit=l; /* that's the easy case */
15070   } else  { 
15071     q=mp->cond_ptr;
15072     while (1) { 
15073       if ( q==null ) mp_confusion(mp, "if");
15074 @:this can't happen if}{\quad if@>
15075       if ( link(q)==p ) { 
15076         type(q)=l; return;
15077       }
15078       q=link(q);
15079     }
15080   }
15081 }
15082
15083 @ The user is supposed to put colons into the proper parts of conditional
15084 statements. Therefore, \MP\ has to check for their presence.
15085
15086 @c 
15087 void mp_check_colon (MP mp) { 
15088   if ( mp->cur_cmd!=colon ) { 
15089     mp_missing_err(mp, ":");
15090 @.Missing `:'@>
15091     help2("There should've been a colon after the condition.")
15092          ("I shall pretend that one was there.");;
15093     mp_back_error(mp);
15094   }
15095 }
15096
15097 @ A condition is started when the |get_x_next| procedure encounters
15098 an |if_test| command; in that case |get_x_next| calls |conditional|,
15099 which is a recursive procedure.
15100 @^recursion@>
15101
15102 @c void mp_conditional (MP mp) {
15103   pointer save_cond_ptr; /* |cond_ptr| corresponding to this conditional */
15104   int new_if_limit; /* future value of |if_limit| */
15105   pointer p; /* temporary register */
15106   @<Push the condition stack@>; 
15107   save_cond_ptr=mp->cond_ptr;
15108 RESWITCH: 
15109   mp_get_boolean(mp); new_if_limit=else_if_code;
15110   if ( mp->internal[tracing_commands]>unity ) {
15111     @<Display the boolean value of |cur_exp|@>;
15112   }
15113 FOUND: 
15114   mp_check_colon(mp);
15115   if ( mp->cur_exp==true_code ) {
15116     mp_change_if_limit(mp, new_if_limit,save_cond_ptr);
15117     return; /* wait for \&{elseif}, \&{else}, or \&{fi} */
15118   };
15119   @<Skip to \&{elseif} or \&{else} or \&{fi}, then |goto done|@>;
15120 DONE: 
15121   mp->cur_if=mp->cur_mod; mp->if_line=mp_true_line(mp);
15122   if ( mp->cur_mod==fi_code ) {
15123     @<Pop the condition stack@>
15124   } else if ( mp->cur_mod==else_if_code ) {
15125     goto RESWITCH;
15126   } else  { 
15127     mp->cur_exp=true_code; new_if_limit=fi_code; mp_get_x_next(mp); 
15128     goto FOUND;
15129   }
15130 }
15131
15132 @ In a construction like `\&{if} \&{if} \&{true}: $0=1$: \\{foo}
15133 \&{else}: \\{bar} \&{fi}', the first \&{else}
15134 that we come to after learning that the \&{if} is false is not the
15135 \&{else} we're looking for. Hence the following curious logic is needed.
15136
15137 @<Skip to \&{elseif}...@>=
15138 while (1) { 
15139   mp_pass_text(mp);
15140   if ( mp->cond_ptr==save_cond_ptr ) goto DONE;
15141   else if ( mp->cur_mod==fi_code ) @<Pop the condition stack@>;
15142 }
15143
15144
15145 @ @<Display the boolean value...@>=
15146 { mp_begin_diagnostic(mp);
15147   if ( mp->cur_exp==true_code ) mp_print(mp, "{true}");
15148   else mp_print(mp, "{false}");
15149   mp_end_diagnostic(mp, false);
15150 }
15151
15152 @ The processing of conditionals is complete except for the following
15153 code, which is actually part of |get_x_next|. It comes into play when
15154 \&{elseif}, \&{else}, or \&{fi} is scanned.
15155
15156 @<Terminate the current conditional and skip to \&{fi}@>=
15157 if ( mp->cur_mod>mp->if_limit ) {
15158   if ( mp->if_limit==if_code ) { /* condition not yet evaluated */
15159     mp_missing_err(mp, ":");
15160 @.Missing `:'@>
15161     mp_back_input(mp); mp->cur_sym=frozen_colon; mp_ins_error(mp);
15162   } else  { 
15163     print_err("Extra "); mp_print_cmd_mod(mp, fi_or_else,mp->cur_mod);
15164 @.Extra else@>
15165 @.Extra elseif@>
15166 @.Extra fi@>
15167     help1("I'm ignoring this; it doesn't match any if.");
15168     mp_error(mp);
15169   }
15170 } else  { 
15171   while ( mp->cur_mod!=fi_code ) mp_pass_text(mp); /* skip to \&{fi} */
15172   @<Pop the condition stack@>;
15173 }
15174
15175 @* \[34] Iterations.
15176 To bring our treatment of |get_x_next| to a close, we need to consider what
15177 \MP\ does when it sees \&{for}, \&{forsuffixes}, and \&{forever}.
15178
15179 There's a global variable |loop_ptr| that keeps track of the \&{for} loops
15180 that are currently active. If |loop_ptr=null|, no loops are in progress;
15181 otherwise |info(loop_ptr)| points to the iterative text of the current
15182 (innermost) loop, and |link(loop_ptr)| points to the data for any other
15183 loops that enclose the current one.
15184
15185 A loop-control node also has two other fields, called |loop_type| and
15186 |loop_list|, whose contents depend on the type of loop:
15187
15188 \yskip\indent|loop_type(loop_ptr)=null| means that |loop_list(loop_ptr)|
15189 points to a list of one-word nodes whose |info| fields point to the
15190 remaining argument values of a suffix list and expression list.
15191
15192 \yskip\indent|loop_type(loop_ptr)=diov| means that the current loop is
15193 `\&{forever}'.
15194
15195 \yskip\indent|loop_type(loop_ptr)=progression_flag| means that
15196 |p=loop_list(loop_ptr)| points to a ``progression node'' and |value(p)|,
15197 |step_size(p)|, and |final_value(p)| contain the data for an arithmetic
15198 progression.
15199
15200 \yskip\indent|loop_type(loop_ptr)=p>diov| means that |p| points to an edge
15201 header and |loop_list(loop_ptr)| points into the graphical object list for
15202 that edge header.
15203
15204 \yskip\noindent In the case of a progression node, the first word is not used
15205 because the link field of words in the dynamic memory area cannot be arbitrary.
15206
15207 @d loop_list_loc(A) ((A)+1) /* where the |loop_list| field resides */
15208 @d loop_type(A) info(loop_list_loc((A))) /* the type of \&{for} loop */
15209 @d loop_list(A) link(loop_list_loc((A))) /* the remaining list elements */
15210 @d loop_node_size 2 /* the number of words in a loop control node */
15211 @d progression_node_size 4 /* the number of words in a progression node */
15212 @d step_size(A) mp->mem[(A)+2].sc /* the step size in an arithmetic progression */
15213 @d final_value(A) mp->mem[(A)+3].sc /* the final value in an arithmetic progression */
15214 @d progression_flag (null+2)
15215   /* |loop_type| value when |loop_list| points to a progression node */
15216
15217 @<Glob...@>=
15218 pointer loop_ptr; /* top of the loop-control-node stack */
15219
15220 @ @<Set init...@>=
15221 mp->loop_ptr=null;
15222
15223 @ If the expressions that define an arithmetic progression in
15224 a \&{for} loop don't have known numeric values, the |bad_for|
15225 subroutine screams at the user.
15226
15227 @c void mp_bad_for (MP mp, char * s) {
15228   mp_disp_err(mp, null,"Improper "); /* show the bad expression above the message */
15229 @.Improper...replaced by 0@>
15230   mp_print(mp, s); mp_print(mp, " has been replaced by 0");
15231   help4("When you say `for x=a step b until c',")
15232     ("the initial value `a' and the step size `b'")
15233     ("and the final value `c' must have known numeric values.")
15234     ("I'm zeroing this one. Proceed, with fingers crossed.");
15235   mp_put_get_flush_error(mp, 0);
15236 };
15237
15238 @ Here's what \MP\ does when \&{for}, \&{forsuffixes}, or \&{forever}
15239 has just been scanned. (This code requires slight familiarity with
15240 expression-parsing routines that we have not yet discussed; but it seems
15241 to belong in the present part of the program, even though the original author
15242 didn't write it until later. The reader may wish to come back to it.)
15243
15244 @c void mp_begin_iteration (MP mp) {
15245   halfword m; /* |expr_base| (\&{for}) or |suffix_base| (\&{forsuffixes}) */
15246   halfword n; /* hash address of the current symbol */
15247   pointer s; /* the new loop-control node */
15248   pointer p; /* substitution list for |scan_toks| */
15249   pointer q;  /* link manipulation register */
15250   pointer pp; /* a new progression node */
15251   m=mp->cur_mod; n=mp->cur_sym; s=mp_get_node(mp, loop_node_size);
15252   if ( m==start_forever ){ 
15253     loop_type(s)=diov; p=null; mp_get_x_next(mp);
15254   } else { 
15255     mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
15256     info(p)=mp->cur_sym; value(p)=m;
15257     mp_get_x_next(mp);
15258     if ( mp->cur_cmd==within_token ) {
15259       @<Set up a picture iteration@>;
15260     } else { 
15261       @<Check for the |"="| or |":="| in a loop header@>;
15262       @<Scan the values to be used in the loop@>;
15263     }
15264   }
15265   @<Check for the presence of a colon@>;
15266   @<Scan the loop text and put it on the loop control stack@>;
15267   mp_resume_iteration(mp);
15268 }
15269
15270 @ @<Check for the |"="| or |":="| in a loop header@>=
15271 if ( (mp->cur_cmd!=equals)&&(mp->cur_cmd!=assignment) ) { 
15272   mp_missing_err(mp, "=");
15273 @.Missing `='@>
15274   help3("The next thing in this loop should have been `=' or `:='.")
15275     ("But don't worry; I'll pretend that an equals sign")
15276     ("was present, and I'll look for the values next.");
15277   mp_back_error(mp);
15278 }
15279
15280 @ @<Check for the presence of a colon@>=
15281 if ( mp->cur_cmd!=colon ) { 
15282   mp_missing_err(mp, ":");
15283 @.Missing `:'@>
15284   help3("The next thing in this loop should have been a `:'.")
15285     ("So I'll pretend that a colon was present;")
15286     ("everything from here to `endfor' will be iterated.");
15287   mp_back_error(mp);
15288 }
15289
15290 @ We append a special |frozen_repeat_loop| token in place of the
15291 `\&{endfor}' at the end of the loop. This will come through \MP's scanner
15292 at the proper time to cause the loop to be repeated.
15293
15294 (If the user tries some shenanigan like `\&{for} $\ldots$ \&{let} \&{endfor}',
15295 he will be foiled by the |get_symbol| routine, which keeps frozen
15296 tokens unchanged. Furthermore the |frozen_repeat_loop| is an \&{outer}
15297 token, so it won't be lost accidentally.)
15298
15299 @ @<Scan the loop text...@>=
15300 q=mp_get_avail(mp); info(q)=frozen_repeat_loop;
15301 mp->scanner_status=loop_defining; mp->warning_info=n;
15302 info(s)=mp_scan_toks(mp, iteration,p,q,0); mp->scanner_status=normal;
15303 link(s)=mp->loop_ptr; mp->loop_ptr=s
15304
15305 @ @<Initialize table...@>=
15306 eq_type(frozen_repeat_loop)=repeat_loop+outer_tag;
15307 text(frozen_repeat_loop)=intern(" ENDFOR");
15308
15309 @ The loop text is inserted into \MP's scanning apparatus by the
15310 |resume_iteration| routine.
15311
15312 @c void mp_resume_iteration (MP mp) {
15313   pointer p,q; /* link registers */
15314   p=loop_type(mp->loop_ptr);
15315   if ( p==progression_flag ) { 
15316     p=loop_list(mp->loop_ptr); /* now |p| points to a progression node */
15317     mp->cur_exp=value(p);
15318     if ( @<The arithmetic progression has ended@> ) {
15319       mp_stop_iteration(mp);
15320       return;
15321     }
15322     mp->cur_type=mp_known; q=mp_stash_cur_exp(mp); /* make |q| an \&{expr} argument */
15323     value(p)=mp->cur_exp+step_size(p); /* set |value(p)| for the next iteration */
15324   } else if ( p==null ) { 
15325     p=loop_list(mp->loop_ptr);
15326     if ( p==null ) {
15327       mp_stop_iteration(mp);
15328       return;
15329     }
15330     loop_list(mp->loop_ptr)=link(p); q=info(p); free_avail(p);
15331   } else if ( p==diov ) { 
15332     mp_begin_token_list(mp, info(mp->loop_ptr),forever_text); return;
15333   } else {
15334     @<Make |q| a capsule containing the next picture component from
15335       |loop_list(loop_ptr)| or |goto not_found|@>;
15336   }
15337   mp_begin_token_list(mp, info(mp->loop_ptr),loop_text);
15338   mp_stack_argument(mp, q);
15339   if ( mp->internal[tracing_commands]>unity ) {
15340      @<Trace the start of a loop@>;
15341   }
15342   return;
15343 NOT_FOUND:
15344   mp_stop_iteration(mp);
15345 }
15346
15347 @ @<The arithmetic progression has ended@>=
15348 ((step_size(p)>0)&&(mp->cur_exp>final_value(p)))||
15349  ((step_size(p)<0)&&(mp->cur_exp<final_value(p)))
15350
15351 @ @<Trace the start of a loop@>=
15352
15353   mp_begin_diagnostic(mp); mp_print_nl(mp, "{loop value=");
15354 @.loop value=n@>
15355   if ( (q!=null)&&(link(q)==diov) ) mp_print_exp(mp, q,1);
15356   else mp_show_token_list(mp, q,null,50,0);
15357   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
15358 }
15359
15360 @ @<Make |q| a capsule containing the next picture component from...@>=
15361 { q=loop_list(mp->loop_ptr);
15362   if ( q==null ) goto NOT_FOUND;
15363   skip_component(q) goto NOT_FOUND;
15364   mp->cur_exp=mp_copy_objects(mp, loop_list(mp->loop_ptr),q);
15365   mp_init_bbox(mp, mp->cur_exp);
15366   mp->cur_type=mp_picture_type;
15367   loop_list(mp->loop_ptr)=q;
15368   q=mp_stash_cur_exp(mp);
15369 }
15370
15371 @ A level of loop control disappears when |resume_iteration| has decided
15372 not to resume, or when an \&{exitif} construction has removed the loop text
15373 from the input stack.
15374
15375 @c void mp_stop_iteration (MP mp) {
15376   pointer p,q; /* the usual */
15377   p=loop_type(mp->loop_ptr);
15378   if ( p==progression_flag )  {
15379     mp_free_node(mp, loop_list(mp->loop_ptr),progression_node_size);
15380   } else if ( p==null ){ 
15381     q=loop_list(mp->loop_ptr);
15382     while ( q!=null ) {
15383       p=info(q);
15384       if ( p!=null ) {
15385         if ( link(p)==diov ) { /* it's an \&{expr} parameter */
15386           mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
15387         } else {
15388           mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
15389         }
15390       }
15391       p=q; q=link(q); free_avail(p);
15392     }
15393   } else if ( p>progression_flag ) {
15394     delete_edge_ref(p);
15395   }
15396   p=mp->loop_ptr; mp->loop_ptr=link(p); mp_flush_token_list(mp, info(p));
15397   mp_free_node(mp, p,loop_node_size);
15398 }
15399
15400 @ Now that we know all about loop control, we can finish up
15401 the missing portion of |begin_iteration| and we'll be done.
15402
15403 The following code is performed after the `\.=' has been scanned in
15404 a \&{for} construction (if |m=expr_base|) or a \&{forsuffixes} construction
15405 (if |m=suffix_base|).
15406
15407 @<Scan the values to be used in the loop@>=
15408 loop_type(s)=null; q=loop_list_loc(s); link(q)=null; /* |link(q)=loop_list(s)| */
15409 do {  
15410   mp_get_x_next(mp);
15411   if ( m!=expr_base ) {
15412     mp_scan_suffix(mp);
15413   } else { 
15414     if ( mp->cur_cmd>=colon ) if ( mp->cur_cmd<=comma ) 
15415           goto CONTINUE;
15416     mp_scan_expression(mp);
15417     if ( mp->cur_cmd==step_token ) if ( q==loop_list_loc(s) ) {
15418       @<Prepare for step-until construction and |break|@>;
15419     }
15420     mp->cur_exp=mp_stash_cur_exp(mp);
15421   }
15422   link(q)=mp_get_avail(mp); q=link(q); 
15423   info(q)=mp->cur_exp; mp->cur_type=mp_vacuous;
15424 CONTINUE:
15425   ;
15426 } while (mp->cur_cmd==comma)
15427
15428 @ @<Prepare for step-until construction and |break|@>=
15429
15430   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "initial value");
15431   pp=mp_get_node(mp, progression_node_size); value(pp)=mp->cur_exp;
15432   mp_get_x_next(mp); mp_scan_expression(mp);
15433   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "step size");
15434   step_size(pp)=mp->cur_exp;
15435   if ( mp->cur_cmd!=until_token ) { 
15436     mp_missing_err(mp, "until");
15437 @.Missing `until'@>
15438     help2("I assume you meant to say `until' after `step'.")
15439       ("So I'll look for the final value and colon next.");
15440     mp_back_error(mp);
15441   }
15442   mp_get_x_next(mp); mp_scan_expression(mp);
15443   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "final value");
15444   final_value(pp)=mp->cur_exp; loop_list(s)=pp;
15445   loop_type(s)=progression_flag; 
15446   break;
15447 }
15448
15449 @ The last case is when we have just seen ``\&{within}'', and we need to
15450 parse a picture expression and prepare to iterate over it.
15451
15452 @<Set up a picture iteration@>=
15453 { mp_get_x_next(mp);
15454   mp_scan_expression(mp);
15455   @<Make sure the current expression is a known picture@>;
15456   loop_type(s)=mp->cur_exp; mp->cur_type=mp_vacuous;
15457   q=link(dummy_loc(mp->cur_exp));
15458   if ( q!= null ) 
15459     if ( is_start_or_stop(q) )
15460       if ( mp_skip_1component(mp, q)==null ) q=link(q);
15461   loop_list(s)=q;
15462 }
15463
15464 @ @<Make sure the current expression is a known picture@>=
15465 if ( mp->cur_type!=mp_picture_type ) {
15466   mp_disp_err(mp, null,"Improper iteration spec has been replaced by nullpicture");
15467   help1("When you say `for x in p', p must be a known picture.");
15468   mp_put_get_flush_error(mp, mp_get_node(mp, edge_header_size));
15469   mp_init_edges(mp, mp->cur_exp); mp->cur_type=mp_picture_type;
15470 }
15471
15472 @* \[35] File names.
15473 It's time now to fret about file names.  Besides the fact that different
15474 operating systems treat files in different ways, we must cope with the
15475 fact that completely different naming conventions are used by different
15476 groups of people. The following programs show what is required for one
15477 particular operating system; similar routines for other systems are not
15478 difficult to devise.
15479 @^system dependencies@>
15480
15481 \MP\ assumes that a file name has three parts: the name proper; its
15482 ``extension''; and a ``file area'' where it is found in an external file
15483 system.  The extension of an input file is assumed to be
15484 `\.{.mp}' unless otherwise specified; it is `\.{.log}' on the
15485 transcript file that records each run of \MP; it is `\.{.tfm}' on the font
15486 metric files that describe characters in any fonts created by \MP; it is
15487 `\.{.ps}' or `.{\it nnn}' for some number {\it nnn} on the \ps\ output files;
15488 and it is `\.{.mem}' on the mem files written by \.{INIMP} to initialize \MP.
15489 The file area can be arbitrary on input files, but files are usually
15490 output to the user's current area.  If an input file cannot be
15491 found on the specified area, \MP\ will look for it on a special system
15492 area; this special area is intended for commonly used input files.
15493
15494 Simple uses of \MP\ refer only to file names that have no explicit
15495 extension or area. For example, a person usually says `\.{input} \.{cmr10}'
15496 instead of `\.{input} \.{cmr10.new}'. Simple file
15497 names are best, because they make the \MP\ source files portable;
15498 whenever a file name consists entirely of letters and digits, it should be
15499 treated in the same way by all implementations of \MP. However, users
15500 need the ability to refer to other files in their environment, especially
15501 when responding to error messages concerning unopenable files; therefore
15502 we want to let them use the syntax that appears in their favorite
15503 operating system.
15504
15505 @ \MP\ uses the same conventions that have proved to be satisfactory for
15506 \TeX\ and \MF. In order to isolate the system-dependent aspects of file names,
15507 @^system dependencies@>
15508 the system-independent parts of \MP\ are expressed in terms
15509 of three system-dependent
15510 procedures called |begin_name|, |more_name|, and |end_name|. In
15511 essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
15512 the system-independent driver program does the operations
15513 $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;|more_name|(c_n);
15514 \,|end_name|.$$
15515 These three procedures communicate with each other via global variables.
15516 Afterwards the file name will appear in the string pool as three strings
15517 called |cur_name|\penalty10000\hskip-.05em,
15518 |cur_area|, and |cur_ext|; the latter two are null (i.e.,
15519 |""|), unless they were explicitly specified by the user.
15520
15521 Actually the situation is slightly more complicated, because \MP\ needs
15522 to know when the file name ends. The |more_name| routine is a function
15523 (with side effects) that returns |true| on the calls |more_name|$(c_1)$,
15524 \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
15525 returns |false|; or, it returns |true| and $c_n$ is the last character
15526 on the current input line. In other words,
15527 |more_name| is supposed to return |true| unless it is sure that the
15528 file name has been completely scanned; and |end_name| is supposed to be able
15529 to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
15530 whether $|more_name|(c_n)$ returned |true| or |false|.
15531
15532 @<Glob...@>=
15533 char * cur_name; /* name of file just scanned */
15534 char * cur_area; /* file area just scanned, or \.{""} */
15535 char * cur_ext; /* file extension just scanned, or \.{""} */
15536
15537 @ It is easier to maintain reference counts if we assign initial values.
15538
15539 @<Set init...@>=
15540 mp->cur_name=xstrdup(""); 
15541 mp->cur_area=xstrdup(""); 
15542 mp->cur_ext=xstrdup("");
15543
15544 @ @<Dealloc variables@>=
15545 xfree(mp->cur_area);
15546 xfree(mp->cur_name);
15547 xfree(mp->cur_ext);
15548
15549 @ The file names we shall deal with for illustrative purposes have the
15550 following structure:  If the name contains `\.>' or `\.:', the file area
15551 consists of all characters up to and including the final such character;
15552 otherwise the file area is null.  If the remaining file name contains
15553 `\..', the file extension consists of all such characters from the first
15554 remaining `\..' to the end, otherwise the file extension is null.
15555 @^system dependencies@>
15556
15557 We can scan such file names easily by using two global variables that keep track
15558 of the occurrences of area and extension delimiters.  Note that these variables
15559 cannot be of type |pool_pointer| because a string pool compaction could occur
15560 while scanning a file name.
15561
15562 @<Glob...@>=
15563 integer area_delimiter;
15564   /* most recent `\.>' or `\.:' relative to |str_start[str_ptr]| */
15565 integer ext_delimiter; /* the relevant `\..', if any */
15566
15567 @ Input files that can't be found in the user's area may appear in standard
15568 system areas called |MP_area| and |MF_area|.  (The latter is used when the file
15569 extension is |".mf"|.)  The standard system area for font metric files
15570 to be read is |MP_font_area|.
15571 This system area name will, of course, vary from place to place.
15572 @^system dependencies@>
15573
15574 @d MP_area "MPinputs:"
15575 @.MPinputs@>
15576 @d MF_area "MFinputs:"
15577 @.MFinputs@>
15578 @d MP_font_area ""
15579 @.TeXfonts@>
15580
15581 @ Here now is the first of the system-dependent routines for file name scanning.
15582 @^system dependencies@>
15583
15584 @<Declare subroutines for parsing file names@>=
15585 void mp_begin_name (MP mp) { 
15586   xfree(mp->cur_name); 
15587   xfree(mp->cur_area); 
15588   xfree(mp->cur_ext);
15589   mp->area_delimiter=-1; 
15590   mp->ext_delimiter=-1;
15591 }
15592
15593 @ And here's the second.
15594 @^system dependencies@>
15595
15596 @<Declare subroutines for parsing file names@>=
15597 boolean mp_more_name (MP mp, ASCII_code c) { 
15598   if (c==' ') {
15599     return false;
15600   } else { 
15601     if ( (c=='>')||(c==':') ) { 
15602       mp->area_delimiter=mp->pool_ptr; 
15603       mp->ext_delimiter=-1;
15604     } else if ( (c=='.')&&(mp->ext_delimiter<0) ) {
15605       mp->ext_delimiter=mp->pool_ptr;
15606     }
15607     str_room(1); append_char(c); /* contribute |c| to the current string */
15608     return true;
15609   }
15610 }
15611
15612 @ The third.
15613 @^system dependencies@>
15614
15615 @d copy_pool_segment(A,B,C) { 
15616       A = xmalloc(C+1,sizeof(char)); 
15617       strncpy(A,(char *)(mp->str_pool+B),C);  
15618       A[C] = 0;}
15619
15620 @<Declare subroutines for parsing file names@>=
15621 void mp_end_name (MP mp) {
15622   pool_pointer s; /* length of area, name, and extension */
15623   unsigned int len;
15624   /* "my/w.mp" */
15625   s = mp->str_start[mp->str_ptr];
15626   if ( mp->area_delimiter<0 ) {    
15627     mp->cur_area=xstrdup("");
15628   } else {
15629     len = mp->area_delimiter-s; 
15630     copy_pool_segment(mp->cur_area,s,len);
15631     s += len+1;
15632   }
15633   if ( mp->ext_delimiter<0 ) {
15634     mp->cur_ext=xstrdup("");
15635     len = mp->pool_ptr-s; 
15636   } else {
15637     copy_pool_segment(mp->cur_ext,mp->ext_delimiter,(mp->pool_ptr-mp->ext_delimiter));
15638     len = mp->ext_delimiter-s;
15639   }
15640   copy_pool_segment(mp->cur_name,s,len);
15641   mp->pool_ptr=s; /* don't need this partial string */
15642 }
15643
15644 @ Conversely, here is a routine that takes three strings and prints a file
15645 name that might have produced them. (The routine is system dependent, because
15646 some operating systems put the file area last instead of first.)
15647 @^system dependencies@>
15648
15649 @<Basic printing...@>=
15650 void mp_print_file_name (MP mp, char * n, char * a, char * e) { 
15651   mp_print(mp, a); mp_print(mp, n); mp_print(mp, e);
15652 };
15653
15654 @ Another system-dependent routine is needed to convert three internal
15655 \MP\ strings
15656 to the |name_of_file| value that is used to open files. The present code
15657 allows both lowercase and uppercase letters in the file name.
15658 @^system dependencies@>
15659
15660 @d append_to_name(A) { c=(A); 
15661   if ( k<file_name_size ) {
15662     mp->name_of_file[k]=xchr(c);
15663     incr(k);
15664   }
15665 }
15666
15667 @<Declare subroutines for parsing file names@>=
15668 void mp_pack_file_name (MP mp, char *n, char *a, char *e) {
15669   integer k; /* number of positions filled in |name_of_file| */
15670   ASCII_code c; /* character being packed */
15671   char *j; /* a character  index */
15672   k=0;
15673   assert(n);
15674   if (a!=NULL) {
15675     for (j=a;*j;j++) { append_to_name(*j); }
15676   }
15677   for (j=n;*j;j++) { append_to_name(*j); }
15678   if (e!=NULL) {
15679     for (j=e;*j;j++) { append_to_name(*j); }
15680   }
15681   mp->name_of_file[k]=0;
15682   mp->name_length=k; 
15683 }
15684
15685 @ @<Exported...@>=
15686 void mp_pack_file_name (MP mp, char *n, char *a, char *e) ;
15687
15688 @ A messier routine is also needed, since mem file names must be scanned
15689 before \MP's string mechanism has been initialized. We shall use the
15690 global variable |MP_mem_default| to supply the text for default system areas
15691 and extensions related to mem files.
15692 @^system dependencies@>
15693
15694 @d mem_default_length 9 /* length of the |MP_mem_default| string */
15695 @d mem_ext_length 4 /* length of its `\.{.mem}' part */
15696 @d mem_extension ".mem" /* the extension, as a \.{WEB} constant */
15697
15698 @<Glob...@>=
15699 char *MP_mem_default;
15700 char *mem_name; /* for commandline */
15701
15702 @ @<Option variables@>=
15703 char *mem_name; /* for commandline */
15704
15705 @ @<Allocate or initialize ...@>=
15706 mp->MP_mem_default = xstrdup("plain.mem");
15707 mp->mem_name = mp_xstrdup(opt->mem_name);
15708 @.plain@>
15709 @^system dependencies@>
15710
15711 @ @<Dealloc variables@>=
15712 xfree(mp->MP_mem_default);
15713 xfree(mp->mem_name);
15714
15715 @ @<Check the ``constant'' values for consistency@>=
15716 if ( mem_default_length>file_name_size ) mp->bad=20;
15717
15718 @ Here is the messy routine that was just mentioned. It sets |name_of_file|
15719 from the first |n| characters of |MP_mem_default|, followed by
15720 |buffer[a..b]|, followed by the last |mem_ext_length| characters of
15721 |MP_mem_default|.
15722
15723 We dare not give error messages here, since \MP\ calls this routine before
15724 the |error| routine is ready to roll. Instead, we simply drop excess characters,
15725 since the error will be detected in another way when a strange file name
15726 isn't found.
15727 @^system dependencies@>
15728
15729 @c void mp_pack_buffered_name (MP mp,small_number n, integer a,
15730                                integer b) {
15731   integer k; /* number of positions filled in |name_of_file| */
15732   ASCII_code c; /* character being packed */
15733   integer j; /* index into |buffer| or |MP_mem_default| */
15734   if ( n+b-a+1+mem_ext_length>file_name_size )
15735     b=a+file_name_size-n-1-mem_ext_length;
15736   k=0;
15737   for (j=0;j<n;j++) {
15738     append_to_name(xord((int)mp->MP_mem_default[j]));
15739   }
15740   for (j=a;j<=b;j++) {
15741     append_to_name(mp->buffer[j]);
15742   }
15743   for (j=mem_default_length-mem_ext_length;
15744       j<mem_default_length;j++) {
15745     append_to_name(xord((int)mp->MP_mem_default[j]));
15746   } 
15747   mp->name_of_file[k]=0;
15748   mp->name_length=k; 
15749 }
15750
15751 @ Here is the only place we use |pack_buffered_name|. This part of the program
15752 becomes active when a ``virgin'' \MP\ is trying to get going, just after
15753 the preliminary initialization, or when the user is substituting another
15754 mem file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
15755 contains the first line of input in |buffer[loc..(last-1)]|, where
15756 |loc<last| and |buffer[loc]<>" "|.
15757
15758 @<Declarations@>=
15759 boolean mp_open_mem_file (MP mp) ;
15760
15761 @ @c
15762 boolean mp_open_mem_file (MP mp) {
15763   int j; /* the first space after the file name */
15764   if (mp->mem_name!=NULL) {
15765     mp->mem_file = mp_open_file(mp, mp->mem_name, "rb", mp_filetype_memfile);
15766     if ( mp->mem_file ) return true;
15767   }
15768   j=loc;
15769   if ( mp->buffer[loc]=='&' ) {
15770     incr(loc); j=loc; mp->buffer[mp->last]=' ';
15771     while ( mp->buffer[j]!=' ' ) incr(j);
15772     mp_pack_buffered_name(mp, 0,loc,j-1); /* try first without the system file area */
15773     if ( mp_w_open_in(mp, &mp->mem_file) ) goto FOUND;
15774     wake_up_terminal;
15775     wterm_ln("Sorry, I can\'t find that mem file; will try PLAIN.");
15776 @.Sorry, I can't find...@>
15777     update_terminal;
15778   }
15779   /* now pull out all the stops: try for the system \.{plain} file */
15780   mp_pack_buffered_name(mp, mem_default_length-mem_ext_length,0,0);
15781   if ( ! mp_w_open_in(mp, &mp->mem_file) ) {
15782     wake_up_terminal;
15783     wterm_ln("I can\'t find the PLAIN mem file!\n");
15784 @.I can't find PLAIN...@>
15785 @.plain@>
15786     return false;
15787   }
15788 FOUND:
15789   loc=j; return true;
15790 }
15791
15792 @ Operating systems often make it possible to determine the exact name (and
15793 possible version number) of a file that has been opened. The following routine,
15794 which simply makes a \MP\ string from the value of |name_of_file|, should
15795 ideally be changed to deduce the full name of file~|f|, which is the file
15796 most recently opened, if it is possible to do this in a \PASCAL\ program.
15797 @^system dependencies@>
15798
15799 @<Declarations@>=
15800 #define mp_a_make_name_string(A,B)  mp_make_name_string(A)
15801 #define mp_b_make_name_string(A,B)  mp_make_name_string(A)
15802 #define mp_w_make_name_string(A,B)  mp_make_name_string(A)
15803
15804 @ @c 
15805 str_number mp_make_name_string (MP mp) {
15806   int k; /* index into |name_of_file| */
15807   str_room(mp->name_length);
15808   for (k=0;k<mp->name_length;k++) {
15809     append_char(xord((int)mp->name_of_file[k]));
15810   }
15811   return mp_make_string(mp);
15812 }
15813
15814 @ Now let's consider the ``driver''
15815 routines by which \MP\ deals with file names
15816 in a system-independent manner.  First comes a procedure that looks for a
15817 file name in the input by taking the information from the input buffer.
15818 (We can't use |get_next|, because the conversion to tokens would
15819 destroy necessary information.)
15820
15821 This procedure doesn't allow semicolons or percent signs to be part of
15822 file names, because of other conventions of \MP.
15823 {\sl The {\logos METAFONT\/}book} doesn't
15824 use semicolons or percents immediately after file names, but some users
15825 no doubt will find it natural to do so; therefore system-dependent
15826 changes to allow such characters in file names should probably
15827 be made with reluctance, and only when an entire file name that
15828 includes special characters is ``quoted'' somehow.
15829 @^system dependencies@>
15830
15831 @c void mp_scan_file_name (MP mp) { 
15832   mp_begin_name(mp);
15833   while ( mp->buffer[loc]==' ' ) incr(loc);
15834   while (1) { 
15835     if ( (mp->buffer[loc]==';')||(mp->buffer[loc]=='%') ) break;
15836     if ( ! mp_more_name(mp, mp->buffer[loc]) ) break;
15837     incr(loc);
15838   }
15839   mp_end_name(mp);
15840 }
15841
15842 @ Here is another version that takes its input from a string.
15843
15844 @<Declare subroutines for parsing file names@>=
15845 void mp_str_scan_file (MP mp,  str_number s) {
15846   pool_pointer p,q; /* current position and stopping point */
15847   mp_begin_name(mp);
15848   p=mp->str_start[s]; q=str_stop(s);
15849   while ( p<q ){ 
15850     if ( ! mp_more_name(mp, mp->str_pool[p]) ) break;
15851     incr(p);
15852   }
15853   mp_end_name(mp);
15854 }
15855
15856 @ And one that reads from a |char*|.
15857
15858 @<Declare subroutines for parsing file names@>=
15859 void mp_ptr_scan_file (MP mp,  char *s) {
15860   char *p, *q; /* current position and stopping point */
15861   mp_begin_name(mp);
15862   p=s; q=p+strlen(s);
15863   while ( p<q ){ 
15864     if ( ! mp_more_name(mp, *p)) break;
15865     p++;
15866   }
15867   mp_end_name(mp);
15868 }
15869
15870
15871 @ The global variable |job_name| contains the file name that was first
15872 \&{input} by the user. This name is extended by `\.{.log}' and `\.{ps}' and
15873 `\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's output files.
15874
15875 @<Glob...@>=
15876 char *job_name; /* principal file name */
15877 boolean log_opened; /* has the transcript file been opened? */
15878 char *log_name; /* full name of the log file */
15879
15880 @ @<Option variables@>=
15881 char *job_name; /* principal file name */
15882
15883 @ Initially |job_name=NULL|; it becomes nonzero as soon as the true name is known.
15884 We have |job_name=NULL| if and only if the `\.{log}' file has not been opened,
15885 except of course for a short time just after |job_name| has become nonzero.
15886
15887 @<Allocate or ...@>=
15888 mp->job_name=opt->job_name; 
15889 mp->log_opened=false;
15890
15891 @ @<Dealloc variables@>=
15892 xfree(mp->job_name);
15893
15894 @ Here is a routine that manufactures the output file names, assuming that
15895 |job_name<>0|. It ignores and changes the current settings of |cur_area|
15896 and |cur_ext|.
15897
15898 @d pack_cur_name mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext)
15899
15900 @<Declarations@>=
15901 void mp_pack_job_name (MP mp, char *s) ;
15902
15903 @ @c void mp_pack_job_name (MP mp, char  *s) { /* |s = ".log"|, |".mem"|, |".ps"|, or .\\{nnn} */
15904   xfree(mp->cur_name); mp->cur_name=xstrdup(mp->job_name);
15905   xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
15906   xfree(mp->cur_ext);  mp->cur_ext=xstrdup(s);
15907   pack_cur_name;
15908 }
15909
15910 @ If some trouble arises when \MP\ tries to open a file, the following
15911 routine calls upon the user to supply another file name. Parameter~|s|
15912 is used in the error message to identify the type of file; parameter~|e|
15913 is the default extension if none is given. Upon exit from the routine,
15914 variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
15915 ready for another attempt at file opening.
15916
15917 @<Declarations@>=
15918 void mp_prompt_file_name (MP mp,char * s, char * e) ;
15919
15920 @ @c void mp_prompt_file_name (MP mp,char * s, char * e) {
15921   size_t k; /* index into |buffer| */
15922   char * saved_cur_name;
15923   if ( mp->interaction==mp_scroll_mode ) 
15924         wake_up_terminal;
15925   if (strcmp(s,"input file name")==0) {
15926         print_err("I can\'t find file `");
15927 @.I can't find file x@>
15928   } else {
15929         print_err("I can\'t write on file `");
15930   }
15931 @.I can't write on file x@>
15932   mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext); 
15933   mp_print(mp, "'.");
15934   if (strcmp(e,"")==0) 
15935         mp_show_context(mp);
15936   mp_print_nl(mp, "Please type another "); mp_print(mp, s);
15937 @.Please type...@>
15938   if ( mp->interaction<mp_scroll_mode )
15939     mp_fatal_error(mp, "*** (job aborted, file error in nonstop mode)");
15940 @.job aborted, file error...@>
15941   saved_cur_name = xstrdup(mp->cur_name);
15942   clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
15943   if (strcmp(mp->cur_ext,"")==0) 
15944         mp->cur_ext=e;
15945   if (strlen(mp->cur_name)==0) {
15946     mp->cur_name=saved_cur_name;
15947   } else {
15948     xfree(saved_cur_name);
15949   }
15950   pack_cur_name;
15951 }
15952
15953 @ @<Scan file name in the buffer@>=
15954
15955   mp_begin_name(mp); k=mp->first;
15956   while ( (mp->buffer[k]==' ')&&(k<mp->last) ) incr(k);
15957   while (1) { 
15958     if ( k==mp->last ) break;
15959     if ( ! mp_more_name(mp, mp->buffer[k]) ) break;
15960     incr(k);
15961   }
15962   mp_end_name(mp);
15963 }
15964
15965 @ The |open_log_file| routine is used to open the transcript file and to help
15966 it catch up to what has previously been printed on the terminal.
15967
15968 @c void mp_open_log_file (MP mp) {
15969   int old_setting; /* previous |selector| setting */
15970   int k; /* index into |months| and |buffer| */
15971   int l; /* end of first input line */
15972   integer m; /* the current month */
15973   char *months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 
15974     /* abbreviations of month names */
15975   old_setting=mp->selector;
15976   if ( mp->job_name==NULL ) {
15977      mp->job_name=xstrdup("mpout");
15978   }
15979   mp_pack_job_name(mp,".log");
15980   while ( ! mp_a_open_out(mp, &mp->log_file, mp_filetype_log) ) {
15981     @<Try to get a different log file name@>;
15982   }
15983   mp->log_name=xstrdup(mp->name_of_file);
15984   mp->selector=log_only; mp->log_opened=true;
15985   @<Print the banner line, including the date and time@>;
15986   mp->input_stack[mp->input_ptr]=mp->cur_input; 
15987     /* make sure bottom level is in memory */
15988   mp_print_nl(mp, "**");
15989 @.**@>
15990   l=mp->input_stack[0].limit_field-1; /* last position of first line */
15991   for (k=0;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
15992   mp_print_ln(mp); /* now the transcript file contains the first line of input */
15993   mp->selector=old_setting+2; /* |log_only| or |term_and_log| */
15994 }
15995
15996 @ @<Dealloc variables@>=
15997 xfree(mp->log_name);
15998
15999 @ Sometimes |open_log_file| is called at awkward moments when \MP\ is
16000 unable to print error messages or even to |show_context|.
16001 The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
16002 routine will not be invoked because |log_opened| will be false.
16003
16004 The normal idea of |mp_batch_mode| is that nothing at all should be written
16005 on the terminal. However, in the unusual case that
16006 no log file could be opened, we make an exception and allow
16007 an explanatory message to be seen.
16008
16009 Incidentally, the program always refers to the log file as a `\.{transcript
16010 file}', because some systems cannot use the extension `\.{.log}' for
16011 this file.
16012
16013 @<Try to get a different log file name@>=
16014 {  
16015   mp->selector=term_only;
16016   mp_prompt_file_name(mp, "transcript file name",".log");
16017 }
16018
16019 @ @<Print the banner...@>=
16020
16021   wlog(banner);
16022   mp_print(mp, mp->mem_ident); mp_print(mp, "  ");
16023   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[day])); 
16024   mp_print_char(mp, ' ');
16025   m=mp_round_unscaled(mp, mp->internal[month]);
16026   for (k=3*m-3;k<3*m;k++) { wlog_chr(months[k]); }
16027   mp_print_char(mp, ' '); 
16028   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[year])); 
16029   mp_print_char(mp, ' ');
16030   m=mp_round_unscaled(mp, mp->internal[mp_time]);
16031   mp_print_dd(mp, m / 60); mp_print_char(mp, ':'); mp_print_dd(mp, m % 60);
16032 }
16033
16034 @ The |try_extension| function tries to open an input file determined by
16035 |cur_name|, |cur_area|, and the argument |ext|.  It returns |false| if it
16036 can't find the file in |cur_area| or the appropriate system area.
16037
16038 @c boolean mp_try_extension (MP mp,char *ext) { 
16039   mp_pack_file_name(mp, mp->cur_name,mp->cur_area, ext);
16040   in_name=xstrdup(mp->cur_name); 
16041   in_area=xstrdup(mp->cur_area);
16042   if ( mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16043     return true;
16044   } else { 
16045     if (strcmp(ext,".mf")==0 ) in_area=xstrdup(MF_area);
16046     else in_area=xstrdup(MP_area);
16047     mp_pack_file_name(mp, mp->cur_name,in_area,ext);
16048     return mp_a_open_in(mp, &cur_file, mp_filetype_program);
16049   }
16050   return false;
16051 }
16052
16053 @ Let's turn now to the procedure that is used to initiate file reading
16054 when an `\.{input}' command is being processed.
16055
16056 @c void mp_start_input (MP mp) { /* \MP\ will \.{input} something */
16057   char *fname = NULL;
16058   @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>;
16059   while (1) { 
16060     mp_begin_file_reading(mp); /* set up |cur_file| and new level of input */
16061     if ( strlen(mp->cur_ext)==0 ) {
16062       if ( mp_try_extension(mp, ".mp") ) break;
16063       else if ( mp_try_extension(mp, "") ) break;
16064       else if ( mp_try_extension(mp, ".mf") ) break;
16065       /* |else do_nothing; | */
16066     } else if ( mp_try_extension(mp, mp->cur_ext) ) {
16067       break;
16068     }
16069     mp_end_file_reading(mp); /* remove the level that didn't work */
16070     mp_prompt_file_name(mp, "input file name","");
16071   }
16072   name=mp_a_make_name_string(mp, cur_file);
16073   fname = xstrdup(mp->name_of_file);
16074   if ( mp->job_name==NULL ) {
16075     mp->job_name=xstrdup(mp->cur_name); 
16076     mp_open_log_file(mp);
16077   } /* |open_log_file| doesn't |show_context|, so |limit|
16078         and |loc| needn't be set to meaningful values yet */
16079   if ( ((int)mp->term_offset+(int)strlen(fname)) > (mp->max_print_line-2)) mp_print_ln(mp);
16080   else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
16081   mp_print_char(mp, '('); incr(mp->open_parens); mp_print(mp, fname); 
16082   xfree(fname);
16083   update_terminal;
16084   @<Flush |name| and replace it with |cur_name| if it won't be needed@>;
16085   @<Read the first line of the new file@>;
16086 }
16087
16088 @ This code should be omitted if |a_make_name_string| returns something other
16089 than just a copy of its argument and the full file name is needed for opening
16090 \.{MPX} files or implementing the switch-to-editor option.
16091 @^system dependencies@>
16092
16093 @<Flush |name| and replace it with |cur_name| if it won't be needed@>=
16094 mp_flush_string(mp, name); name=rts(mp->cur_name); xfree(mp->cur_name)
16095
16096 @ Here we have to remember to tell the |input_ln| routine not to
16097 start with a |get|. If the file is empty, it is considered to
16098 contain a single blank line.
16099 @^system dependencies@>
16100
16101 @<Read the first line...@>=
16102
16103   line=1;
16104   (void)mp_input_ln(mp, cur_file,false); 
16105   mp_firm_up_the_line(mp);
16106   mp->buffer[limit]='%'; mp->first=limit+1; loc=start;
16107 }
16108
16109 @ @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>=
16110 while ( token_state &&(loc==null) ) mp_end_token_list(mp);
16111 if ( token_state ) { 
16112   print_err("File names can't appear within macros");
16113 @.File names can't...@>
16114   help3("Sorry...I've converted what follows to tokens,")
16115     ("possibly garbaging the name you gave.")
16116     ("Please delete the tokens and insert the name again.");
16117   mp_error(mp);
16118 }
16119 if ( file_state ) {
16120   mp_scan_file_name(mp);
16121 } else { 
16122    xfree(mp->cur_name); mp->cur_name=xstrdup(""); 
16123    xfree(mp->cur_ext);  mp->cur_ext =xstrdup(""); 
16124    xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16125 }
16126
16127 @ Sometimes we need to deal with two file names at once.  This procedure
16128 copies the given string into a special array for an old file name.
16129
16130 @c void mp_copy_old_name (MP mp,str_number s) {
16131   integer k; /* number of positions filled in |old_file_name| */
16132   pool_pointer j; /* index into |str_pool| */
16133   k=0;
16134   for (j=mp->str_start[s];j<=str_stop(s)-1;j++) { 
16135     incr(k);
16136     if ( k<=file_name_size ) 
16137       mp->old_file_name[k]=xchr(mp->str_pool[j]);
16138   }
16139   mp->old_file_name[++k] = 0;
16140 }
16141
16142 @ @<Glob...@>=
16143 char old_file_name[file_name_size+1];  /* analogous to |name_of_file| */
16144
16145 @ The following simple routine starts reading the \.{MPX} file associated
16146 with the current input file.
16147
16148 @c void mp_start_mpx_input (MP mp) {
16149   mp_pack_file_name(mp, in_name, in_area, ".mpx");
16150   @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16151     |goto not_found| if there is a problem@>;
16152   mp_begin_file_reading(mp);
16153   if ( ! mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16154     mp_end_file_reading(mp);
16155     goto NOT_FOUND;
16156   }
16157   name=mp_a_make_name_string(mp, cur_file);
16158   mp->mpx_name[index]=name; add_str_ref(name);
16159   @<Read the first line of the new file@>;
16160   return;
16161 NOT_FOUND: 
16162     @<Explain that the \.{MPX} file can't be read and |succumb|@>;
16163 }
16164
16165 @ This should ideally be changed to do whatever is necessary to create the
16166 \.{MPX} file given by |name_of_file| if it does not exist or if it is out
16167 of date.  This requires invoking \.{MPtoTeX} on the |old_file_name| and passing
16168 the results through \TeX\ and \.{DVItoMP}.  (It is possible to use a
16169 completely different typesetting program if suitable postprocessor is
16170 available to perform the function of \.{DVItoMP}.)
16171 @^system dependencies@>
16172
16173 @ @<Types...@>=
16174 typedef boolean (*run_make_mpx_command)(MP mp, char *origname, char *mtxname);
16175
16176 @ @<Glob...@>=
16177 run_make_mpx_command run_make_mpx;
16178
16179 @ @<Option variables@>=
16180 run_make_mpx_command run_make_mpx;
16181
16182 @ @<Allocate or initialize ...@>=
16183 set_callback_option(run_make_mpx);
16184
16185 @ @<Exported function headers@>=
16186 boolean mp_run_make_mpx (MP mp, char *origname, char *mtxname);
16187
16188 @ The default does nothing.
16189 @c 
16190 boolean mp_run_make_mpx (MP mp, char *origname, char *mtxname) {
16191   if (mp && origname && mtxname) /* for -W */
16192     return false;
16193   return false;
16194 }
16195
16196
16197
16198 @ @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16199   |goto not_found| if there is a problem@>=
16200 mp_copy_old_name(mp, name);
16201 if (!(mp->run_make_mpx)(mp, mp->old_file_name, mp->name_of_file))
16202    goto NOT_FOUND
16203
16204 @ @<Explain that the \.{MPX} file can't be read and |succumb|@>=
16205 if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16206 mp_print_nl(mp, ">> ");
16207 mp_print(mp, mp->old_file_name);
16208 mp_print_nl(mp, ">> ");
16209 mp_print(mp, mp->name_of_file);
16210 mp_print_nl(mp, "! Unable to make mpx file");
16211 help4("The two files given above are one of your source files")
16212   ("and an auxiliary file I need to read to find out what your")
16213   ("btex..etex blocks mean. If you don't know why I had trouble,")
16214   ("try running it manually through MPtoTeX, TeX, and DVItoMP");
16215 succumb;
16216
16217 @ The last file-opening commands are for files accessed via the \&{readfrom}
16218 @:read_from_}{\&{readfrom} primitive@>
16219 operator and the \&{write} command.  Such files are stored in separate arrays.
16220 @:write_}{\&{write} primitive@>
16221
16222 @<Types in the outer block@>=
16223 typedef unsigned int readf_index; /* |0..max_read_files| */
16224 typedef unsigned int write_index;  /* |0..max_write_files| */
16225
16226 @ @<Glob...@>=
16227 readf_index max_read_files; /* maximum number of simultaneously open \&{readfrom} files */
16228 FILE ** rd_file; /* \&{readfrom} files */
16229 char ** rd_fname; /* corresponding file name or 0 if file not open */
16230 readf_index read_files; /* number of valid entries in the above arrays */
16231 write_index max_write_files; /* maximum number of simultaneously open \&{write} */
16232 FILE ** wr_file; /* \&{write} files */
16233 char ** wr_fname; /* corresponding file name or 0 if file not open */
16234 write_index write_files; /* number of valid entries in the above arrays */
16235
16236 @ @<Allocate or initialize ...@>=
16237 mp->max_read_files=8;
16238 mp->rd_file = xmalloc((mp->max_read_files+1),sizeof(FILE *));
16239 mp->rd_fname = xmalloc((mp->max_read_files+1),sizeof(char *));
16240 memset(mp->rd_fname, 0, sizeof(char *)*(mp->max_read_files+1));
16241 mp->read_files=0;
16242 mp->max_write_files=8;
16243 mp->wr_file = xmalloc((mp->max_write_files+1),sizeof(FILE *));
16244 mp->wr_fname = xmalloc((mp->max_write_files+1),sizeof(char *));
16245 memset(mp->wr_fname, 0, sizeof(char *)*(mp->max_write_files+1));
16246 mp->write_files=0;
16247
16248
16249 @ This routine starts reading the file named by string~|s| without setting
16250 |loc|, |limit|, or |name|.  It returns |false| if the file is empty or cannot
16251 be opened.  Otherwise it updates |rd_file[n]| and |rd_fname[n]|.
16252
16253 @c boolean mp_start_read_input (MP mp,char *s, readf_index  n) {
16254   mp_ptr_scan_file(mp, s);
16255   pack_cur_name;
16256   mp_begin_file_reading(mp);
16257   if ( ! mp_a_open_in(mp, &mp->rd_file[n], mp_filetype_text) ) 
16258         goto NOT_FOUND;
16259   if ( ! mp_input_ln(mp, mp->rd_file[n], false) ) {
16260     fclose(mp->rd_file[n]); 
16261         goto NOT_FOUND; 
16262   }
16263   mp->rd_fname[n]=xstrdup(mp->name_of_file);
16264   return true;
16265 NOT_FOUND: 
16266   mp_end_file_reading(mp);
16267   return false;
16268 }
16269
16270 @ Open |wr_file[n]| using file name~|s| and update |wr_fname[n]|.
16271
16272 @<Declarations@>=
16273 void mp_open_write_file (MP mp, char *s, readf_index  n) ;
16274
16275 @ @c void mp_open_write_file (MP mp,char *s, readf_index  n) {
16276   mp_ptr_scan_file(mp, s);
16277   pack_cur_name;
16278   while ( ! mp_a_open_out(mp, &mp->wr_file[n], mp_filetype_text) )
16279     mp_prompt_file_name(mp, "file name for write output","");
16280   mp->wr_fname[n]=xstrdup(mp->name_of_file);
16281 }
16282
16283
16284 @* \[36] Introduction to the parsing routines.
16285 We come now to the central nervous system that sparks many of \MP's activities.
16286 By evaluating expressions, from their primary constituents to ever larger
16287 subexpressions, \MP\ builds the structures that ultimately define complete
16288 pictures or fonts of type.
16289
16290 Four mutually recursive subroutines are involved in this process: We call them
16291 $$\hbox{|scan_primary|, |scan_secondary|, |scan_tertiary|,
16292 and |scan_expression|.}$$
16293 @^recursion@>
16294 Each of them is parameterless and begins with the first token to be scanned
16295 already represented in |cur_cmd|, |cur_mod|, and |cur_sym|. After execution,
16296 the value of the primary or secondary or tertiary or expression that was
16297 found will appear in the global variables |cur_type| and |cur_exp|. The
16298 token following the expression will be represented in |cur_cmd|, |cur_mod|,
16299 and |cur_sym|.
16300
16301 Technically speaking, the parsing algorithms are ``LL(1),'' more or less;
16302 backup mechanisms have been added in order to provide reasonable error
16303 recovery.
16304
16305 @<Glob...@>=
16306 small_number cur_type; /* the type of the expression just found */
16307 integer cur_exp; /* the value of the expression just found */
16308
16309 @ @<Set init...@>=
16310 mp->cur_exp=0;
16311
16312 @ Many different kinds of expressions are possible, so it is wise to have
16313 precise descriptions of what |cur_type| and |cur_exp| mean in all cases:
16314
16315 \smallskip\hang
16316 |cur_type=mp_vacuous| means that this expression didn't turn out to have a
16317 value at all, because it arose from a \&{begingroup}$\,\ldots\,$\&{endgroup}
16318 construction in which there was no expression before the \&{endgroup}.
16319 In this case |cur_exp| has some irrelevant value.
16320
16321 \smallskip\hang
16322 |cur_type=mp_boolean_type| means that |cur_exp| is either |true_code|
16323 or |false_code|.
16324
16325 \smallskip\hang
16326 |cur_type=mp_unknown_boolean| means that |cur_exp| points to a capsule
16327 node that is in the ring of variables equivalent
16328 to at least one undefined boolean variable.
16329
16330 \smallskip\hang
16331 |cur_type=mp_string_type| means that |cur_exp| is a string number (i.e., an
16332 integer in the range |0<=cur_exp<str_ptr|). That string's reference count
16333 includes this particular reference.
16334
16335 \smallskip\hang
16336 |cur_type=mp_unknown_string| means that |cur_exp| points to a capsule
16337 node that is in the ring of variables equivalent
16338 to at least one undefined string variable.
16339
16340 \smallskip\hang
16341 |cur_type=mp_pen_type| means that |cur_exp| points to a node in a pen.  Nobody
16342 else points to any of the nodes in this pen.  The pen may be polygonal or
16343 elliptical.
16344
16345 \smallskip\hang
16346 |cur_type=mp_unknown_pen| means that |cur_exp| points to a capsule
16347 node that is in the ring of variables equivalent
16348 to at least one undefined pen variable.
16349
16350 \smallskip\hang
16351 |cur_type=mp_path_type| means that |cur_exp| points to a the first node of
16352 a path; nobody else points to this particular path. The control points of
16353 the path will have been chosen.
16354
16355 \smallskip\hang
16356 |cur_type=mp_unknown_path| means that |cur_exp| points to a capsule
16357 node that is in the ring of variables equivalent
16358 to at least one undefined path variable.
16359
16360 \smallskip\hang
16361 |cur_type=mp_picture_type| means that |cur_exp| points to an edge header node.
16362 There may be other pointers to this particular set of edges.  The header node
16363 contains a reference count that includes this particular reference.
16364
16365 \smallskip\hang
16366 |cur_type=mp_unknown_picture| means that |cur_exp| points to a capsule
16367 node that is in the ring of variables equivalent
16368 to at least one undefined picture variable.
16369
16370 \smallskip\hang
16371 |cur_type=mp_transform_type| means that |cur_exp| points to a |mp_transform_type|
16372 capsule node. The |value| part of this capsule
16373 points to a transform node that contains six numeric values,
16374 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16375
16376 \smallskip\hang
16377 |cur_type=mp_color_type| means that |cur_exp| points to a |color_type|
16378 capsule node. The |value| part of this capsule
16379 points to a color node that contains three numeric values,
16380 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16381
16382 \smallskip\hang
16383 |cur_type=mp_cmykcolor_type| means that |cur_exp| points to a |mp_cmykcolor_type|
16384 capsule node. The |value| part of this capsule
16385 points to a color node that contains four numeric values,
16386 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16387
16388 \smallskip\hang
16389 |cur_type=mp_pair_type| means that |cur_exp| points to a capsule
16390 node whose type is |mp_pair_type|. The |value| part of this capsule
16391 points to a pair node that contains two numeric values,
16392 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16393
16394 \smallskip\hang
16395 |cur_type=mp_known| means that |cur_exp| is a |scaled| value.
16396
16397 \smallskip\hang
16398 |cur_type=mp_dependent| means that |cur_exp| points to a capsule node whose type
16399 is |dependent|. The |dep_list| field in this capsule points to the associated
16400 dependency list.
16401
16402 \smallskip\hang
16403 |cur_type=mp_proto_dependent| means that |cur_exp| points to a |mp_proto_dependent|
16404 capsule node. The |dep_list| field in this capsule
16405 points to the associated dependency list.
16406
16407 \smallskip\hang
16408 |cur_type=independent| means that |cur_exp| points to a capsule node
16409 whose type is |independent|. This somewhat unusual case can arise, for
16410 example, in the expression
16411 `$x+\&{begingroup}\penalty0\,\&{string}\,x; 0\,\&{endgroup}$'.
16412
16413 \smallskip\hang
16414 |cur_type=mp_token_list| means that |cur_exp| points to a linked list of
16415 tokens. This case arises only on the left-hand side of an assignment
16416 (`\.{:=}') operation, under very special circumstances.
16417
16418 \smallskip\noindent
16419 The possible settings of |cur_type| have been listed here in increasing
16420 numerical order. Notice that |cur_type| will never be |mp_numeric_type| or
16421 |suffixed_macro| or |mp_unsuffixed_macro|, although variables of those types
16422 are allowed.  Conversely, \MP\ has no variables of type |mp_vacuous| or
16423 |token_list|.
16424
16425 @ Capsules are two-word nodes that have a similar meaning
16426 to |cur_type| and |cur_exp|. Such nodes have |name_type=capsule|
16427 and |link<=diov|; and their |type| field is one of the possibilities for
16428 |cur_type| listed above.
16429
16430 The |value| field of a capsule is, in most cases, the value that
16431 corresponds to its |type|, as |cur_exp| corresponds to |cur_type|.
16432 However, when |cur_exp| would point to a capsule,
16433 no extra layer of indirection is present; the |value|
16434 field is what would have been called |value(cur_exp)| if it had not been
16435 encapsulated.  Furthermore, if the type is |dependent| or
16436 |mp_proto_dependent|, the |value| field of a capsule is replaced by
16437 |dep_list| and |prev_dep| fields, since dependency lists in capsules are
16438 always part of the general |dep_list| structure.
16439
16440 The |get_x_next| routine is careful not to change the values of |cur_type|
16441 and |cur_exp| when it gets an expanded token. However, |get_x_next| might
16442 call a macro, which might parse an expression, which might execute lots of
16443 commands in a group; hence it's possible that |cur_type| might change
16444 from, say, |mp_unknown_boolean| to |mp_boolean_type|, or from |dependent| to
16445 |known| or |independent|, during the time |get_x_next| is called. The
16446 programs below are careful to stash sensitive intermediate results in
16447 capsules, so that \MP's generality doesn't cause trouble.
16448
16449 Here's a procedure that illustrates these conventions. It takes
16450 the contents of $(|cur_type|\kern-.3pt,|cur_exp|\kern-.3pt)$
16451 and stashes them away in a
16452 capsule. It is not used when |cur_type=mp_token_list|.
16453 After the operation, |cur_type=mp_vacuous|; hence there is no need to
16454 copy path lists or to update reference counts, etc.
16455
16456 The special link |diov| is put on the capsule returned by
16457 |stash_cur_exp|, because this procedure is used to store macro parameters
16458 that must be easily distinguishable from token lists.
16459
16460 @<Declare the stashing/unstashing routines@>=
16461 pointer mp_stash_cur_exp (MP mp) {
16462   pointer p; /* the capsule that will be returned */
16463   switch (mp->cur_type) {
16464   case unknown_types:
16465   case mp_transform_type:
16466   case mp_color_type:
16467   case mp_pair_type:
16468   case mp_dependent:
16469   case mp_proto_dependent:
16470   case mp_independent: 
16471   case mp_cmykcolor_type:
16472     p=mp->cur_exp;
16473     break;
16474   default: 
16475     p=mp_get_node(mp, value_node_size); name_type(p)=mp_capsule;
16476     type(p)=mp->cur_type; value(p)=mp->cur_exp;
16477     break;
16478   }
16479   mp->cur_type=mp_vacuous; link(p)=diov; 
16480   return p;
16481 }
16482
16483 @ The inverse of |stash_cur_exp| is the following procedure, which
16484 deletes an unnecessary capsule and puts its contents into |cur_type|
16485 and |cur_exp|.
16486
16487 The program steps of \MP\ can be divided into two categories: those in
16488 which |cur_type| and |cur_exp| are ``alive'' and those in which they are
16489 ``dead,'' in the sense that |cur_type| and |cur_exp| contain relevant
16490 information or not. It's important not to ignore them when they're alive,
16491 and it's important not to pay attention to them when they're dead.
16492
16493 There's also an intermediate category: If |cur_type=mp_vacuous|, then
16494 |cur_exp| is irrelevant, hence we can proceed without caring if |cur_type|
16495 and |cur_exp| are alive or dead. In such cases we say that |cur_type|
16496 and |cur_exp| are {\sl dormant}. It is permissible to call |get_x_next|
16497 only when they are alive or dormant.
16498
16499 The \\{stash} procedure above assumes that |cur_type| and |cur_exp|
16500 are alive or dormant. The \\{unstash} procedure assumes that they are
16501 dead or dormant; it resuscitates them.
16502
16503 @<Declare the stashing/unstashing...@>=
16504 void mp_unstash_cur_exp (MP mp,pointer p) ;
16505
16506 @ @c
16507 void mp_unstash_cur_exp (MP mp,pointer p) { 
16508   mp->cur_type=type(p);
16509   switch (mp->cur_type) {
16510   case unknown_types:
16511   case mp_transform_type:
16512   case mp_color_type:
16513   case mp_pair_type:
16514   case mp_dependent: 
16515   case mp_proto_dependent:
16516   case mp_independent:
16517   case mp_cmykcolor_type: 
16518     mp->cur_exp=p;
16519     break;
16520   default:
16521     mp->cur_exp=value(p);
16522     mp_free_node(mp, p,value_node_size);
16523     break;
16524   }
16525 }
16526
16527 @ The following procedure prints the values of expressions in an
16528 abbreviated format. If its first parameter |p| is null, the value of
16529 |(cur_type,cur_exp)| is displayed; otherwise |p| should be a capsule
16530 containing the desired value. The second parameter controls the amount of
16531 output. If it is~0, dependency lists will be abbreviated to
16532 `\.{linearform}' unless they consist of a single term.  If it is greater
16533 than~1, complicated structures (pens, pictures, and paths) will be displayed
16534 in full.
16535
16536 @<Declare subroutines for printing expressions@>=
16537 @<Declare the procedure called |print_dp|@>;
16538 @<Declare the stashing/unstashing routines@>;
16539 void mp_print_exp (MP mp,pointer p, small_number verbosity) {
16540   boolean restore_cur_exp; /* should |cur_exp| be restored? */
16541   small_number t; /* the type of the expression */
16542   pointer q; /* a big node being displayed */
16543   integer v=0; /* the value of the expression */
16544   if ( p!=null ) {
16545     restore_cur_exp=false;
16546   } else { 
16547     p=mp_stash_cur_exp(mp); restore_cur_exp=true;
16548   }
16549   t=type(p);
16550   if ( t<mp_dependent ) v=value(p); else if ( t<mp_independent ) v=dep_list(p);
16551   @<Print an abbreviated value of |v| with format depending on |t|@>;
16552   if ( restore_cur_exp ) mp_unstash_cur_exp(mp, p);
16553 }
16554
16555 @ @<Print an abbreviated value of |v| with format depending on |t|@>=
16556 switch (t) {
16557 case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
16558 case mp_boolean_type:
16559   if ( v==true_code ) mp_print(mp, "true"); else mp_print(mp, "false");
16560   break;
16561 case unknown_types: case mp_numeric_type:
16562   @<Display a variable that's been declared but not defined@>;
16563   break;
16564 case mp_string_type:
16565   mp_print_char(mp, '"'); mp_print_str(mp, v); mp_print_char(mp, '"');
16566   break;
16567 case mp_pen_type: case mp_path_type: case mp_picture_type:
16568   @<Display a complex type@>;
16569   break;
16570 case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_cmykcolor_type:
16571   if ( v==null ) mp_print_type(mp, t);
16572   else @<Display a big node@>;
16573   break;
16574 case mp_known:mp_print_scaled(mp, v); break;
16575 case mp_dependent: case mp_proto_dependent:
16576   mp_print_dp(mp, t,v,verbosity);
16577   break;
16578 case mp_independent:mp_print_variable_name(mp, p); break;
16579 default: mp_confusion(mp, "exp"); break;
16580 @:this can't happen exp}{\quad exp@>
16581 }
16582
16583 @ @<Display a big node@>=
16584
16585   mp_print_char(mp, '('); q=v+mp->big_node_size[t];
16586   do {  
16587     if ( type(v)==mp_known ) mp_print_scaled(mp, value(v));
16588     else if ( type(v)==mp_independent ) mp_print_variable_name(mp, v);
16589     else mp_print_dp(mp, type(v),dep_list(v),verbosity);
16590     v=v+2;
16591     if ( v!=q ) mp_print_char(mp, ',');
16592   } while (v!=q);
16593   mp_print_char(mp, ')');
16594 }
16595
16596 @ Values of type \&{picture}, \&{path}, and \&{pen} are displayed verbosely
16597 in the log file only, unless the user has given a positive value to
16598 \\{tracingonline}.
16599
16600 @<Display a complex type@>=
16601 if ( verbosity<=1 ) {
16602   mp_print_type(mp, t);
16603 } else { 
16604   if ( mp->selector==term_and_log )
16605    if ( mp->internal[tracing_online]<=0 ) {
16606     mp->selector=term_only;
16607     mp_print_type(mp, t); mp_print(mp, " (see the transcript file)");
16608     mp->selector=term_and_log;
16609   };
16610   switch (t) {
16611   case mp_pen_type:mp_print_pen(mp, v,"",false); break;
16612   case mp_path_type:mp_print_path(mp, v,"",false); break;
16613   case mp_picture_type:mp_print_edges(mp, v,"",false); break;
16614   } /* there are no other cases */
16615 }
16616
16617 @ @<Declare the procedure called |print_dp|@>=
16618 void mp_print_dp (MP mp,small_number t, pointer p, 
16619                   small_number verbosity)  {
16620   pointer q; /* the node following |p| */
16621   q=link(p);
16622   if ( (info(q)==null) || (verbosity>0) ) mp_print_dependency(mp, p,t);
16623   else mp_print(mp, "linearform");
16624 }
16625
16626 @ The displayed name of a variable in a ring will not be a capsule unless
16627 the ring consists entirely of capsules.
16628
16629 @<Display a variable that's been declared but not defined@>=
16630 { mp_print_type(mp, t);
16631 if ( v!=null )
16632   { mp_print_char(mp, ' ');
16633   while ( (name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
16634   mp_print_variable_name(mp, v);
16635   };
16636 }
16637
16638 @ When errors are detected during parsing, it is often helpful to
16639 display an expression just above the error message, using |exp_err|
16640 or |disp_err| instead of |print_err|.
16641
16642 @d exp_err(A) mp_disp_err(mp, null,(A)) /* displays the current expression */
16643
16644 @<Declare subroutines for printing expressions@>=
16645 void mp_disp_err (MP mp,pointer p, char *s) { 
16646   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16647   mp_print_nl(mp, ">> ");
16648 @.>>@>
16649   mp_print_exp(mp, p,1); /* ``medium verbose'' printing of the expression */
16650   if (strlen(s)) { 
16651     mp_print_nl(mp, "! "); mp_print(mp, s);
16652 @.!\relax@>
16653   }
16654 }
16655
16656 @ If |cur_type| and |cur_exp| contain relevant information that should
16657 be recycled, we will use the following procedure, which changes |cur_type|
16658 to |known| and stores a given value in |cur_exp|. We can think of |cur_type|
16659 and |cur_exp| as either alive or dormant after this has been done,
16660 because |cur_exp| will not contain a pointer value.
16661
16662 @ @c void mp_flush_cur_exp (MP mp,scaled v) { 
16663   switch (mp->cur_type) {
16664   case unknown_types: case mp_transform_type: case mp_color_type: case mp_pair_type:
16665   case mp_dependent: case mp_proto_dependent: case mp_independent: case mp_cmykcolor_type:
16666     mp_recycle_value(mp, mp->cur_exp); 
16667     mp_free_node(mp, mp->cur_exp,value_node_size);
16668     break;
16669   case mp_string_type:
16670     delete_str_ref(mp->cur_exp); break;
16671   case mp_pen_type: case mp_path_type: 
16672     mp_toss_knot_list(mp, mp->cur_exp); break;
16673   case mp_picture_type:
16674     delete_edge_ref(mp->cur_exp); break;
16675   default: 
16676     break;
16677   }
16678   mp->cur_type=mp_known; mp->cur_exp=v;
16679 }
16680
16681 @ There's a much more general procedure that is capable of releasing
16682 the storage associated with any two-word value packet.
16683
16684 @<Declare the recycling subroutines@>=
16685 void mp_recycle_value (MP mp,pointer p) ;
16686
16687 @ @c void mp_recycle_value (MP mp,pointer p) {
16688   small_number t; /* a type code */
16689   integer vv; /* another value */
16690   pointer q,r,s,pp; /* link manipulation registers */
16691   integer v=0; /* a value */
16692   t=type(p);
16693   if ( t<mp_dependent ) v=value(p);
16694   switch (t) {
16695   case undefined: case mp_vacuous: case mp_boolean_type: case mp_known:
16696   case mp_numeric_type:
16697     break;
16698   case unknown_types:
16699     mp_ring_delete(mp, p); break;
16700   case mp_string_type:
16701     delete_str_ref(v); break;
16702   case mp_path_type: case mp_pen_type:
16703     mp_toss_knot_list(mp, v); break;
16704   case mp_picture_type:
16705     delete_edge_ref(v); break;
16706   case mp_cmykcolor_type: case mp_pair_type: case mp_color_type:
16707   case mp_transform_type:
16708     @<Recycle a big node@>; break; 
16709   case mp_dependent: case mp_proto_dependent:
16710     @<Recycle a dependency list@>; break;
16711   case mp_independent:
16712     @<Recycle an independent variable@>; break;
16713   case mp_token_list: case mp_structured:
16714     mp_confusion(mp, "recycle"); break;
16715 @:this can't happen recycle}{\quad recycle@>
16716   case mp_unsuffixed_macro: case mp_suffixed_macro:
16717     mp_delete_mac_ref(mp, value(p)); break;
16718   } /* there are no other cases */
16719   type(p)=undefined;
16720 }
16721
16722 @ @<Recycle a big node@>=
16723 if ( v!=null ){ 
16724   q=v+mp->big_node_size[t];
16725   do {  
16726     q=q-2; mp_recycle_value(mp, q);
16727   } while (q!=v);
16728   mp_free_node(mp, v,mp->big_node_size[t]);
16729 }
16730
16731 @ @<Recycle a dependency list@>=
16732
16733   q=dep_list(p);
16734   while ( info(q)!=null ) q=link(q);
16735   link(prev_dep(p))=link(q);
16736   prev_dep(link(q))=prev_dep(p);
16737   link(q)=null; mp_flush_node_list(mp, dep_list(p));
16738 }
16739
16740 @ When an independent variable disappears, it simply fades away, unless
16741 something depends on it. In the latter case, a dependent variable whose
16742 coefficient of dependence is maximal will take its place.
16743 The relevant algorithm is due to Ignacio~A. Zabala, who implemented it
16744 as part of his Ph.D. thesis (Stanford University, December 1982).
16745 @^Zabala Salelles, Ignacio Andres@>
16746
16747 For example, suppose that variable $x$ is being recycled, and that the
16748 only variables depending on~$x$ are $y=2x+a$ and $z=x+b$. In this case
16749 we want to make $y$ independent and $z=.5y-.5a+b$; no other variables
16750 will depend on~$y$. If $\\{tracingequations}>0$ in this situation,
16751 we will print `\.{\#\#\# -2x=-y+a}'.
16752
16753 There's a slight complication, however: An independent variable $x$
16754 can occur both in dependency lists and in proto-dependency lists.
16755 This makes it necessary to be careful when deciding which coefficient
16756 is maximal.
16757
16758 Furthermore, this complication is not so slight when
16759 a proto-dependent variable is chosen to become independent. For example,
16760 suppose that $y=2x+100a$ is proto-dependent while $z=x+b$ is dependent;
16761 then we must change $z=.5y-50a+b$ to a proto-dependency, because of the
16762 large coefficient `50'.
16763
16764 In order to deal with these complications without wasting too much time,
16765 we shall link together the occurrences of~$x$ among all the linear
16766 dependencies, maintaining separate lists for the dependent and
16767 proto-dependent cases.
16768
16769 @<Recycle an independent variable@>=
16770
16771   mp->max_c[mp_dependent]=0; mp->max_c[mp_proto_dependent]=0;
16772   mp->max_link[mp_dependent]=null; mp->max_link[mp_proto_dependent]=null;
16773   q=link(dep_head);
16774   while ( q!=dep_head ) { 
16775     s=value_loc(q); /* now |link(s)=dep_list(q)| */
16776     while (1) { 
16777       r=link(s);
16778       if ( info(r)==null ) break;;
16779       if ( info(r)!=p ) { 
16780        s=r;
16781       } else  { 
16782         t=type(q); link(s)=link(r); info(r)=q;
16783         if ( abs(value(r))>mp->max_c[t] ) {
16784           @<Record a new maximum coefficient of type |t|@>;
16785         } else { 
16786           link(r)=mp->max_link[t]; mp->max_link[t]=r;
16787         }
16788       }
16789     }   
16790     q=link(r);
16791   }
16792   if ( (mp->max_c[mp_dependent]>0)||(mp->max_c[mp_proto_dependent]>0) ) {
16793     @<Choose a dependent variable to take the place of the disappearing
16794     independent variable, and change all remaining dependencies
16795     accordingly@>;
16796   }
16797 }
16798
16799 @ The code for independency removal makes use of three two-word arrays.
16800
16801 @<Glob...@>=
16802 integer max_c[mp_proto_dependent+1];  /* max coefficient magnitude */
16803 pointer max_ptr[mp_proto_dependent+1]; /* where |p| occurs with |max_c| */
16804 pointer max_link[mp_proto_dependent+1]; /* other occurrences of |p| */
16805
16806 @ @<Record a new maximum coefficient...@>=
16807
16808   if ( mp->max_c[t]>0 ) {
16809     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
16810   }
16811   mp->max_c[t]=abs(value(r)); mp->max_ptr[t]=r;
16812 }
16813
16814 @ @<Choose a dependent...@>=
16815
16816   if ( (mp->max_c[mp_dependent] / 010000 >= mp->max_c[mp_proto_dependent]) )
16817     t=mp_dependent;
16818   else 
16819     t=mp_proto_dependent;
16820   @<Determine the dependency list |s| to substitute for the independent
16821     variable~|p|@>;
16822   t=mp_dependent+mp_proto_dependent-t; /* complement |t| */
16823   if ( mp->max_c[t]>0 ) { /* we need to pick up an unchosen dependency */ 
16824     link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
16825   }
16826   if ( t!=mp_dependent ) { @<Substitute new dependencies in place of |p|@>; }
16827   else { @<Substitute new proto-dependencies in place of |p|@>;}
16828   mp_flush_node_list(mp, s);
16829   if ( mp->fix_needed ) mp_fix_dependencies(mp);
16830   check_arith;
16831 }
16832
16833 @ Let |s=max_ptr[t]|. At this point we have $|value|(s)=\pm|max_c|[t]$,
16834 and |info(s)| points to the dependent variable~|pp| of type~|t| from
16835 whose dependency list we have removed node~|s|. We must reinsert
16836 node~|s| into the dependency list, with coefficient $-1.0$, and with
16837 |pp| as the new independent variable. Since |pp| will have a larger serial
16838 number than any other variable, we can put node |s| at the head of the
16839 list.
16840
16841 @<Determine the dep...@>=
16842 s=mp->max_ptr[t]; pp=info(s); v=value(s);
16843 if ( t==mp_dependent ) value(s)=-fraction_one; else value(s)=-unity;
16844 r=dep_list(pp); link(s)=r;
16845 while ( info(r)!=null ) r=link(r);
16846 q=link(r); link(r)=null;
16847 prev_dep(q)=prev_dep(pp); link(prev_dep(pp))=q;
16848 new_indep(pp);
16849 if ( mp->cur_exp==pp ) if ( mp->cur_type==t ) mp->cur_type=mp_independent;
16850 if ( mp->internal[tracing_equations]>0 ) { 
16851   @<Show the transformed dependency@>; 
16852 }
16853
16854 @ Now $(-v)$ times the formerly independent variable~|p| is being replaced
16855 by the dependency list~|s|.
16856
16857 @<Show the transformed...@>=
16858 if ( mp_interesting(mp, p) ) {
16859   mp_begin_diagnostic(mp); mp_print_nl(mp, "### ");
16860 @:]]]\#\#\#_}{\.{\#\#\#}@>
16861   if ( v>0 ) mp_print_char(mp, '-');
16862   if ( t==mp_dependent ) vv=mp_round_fraction(mp, mp->max_c[mp_dependent]);
16863   else vv=mp->max_c[mp_proto_dependent];
16864   if ( vv!=unity ) mp_print_scaled(mp, vv);
16865   mp_print_variable_name(mp, p);
16866   while ( value(p) % s_scale>0 ) {
16867     mp_print(mp, "*4"); value(p)=value(p)-2;
16868   }
16869   if ( t==mp_dependent ) mp_print_char(mp, '='); else mp_print(mp, " = ");
16870   mp_print_dependency(mp, s,t);
16871   mp_end_diagnostic(mp, false);
16872 }
16873
16874 @ Finally, there are dependent and proto-dependent variables whose
16875 dependency lists must be brought up to date.
16876
16877 @<Substitute new dependencies...@>=
16878 for (t=mp_dependent;t<=mp_proto_dependent;t++){ 
16879   r=mp->max_link[t];
16880   while ( r!=null ) {
16881     q=info(r);
16882     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
16883      mp_make_fraction(mp, value(r),-v),s,t,mp_dependent);
16884     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
16885     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
16886   }
16887 }
16888
16889 @ @<Substitute new proto...@>=
16890 for (t=mp_dependent;t<=mp_proto_dependent;t++) {
16891   r=mp->max_link[t];
16892   while ( r!=null ) {
16893     q=info(r);
16894     if ( t==mp_dependent ) { /* for safety's sake, we change |q| to |mp_proto_dependent| */
16895       if ( mp->cur_exp==q ) if ( mp->cur_type==mp_dependent )
16896         mp->cur_type=mp_proto_dependent;
16897       dep_list(q)=mp_p_over_v(mp, dep_list(q),unity,mp_dependent,mp_proto_dependent);
16898       type(q)=mp_proto_dependent; value(r)=mp_round_fraction(mp, value(r));
16899     }
16900     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
16901       mp_make_scaled(mp, value(r),-v),s,mp_proto_dependent,mp_proto_dependent);
16902     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
16903     q=r; r=link(r); mp_free_node(mp, q,dep_node_size);
16904   }
16905 }
16906
16907 @ Here are some routines that provide handy combinations of actions
16908 that are often needed during error recovery. For example,
16909 `|flush_error|' flushes the current expression, replaces it by
16910 a given value, and calls |error|.
16911
16912 Errors often are detected after an extra token has already been scanned.
16913 The `\\{put\_get}' routines put that token back before calling |error|;
16914 then they get it back again. (Or perhaps they get another token, if
16915 the user has changed things.)
16916
16917 @<Declarations@>=
16918 void mp_flush_error (MP mp,scaled v);
16919 void mp_put_get_error (MP mp);
16920 void mp_put_get_flush_error (MP mp,scaled v) ;
16921
16922 @ @c
16923 void mp_flush_error (MP mp,scaled v) { 
16924   mp_error(mp); mp_flush_cur_exp(mp, v); 
16925 }
16926 void mp_put_get_error (MP mp) { 
16927   mp_back_error(mp); mp_get_x_next(mp); 
16928 }
16929 void mp_put_get_flush_error (MP mp,scaled v) { 
16930   mp_put_get_error(mp);
16931   mp_flush_cur_exp(mp, v); 
16932 }
16933
16934 @ A global variable |var_flag| is set to a special command code
16935 just before \MP\ calls |scan_expression|, if the expression should be
16936 treated as a variable when this command code immediately follows. For
16937 example, |var_flag| is set to |assignment| at the beginning of a
16938 statement, because we want to know the {\sl location\/} of a variable at
16939 the left of `\.{:=}', not the {\sl value\/} of that variable.
16940
16941 The |scan_expression| subroutine calls |scan_tertiary|,
16942 which calls |scan_secondary|, which calls |scan_primary|, which sets
16943 |var_flag:=0|. In this way each of the scanning routines ``knows''
16944 when it has been called with a special |var_flag|, but |var_flag| is
16945 usually zero.
16946
16947 A variable preceding a command that equals |var_flag| is converted to a
16948 token list rather than a value. Furthermore, an `\.{=}' sign following an
16949 expression with |var_flag=assignment| is not considered to be a relation
16950 that produces boolean expressions.
16951
16952
16953 @<Glob...@>=
16954 int var_flag; /* command that wants a variable */
16955
16956 @ @<Set init...@>=
16957 mp->var_flag=0;
16958
16959 @* \[37] Parsing primary expressions.
16960 The first parsing routine, |scan_primary|, is also the most complicated one,
16961 since it involves so many different cases. But each case---with one
16962 exception---is fairly simple by itself.
16963
16964 When |scan_primary| begins, the first token of the primary to be scanned
16965 should already appear in |cur_cmd|, |cur_mod|, and |cur_sym|. The values
16966 of |cur_type| and |cur_exp| should be either dead or dormant, as explained
16967 earlier. If |cur_cmd| is not between |min_primary_command| and
16968 |max_primary_command|, inclusive, a syntax error will be signaled.
16969
16970 @<Declare the basic parsing subroutines@>=
16971 void mp_scan_primary (MP mp) {
16972   pointer p,q,r; /* for list manipulation */
16973   quarterword c; /* a primitive operation code */
16974   int my_var_flag; /* initial value of |my_var_flag| */
16975   pointer l_delim,r_delim; /* hash addresses of a delimiter pair */
16976   @<Other local variables for |scan_primary|@>;
16977   my_var_flag=mp->var_flag; mp->var_flag=0;
16978 RESTART:
16979   check_arith;
16980   @<Supply diagnostic information, if requested@>;
16981   switch (mp->cur_cmd) {
16982   case left_delimiter:
16983     @<Scan a delimited primary@>; break;
16984   case begin_group:
16985     @<Scan a grouped primary@>; break;
16986   case string_token:
16987     @<Scan a string constant@>; break;
16988   case numeric_token:
16989     @<Scan a primary that starts with a numeric token@>; break;
16990   case nullary:
16991     @<Scan a nullary operation@>; break;
16992   case unary: case type_name: case cycle: case plus_or_minus:
16993     @<Scan a unary operation@>; break;
16994   case primary_binary:
16995     @<Scan a binary operation with `\&{of}' between its operands@>; break;
16996   case str_op:
16997     @<Convert a suffix to a string@>; break;
16998   case internal_quantity:
16999     @<Scan an internal numeric quantity@>; break;
17000   case capsule_token:
17001     mp_make_exp_copy(mp, mp->cur_mod); break;
17002   case tag_token:
17003     @<Scan a variable primary; |goto restart| if it turns out to be a macro@>; break;
17004   default: 
17005     mp_bad_exp(mp, "A primary"); goto RESTART; break;
17006 @.A primary expression...@>
17007   }
17008   mp_get_x_next(mp); /* the routines |goto done| if they don't want this */
17009 DONE: 
17010   if ( mp->cur_cmd==left_bracket ) {
17011     if ( mp->cur_type>=mp_known ) {
17012       @<Scan a mediation construction@>;
17013     }
17014   }
17015 }
17016
17017
17018
17019 @ Errors at the beginning of expressions are flagged by |bad_exp|.
17020
17021 @c void mp_bad_exp (MP mp,char * s) {
17022   int save_flag;
17023   print_err(s); mp_print(mp, " expression can't begin with `");
17024   mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); 
17025   mp_print_char(mp, '\'');
17026   help4("I'm afraid I need some sort of value in order to continue,")
17027     ("so I've tentatively inserted `0'. You may want to")
17028     ("delete this zero and insert something else;")
17029     ("see Chapter 27 of The METAFONTbook for an example.");
17030 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17031   mp_back_input(mp); mp->cur_sym=0; mp->cur_cmd=numeric_token; 
17032   mp->cur_mod=0; mp_ins_error(mp);
17033   save_flag=mp->var_flag; mp->var_flag=0; mp_get_x_next(mp);
17034   mp->var_flag=save_flag;
17035 }
17036
17037 @ @<Supply diagnostic information, if requested@>=
17038 #ifdef DEBUG
17039 if ( mp->panicking ) mp_check_mem(mp, false);
17040 #endif
17041 if ( mp->interrupt!=0 ) if ( mp->OK_to_interrupt ) {
17042   mp_back_input(mp); check_interrupt; mp_get_x_next(mp);
17043 }
17044
17045 @ @<Scan a delimited primary@>=
17046
17047   l_delim=mp->cur_sym; r_delim=mp->cur_mod; 
17048   mp_get_x_next(mp); mp_scan_expression(mp);
17049   if ( (mp->cur_cmd==comma) && (mp->cur_type>=mp_known) ) {
17050     @<Scan the rest of a delimited set of numerics@>;
17051   } else {
17052     mp_check_delimiter(mp, l_delim,r_delim);
17053   }
17054 }
17055
17056 @ The |stash_in| subroutine puts the current (numeric) expression into a field
17057 within a ``big node.''
17058
17059 @c void mp_stash_in (MP mp,pointer p) {
17060   pointer q; /* temporary register */
17061   type(p)=mp->cur_type;
17062   if ( mp->cur_type==mp_known ) {
17063     value(p)=mp->cur_exp;
17064   } else { 
17065     if ( mp->cur_type==mp_independent ) {
17066       @<Stash an independent |cur_exp| into a big node@>;
17067     } else { 
17068       mp->mem[value_loc(p)]=mp->mem[value_loc(mp->cur_exp)];
17069       /* |dep_list(p):=dep_list(cur_exp)| and |prev_dep(p):=prev_dep(cur_exp)| */
17070       link(prev_dep(p))=p;
17071     }
17072     mp_free_node(mp, mp->cur_exp,value_node_size);
17073   }
17074   mp->cur_type=mp_vacuous;
17075 }
17076
17077 @ In rare cases the current expression can become |independent|. There
17078 may be many dependency lists pointing to such an independent capsule,
17079 so we can't simply move it into place within a big node. Instead,
17080 we copy it, then recycle it.
17081
17082 @ @<Stash an independent |cur_exp|...@>=
17083
17084   q=mp_single_dependency(mp, mp->cur_exp);
17085   if ( q==mp->dep_final ){ 
17086     type(p)=mp_known; value(p)=0; mp_free_node(mp, q,dep_node_size);
17087   } else { 
17088     type(p)=mp_dependent; mp_new_dep(mp, p,q);
17089   }
17090   mp_recycle_value(mp, mp->cur_exp);
17091 }
17092
17093 @ This code uses the fact that |red_part_loc| and |green_part_loc|
17094 are synonymous with |x_part_loc| and |y_part_loc|.
17095
17096 @<Scan the rest of a delimited set of numerics@>=
17097
17098 p=mp_stash_cur_exp(mp);
17099 mp_get_x_next(mp); mp_scan_expression(mp);
17100 @<Make sure the second part of a pair or color has a numeric type@>;
17101 q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
17102 if ( mp->cur_cmd==comma ) type(q)=mp_color_type;
17103 else type(q)=mp_pair_type;
17104 mp_init_big_node(mp, q); r=value(q);
17105 mp_stash_in(mp, y_part_loc(r));
17106 mp_unstash_cur_exp(mp, p);
17107 mp_stash_in(mp, x_part_loc(r));
17108 if ( mp->cur_cmd==comma ) {
17109   @<Scan the last of a triplet of numerics@>;
17110 }
17111 if ( mp->cur_cmd==comma ) {
17112   type(q)=mp_cmykcolor_type;
17113   mp_init_big_node(mp, q); t=value(q);
17114   mp->mem[cyan_part_loc(t)]=mp->mem[red_part_loc(r)];
17115   value(cyan_part_loc(t))=value(red_part_loc(r));
17116   mp->mem[magenta_part_loc(t)]=mp->mem[green_part_loc(r)];
17117   value(magenta_part_loc(t))=value(green_part_loc(r));
17118   mp->mem[yellow_part_loc(t)]=mp->mem[blue_part_loc(r)];
17119   value(yellow_part_loc(t))=value(blue_part_loc(r));
17120   mp_recycle_value(mp, r);
17121   r=t;
17122   @<Scan the last of a quartet of numerics@>;
17123 }
17124 mp_check_delimiter(mp, l_delim,r_delim);
17125 mp->cur_type=type(q);
17126 mp->cur_exp=q;
17127 }
17128
17129 @ @<Make sure the second part of a pair or color has a numeric type@>=
17130 if ( mp->cur_type<mp_known ) {
17131   exp_err("Nonnumeric ypart has been replaced by 0");
17132 @.Nonnumeric...replaced by 0@>
17133   help4("I've started to scan a pair `(a,b)' or a color `(a,b,c)';")
17134     ("but after finding a nice `a' I found a `b' that isn't")
17135     ("of numeric type. So I've changed that part to zero.")
17136     ("(The b that I didn't like appears above the error message.)");
17137   mp_put_get_flush_error(mp, 0);
17138 }
17139
17140 @ @<Scan the last of a triplet of numerics@>=
17141
17142   mp_get_x_next(mp); mp_scan_expression(mp);
17143   if ( mp->cur_type<mp_known ) {
17144     exp_err("Nonnumeric third part has been replaced by 0");
17145 @.Nonnumeric...replaced by 0@>
17146     help3("I've just scanned a color `(a,b,c)' or cmykcolor(a,b,c,d); but the `c'")
17147       ("isn't of numeric type. So I've changed that part to zero.")
17148       ("(The c that I didn't like appears above the error message.)");
17149     mp_put_get_flush_error(mp, 0);
17150   }
17151   mp_stash_in(mp, blue_part_loc(r));
17152 }
17153
17154 @ @<Scan the last of a quartet of numerics@>=
17155
17156   mp_get_x_next(mp); mp_scan_expression(mp);
17157   if ( mp->cur_type<mp_known ) {
17158     exp_err("Nonnumeric blackpart has been replaced by 0");
17159 @.Nonnumeric...replaced by 0@>
17160     help3("I've just scanned a cmykcolor `(c,m,y,k)'; but the `k' isn't")
17161       ("of numeric type. So I've changed that part to zero.")
17162       ("(The k that I didn't like appears above the error message.)");
17163     mp_put_get_flush_error(mp, 0);
17164   }
17165   mp_stash_in(mp, black_part_loc(r));
17166 }
17167
17168 @ The local variable |group_line| keeps track of the line
17169 where a \&{begingroup} command occurred; this will be useful
17170 in an error message if the group doesn't actually end.
17171
17172 @<Other local variables for |scan_primary|@>=
17173 integer group_line; /* where a group began */
17174
17175 @ @<Scan a grouped primary@>=
17176
17177   group_line=mp_true_line(mp);
17178   if ( mp->internal[tracing_commands]>0 ) show_cur_cmd_mod;
17179   save_boundary_item(p);
17180   do {  
17181     mp_do_statement(mp); /* ends with |cur_cmd>=semicolon| */
17182   } while (! (mp->cur_cmd!=semicolon));
17183   if ( mp->cur_cmd!=end_group ) {
17184     print_err("A group begun on line ");
17185 @.A group...never ended@>
17186     mp_print_int(mp, group_line);
17187     mp_print(mp, " never ended");
17188     help2("I saw a `begingroup' back there that hasn't been matched")
17189          ("by `endgroup'. So I've inserted `endgroup' now.");
17190     mp_back_error(mp); mp->cur_cmd=end_group;
17191   }
17192   mp_unsave(mp); 
17193     /* this might change |cur_type|, if independent variables are recycled */
17194   if ( mp->internal[tracing_commands]>0 ) show_cur_cmd_mod;
17195 }
17196
17197 @ @<Scan a string constant@>=
17198
17199   mp->cur_type=mp_string_type; mp->cur_exp=mp->cur_mod;
17200 }
17201
17202 @ Later we'll come to procedures that perform actual operations like
17203 addition, square root, and so on; our purpose now is to do the parsing.
17204 But we might as well mention those future procedures now, so that the
17205 suspense won't be too bad:
17206
17207 \smallskip
17208 |do_nullary(c)| does primitive operations that have no operands (e.g.,
17209 `\&{true}' or `\&{pencircle}');
17210
17211 \smallskip
17212 |do_unary(c)| applies a primitive operation to the current expression;
17213
17214 \smallskip
17215 |do_binary(p,c)| applies a primitive operation to the capsule~|p|
17216 and the current expression.
17217
17218 @<Scan a nullary operation@>=mp_do_nullary(mp, mp->cur_mod)
17219
17220 @ @<Scan a unary operation@>=
17221
17222   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_primary(mp); 
17223   mp_do_unary(mp, c); goto DONE;
17224 }
17225
17226 @ A numeric token might be a primary by itself, or it might be the
17227 numerator of a fraction composed solely of numeric tokens, or it might
17228 multiply the primary that follows (provided that the primary doesn't begin
17229 with a plus sign or a minus sign). The code here uses the facts that
17230 |max_primary_command=plus_or_minus| and
17231 |max_primary_command-1=numeric_token|. If a fraction is found that is less
17232 than unity, we try to retain higher precision when we use it in scalar
17233 multiplication.
17234
17235 @<Other local variables for |scan_primary|@>=
17236 scaled num,denom; /* for primaries that are fractions, like `1/2' */
17237
17238 @ @<Scan a primary that starts with a numeric token@>=
17239
17240   mp->cur_exp=mp->cur_mod; mp->cur_type=mp_known; mp_get_x_next(mp);
17241   if ( mp->cur_cmd!=slash ) { 
17242     num=0; denom=0;
17243   } else { 
17244     mp_get_x_next(mp);
17245     if ( mp->cur_cmd!=numeric_token ) { 
17246       mp_back_input(mp);
17247       mp->cur_cmd=slash; mp->cur_mod=over; mp->cur_sym=frozen_slash;
17248       goto DONE;
17249     }
17250     num=mp->cur_exp; denom=mp->cur_mod;
17251     if ( denom==0 ) { @<Protest division by zero@>; }
17252     else { mp->cur_exp=mp_make_scaled(mp, num,denom); }
17253     check_arith; mp_get_x_next(mp);
17254   }
17255   if ( mp->cur_cmd>=min_primary_command ) {
17256    if ( mp->cur_cmd<numeric_token ) { /* in particular, |cur_cmd<>plus_or_minus| */
17257      p=mp_stash_cur_exp(mp); mp_scan_primary(mp);
17258      if ( (abs(num)>=abs(denom))||(mp->cur_type<mp_color_type) ) {
17259        mp_do_binary(mp, p,times);
17260      } else {
17261        mp_frac_mult(mp, num,denom);
17262        mp_free_node(mp, p,value_node_size);
17263      }
17264     }
17265   }
17266   goto DONE;
17267 }
17268
17269 @ @<Protest division...@>=
17270
17271   print_err("Division by zero");
17272 @.Division by zero@>
17273   help1("I'll pretend that you meant to divide by 1."); mp_error(mp);
17274 }
17275
17276 @ @<Scan a binary operation with `\&{of}' between its operands@>=
17277
17278   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
17279   if ( mp->cur_cmd!=of_token ) {
17280     mp_missing_err(mp, "of"); mp_print(mp, " for "); 
17281     mp_print_cmd_mod(mp, primary_binary,c);
17282 @.Missing `of'@>
17283     help1("I've got the first argument; will look now for the other.");
17284     mp_back_error(mp);
17285   }
17286   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_primary(mp); 
17287   mp_do_binary(mp, p,c); goto DONE;
17288 }
17289
17290 @ @<Convert a suffix to a string@>=
17291
17292   mp_get_x_next(mp); mp_scan_suffix(mp); 
17293   mp->old_setting=mp->selector; mp->selector=new_string;
17294   mp_show_token_list(mp, mp->cur_exp,null,100000,0); 
17295   mp_flush_token_list(mp, mp->cur_exp);
17296   mp->cur_exp=mp_make_string(mp); mp->selector=mp->old_setting; 
17297   mp->cur_type=mp_string_type;
17298   goto DONE;
17299 }
17300
17301 @ If an internal quantity appears all by itself on the left of an
17302 assignment, we return a token list of length one, containing the address
17303 of the internal quantity plus |hash_end|. (This accords with the conventions
17304 of the save stack, as described earlier.)
17305
17306 @<Scan an internal...@>=
17307
17308   q=mp->cur_mod;
17309   if ( my_var_flag==assignment ) {
17310     mp_get_x_next(mp);
17311     if ( mp->cur_cmd==assignment ) {
17312       mp->cur_exp=mp_get_avail(mp);
17313       info(mp->cur_exp)=q+hash_end; mp->cur_type=mp_token_list; 
17314       goto DONE;
17315     }
17316     mp_back_input(mp);
17317   }
17318   mp->cur_type=mp_known; mp->cur_exp=mp->internal[q];
17319 }
17320
17321 @ The most difficult part of |scan_primary| has been saved for last, since
17322 it was necessary to build up some confidence first. We can now face the task
17323 of scanning a variable.
17324
17325 As we scan a variable, we build a token list containing the relevant
17326 names and subscript values, simultaneously following along in the
17327 ``collective'' structure to see if we are actually dealing with a macro
17328 instead of a value.
17329
17330 The local variables |pre_head| and |post_head| will point to the beginning
17331 of the prefix and suffix lists; |tail| will point to the end of the list
17332 that is currently growing.
17333
17334 Another local variable, |tt|, contains partial information about the
17335 declared type of the variable-so-far. If |tt>=mp_unsuffixed_macro|, the
17336 relation |tt=type(q)| will always hold. If |tt=undefined|, the routine
17337 doesn't bother to update its information about type. And if
17338 |undefined<tt<mp_unsuffixed_macro|, the precise value of |tt| isn't critical.
17339
17340 @ @<Other local variables for |scan_primary|@>=
17341 pointer pre_head,post_head,tail;
17342   /* prefix and suffix list variables */
17343 small_number tt; /* approximation to the type of the variable-so-far */
17344 pointer t; /* a token */
17345 pointer macro_ref = 0; /* reference count for a suffixed macro */
17346
17347 @ @<Scan a variable primary...@>=
17348
17349   fast_get_avail(pre_head); tail=pre_head; post_head=null; tt=mp_vacuous;
17350   while (1) { 
17351     t=mp_cur_tok(mp); link(tail)=t;
17352     if ( tt!=undefined ) {
17353        @<Find the approximate type |tt| and corresponding~|q|@>;
17354       if ( tt>=mp_unsuffixed_macro ) {
17355         @<Either begin an unsuffixed macro call or
17356           prepare for a suffixed one@>;
17357       }
17358     }
17359     mp_get_x_next(mp); tail=t;
17360     if ( mp->cur_cmd==left_bracket ) {
17361       @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>;
17362     }
17363     if ( mp->cur_cmd>max_suffix_token ) break;
17364     if ( mp->cur_cmd<min_suffix_token ) break;
17365   } /* now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| */
17366   @<Handle unusual cases that masquerade as variables, and |goto restart|
17367     or |goto done| if appropriate;
17368     otherwise make a copy of the variable and |goto done|@>;
17369 }
17370
17371 @ @<Either begin an unsuffixed macro call or...@>=
17372
17373   link(tail)=null;
17374   if ( tt>mp_unsuffixed_macro ) { /* |tt=mp_suffixed_macro| */
17375     post_head=mp_get_avail(mp); tail=post_head; link(tail)=t;
17376     tt=undefined; macro_ref=value(q); add_mac_ref(macro_ref);
17377   } else {
17378     @<Set up unsuffixed macro call and |goto restart|@>;
17379   }
17380 }
17381
17382 @ @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>=
17383
17384   mp_get_x_next(mp); mp_scan_expression(mp);
17385   if ( mp->cur_cmd!=right_bracket ) {
17386     @<Put the left bracket and the expression back to be rescanned@>;
17387   } else { 
17388     if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17389     mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp; mp->cur_sym=0;
17390   }
17391 }
17392
17393 @ The left bracket that we thought was introducing a subscript might have
17394 actually been the left bracket in a mediation construction like `\.{x[a,b]}'.
17395 So we don't issue an error message at this point; but we do want to back up
17396 so as to avoid any embarrassment about our incorrect assumption.
17397
17398 @<Put the left bracket and the expression back to be rescanned@>=
17399
17400   mp_back_input(mp); /* that was the token following the current expression */
17401   mp_back_expr(mp); mp->cur_cmd=left_bracket; 
17402   mp->cur_mod=0; mp->cur_sym=frozen_left_bracket;
17403 }
17404
17405 @ Here's a routine that puts the current expression back to be read again.
17406
17407 @c void mp_back_expr (MP mp) {
17408   pointer p; /* capsule token */
17409   p=mp_stash_cur_exp(mp); link(p)=null; back_list(p);
17410 }
17411
17412 @ Unknown subscripts lead to the following error message.
17413
17414 @c void mp_bad_subscript (MP mp) { 
17415   exp_err("Improper subscript has been replaced by zero");
17416 @.Improper subscript...@>
17417   help3("A bracketed subscript must have a known numeric value;")
17418     ("unfortunately, what I found was the value that appears just")
17419     ("above this error message. So I'll try a zero subscript.");
17420   mp_flush_error(mp, 0);
17421 }
17422
17423 @ Every time we call |get_x_next|, there's a chance that the variable we've
17424 been looking at will disappear. Thus, we cannot safely keep |q| pointing
17425 into the variable structure; we need to start searching from the root each time.
17426
17427 @<Find the approximate type |tt| and corresponding~|q|@>=
17428 @^inner loop@>
17429
17430   p=link(pre_head); q=info(p); tt=undefined;
17431   if ( eq_type(q) % outer_tag==tag_token ) {
17432     q=equiv(q);
17433     if ( q==null ) goto DONE2;
17434     while (1) { 
17435       p=link(p);
17436       if ( p==null ) {
17437         tt=type(q); goto DONE2;
17438       };
17439       if ( type(q)!=mp_structured ) goto DONE2;
17440       q=link(attr_head(q)); /* the |collective_subscript| attribute */
17441       if ( p>=mp->hi_mem_min ) { /* it's not a subscript */
17442         do {  q=link(q); } while (! (attr_loc(q)>=info(p)));
17443         if ( attr_loc(q)>info(p) ) goto DONE2;
17444       }
17445     }
17446   }
17447 DONE2:
17448   ;
17449 }
17450
17451 @ How do things stand now? Well, we have scanned an entire variable name,
17452 including possible subscripts and/or attributes; |cur_cmd|, |cur_mod|, and
17453 |cur_sym| represent the token that follows. If |post_head=null|, a
17454 token list for this variable name starts at |link(pre_head)|, with all
17455 subscripts evaluated. But if |post_head<>null|, the variable turned out
17456 to be a suffixed macro; |pre_head| is the head of the prefix list, while
17457 |post_head| is the head of a token list containing both `\.{\AT!}' and
17458 the suffix.
17459
17460 Our immediate problem is to see if this variable still exists. (Variable
17461 structures can change drastically whenever we call |get_x_next|; users
17462 aren't supposed to do this, but the fact that it is possible means that
17463 we must be cautious.)
17464
17465 The following procedure prints an error message when a variable
17466 unexpectedly disappears. Its help message isn't quite right for
17467 our present purposes, but we'll be able to fix that up.
17468
17469 @c 
17470 void mp_obliterated (MP mp,pointer q) { 
17471   print_err("Variable "); mp_show_token_list(mp, q,null,1000,0);
17472   mp_print(mp, " has been obliterated");
17473 @.Variable...obliterated@>
17474   help5("It seems you did a nasty thing---probably by accident,")
17475     ("but nevertheless you nearly hornswoggled me...")
17476     ("While I was evaluating the right-hand side of this")
17477     ("command, something happened, and the left-hand side")
17478     ("is no longer a variable! So I won't change anything.");
17479 }
17480
17481 @ If the variable does exist, we also need to check
17482 for a few other special cases before deciding that a plain old ordinary
17483 variable has, indeed, been scanned.
17484
17485 @<Handle unusual cases that masquerade as variables...@>=
17486 if ( post_head!=null ) {
17487   @<Set up suffixed macro call and |goto restart|@>;
17488 }
17489 q=link(pre_head); free_avail(pre_head);
17490 if ( mp->cur_cmd==my_var_flag ) { 
17491   mp->cur_type=mp_token_list; mp->cur_exp=q; goto DONE;
17492 }
17493 p=mp_find_variable(mp, q);
17494 if ( p!=null ) {
17495   mp_make_exp_copy(mp, p);
17496 } else { 
17497   mp_obliterated(mp, q);
17498   mp->help_line[2]="While I was evaluating the suffix of this variable,";
17499   mp->help_line[1]="something was redefined, and it's no longer a variable!";
17500   mp->help_line[0]="In order to get back on my feet, I've inserted `0' instead.";
17501   mp_put_get_flush_error(mp, 0);
17502 }
17503 mp_flush_node_list(mp, q); 
17504 goto DONE
17505
17506 @ The only complication associated with macro calling is that the prefix
17507 and ``at'' parameters must be packaged in an appropriate list of lists.
17508
17509 @<Set up unsuffixed macro call and |goto restart|@>=
17510
17511   p=mp_get_avail(mp); info(pre_head)=link(pre_head); link(pre_head)=p;
17512   info(p)=t; mp_macro_call(mp, value(q),pre_head,null);
17513   mp_get_x_next(mp); 
17514   goto RESTART;
17515 }
17516
17517 @ If the ``variable'' that turned out to be a suffixed macro no longer exists,
17518 we don't care, because we have reserved a pointer (|macro_ref|) to its
17519 token list.
17520
17521 @<Set up suffixed macro call and |goto restart|@>=
17522
17523   mp_back_input(mp); p=mp_get_avail(mp); q=link(post_head);
17524   info(pre_head)=link(pre_head); link(pre_head)=post_head;
17525   info(post_head)=q; link(post_head)=p; info(p)=link(q); link(q)=null;
17526   mp_macro_call(mp, macro_ref,pre_head,null); decr(ref_count(macro_ref));
17527   mp_get_x_next(mp); goto RESTART;
17528 }
17529
17530 @ Our remaining job is simply to make a copy of the value that has been
17531 found. Some cases are harder than others, but complexity arises solely
17532 because of the multiplicity of possible cases.
17533
17534 @<Declare the procedure called |make_exp_copy|@>=
17535 @<Declare subroutines needed by |make_exp_copy|@>;
17536 void mp_make_exp_copy (MP mp,pointer p) {
17537   pointer q,r,t; /* registers for list manipulation */
17538 RESTART: 
17539   mp->cur_type=type(p);
17540   switch (mp->cur_type) {
17541   case mp_vacuous: case mp_boolean_type: case mp_known:
17542     mp->cur_exp=value(p); break;
17543   case unknown_types:
17544     mp->cur_exp=mp_new_ring_entry(mp, p);
17545     break;
17546   case mp_string_type: 
17547     mp->cur_exp=value(p); add_str_ref(mp->cur_exp);
17548     break;
17549   case mp_picture_type:
17550     mp->cur_exp=value(p);add_edge_ref(mp->cur_exp);
17551     break;
17552   case mp_pen_type:
17553     mp->cur_exp=copy_pen(value(p));
17554     break; 
17555   case mp_path_type:
17556     mp->cur_exp=mp_copy_path(mp, value(p));
17557     break;
17558   case mp_transform_type: case mp_color_type: 
17559   case mp_cmykcolor_type: case mp_pair_type:
17560     @<Copy the big node |p|@>;
17561     break;
17562   case mp_dependent: case mp_proto_dependent:
17563     mp_encapsulate(mp, mp_copy_dep_list(mp, dep_list(p)));
17564     break;
17565   case mp_numeric_type: 
17566     new_indep(p); goto RESTART;
17567     break;
17568   case mp_independent: 
17569     q=mp_single_dependency(mp, p);
17570     if ( q==mp->dep_final ){ 
17571       mp->cur_type=mp_known; mp->cur_exp=0; mp_free_node(mp, q,value_node_size);
17572     } else { 
17573       mp->cur_type=mp_dependent; mp_encapsulate(mp, q);
17574     }
17575     break;
17576   default: 
17577     mp_confusion(mp, "copy");
17578 @:this can't happen copy}{\quad copy@>
17579     break;
17580   }
17581 }
17582
17583 @ The |encapsulate| subroutine assumes that |dep_final| is the
17584 tail of dependency list~|p|.
17585
17586 @<Declare subroutines needed by |make_exp_copy|@>=
17587 void mp_encapsulate (MP mp,pointer p) { 
17588   mp->cur_exp=mp_get_node(mp, value_node_size); type(mp->cur_exp)=mp->cur_type;
17589   name_type(mp->cur_exp)=mp_capsule; mp_new_dep(mp, mp->cur_exp,p);
17590 }
17591
17592 @ The most tedious case arises when the user refers to a
17593 \&{pair}, \&{color}, or \&{transform} variable; we must copy several fields,
17594 each of which can be |independent|, |dependent|, |mp_proto_dependent|,
17595 or |known|.
17596
17597 @<Copy the big node |p|@>=
17598
17599   if ( value(p)==null ) 
17600     mp_init_big_node(mp, p);
17601   t=mp_get_node(mp, value_node_size); name_type(t)=mp_capsule; type(t)=mp->cur_type;
17602   mp_init_big_node(mp, t);
17603   q=value(p)+mp->big_node_size[mp->cur_type]; 
17604   r=value(t)+mp->big_node_size[mp->cur_type];
17605   do {  
17606     q=q-2; r=r-2; mp_install(mp, r,q);
17607   } while (q!=value(p));
17608   mp->cur_exp=t;
17609 }
17610
17611 @ The |install| procedure copies a numeric field~|q| into field~|r| of
17612 a big node that will be part of a capsule.
17613
17614 @<Declare subroutines needed by |make_exp_copy|@>=
17615 void mp_install (MP mp,pointer r, pointer q) {
17616   pointer p; /* temporary register */
17617   if ( type(q)==mp_known ){ 
17618     value(r)=value(q); type(r)=mp_known;
17619   } else  if ( type(q)==mp_independent ) {
17620     p=mp_single_dependency(mp, q);
17621     if ( p==mp->dep_final ) {
17622       type(r)=mp_known; value(r)=0; mp_free_node(mp, p,value_node_size);
17623     } else  { 
17624       type(r)=mp_dependent; mp_new_dep(mp, r,p);
17625     }
17626   } else {
17627     type(r)=type(q); mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(q)));
17628   }
17629 }
17630
17631 @ Expressions of the form `\.{a[b,c]}' are converted into
17632 `\.{b+a*(c-b)}', without checking the types of \.b~or~\.c,
17633 provided that \.a is numeric.
17634
17635 @<Scan a mediation...@>=
17636
17637   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17638   if ( mp->cur_cmd!=comma ) {
17639     @<Put the left bracket and the expression back...@>;
17640     mp_unstash_cur_exp(mp, p);
17641   } else { 
17642     q=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17643     if ( mp->cur_cmd!=right_bracket ) {
17644       mp_missing_err(mp, "]");
17645 @.Missing `]'@>
17646       help3("I've scanned an expression of the form `a[b,c',")
17647       ("so a right bracket should have come next.")
17648       ("I shall pretend that one was there.");
17649       mp_back_error(mp);
17650     }
17651     r=mp_stash_cur_exp(mp); mp_make_exp_copy(mp, q);
17652     mp_do_binary(mp, r,minus); mp_do_binary(mp, p,times); 
17653     mp_do_binary(mp, q,plus); mp_get_x_next(mp);
17654   }
17655 }
17656
17657 @ Here is a comparatively simple routine that is used to scan the
17658 \&{suffix} parameters of a macro.
17659
17660 @<Declare the basic parsing subroutines@>=
17661 void mp_scan_suffix (MP mp) {
17662   pointer h,t; /* head and tail of the list being built */
17663   pointer p; /* temporary register */
17664   h=mp_get_avail(mp); t=h;
17665   while (1) { 
17666     if ( mp->cur_cmd==left_bracket ) {
17667       @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>;
17668     }
17669     if ( mp->cur_cmd==numeric_token ) {
17670       p=mp_new_num_tok(mp, mp->cur_mod);
17671     } else if ((mp->cur_cmd==tag_token)||(mp->cur_cmd==internal_quantity) ) {
17672        p=mp_get_avail(mp); info(p)=mp->cur_sym;
17673     } else {
17674       break;
17675     }
17676     link(t)=p; t=p; mp_get_x_next(mp);
17677   }
17678   mp->cur_exp=link(h); free_avail(h); mp->cur_type=mp_token_list;
17679 }
17680
17681 @ @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>=
17682
17683   mp_get_x_next(mp); mp_scan_expression(mp);
17684   if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17685   if ( mp->cur_cmd!=right_bracket ) {
17686      mp_missing_err(mp, "]");
17687 @.Missing `]'@>
17688     help3("I've seen a `[' and a subscript value, in a suffix,")
17689       ("so a right bracket should have come next.")
17690       ("I shall pretend that one was there.");
17691     mp_back_error(mp);
17692   }
17693   mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp;
17694 }
17695
17696 @* \[38] Parsing secondary and higher expressions.
17697 After the intricacies of |scan_primary|\kern-1pt,
17698 the |scan_secondary| routine is
17699 refreshingly simple. It's not trivial, but the operations are relatively
17700 straightforward; the main difficulty is, again, that expressions and data
17701 structures might change drastically every time we call |get_x_next|, so a
17702 cautious approach is mandatory. For example, a macro defined by
17703 \&{primarydef} might have disappeared by the time its second argument has
17704 been scanned; we solve this by increasing the reference count of its token
17705 list, so that the macro can be called even after it has been clobbered.
17706
17707 @<Declare the basic parsing subroutines@>=
17708 void mp_scan_secondary (MP mp) {
17709   pointer p; /* for list manipulation */
17710   halfword c,d; /* operation codes or modifiers */
17711   pointer mac_name; /* token defined with \&{primarydef} */
17712 RESTART:
17713   if ((mp->cur_cmd<min_primary_command)||
17714       (mp->cur_cmd>max_primary_command) )
17715     mp_bad_exp(mp, "A secondary");
17716 @.A secondary expression...@>
17717   mp_scan_primary(mp);
17718 CONTINUE: 
17719   if ( mp->cur_cmd<=max_secondary_command )
17720     if ( mp->cur_cmd>=min_secondary_command ) {
17721       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17722       if ( d==secondary_primary_macro ) { 
17723         mac_name=mp->cur_sym; add_mac_ref(c);
17724      }
17725      mp_get_x_next(mp); mp_scan_primary(mp);
17726      if ( d!=secondary_primary_macro ) {
17727        mp_do_binary(mp, p,c);
17728      } else  { 
17729        mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17730        decr(ref_count(c)); mp_get_x_next(mp); 
17731        goto RESTART;
17732     }
17733     goto CONTINUE;
17734   }
17735 }
17736
17737 @ The following procedure calls a macro that has two parameters,
17738 |p| and |cur_exp|.
17739
17740 @c void mp_binary_mac (MP mp,pointer p, pointer c, pointer n) {
17741   pointer q,r; /* nodes in the parameter list */
17742   q=mp_get_avail(mp); r=mp_get_avail(mp); link(q)=r;
17743   info(q)=p; info(r)=mp_stash_cur_exp(mp);
17744   mp_macro_call(mp, c,q,n);
17745 }
17746
17747 @ The next procedure, |scan_tertiary|, is pretty much the same deal.
17748
17749 @<Declare the basic parsing subroutines@>=
17750 void mp_scan_tertiary (MP mp) {
17751   pointer p; /* for list manipulation */
17752   halfword c,d; /* operation codes or modifiers */
17753   pointer mac_name; /* token defined with \&{secondarydef} */
17754 RESTART:
17755   if ((mp->cur_cmd<min_primary_command)||
17756       (mp->cur_cmd>max_primary_command) )
17757     mp_bad_exp(mp, "A tertiary");
17758 @.A tertiary expression...@>
17759   mp_scan_secondary(mp);
17760 CONTINUE: 
17761   if ( mp->cur_cmd<=max_tertiary_command ) {
17762     if ( mp->cur_cmd>=min_tertiary_command ) {
17763       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17764       if ( d==tertiary_secondary_macro ) { 
17765         mac_name=mp->cur_sym; add_mac_ref(c);
17766       };
17767       mp_get_x_next(mp); mp_scan_secondary(mp);
17768       if ( d!=tertiary_secondary_macro ) {
17769         mp_do_binary(mp, p,c);
17770       } else { 
17771         mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17772         decr(ref_count(c)); mp_get_x_next(mp); 
17773         goto RESTART;
17774       }
17775       goto CONTINUE;
17776     }
17777   }
17778 }
17779
17780 @ Finally we reach the deepest level in our quartet of parsing routines.
17781 This one is much like the others; but it has an extra complication from
17782 paths, which materialize here.
17783
17784 @d continue_path 25 /* a label inside of |scan_expression| */
17785 @d finish_path 26 /* another */
17786
17787 @<Declare the basic parsing subroutines@>=
17788 void mp_scan_expression (MP mp) {
17789   pointer p,q,r,pp,qq; /* for list manipulation */
17790   halfword c,d; /* operation codes or modifiers */
17791   int my_var_flag; /* initial value of |var_flag| */
17792   pointer mac_name; /* token defined with \&{tertiarydef} */
17793   boolean cycle_hit; /* did a path expression just end with `\&{cycle}'? */
17794   scaled x,y; /* explicit coordinates or tension at a path join */
17795   int t; /* knot type following a path join */
17796   t=0; y=0; x=0;
17797   my_var_flag=mp->var_flag; mac_name=null;
17798 RESTART:
17799   if ((mp->cur_cmd<min_primary_command)||
17800       (mp->cur_cmd>max_primary_command) )
17801     mp_bad_exp(mp, "An");
17802 @.An expression...@>
17803   mp_scan_tertiary(mp);
17804 CONTINUE: 
17805   if ( mp->cur_cmd<=max_expression_command )
17806     if ( mp->cur_cmd>=min_expression_command ) {
17807       if ( (mp->cur_cmd!=equals)||(my_var_flag!=assignment) ) {
17808         p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
17809         if ( d==expression_tertiary_macro ) {
17810           mac_name=mp->cur_sym; add_mac_ref(c);
17811         }
17812         if ( (d<ampersand)||((d==ampersand)&&
17813              ((type(p)==mp_pair_type)||(type(p)==mp_path_type))) ) {
17814           @<Scan a path construction operation;
17815             but |return| if |p| has the wrong type@>;
17816         } else { 
17817           mp_get_x_next(mp); mp_scan_tertiary(mp);
17818           if ( d!=expression_tertiary_macro ) {
17819             mp_do_binary(mp, p,c);
17820           } else  { 
17821             mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
17822             decr(ref_count(c)); mp_get_x_next(mp); 
17823             goto RESTART;
17824           }
17825         }
17826         goto CONTINUE;
17827      }
17828   }
17829 }
17830
17831 @ The reader should review the data structure conventions for paths before
17832 hoping to understand the next part of this code.
17833
17834 @<Scan a path construction operation...@>=
17835
17836   cycle_hit=false;
17837   @<Convert the left operand, |p|, into a partial path ending at~|q|;
17838     but |return| if |p| doesn't have a suitable type@>;
17839 CONTINUE_PATH: 
17840   @<Determine the path join parameters;
17841     but |goto finish_path| if there's only a direction specifier@>;
17842   if ( mp->cur_cmd==cycle ) {
17843     @<Get ready to close a cycle@>;
17844   } else { 
17845     mp_scan_tertiary(mp);
17846     @<Convert the right operand, |cur_exp|,
17847       into a partial path from |pp| to~|qq|@>;
17848   }
17849   @<Join the partial paths and reset |p| and |q| to the head and tail
17850     of the result@>;
17851   if ( mp->cur_cmd>=min_expression_command )
17852     if ( mp->cur_cmd<=ampersand ) if ( ! cycle_hit ) goto CONTINUE_PATH;
17853 FINISH_PATH:
17854   @<Choose control points for the path and put the result into |cur_exp|@>;
17855 }
17856
17857 @ @<Convert the left operand, |p|, into a partial path ending at~|q|...@>=
17858
17859   mp_unstash_cur_exp(mp, p);
17860   if ( mp->cur_type==mp_pair_type ) p=mp_new_knot(mp);
17861   else if ( mp->cur_type==mp_path_type ) p=mp->cur_exp;
17862   else return;
17863   q=p;
17864   while ( link(q)!=p ) q=link(q);
17865   if ( left_type(p)!=endpoint ) { /* open up a cycle */
17866     r=mp_copy_knot(mp, p); link(q)=r; q=r;
17867   }
17868   left_type(p)=open; right_type(q)=open;
17869 }
17870
17871 @ A pair of numeric values is changed into a knot node for a one-point path
17872 when \MP\ discovers that the pair is part of a path.
17873
17874 @c@<Declare the procedure called |known_pair|@>;
17875 pointer mp_new_knot (MP mp) { /* convert a pair to a knot with two endpoints */
17876   pointer q; /* the new node */
17877   q=mp_get_node(mp, knot_node_size); left_type(q)=endpoint;
17878   right_type(q)=endpoint; originator(q)=metapost_user; link(q)=q;
17879   mp_known_pair(mp); x_coord(q)=mp->cur_x; y_coord(q)=mp->cur_y;
17880   return q;
17881 }
17882
17883 @ The |known_pair| subroutine sets |cur_x| and |cur_y| to the components
17884 of the current expression, assuming that the current expression is a
17885 pair of known numerics. Unknown components are zeroed, and the
17886 current expression is flushed.
17887
17888 @<Declare the procedure called |known_pair|@>=
17889 void mp_known_pair (MP mp) {
17890   pointer p; /* the pair node */
17891   if ( mp->cur_type!=mp_pair_type ) {
17892     exp_err("Undefined coordinates have been replaced by (0,0)");
17893 @.Undefined coordinates...@>
17894     help5("I need x and y numbers for this part of the path.")
17895       ("The value I found (see above) was no good;")
17896       ("so I'll try to keep going by using zero instead.")
17897       ("(Chapter 27 of The METAFONTbook explains that")
17898 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17899       ("you might want to type `I ??" "?' now.)");
17900     mp_put_get_flush_error(mp, 0); mp->cur_x=0; mp->cur_y=0;
17901   } else { 
17902     p=value(mp->cur_exp);
17903      @<Make sure that both |x| and |y| parts of |p| are known;
17904        copy them into |cur_x| and |cur_y|@>;
17905     mp_flush_cur_exp(mp, 0);
17906   }
17907 }
17908
17909 @ @<Make sure that both |x| and |y| parts of |p| are known...@>=
17910 if ( type(x_part_loc(p))==mp_known ) {
17911   mp->cur_x=value(x_part_loc(p));
17912 } else { 
17913   mp_disp_err(mp, x_part_loc(p),
17914     "Undefined x coordinate has been replaced by 0");
17915 @.Undefined coordinates...@>
17916   help5("I need a `known' x value for this part of the path.")
17917     ("The value I found (see above) was no good;")
17918     ("so I'll try to keep going by using zero instead.")
17919     ("(Chapter 27 of The METAFONTbook explains that")
17920 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17921     ("you might want to type `I ??" "?' now.)");
17922   mp_put_get_error(mp); mp_recycle_value(mp, x_part_loc(p)); mp->cur_x=0;
17923 }
17924 if ( type(y_part_loc(p))==mp_known ) {
17925   mp->cur_y=value(y_part_loc(p));
17926 } else { 
17927   mp_disp_err(mp, y_part_loc(p),
17928     "Undefined y coordinate has been replaced by 0");
17929   help5("I need a `known' y value for this part of the path.")
17930     ("The value I found (see above) was no good;")
17931     ("so I'll try to keep going by using zero instead.")
17932     ("(Chapter 27 of The METAFONTbook explains that")
17933     ("you might want to type `I ??" "?' now.)");
17934   mp_put_get_error(mp); mp_recycle_value(mp, y_part_loc(p)); mp->cur_y=0;
17935 }
17936
17937 @ At this point |cur_cmd| is either |ampersand|, |left_brace|, or |path_join|.
17938
17939 @<Determine the path join parameters...@>=
17940 if ( mp->cur_cmd==left_brace ) {
17941   @<Put the pre-join direction information into node |q|@>;
17942 }
17943 d=mp->cur_cmd;
17944 if ( d==path_join ) {
17945   @<Determine the tension and/or control points@>;
17946 } else if ( d!=ampersand ) {
17947   goto FINISH_PATH;
17948 }
17949 mp_get_x_next(mp);
17950 if ( mp->cur_cmd==left_brace ) {
17951   @<Put the post-join direction information into |x| and |t|@>;
17952 } else if ( right_type(q)!=explicit ) {
17953   t=open; x=0;
17954 }
17955
17956 @ The |scan_direction| subroutine looks at the directional information
17957 that is enclosed in braces, and also scans ahead to the following character.
17958 A type code is returned, either |open| (if the direction was $(0,0)$),
17959 or |curl| (if the direction was a curl of known value |cur_exp|), or
17960 |given| (if the direction is given by the |angle| value that now
17961 appears in |cur_exp|).
17962
17963 There's nothing difficult about this subroutine, but the program is rather
17964 lengthy because a variety of potential errors need to be nipped in the bud.
17965
17966 @c small_number mp_scan_direction (MP mp) {
17967   int t; /* the type of information found */
17968   scaled x; /* an |x| coordinate */
17969   mp_get_x_next(mp);
17970   if ( mp->cur_cmd==curl_command ) {
17971      @<Scan a curl specification@>;
17972   } else {
17973     @<Scan a given direction@>;
17974   }
17975   if ( mp->cur_cmd!=right_brace ) {
17976     mp_missing_err(mp, "}");
17977 @.Missing `\char`\}'@>
17978     help3("I've scanned a direction spec for part of a path,")
17979       ("so a right brace should have come next.")
17980       ("I shall pretend that one was there.");
17981     mp_back_error(mp);
17982   }
17983   mp_get_x_next(mp); 
17984   return t;
17985 }
17986
17987 @ @<Scan a curl specification@>=
17988 { mp_get_x_next(mp); mp_scan_expression(mp);
17989 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<0) ){ 
17990   exp_err("Improper curl has been replaced by 1");
17991 @.Improper curl@>
17992   help1("A curl must be a known, nonnegative number.");
17993   mp_put_get_flush_error(mp, unity);
17994 }
17995 t=curl;
17996 }
17997
17998 @ @<Scan a given direction@>=
17999 { mp_scan_expression(mp);
18000   if ( mp->cur_type>mp_pair_type ) {
18001     @<Get given directions separated by commas@>;
18002   } else {
18003     mp_known_pair(mp);
18004   }
18005   if ( (mp->cur_x==0)&&(mp->cur_y==0) )  t=open;
18006   else  { t=given; mp->cur_exp=mp_n_arg(mp, mp->cur_x,mp->cur_y);}
18007 }
18008
18009 @ @<Get given directions separated by commas@>=
18010
18011   if ( mp->cur_type!=mp_known ) {
18012     exp_err("Undefined x coordinate has been replaced by 0");
18013 @.Undefined coordinates...@>
18014     help5("I need a `known' x value for this part of the path.")
18015       ("The value I found (see above) was no good;")
18016       ("so I'll try to keep going by using zero instead.")
18017       ("(Chapter 27 of The METAFONTbook explains that")
18018 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18019       ("you might want to type `I ??" "?' now.)");
18020     mp_put_get_flush_error(mp, 0);
18021   }
18022   x=mp->cur_exp;
18023   if ( mp->cur_cmd!=comma ) {
18024     mp_missing_err(mp, ",");
18025 @.Missing `,'@>
18026     help2("I've got the x coordinate of a path direction;")
18027       ("will look for the y coordinate next.");
18028     mp_back_error(mp);
18029   }
18030   mp_get_x_next(mp); mp_scan_expression(mp);
18031   if ( mp->cur_type!=mp_known ) {
18032      exp_err("Undefined y coordinate has been replaced by 0");
18033     help5("I need a `known' y value for this part of the path.")
18034       ("The value I found (see above) was no good;")
18035       ("so I'll try to keep going by using zero instead.")
18036       ("(Chapter 27 of The METAFONTbook explains that")
18037       ("you might want to type `I ??" "?' now.)");
18038     mp_put_get_flush_error(mp, 0);
18039   }
18040   mp->cur_y=mp->cur_exp; mp->cur_x=x;
18041 }
18042
18043 @ At this point |right_type(q)| is usually |open|, but it may have been
18044 set to some other value by a previous splicing operation. We must maintain
18045 the value of |right_type(q)| in unusual cases such as
18046 `\.{..z1\{z2\}\&\{z3\}z1\{0,0\}..}'.
18047
18048 @<Put the pre-join...@>=
18049
18050   t=mp_scan_direction(mp);
18051   if ( t!=open ) {
18052     right_type(q)=t; right_given(q)=mp->cur_exp;
18053     if ( left_type(q)==open ) {
18054       left_type(q)=t; left_given(q)=mp->cur_exp;
18055     } /* note that |left_given(q)=left_curl(q)| */
18056   }
18057 }
18058
18059 @ Since |left_tension| and |left_y| share the same position in knot nodes,
18060 and since |left_given| is similarly equivalent to |left_x|, we use
18061 |x| and |y| to hold the given direction and tension information when
18062 there are no explicit control points.
18063
18064 @<Put the post-join...@>=
18065
18066   t=mp_scan_direction(mp);
18067   if ( right_type(q)!=explicit ) x=mp->cur_exp;
18068   else t=explicit; /* the direction information is superfluous */
18069 }
18070
18071 @ @<Determine the tension and/or...@>=
18072
18073   mp_get_x_next(mp);
18074   if ( mp->cur_cmd==tension ) {
18075     @<Set explicit tensions@>;
18076   } else if ( mp->cur_cmd==controls ) {
18077     @<Set explicit control points@>;
18078   } else  { 
18079     right_tension(q)=unity; y=unity; mp_back_input(mp); /* default tension */
18080     goto DONE;
18081   };
18082   if ( mp->cur_cmd!=path_join ) {
18083      mp_missing_err(mp, "..");
18084 @.Missing `..'@>
18085     help1("A path join command should end with two dots.");
18086     mp_back_error(mp);
18087   }
18088 DONE:
18089   ;
18090 }
18091
18092 @ @<Set explicit tensions@>=
18093
18094   mp_get_x_next(mp); y=mp->cur_cmd;
18095   if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18096   mp_scan_primary(mp);
18097   @<Make sure that the current expression is a valid tension setting@>;
18098   if ( y==at_least ) negate(mp->cur_exp);
18099   right_tension(q)=mp->cur_exp;
18100   if ( mp->cur_cmd==and_command ) {
18101     mp_get_x_next(mp); y=mp->cur_cmd;
18102     if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18103     mp_scan_primary(mp);
18104     @<Make sure that the current expression is a valid tension setting@>;
18105     if ( y==at_least ) negate(mp->cur_exp);
18106   }
18107   y=mp->cur_exp;
18108 }
18109
18110 @ @d min_tension three_quarter_unit
18111
18112 @<Make sure that the current expression is a valid tension setting@>=
18113 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<min_tension) ) {
18114   exp_err("Improper tension has been set to 1");
18115 @.Improper tension@>
18116   help1("The expression above should have been a number >=3/4.");
18117   mp_put_get_flush_error(mp, unity);
18118 }
18119
18120 @ @<Set explicit control points@>=
18121
18122   right_type(q)=explicit; t=explicit; mp_get_x_next(mp); mp_scan_primary(mp);
18123   mp_known_pair(mp); right_x(q)=mp->cur_x; right_y(q)=mp->cur_y;
18124   if ( mp->cur_cmd!=and_command ) {
18125     x=right_x(q); y=right_y(q);
18126   } else { 
18127     mp_get_x_next(mp); mp_scan_primary(mp);
18128     mp_known_pair(mp); x=mp->cur_x; y=mp->cur_y;
18129   }
18130 }
18131
18132 @ @<Convert the right operand, |cur_exp|, into a partial path...@>=
18133
18134   if ( mp->cur_type!=mp_path_type ) pp=mp_new_knot(mp);
18135   else pp=mp->cur_exp;
18136   qq=pp;
18137   while ( link(qq)!=pp ) qq=link(qq);
18138   if ( left_type(pp)!=endpoint ) { /* open up a cycle */
18139     r=mp_copy_knot(mp, pp); link(qq)=r; qq=r;
18140   }
18141   left_type(pp)=open; right_type(qq)=open;
18142 }
18143
18144 @ If a person tries to define an entire path by saying `\.{(x,y)\&cycle}',
18145 we silently change the specification to `\.{(x,y)..cycle}', since a cycle
18146 shouldn't have length zero.
18147
18148 @<Get ready to close a cycle@>=
18149
18150   cycle_hit=true; mp_get_x_next(mp); pp=p; qq=p;
18151   if ( d==ampersand ) if ( p==q ) {
18152     d=path_join; right_tension(q)=unity; y=unity;
18153   }
18154 }
18155
18156 @ @<Join the partial paths and reset |p| and |q|...@>=
18157
18158 if ( d==ampersand ) {
18159   if ( (x_coord(q)!=x_coord(pp))||(y_coord(q)!=y_coord(pp)) ) {
18160     print_err("Paths don't touch; `&' will be changed to `..'");
18161 @.Paths don't touch@>
18162     help3("When you join paths `p&q', the ending point of p")
18163       ("must be exactly equal to the starting point of q.")
18164       ("So I'm going to pretend that you said `p..q' instead.");
18165     mp_put_get_error(mp); d=path_join; right_tension(q)=unity; y=unity;
18166   }
18167 }
18168 @<Plug an opening in |right_type(pp)|, if possible@>;
18169 if ( d==ampersand ) {
18170   @<Splice independent paths together@>;
18171 } else  { 
18172   @<Plug an opening in |right_type(q)|, if possible@>;
18173   link(q)=pp; left_y(pp)=y;
18174   if ( t!=open ) { left_x(pp)=x; left_type(pp)=t;  };
18175 }
18176 q=qq;
18177 }
18178
18179 @ @<Plug an opening in |right_type(q)|...@>=
18180 if ( right_type(q)==open ) {
18181   if ( (left_type(q)==curl)||(left_type(q)==given) ) {
18182     right_type(q)=left_type(q); right_given(q)=left_given(q);
18183   }
18184 }
18185
18186 @ @<Plug an opening in |right_type(pp)|...@>=
18187 if ( right_type(pp)==open ) {
18188   if ( (t==curl)||(t==given) ) {
18189     right_type(pp)=t; right_given(pp)=x;
18190   }
18191 }
18192
18193 @ @<Splice independent paths together@>=
18194
18195   if ( left_type(q)==open ) if ( right_type(q)==open ) {
18196     left_type(q)=curl; left_curl(q)=unity;
18197   }
18198   if ( right_type(pp)==open ) if ( t==open ) {
18199     right_type(pp)=curl; right_curl(pp)=unity;
18200   }
18201   right_type(q)=right_type(pp); link(q)=link(pp);
18202   right_x(q)=right_x(pp); right_y(q)=right_y(pp);
18203   mp_free_node(mp, pp,knot_node_size);
18204   if ( qq==pp ) qq=q;
18205 }
18206
18207 @ @<Choose control points for the path...@>=
18208 if ( cycle_hit ) { 
18209   if ( d==ampersand ) p=q;
18210 } else  { 
18211   left_type(p)=endpoint;
18212   if ( right_type(p)==open ) { 
18213     right_type(p)=curl; right_curl(p)=unity;
18214   }
18215   right_type(q)=endpoint;
18216   if ( left_type(q)==open ) { 
18217     left_type(q)=curl; left_curl(q)=unity;
18218   }
18219   link(q)=p;
18220 }
18221 mp_make_choices(mp, p);
18222 mp->cur_type=mp_path_type; mp->cur_exp=p
18223
18224 @ Finally, we sometimes need to scan an expression whose value is
18225 supposed to be either |true_code| or |false_code|.
18226
18227 @<Declare the basic parsing subroutines@>=
18228 void mp_get_boolean (MP mp) { 
18229   mp_get_x_next(mp); mp_scan_expression(mp);
18230   if ( mp->cur_type!=mp_boolean_type ) {
18231     exp_err("Undefined condition will be treated as `false'");
18232 @.Undefined condition...@>
18233     help2("The expression shown above should have had a definite")
18234       ("true-or-false value. I'm changing it to `false'.");
18235     mp_put_get_flush_error(mp, false_code); mp->cur_type=mp_boolean_type;
18236   }
18237 }
18238
18239 @* \[39] Doing the operations.
18240 The purpose of parsing is primarily to permit people to avoid piles of
18241 parentheses. But the real work is done after the structure of an expression
18242 has been recognized; that's when new expressions are generated. We
18243 turn now to the guts of \MP, which handles individual operators that
18244 have come through the parsing mechanism.
18245
18246 We'll start with the easy ones that take no operands, then work our way
18247 up to operators with one and ultimately two arguments. In other words,
18248 we will write the three procedures |do_nullary|, |do_unary|, and |do_binary|
18249 that are invoked periodically by the expression scanners.
18250
18251 First let's make sure that all of the primitive operators are in the
18252 hash table. Although |scan_primary| and its relatives made use of the
18253 \\{cmd} code for these operators, the \\{do} routines base everything
18254 on the \\{mod} code. For example, |do_binary| doesn't care whether the
18255 operation it performs is a |primary_binary| or |secondary_binary|, etc.
18256
18257 @<Put each...@>=
18258 mp_primitive(mp, "true",nullary,true_code);
18259 @:true_}{\&{true} primitive@>
18260 mp_primitive(mp, "false",nullary,false_code);
18261 @:false_}{\&{false} primitive@>
18262 mp_primitive(mp, "nullpicture",nullary,null_picture_code);
18263 @:null_picture_}{\&{nullpicture} primitive@>
18264 mp_primitive(mp, "nullpen",nullary,null_pen_code);
18265 @:null_pen_}{\&{nullpen} primitive@>
18266 mp_primitive(mp, "jobname",nullary,job_name_op);
18267 @:job_name_}{\&{jobname} primitive@>
18268 mp_primitive(mp, "readstring",nullary,read_string_op);
18269 @:read_string_}{\&{readstring} primitive@>
18270 mp_primitive(mp, "pencircle",nullary,pen_circle);
18271 @:pen_circle_}{\&{pencircle} primitive@>
18272 mp_primitive(mp, "normaldeviate",nullary,normal_deviate);
18273 @:normal_deviate_}{\&{normaldeviate} primitive@>
18274 mp_primitive(mp, "readfrom",unary,read_from_op);
18275 @:read_from_}{\&{readfrom} primitive@>
18276 mp_primitive(mp, "closefrom",unary,close_from_op);
18277 @:close_from_}{\&{closefrom} primitive@>
18278 mp_primitive(mp, "odd",unary,odd_op);
18279 @:odd_}{\&{odd} primitive@>
18280 mp_primitive(mp, "known",unary,known_op);
18281 @:known_}{\&{known} primitive@>
18282 mp_primitive(mp, "unknown",unary,unknown_op);
18283 @:unknown_}{\&{unknown} primitive@>
18284 mp_primitive(mp, "not",unary,not_op);
18285 @:not_}{\&{not} primitive@>
18286 mp_primitive(mp, "decimal",unary,decimal);
18287 @:decimal_}{\&{decimal} primitive@>
18288 mp_primitive(mp, "reverse",unary,reverse);
18289 @:reverse_}{\&{reverse} primitive@>
18290 mp_primitive(mp, "makepath",unary,make_path_op);
18291 @:make_path_}{\&{makepath} primitive@>
18292 mp_primitive(mp, "makepen",unary,make_pen_op);
18293 @:make_pen_}{\&{makepen} primitive@>
18294 mp_primitive(mp, "oct",unary,oct_op);
18295 @:oct_}{\&{oct} primitive@>
18296 mp_primitive(mp, "hex",unary,hex_op);
18297 @:hex_}{\&{hex} primitive@>
18298 mp_primitive(mp, "ASCII",unary,ASCII_op);
18299 @:ASCII_}{\&{ASCII} primitive@>
18300 mp_primitive(mp, "char",unary,char_op);
18301 @:char_}{\&{char} primitive@>
18302 mp_primitive(mp, "length",unary,length_op);
18303 @:length_}{\&{length} primitive@>
18304 mp_primitive(mp, "turningnumber",unary,turning_op);
18305 @:turning_number_}{\&{turningnumber} primitive@>
18306 mp_primitive(mp, "xpart",unary,x_part);
18307 @:x_part_}{\&{xpart} primitive@>
18308 mp_primitive(mp, "ypart",unary,y_part);
18309 @:y_part_}{\&{ypart} primitive@>
18310 mp_primitive(mp, "xxpart",unary,xx_part);
18311 @:xx_part_}{\&{xxpart} primitive@>
18312 mp_primitive(mp, "xypart",unary,xy_part);
18313 @:xy_part_}{\&{xypart} primitive@>
18314 mp_primitive(mp, "yxpart",unary,yx_part);
18315 @:yx_part_}{\&{yxpart} primitive@>
18316 mp_primitive(mp, "yypart",unary,yy_part);
18317 @:yy_part_}{\&{yypart} primitive@>
18318 mp_primitive(mp, "redpart",unary,red_part);
18319 @:red_part_}{\&{redpart} primitive@>
18320 mp_primitive(mp, "greenpart",unary,green_part);
18321 @:green_part_}{\&{greenpart} primitive@>
18322 mp_primitive(mp, "bluepart",unary,blue_part);
18323 @:blue_part_}{\&{bluepart} primitive@>
18324 mp_primitive(mp, "cyanpart",unary,cyan_part);
18325 @:cyan_part_}{\&{cyanpart} primitive@>
18326 mp_primitive(mp, "magentapart",unary,magenta_part);
18327 @:magenta_part_}{\&{magentapart} primitive@>
18328 mp_primitive(mp, "yellowpart",unary,yellow_part);
18329 @:yellow_part_}{\&{yellowpart} primitive@>
18330 mp_primitive(mp, "blackpart",unary,black_part);
18331 @:black_part_}{\&{blackpart} primitive@>
18332 mp_primitive(mp, "greypart",unary,grey_part);
18333 @:grey_part_}{\&{greypart} primitive@>
18334 mp_primitive(mp, "colormodel",unary,color_model_part);
18335 @:color_model_part_}{\&{colormodel} primitive@>
18336 mp_primitive(mp, "fontpart",unary,font_part);
18337 @:font_part_}{\&{fontpart} primitive@>
18338 mp_primitive(mp, "textpart",unary,text_part);
18339 @:text_part_}{\&{textpart} primitive@>
18340 mp_primitive(mp, "pathpart",unary,path_part);
18341 @:path_part_}{\&{pathpart} primitive@>
18342 mp_primitive(mp, "penpart",unary,pen_part);
18343 @:pen_part_}{\&{penpart} primitive@>
18344 mp_primitive(mp, "dashpart",unary,dash_part);
18345 @:dash_part_}{\&{dashpart} primitive@>
18346 mp_primitive(mp, "sqrt",unary,sqrt_op);
18347 @:sqrt_}{\&{sqrt} primitive@>
18348 mp_primitive(mp, "mexp",unary,m_exp_op);
18349 @:m_exp_}{\&{mexp} primitive@>
18350 mp_primitive(mp, "mlog",unary,m_log_op);
18351 @:m_log_}{\&{mlog} primitive@>
18352 mp_primitive(mp, "sind",unary,sin_d_op);
18353 @:sin_d_}{\&{sind} primitive@>
18354 mp_primitive(mp, "cosd",unary,cos_d_op);
18355 @:cos_d_}{\&{cosd} primitive@>
18356 mp_primitive(mp, "floor",unary,floor_op);
18357 @:floor_}{\&{floor} primitive@>
18358 mp_primitive(mp, "uniformdeviate",unary,uniform_deviate);
18359 @:uniform_deviate_}{\&{uniformdeviate} primitive@>
18360 mp_primitive(mp, "charexists",unary,char_exists_op);
18361 @:char_exists_}{\&{charexists} primitive@>
18362 mp_primitive(mp, "fontsize",unary,font_size);
18363 @:font_size_}{\&{fontsize} primitive@>
18364 mp_primitive(mp, "llcorner",unary,ll_corner_op);
18365 @:ll_corner_}{\&{llcorner} primitive@>
18366 mp_primitive(mp, "lrcorner",unary,lr_corner_op);
18367 @:lr_corner_}{\&{lrcorner} primitive@>
18368 mp_primitive(mp, "ulcorner",unary,ul_corner_op);
18369 @:ul_corner_}{\&{ulcorner} primitive@>
18370 mp_primitive(mp, "urcorner",unary,ur_corner_op);
18371 @:ur_corner_}{\&{urcorner} primitive@>
18372 mp_primitive(mp, "arclength",unary,arc_length);
18373 @:arc_length_}{\&{arclength} primitive@>
18374 mp_primitive(mp, "angle",unary,angle_op);
18375 @:angle_}{\&{angle} primitive@>
18376 mp_primitive(mp, "cycle",cycle,cycle_op);
18377 @:cycle_}{\&{cycle} primitive@>
18378 mp_primitive(mp, "stroked",unary,stroked_op);
18379 @:stroked_}{\&{stroked} primitive@>
18380 mp_primitive(mp, "filled",unary,filled_op);
18381 @:filled_}{\&{filled} primitive@>
18382 mp_primitive(mp, "textual",unary,textual_op);
18383 @:textual_}{\&{textual} primitive@>
18384 mp_primitive(mp, "clipped",unary,clipped_op);
18385 @:clipped_}{\&{clipped} primitive@>
18386 mp_primitive(mp, "bounded",unary,bounded_op);
18387 @:bounded_}{\&{bounded} primitive@>
18388 mp_primitive(mp, "+",plus_or_minus,plus);
18389 @:+ }{\.{+} primitive@>
18390 mp_primitive(mp, "-",plus_or_minus,minus);
18391 @:- }{\.{-} primitive@>
18392 mp_primitive(mp, "*",secondary_binary,times);
18393 @:* }{\.{*} primitive@>
18394 mp_primitive(mp, "/",slash,over); mp->eqtb[frozen_slash]=mp->eqtb[mp->cur_sym];
18395 @:/ }{\.{/} primitive@>
18396 mp_primitive(mp, "++",tertiary_binary,pythag_add);
18397 @:++_}{\.{++} primitive@>
18398 mp_primitive(mp, "+-+",tertiary_binary,pythag_sub);
18399 @:+-+_}{\.{+-+} primitive@>
18400 mp_primitive(mp, "or",tertiary_binary,or_op);
18401 @:or_}{\&{or} primitive@>
18402 mp_primitive(mp, "and",and_command,and_op);
18403 @:and_}{\&{and} primitive@>
18404 mp_primitive(mp, "<",expression_binary,less_than);
18405 @:< }{\.{<} primitive@>
18406 mp_primitive(mp, "<=",expression_binary,less_or_equal);
18407 @:<=_}{\.{<=} primitive@>
18408 mp_primitive(mp, ">",expression_binary,greater_than);
18409 @:> }{\.{>} primitive@>
18410 mp_primitive(mp, ">=",expression_binary,greater_or_equal);
18411 @:>=_}{\.{>=} primitive@>
18412 mp_primitive(mp, "=",equals,equal_to);
18413 @:= }{\.{=} primitive@>
18414 mp_primitive(mp, "<>",expression_binary,unequal_to);
18415 @:<>_}{\.{<>} primitive@>
18416 mp_primitive(mp, "substring",primary_binary,substring_of);
18417 @:substring_}{\&{substring} primitive@>
18418 mp_primitive(mp, "subpath",primary_binary,subpath_of);
18419 @:subpath_}{\&{subpath} primitive@>
18420 mp_primitive(mp, "directiontime",primary_binary,direction_time_of);
18421 @:direction_time_}{\&{directiontime} primitive@>
18422 mp_primitive(mp, "point",primary_binary,point_of);
18423 @:point_}{\&{point} primitive@>
18424 mp_primitive(mp, "precontrol",primary_binary,precontrol_of);
18425 @:precontrol_}{\&{precontrol} primitive@>
18426 mp_primitive(mp, "postcontrol",primary_binary,postcontrol_of);
18427 @:postcontrol_}{\&{postcontrol} primitive@>
18428 mp_primitive(mp, "penoffset",primary_binary,pen_offset_of);
18429 @:pen_offset_}{\&{penoffset} primitive@>
18430 mp_primitive(mp, "arctime",primary_binary,arc_time_of);
18431 @:arc_time_of_}{\&{arctime} primitive@>
18432 mp_primitive(mp, "mpversion",nullary,mp_version);
18433 @:mp_verison_}{\&{mpversion} primitive@>
18434 mp_primitive(mp, "&",ampersand,concatenate);
18435 @:!!!}{\.{\&} primitive@>
18436 mp_primitive(mp, "rotated",secondary_binary,rotated_by);
18437 @:rotated_}{\&{rotated} primitive@>
18438 mp_primitive(mp, "slanted",secondary_binary,slanted_by);
18439 @:slanted_}{\&{slanted} primitive@>
18440 mp_primitive(mp, "scaled",secondary_binary,scaled_by);
18441 @:scaled_}{\&{scaled} primitive@>
18442 mp_primitive(mp, "shifted",secondary_binary,shifted_by);
18443 @:shifted_}{\&{shifted} primitive@>
18444 mp_primitive(mp, "transformed",secondary_binary,transformed_by);
18445 @:transformed_}{\&{transformed} primitive@>
18446 mp_primitive(mp, "xscaled",secondary_binary,x_scaled);
18447 @:x_scaled_}{\&{xscaled} primitive@>
18448 mp_primitive(mp, "yscaled",secondary_binary,y_scaled);
18449 @:y_scaled_}{\&{yscaled} primitive@>
18450 mp_primitive(mp, "zscaled",secondary_binary,z_scaled);
18451 @:z_scaled_}{\&{zscaled} primitive@>
18452 mp_primitive(mp, "infont",secondary_binary,in_font);
18453 @:in_font_}{\&{infont} primitive@>
18454 mp_primitive(mp, "intersectiontimes",tertiary_binary,intersect);
18455 @:intersection_times_}{\&{intersectiontimes} primitive@>
18456
18457 @ @<Cases of |print_cmd...@>=
18458 case nullary:
18459 case unary:
18460 case primary_binary:
18461 case secondary_binary:
18462 case tertiary_binary:
18463 case expression_binary:
18464 case cycle:
18465 case plus_or_minus:
18466 case slash:
18467 case ampersand:
18468 case equals:
18469 case and_command:
18470   mp_print_op(mp, m);
18471   break;
18472
18473 @ OK, let's look at the simplest \\{do} procedure first.
18474
18475 @c @<Declare nullary action procedure@>;
18476 void mp_do_nullary (MP mp,quarterword c) { 
18477   check_arith;
18478   if ( mp->internal[tracing_commands]>two )
18479     mp_show_cmd_mod(mp, nullary,c);
18480   switch (c) {
18481   case true_code: case false_code: 
18482     mp->cur_type=mp_boolean_type; mp->cur_exp=c;
18483     break;
18484   case null_picture_code: 
18485     mp->cur_type=mp_picture_type;
18486     mp->cur_exp=mp_get_node(mp, edge_header_size); 
18487     mp_init_edges(mp, mp->cur_exp);
18488     break;
18489   case null_pen_code: 
18490     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, 0);
18491     break;
18492   case normal_deviate: 
18493     mp->cur_type=mp_known; mp->cur_exp=mp_norm_rand(mp);
18494     break;
18495   case pen_circle: 
18496     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, unity);
18497     break;
18498   case job_name_op:  
18499     if ( mp->job_name==NULL ) mp_open_log_file(mp);
18500     mp->cur_type=mp_string_type; mp->cur_exp=rts(mp->job_name);
18501     break;
18502   case mp_version: 
18503     mp->cur_type=mp_string_type; 
18504     mp->cur_exp=intern(metapost_version) ;
18505     break;
18506   case read_string_op:
18507     @<Read a string from the terminal@>;
18508     break;
18509   } /* there are no other cases */
18510   check_arith;
18511 }
18512
18513 @ @<Read a string...@>=
18514
18515   if ( mp->interaction<=mp_nonstop_mode )
18516     mp_fatal_error(mp, "*** (cannot readstring in nonstop modes)");
18517   mp_begin_file_reading(mp); name=is_read;
18518   limit=start; prompt_input("");
18519   mp_finish_read(mp);
18520 }
18521
18522 @ @<Declare nullary action procedure@>=
18523 void mp_finish_read (MP mp) { /* copy |buffer| line to |cur_exp| */
18524   size_t k;
18525   str_room((int)mp->last-start);
18526   for (k=start;k<=mp->last-1;k++) {
18527    append_char(mp->buffer[k]);
18528   }
18529   mp_end_file_reading(mp); mp->cur_type=mp_string_type; 
18530   mp->cur_exp=mp_make_string(mp);
18531 }
18532
18533 @ Things get a bit more interesting when there's an operand. The
18534 operand to |do_unary| appears in |cur_type| and |cur_exp|.
18535
18536 @c @<Declare unary action procedures@>;
18537 void mp_do_unary (MP mp,quarterword c) {
18538   pointer p,q,r; /* for list manipulation */
18539   integer x; /* a temporary register */
18540   check_arith;
18541   if ( mp->internal[tracing_commands]>two )
18542     @<Trace the current unary operation@>;
18543   switch (c) {
18544   case plus:
18545     if ( mp->cur_type<mp_color_type ) mp_bad_unary(mp, plus);
18546     break;
18547   case minus:
18548     @<Negate the current expression@>;
18549     break;
18550   @<Additional cases of unary operators@>;
18551   } /* there are no other cases */
18552   check_arith;
18553 };
18554
18555 @ The |nice_pair| function returns |true| if both components of a pair
18556 are known.
18557
18558 @<Declare unary action procedures@>=
18559 boolean mp_nice_pair (MP mp,integer p, quarterword t) { 
18560   if ( t==mp_pair_type ) {
18561     p=value(p);
18562     if ( type(x_part_loc(p))==mp_known )
18563       if ( type(y_part_loc(p))==mp_known )
18564         return true;
18565   }
18566   return false;
18567 }
18568
18569 @ The |nice_color_or_pair| function is analogous except that it also accepts
18570 fully known colors.
18571
18572 @<Declare unary action procedures@>=
18573 boolean mp_nice_color_or_pair (MP mp,integer p, quarterword t) {
18574   pointer q,r; /* for scanning the big node */
18575   if ( (t!=mp_pair_type)&&(t!=mp_color_type)&&(t!=mp_cmykcolor_type) ) {
18576     return false;
18577   } else { 
18578     q=value(p);
18579     r=q+mp->big_node_size[type(p)];
18580     do {  
18581       r=r-2;
18582       if ( type(r)!=mp_known )
18583         return false;
18584     } while (r!=q);
18585     return true;
18586   }
18587 }
18588
18589 @ @<Declare unary action...@>=
18590 void mp_print_known_or_unknown_type (MP mp,small_number t, integer v) { 
18591   mp_print_char(mp, '(');
18592   if ( t>mp_known ) mp_print(mp, "unknown numeric");
18593   else { if ( (t==mp_pair_type)||(t==mp_color_type)||(t==mp_cmykcolor_type) )
18594     if ( ! mp_nice_color_or_pair(mp, v,t) ) mp_print(mp, "unknown ");
18595     mp_print_type(mp, t);
18596   }
18597   mp_print_char(mp, ')');
18598 }
18599
18600 @ @<Declare unary action...@>=
18601 void mp_bad_unary (MP mp,quarterword c) { 
18602   exp_err("Not implemented: "); mp_print_op(mp, c);
18603 @.Not implemented...@>
18604   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
18605   help3("I'm afraid I don't know how to apply that operation to that")
18606     ("particular type. Continue, and I'll simply return the")
18607     ("argument (shown above) as the result of the operation.");
18608   mp_put_get_error(mp);
18609 }
18610
18611 @ @<Trace the current unary operation@>=
18612
18613   mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); 
18614   mp_print_op(mp, c); mp_print_char(mp, '(');
18615   mp_print_exp(mp, null,0); /* show the operand, but not verbosely */
18616   mp_print(mp, ")}"); mp_end_diagnostic(mp, false);
18617 }
18618
18619 @ Negation is easy except when the current expression
18620 is of type |independent|, or when it is a pair with one or more
18621 |independent| components.
18622
18623 It is tempting to argue that the negative of an independent variable
18624 is an independent variable, hence we don't have to do anything when
18625 negating it. The fallacy is that other dependent variables pointing
18626 to the current expression must change the sign of their
18627 coefficients if we make no change to the current expression.
18628
18629 Instead, we work around the problem by copying the current expression
18630 and recycling it afterwards (cf.~the |stash_in| routine).
18631
18632 @<Negate the current expression@>=
18633 switch (mp->cur_type) {
18634 case mp_color_type:
18635 case mp_cmykcolor_type:
18636 case mp_pair_type:
18637 case mp_independent: 
18638   q=mp->cur_exp; mp_make_exp_copy(mp, q);
18639   if ( mp->cur_type==mp_dependent ) {
18640     mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18641   } else if ( mp->cur_type<=mp_pair_type ) { /* |mp_color_type| or |mp_pair_type| */
18642     p=value(mp->cur_exp);
18643     r=p+mp->big_node_size[mp->cur_type];
18644     do {  
18645       r=r-2;
18646       if ( type(r)==mp_known ) negate(value(r));
18647       else mp_negate_dep_list(mp, dep_list(r));
18648     } while (r!=p);
18649   } /* if |cur_type=mp_known| then |cur_exp=0| */
18650   mp_recycle_value(mp, q); mp_free_node(mp, q,value_node_size);
18651   break;
18652 case mp_dependent:
18653 case mp_proto_dependent:
18654   mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18655   break;
18656 case mp_known:
18657   negate(mp->cur_exp);
18658   break;
18659 default:
18660   mp_bad_unary(mp, minus);
18661   break;
18662 }
18663
18664 @ @<Declare unary action...@>=
18665 void mp_negate_dep_list (MP mp,pointer p) { 
18666   while (1) { 
18667     negate(value(p));
18668     if ( info(p)==null ) return;
18669     p=link(p);
18670   }
18671 }
18672
18673 @ @<Additional cases of unary operators@>=
18674 case not_op: 
18675   if ( mp->cur_type!=mp_boolean_type ) mp_bad_unary(mp, not_op);
18676   else mp->cur_exp=true_code+false_code-mp->cur_exp;
18677   break;
18678
18679 @ @d three_sixty_units 23592960 /* that's |360*unity| */
18680 @d boolean_reset(A) if ( (A) ) mp->cur_exp=true_code; else mp->cur_exp=false_code
18681
18682 @<Additional cases of unary operators@>=
18683 case sqrt_op:
18684 case m_exp_op:
18685 case m_log_op:
18686 case sin_d_op:
18687 case cos_d_op:
18688 case floor_op:
18689 case  uniform_deviate:
18690 case odd_op:
18691 case char_exists_op:
18692   if ( mp->cur_type!=mp_known ) {
18693     mp_bad_unary(mp, c);
18694   } else {
18695     switch (c) {
18696     case sqrt_op:mp->cur_exp=mp_square_rt(mp, mp->cur_exp);break;
18697     case m_exp_op:mp->cur_exp=mp_m_exp(mp, mp->cur_exp);break;
18698     case m_log_op:mp->cur_exp=mp_m_log(mp, mp->cur_exp);break;
18699     case sin_d_op:
18700     case cos_d_op:
18701       mp_n_sin_cos(mp, (mp->cur_exp % three_sixty_units)*16);
18702       if ( c==sin_d_op ) mp->cur_exp=mp_round_fraction(mp, mp->n_sin);
18703       else mp->cur_exp=mp_round_fraction(mp, mp->n_cos);
18704       break;
18705     case floor_op:mp->cur_exp=mp_floor_scaled(mp, mp->cur_exp);break;
18706     case uniform_deviate:mp->cur_exp=mp_unif_rand(mp, mp->cur_exp);break;
18707     case odd_op: 
18708       boolean_reset(odd(mp_round_unscaled(mp, mp->cur_exp)));
18709       mp->cur_type=mp_boolean_type;
18710       break;
18711     case char_exists_op:
18712       @<Determine if a character has been shipped out@>;
18713       break;
18714     } /* there are no other cases */
18715   }
18716   break;
18717
18718 @ @<Additional cases of unary operators@>=
18719 case angle_op:
18720   if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) ) {
18721     p=value(mp->cur_exp);
18722     x=mp_n_arg(mp, value(x_part_loc(p)),value(y_part_loc(p)));
18723     if ( x>=0 ) mp_flush_cur_exp(mp, (x+8)/ 16);
18724     else mp_flush_cur_exp(mp, -((-x+8)/ 16));
18725   } else {
18726     mp_bad_unary(mp, angle_op);
18727   }
18728   break;
18729
18730 @ If the current expression is a pair, but the context wants it to
18731 be a path, we call |pair_to_path|.
18732
18733 @<Declare unary action...@>=
18734 void mp_pair_to_path (MP mp) { 
18735   mp->cur_exp=mp_new_knot(mp); 
18736   mp->cur_type=mp_path_type;
18737 };
18738
18739 @ @<Additional cases of unary operators@>=
18740 case x_part:
18741 case y_part:
18742   if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_transform_type) )
18743     mp_take_part(mp, c);
18744   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18745   else mp_bad_unary(mp, c);
18746   break;
18747 case xx_part:
18748 case xy_part:
18749 case yx_part:
18750 case yy_part: 
18751   if ( mp->cur_type==mp_transform_type ) mp_take_part(mp, c);
18752   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18753   else mp_bad_unary(mp, c);
18754   break;
18755 case red_part:
18756 case green_part:
18757 case blue_part: 
18758   if ( mp->cur_type==mp_color_type ) mp_take_part(mp, c);
18759   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18760   else mp_bad_unary(mp, c);
18761   break;
18762 case cyan_part:
18763 case magenta_part:
18764 case yellow_part:
18765 case black_part: 
18766   if ( mp->cur_type==mp_cmykcolor_type) mp_take_part(mp, c); 
18767   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18768   else mp_bad_unary(mp, c);
18769   break;
18770 case grey_part: 
18771   if ( mp->cur_type==mp_known ) mp->cur_exp=value(c);
18772   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18773   else mp_bad_unary(mp, c);
18774   break;
18775 case color_model_part: 
18776   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18777   else mp_bad_unary(mp, c);
18778   break;
18779
18780 @ In the following procedure, |cur_exp| points to a capsule, which points to
18781 a big node. We want to delete all but one part of the big node.
18782
18783 @<Declare unary action...@>=
18784 void mp_take_part (MP mp,quarterword c) {
18785   pointer p; /* the big node */
18786   p=value(mp->cur_exp); value(temp_val)=p; type(temp_val)=mp->cur_type;
18787   link(p)=temp_val; mp_free_node(mp, mp->cur_exp,value_node_size);
18788   mp_make_exp_copy(mp, p+mp->sector_offset[c+mp_x_part_sector-x_part]);
18789   mp_recycle_value(mp, temp_val);
18790 }
18791
18792 @ @<Initialize table entries...@>=
18793 name_type(temp_val)=mp_capsule;
18794
18795 @ @<Additional cases of unary operators@>=
18796 case font_part:
18797 case text_part:
18798 case path_part:
18799 case pen_part:
18800 case dash_part:
18801   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
18802   else mp_bad_unary(mp, c);
18803   break;
18804
18805 @ @<Declarations@>=
18806 void mp_scale_edges (MP mp);
18807
18808 @ @<Declare unary action...@>=
18809 void mp_take_pict_part (MP mp,quarterword c) {
18810   pointer p; /* first graphical object in |cur_exp| */
18811   p=link(dummy_loc(mp->cur_exp));
18812   if ( p!=null ) {
18813     switch (c) {
18814     case x_part: case y_part: case xx_part:
18815     case xy_part: case yx_part: case yy_part:
18816       if ( type(p)==text_code ) mp_flush_cur_exp(mp, text_trans_part(p+c));
18817       else goto NOT_FOUND;
18818       break;
18819     case red_part: case green_part: case blue_part:
18820       if ( has_color(p) ) mp_flush_cur_exp(mp, obj_color_part(p+c));
18821       else goto NOT_FOUND;
18822       break;
18823     case cyan_part: case magenta_part: case yellow_part:
18824     case black_part:
18825       if ( has_color(p) ) {
18826         if ( color_model(p)==uninitialized_model )
18827           mp_flush_cur_exp(mp, unity);
18828         else
18829           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-cyan_part)));
18830       } else goto NOT_FOUND;
18831       break;
18832     case grey_part:
18833       if ( has_color(p) )
18834           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-grey_part)));
18835       else goto NOT_FOUND;
18836       break;
18837     case color_model_part:
18838       if ( has_color(p) ) {
18839         if ( color_model(p)==uninitialized_model )
18840           mp_flush_cur_exp(mp, mp->internal[default_color_model]);
18841         else
18842           mp_flush_cur_exp(mp, color_model(p)*unity);
18843       } else goto NOT_FOUND;
18844       break;
18845     @<Handle other cases in |take_pict_part| or |goto not_found|@>;
18846     } /* all cases have been enumerated */
18847     return;
18848   };
18849 NOT_FOUND:
18850   @<Convert the current expression to a null value appropriate
18851     for |c|@>;
18852 }
18853
18854 @ @<Handle other cases in |take_pict_part| or |goto not_found|@>=
18855 case text_part: 
18856   if ( type(p)!=text_code ) goto NOT_FOUND;
18857   else { 
18858     mp_flush_cur_exp(mp, text_p(p));
18859     add_str_ref(mp->cur_exp);
18860     mp->cur_type=mp_string_type;
18861     };
18862   break;
18863 case font_part: 
18864   if ( type(p)!=text_code ) goto NOT_FOUND;
18865   else { 
18866     mp_flush_cur_exp(mp, rts(mp->font_name[font_n(p)])); 
18867     add_str_ref(mp->cur_exp);
18868     mp->cur_type=mp_string_type;
18869   };
18870   break;
18871 case path_part:
18872   if ( type(p)==text_code ) goto NOT_FOUND;
18873   else if ( is_stop(p) ) mp_confusion(mp, "pict");
18874 @:this can't happen pict}{\quad pict@>
18875   else { 
18876     mp_flush_cur_exp(mp, mp_copy_path(mp, path_p(p)));
18877     mp->cur_type=mp_path_type;
18878   }
18879   break;
18880 case pen_part: 
18881   if ( ! has_pen(p) ) goto NOT_FOUND;
18882   else {
18883     if ( pen_p(p)==null ) goto NOT_FOUND;
18884     else { mp_flush_cur_exp(mp, copy_pen(pen_p(p)));
18885       mp->cur_type=mp_pen_type;
18886     };
18887   }
18888   break;
18889 case dash_part: 
18890   if ( type(p)!=stroked_code ) goto NOT_FOUND;
18891   else { if ( dash_p(p)==null ) goto NOT_FOUND;
18892     else { add_edge_ref(dash_p(p));
18893     mp->se_sf=dash_scale(p);
18894     mp->se_pic=dash_p(p);
18895     mp_scale_edges(mp);
18896     mp_flush_cur_exp(mp, mp->se_pic);
18897     mp->cur_type=mp_picture_type;
18898     };
18899   }
18900   break;
18901
18902 @ Since |scale_edges| had to be declared |forward|, it had to be declared as a
18903 parameterless procedure even though it really takes two arguments and updates
18904 one of them.  Hence the following globals are needed.
18905
18906 @<Global...@>=
18907 pointer se_pic;  /* edge header used and updated by |scale_edges| */
18908 scaled se_sf;  /* the scale factor argument to |scale_edges| */
18909
18910 @ @<Convert the current expression to a null value appropriate...@>=
18911 switch (c) {
18912 case text_part: case font_part: 
18913   mp_flush_cur_exp(mp, rts(""));
18914   mp->cur_type=mp_string_type;
18915   break;
18916 case path_part: 
18917   mp_flush_cur_exp(mp, mp_get_node(mp, knot_node_size));
18918   left_type(mp->cur_exp)=endpoint;
18919   right_type(mp->cur_exp)=endpoint;
18920   link(mp->cur_exp)=mp->cur_exp;
18921   x_coord(mp->cur_exp)=0;
18922   y_coord(mp->cur_exp)=0;
18923   originator(mp->cur_exp)=metapost_user;
18924   mp->cur_type=mp_path_type;
18925   break;
18926 case pen_part: 
18927   mp_flush_cur_exp(mp, mp_get_pen_circle(mp, 0));
18928   mp->cur_type=mp_pen_type;
18929   break;
18930 case dash_part: 
18931   mp_flush_cur_exp(mp, mp_get_node(mp, edge_header_size));
18932   mp_init_edges(mp, mp->cur_exp);
18933   mp->cur_type=mp_picture_type;
18934   break;
18935 default: 
18936    mp_flush_cur_exp(mp, 0);
18937   break;
18938 }
18939
18940 @ @<Additional cases of unary...@>=
18941 case char_op: 
18942   if ( mp->cur_type!=mp_known ) { 
18943     mp_bad_unary(mp, char_op);
18944   } else { 
18945     mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256; 
18946     mp->cur_type=mp_string_type;
18947     if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
18948   }
18949   break;
18950 case decimal: 
18951   if ( mp->cur_type!=mp_known ) {
18952      mp_bad_unary(mp, decimal);
18953   } else { 
18954     mp->old_setting=mp->selector; mp->selector=new_string;
18955     mp_print_scaled(mp, mp->cur_exp); mp->cur_exp=mp_make_string(mp);
18956     mp->selector=mp->old_setting; mp->cur_type=mp_string_type;
18957   }
18958   break;
18959 case oct_op:
18960 case hex_op:
18961 case ASCII_op: 
18962   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
18963   else mp_str_to_num(mp, c);
18964   break;
18965 case font_size: 
18966   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, font_size);
18967   else @<Find the design size of the font whose name is |cur_exp|@>;
18968   break;
18969
18970 @ @<Declare unary action...@>=
18971 void mp_str_to_num (MP mp,quarterword c) { /* converts a string to a number */
18972   integer n; /* accumulator */
18973   ASCII_code m; /* current character */
18974   pool_pointer k; /* index into |str_pool| */
18975   int b; /* radix of conversion */
18976   boolean bad_char; /* did the string contain an invalid digit? */
18977   if ( c==ASCII_op ) {
18978     if ( length(mp->cur_exp)==0 ) n=-1;
18979     else n=mp->str_pool[mp->str_start[mp->cur_exp]];
18980   } else { 
18981     if ( c==oct_op ) b=8; else b=16;
18982     n=0; bad_char=false;
18983     for (k=mp->str_start[mp->cur_exp];k<=str_stop(mp->cur_exp)-1;k++) {
18984       m=mp->str_pool[k];
18985       if ( (m>='0')&&(m<='9') ) m=m-'0';
18986       else if ( (m>='A')&&(m<='F') ) m=m-'A'+10;
18987       else if ( (m>='a')&&(m<='f') ) m=m-'a'+10;
18988       else  { bad_char=true; m=0; };
18989       if ( m>=b ) { bad_char=true; m=0; };
18990       if ( n<32768 / b ) n=n*b+m; else n=32767;
18991     }
18992     @<Give error messages if |bad_char| or |n>=4096|@>;
18993   }
18994   mp_flush_cur_exp(mp, n*unity);
18995 }
18996
18997 @ @<Give error messages if |bad_char|...@>=
18998 if ( bad_char ) { 
18999   exp_err("String contains illegal digits");
19000 @.String contains illegal digits@>
19001   if ( c==oct_op ) {
19002     help1("I zeroed out characters that weren't in the range 0..7.");
19003   } else  {
19004     help1("I zeroed out characters that weren't hex digits.");
19005   }
19006   mp_put_get_error(mp);
19007 }
19008 if ( (n>4095) ) {
19009   if ( mp->internal[warning_check]>0 ) {
19010     print_err("Number too large ("); 
19011     mp_print_int(mp, n); mp_print_char(mp, ')');
19012 @.Number too large@>
19013     help2("I have trouble with numbers greater than 4095; watch out.")
19014       ("(Set warningcheck:=0 to suppress this message.)");
19015     mp_put_get_error(mp);
19016   }
19017 }
19018
19019 @ The length operation is somewhat unusual in that it applies to a variety
19020 of different types of operands.
19021
19022 @<Additional cases of unary...@>=
19023 case length_op: 
19024   switch (mp->cur_type) {
19025   case mp_string_type: mp_flush_cur_exp(mp, length(mp->cur_exp)*unity); break;
19026   case mp_path_type: mp_flush_cur_exp(mp, mp_path_length(mp)); break;
19027   case mp_known: mp->cur_exp=abs(mp->cur_exp); break;
19028   case mp_picture_type: mp_flush_cur_exp(mp, mp_pict_length(mp)); break;
19029   default: 
19030     if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) )
19031       mp_flush_cur_exp(mp, mp_pyth_add(mp, 
19032         value(x_part_loc(value(mp->cur_exp))),
19033         value(y_part_loc(value(mp->cur_exp)))));
19034     else mp_bad_unary(mp, c);
19035     break;
19036   }
19037   break;
19038
19039 @ @<Declare unary action...@>=
19040 scaled mp_path_length (MP mp) { /* computes the length of the current path */
19041   scaled n; /* the path length so far */
19042   pointer p; /* traverser */
19043   p=mp->cur_exp;
19044   if ( left_type(p)==endpoint ) n=-unity; else n=0;
19045   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
19046   return n;
19047 }
19048
19049 @ @<Declare unary action...@>=
19050 scaled mp_pict_length (MP mp) { 
19051   /* counts interior components in picture |cur_exp| */
19052   scaled n; /* the count so far */
19053   pointer p; /* traverser */
19054   n=0;
19055   p=link(dummy_loc(mp->cur_exp));
19056   if ( p!=null ) {
19057     if ( is_start_or_stop(p) )
19058       if ( mp_skip_1component(mp, p)==null ) p=link(p);
19059     while ( p!=null )  { 
19060       skip_component(p) return n; 
19061       n=n+unity;   
19062     }
19063   }
19064   return n;
19065 }
19066
19067 @ Implement |turningnumber|
19068
19069 @<Additional cases of unary...@>=
19070 case turning_op:
19071   if ( mp->cur_type==mp_pair_type ) mp_flush_cur_exp(mp, 0);
19072   else if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, turning_op);
19073   else if ( left_type(mp->cur_exp)==endpoint )
19074      mp_flush_cur_exp(mp, 0); /* not a cyclic path */
19075   else
19076     mp_flush_cur_exp(mp, mp_turn_cycles_wrapper(mp, mp->cur_exp));
19077   break;
19078
19079 @ The function |an_angle| returns the value of the |angle| primitive, or $0$ if the
19080 argument is |origin|.
19081
19082 @<Declare unary action...@>=
19083 angle mp_an_angle (MP mp,scaled xpar, scaled ypar) {
19084   if ( (! ((xpar==0) && (ypar==0))) )
19085     return mp_n_arg(mp, xpar,ypar);
19086   return 0;
19087 }
19088
19089
19090 @ The actual turning number is (for the moment) computed in a C function
19091 that receives eight integers corresponding to the four controlling points,
19092 and returns a single angle.  Besides those, we have to account for discrete
19093 moves at the actual points.
19094
19095 @d floor(a) (a>=0 ? a : -(int)(-a))
19096 @d bezier_error (720<<20)+1
19097 @d sign(v) ((v)>0 ? 1 : ((v)<0 ? -1 : 0 ))
19098 @d print_roots(a) { if (debuglevel>(65536*2))
19099    fprintf(stdout,"bezier_slope(): %s, i=%f, o=%f, angle=%f\n", (a),in,out,res); }
19100 @d out ((double)(xo>>20))
19101 @d mid ((double)(xm>>20))
19102 @d in  ((double)(xi>>20))
19103 @d divisor (256*256)
19104 @d double2angle(a) (int)floor(a*256.0*256.0*16.0)
19105
19106 @<Declare unary action...@>=
19107 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19108             integer CX,integer CY,integer DX,integer DY, int debuglevel);
19109
19110 @ @c 
19111 angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19112             integer CX,integer CY,integer DX,integer DY, int debuglevel) {
19113   double a, b, c;
19114   integer deltax,deltay;
19115   double ax,ay,bx,by,cx,cy,dx,dy;
19116   angle xi = 0, xo = 0, xm = 0;
19117   double res = 0;
19118   ax=AX/divisor;  ay=AY/divisor;
19119   bx=BX/divisor;  by=BY/divisor;
19120   cx=CX/divisor;  cy=CY/divisor;
19121   dx=DX/divisor;  dy=DY/divisor;
19122
19123   deltax = (BX-AX); deltay = (BY-AY);
19124   if (deltax==0 && deltay == 0) { deltax=(CX-AX); deltay=(CY-AY); }
19125   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19126   xi = mp_an_angle(mp,deltax,deltay);
19127
19128   deltax = (CX-BX); deltay = (CY-BY);
19129   xm = mp_an_angle(mp,deltax,deltay);
19130
19131   deltax = (DX-CX); deltay = (DY-CY);
19132   if (deltax==0 && deltay == 0) { deltax=(DX-BX); deltay=(DY-BY); }
19133   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19134   xo = mp_an_angle(mp,deltax,deltay);
19135
19136   a = (bx-ax)*(cy-by) - (cx-bx)*(by-ay); /* a = (bp-ap)x(cp-bp); */
19137   b = (bx-ax)*(dy-cy) - (by-ay)*(dx-cx);; /* b = (bp-ap)x(dp-cp);*/
19138   c = (cx-bx)*(dy-cy) - (dx-cx)*(cy-by); /* c = (cp-bp)x(dp-cp);*/
19139
19140   if (debuglevel>(65536*2)) {
19141     fprintf(stdout,
19142       "bezier_slope(): (%.2f,%.2f),(%.2f,%.2f),(%.2f,%.2f),(%.2f,%.2f)\n",
19143               ax,ay,bx,by,cx,cy,dx,dy);
19144     fprintf(stdout,
19145       "bezier_slope(): a,b,c,b^2,4ac: (%.2f,%.2f,%.2f,%.2f,%.2f)\n",a,b,c,b*b,4*a*c);
19146   }
19147
19148   if ((a==0)&&(c==0)) {
19149     res = (b==0 ?  0 :  (out-in)); 
19150     print_roots("no roots (a)");
19151   } else if ((a==0)||(c==0)) {
19152     if ((sign(b) == sign(a)) || (sign(b) == sign(c))) {
19153       res = out-in; /* ? */
19154       if (res<-180.0) 
19155         res += 360.0;
19156       else if (res>180.0)
19157         res -= 360.0;
19158       print_roots("no roots (b)");
19159     } else {
19160       res = out-in; /* ? */
19161       print_roots("one root (a)");
19162     }
19163   } else if ((sign(a)*sign(c))<0) {
19164     res = out-in; /* ? */
19165       if (res<-180.0) 
19166         res += 360.0;
19167       else if (res>180.0)
19168         res -= 360.0;
19169     print_roots("one root (b)");
19170   } else {
19171     if (sign(a) == sign(b)) {
19172       res = out-in; /* ? */
19173       if (res<-180.0) 
19174         res += 360.0;
19175       else if (res>180.0)
19176         res -= 360.0;
19177       print_roots("no roots (d)");
19178     } else {
19179       if ((b*b) == (4*a*c)) {
19180         res = bezier_error;
19181         print_roots("double root"); /* cusp */
19182       } else if ((b*b) < (4*a*c)) {
19183         res = out-in; /* ? */
19184         if (res<=0.0 &&res>-180.0) 
19185           res += 360.0;
19186         else if (res>=0.0 && res<180.0)
19187           res -= 360.0;
19188         print_roots("no roots (e)");
19189       } else {
19190         res = out-in;
19191         if (res<-180.0) 
19192           res += 360.0;
19193         else if (res>180.0)
19194           res -= 360.0;
19195         print_roots("two roots"); /* two inflections */
19196       }
19197     }
19198   }
19199   return double2angle(res);
19200 }
19201
19202 @
19203 @d p_nextnext link(link(p))
19204 @d p_next link(p)
19205 @d seven_twenty_deg 05500000000 /* $720\cdot2^{20}$, represents $720^\circ$ */
19206
19207 @<Declare unary action...@>=
19208 scaled mp_new_turn_cycles (MP mp,pointer c) {
19209   angle res,ang; /*  the angles of intermediate results  */
19210   scaled turns;  /*  the turn counter  */
19211   pointer p;     /*  for running around the path  */
19212   integer xp,yp;   /*  coordinates of next point  */
19213   integer x,y;   /*  helper coordinates  */
19214   angle in_angle,out_angle;     /*  helper angles */
19215   int old_setting; /* saved |selector| setting */
19216   res=0;
19217   turns= 0;
19218   p=c;
19219   old_setting = mp->selector; mp->selector=term_only;
19220   if ( mp->internal[tracing_commands]>unity ) {
19221     mp_begin_diagnostic(mp);
19222     mp_print_nl(mp, "");
19223     mp_end_diagnostic(mp, false);
19224   }
19225   do { 
19226     xp = x_coord(p_next); yp = y_coord(p_next);
19227     ang  = mp_bezier_slope(mp,x_coord(p), y_coord(p), right_x(p), right_y(p),
19228              left_x(p_next), left_y(p_next), xp, yp, 
19229              mp->internal[tracing_commands]);
19230     if ( ang>seven_twenty_deg ) {
19231       print_err("Strange path");
19232       mp_error(mp);
19233       mp->selector=old_setting;
19234       return 0;
19235     }
19236     res  = res + ang;
19237     if ( res > one_eighty_deg ) {
19238       res = res - three_sixty_deg;
19239       turns = turns + unity;
19240     }
19241     if ( res <= -one_eighty_deg ) {
19242       res = res + three_sixty_deg;
19243       turns = turns - unity;
19244     }
19245     /*  incoming angle at next point  */
19246     x = left_x(p_next);  y = left_y(p_next);
19247     if ( (xp==x)&&(yp==y) ) { x = right_x(p);  y = right_y(p);  };
19248     if ( (xp==x)&&(yp==y) ) { x = x_coord(p);  y = y_coord(p);  };
19249     in_angle = mp_an_angle(mp, xp - x, yp - y);
19250     /*  outgoing angle at next point  */
19251     x = right_x(p_next);  y = right_y(p_next);
19252     if ( (xp==x)&&(yp==y) ) { x = left_x(p_nextnext);  y = left_y(p_nextnext);  };
19253     if ( (xp==x)&&(yp==y) ) { x = x_coord(p_nextnext); y = y_coord(p_nextnext); };
19254     out_angle = mp_an_angle(mp, x - xp, y- yp);
19255     ang  = (out_angle - in_angle);
19256     reduce_angle(ang);
19257     if ( ang!=0 ) {
19258       res  = res + ang;
19259       if ( res >= one_eighty_deg ) {
19260         res = res - three_sixty_deg;
19261         turns = turns + unity;
19262       };
19263       if ( res <= -one_eighty_deg ) {
19264         res = res + three_sixty_deg;
19265         turns = turns - unity;
19266       };
19267     };
19268     p = link(p);
19269   } while (p!=c);
19270   mp->selector=old_setting;
19271   return turns;
19272 }
19273
19274
19275 @ This code is based on Bogus\l{}av Jackowski's
19276 |emergency_turningnumber| macro, with some minor changes by Taco
19277 Hoekwater. The macro code looked more like this:
19278 {\obeylines
19279 vardef turning\_number primary p =
19280 ~~save res, ang, turns;
19281 ~~res := 0;
19282 ~~if length p <= 2:
19283 ~~~~if Angle ((point 0 of p) - (postcontrol 0 of p)) >= 0:  1  else: -1 fi
19284 ~~else:
19285 ~~~~for t = 0 upto length p-1 :
19286 ~~~~~~angc := Angle ((point t+1 of p)  - (point t of p))
19287 ~~~~~~~~- Angle ((point t of p) - (point t-1 of p));
19288 ~~~~~~if angc > 180: angc := angc - 360; fi;
19289 ~~~~~~if angc < -180: angc := angc + 360; fi;
19290 ~~~~~~res  := res + angc;
19291 ~~~~endfor;
19292 ~~res/360
19293 ~~fi
19294 enddef;}
19295 The general idea is to calculate only the sum of the angles of
19296 straight lines between the points, of a path, not worrying about cusps
19297 or self-intersections in the segments at all. If the segment is not
19298 well-behaved, the result is not necesarily correct. But the old code
19299 was not always correct either, and worse, it sometimes failed for
19300 well-behaved paths as well. All known bugs that were triggered by the
19301 original code no longer occur with this code, and it runs roughly 3
19302 times as fast because the algorithm is much simpler.
19303
19304 @ It is possible to overflow the return value of the |turn_cycles|
19305 function when the path is sufficiently long and winding, but I am not
19306 going to bother testing for that. In any case, it would only return
19307 the looped result value, which is not a big problem.
19308
19309 The macro code for the repeat loop was a bit nicer to look
19310 at than the pascal code, because it could use |point -1 of p|. In
19311 pascal, the fastest way to loop around the path is not to look
19312 backward once, but forward twice. These defines help hide the trick.
19313
19314 @d p_to link(link(p))
19315 @d p_here link(p)
19316 @d p_from p
19317
19318 @<Declare unary action...@>=
19319 scaled mp_turn_cycles (MP mp,pointer c) {
19320   angle res,ang; /*  the angles of intermediate results  */
19321   scaled turns;  /*  the turn counter  */
19322   pointer p;     /*  for running around the path  */
19323   res=0;  turns= 0; p=c;
19324   do { 
19325     ang  = mp_an_angle (mp, x_coord(p_to) - x_coord(p_here), 
19326                             y_coord(p_to) - y_coord(p_here))
19327         - mp_an_angle (mp, x_coord(p_here) - x_coord(p_from), 
19328                            y_coord(p_here) - y_coord(p_from));
19329     reduce_angle(ang);
19330     res  = res + ang;
19331     if ( res >= three_sixty_deg )  {
19332       res = res - three_sixty_deg;
19333       turns = turns + unity;
19334     };
19335     if ( res <= -three_sixty_deg ) {
19336       res = res + three_sixty_deg;
19337       turns = turns - unity;
19338     };
19339     p = link(p);
19340   } while (p!=c);
19341   return turns;
19342 }
19343
19344 @ @<Declare unary action...@>=
19345 scaled mp_turn_cycles_wrapper (MP mp,pointer c) {
19346   scaled nval,oval;
19347   scaled saved_t_o; /* tracing\_online saved  */
19348   if ( (link(c)==c)||(link(link(c))==c) ) {
19349     if ( mp_an_angle (mp, x_coord(c) - right_x(c),  y_coord(c) - right_y(c)) > 0 )
19350       return unity;
19351     else
19352       return -unity;
19353   } else {
19354     nval = mp_new_turn_cycles(mp, c);
19355     oval = mp_turn_cycles(mp, c);
19356     if ( nval!=oval ) {
19357       saved_t_o=mp->internal[tracing_online];
19358       mp->internal[tracing_online]=unity;
19359       mp_begin_diagnostic(mp);
19360       mp_print_nl (mp, "Warning: the turningnumber algorithms do not agree."
19361                        " The current computed value is ");
19362       mp_print_scaled(mp, nval);
19363       mp_print(mp, ", but the 'connect-the-dots' algorithm returned ");
19364       mp_print_scaled(mp, oval);
19365       mp_end_diagnostic(mp, false);
19366       mp->internal[tracing_online]=saved_t_o;
19367     }
19368     return nval;
19369   }
19370 }
19371
19372 @ @<Declare unary action...@>=
19373 scaled mp_count_turns (MP mp,pointer c) {
19374   pointer p; /* a knot in envelope spec |c| */
19375   integer t; /* total pen offset changes counted */
19376   t=0; p=c;
19377   do {  
19378     t=t+info(p)-zero_off;
19379     p=link(p);
19380   } while (p!=c);
19381   return ((t / 3)*unity);
19382 }
19383
19384 @ @d type_range(A,B) { 
19385   if ( (mp->cur_type>=(A)) && (mp->cur_type<=(B)) ) 
19386     mp_flush_cur_exp(mp, true_code);
19387   else mp_flush_cur_exp(mp, false_code);
19388   mp->cur_type=mp_boolean_type;
19389   }
19390 @d type_test(A) { 
19391   if ( mp->cur_type==(A) ) mp_flush_cur_exp(mp, true_code);
19392   else mp_flush_cur_exp(mp, false_code);
19393   mp->cur_type=mp_boolean_type;
19394   }
19395
19396 @<Additional cases of unary operators@>=
19397 case mp_boolean_type: 
19398   type_range(mp_boolean_type,mp_unknown_boolean); break;
19399 case mp_string_type: 
19400   type_range(mp_string_type,mp_unknown_string); break;
19401 case mp_pen_type: 
19402   type_range(mp_pen_type,mp_unknown_pen); break;
19403 case mp_path_type: 
19404   type_range(mp_path_type,mp_unknown_path); break;
19405 case mp_picture_type: 
19406   type_range(mp_picture_type,mp_unknown_picture); break;
19407 case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
19408 case mp_pair_type: 
19409   type_test(c); break;
19410 case mp_numeric_type: 
19411   type_range(mp_known,mp_independent); break;
19412 case known_op: case unknown_op: 
19413   mp_test_known(mp, c); break;
19414
19415 @ @<Declare unary action procedures@>=
19416 void mp_test_known (MP mp,quarterword c) {
19417   int b; /* is the current expression known? */
19418   pointer p,q; /* locations in a big node */
19419   b=false_code;
19420   switch (mp->cur_type) {
19421   case mp_vacuous: case mp_boolean_type: case mp_string_type:
19422   case mp_pen_type: case mp_path_type: case mp_picture_type:
19423   case mp_known: 
19424     b=true_code;
19425     break;
19426   case mp_transform_type:
19427   case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: 
19428     p=value(mp->cur_exp);
19429     q=p+mp->big_node_size[mp->cur_type];
19430     do {  
19431       q=q-2;
19432       if ( type(q)!=mp_known ) 
19433        goto DONE;
19434     } while (q!=p);
19435     b=true_code;
19436   DONE:  
19437     break;
19438   default: 
19439     break;
19440   }
19441   if ( c==known_op ) mp_flush_cur_exp(mp, b);
19442   else mp_flush_cur_exp(mp, true_code+false_code-b);
19443   mp->cur_type=mp_boolean_type;
19444 }
19445
19446 @ @<Additional cases of unary operators@>=
19447 case cycle_op: 
19448   if ( mp->cur_type!=mp_path_type ) mp_flush_cur_exp(mp, false_code);
19449   else if ( left_type(mp->cur_exp)!=endpoint ) mp_flush_cur_exp(mp, true_code);
19450   else mp_flush_cur_exp(mp, false_code);
19451   mp->cur_type=mp_boolean_type;
19452   break;
19453
19454 @ @<Additional cases of unary operators@>=
19455 case arc_length: 
19456   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19457   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, arc_length);
19458   else mp_flush_cur_exp(mp, mp_get_arc_length(mp, mp->cur_exp));
19459   break;
19460
19461 @ Here we use the fact that |c-filled_op+fill_code| is the desired graphical
19462 object |type|.
19463 @^data structure assumptions@>
19464
19465 @<Additional cases of unary operators@>=
19466 case filled_op:
19467 case stroked_op:
19468 case textual_op:
19469 case clipped_op:
19470 case bounded_op:
19471   if ( mp->cur_type!=mp_picture_type ) mp_flush_cur_exp(mp, false_code);
19472   else if ( link(dummy_loc(mp->cur_exp))==null ) mp_flush_cur_exp(mp, false_code);
19473   else if ( type(link(dummy_loc(mp->cur_exp)))==c+fill_code-filled_op )
19474     mp_flush_cur_exp(mp, true_code);
19475   else mp_flush_cur_exp(mp, false_code);
19476   mp->cur_type=mp_boolean_type;
19477   break;
19478
19479 @ @<Additional cases of unary operators@>=
19480 case make_pen_op: 
19481   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19482   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, make_pen_op);
19483   else { 
19484     mp->cur_type=mp_pen_type;
19485     mp->cur_exp=mp_make_pen(mp, mp->cur_exp,true);
19486   };
19487   break;
19488 case make_path_op: 
19489   if ( mp->cur_type!=mp_pen_type ) mp_bad_unary(mp, make_path_op);
19490   else  { 
19491     mp->cur_type=mp_path_type;
19492     mp_make_path(mp, mp->cur_exp);
19493   };
19494   break;
19495 case reverse: 
19496   if ( mp->cur_type==mp_path_type ) {
19497     p=mp_htap_ypoc(mp, mp->cur_exp);
19498     if ( right_type(p)==endpoint ) p=link(p);
19499     mp_toss_knot_list(mp, mp->cur_exp); mp->cur_exp=p;
19500   } else if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19501   else mp_bad_unary(mp, reverse);
19502   break;
19503
19504 @ The |pair_value| routine changes the current expression to a
19505 given ordered pair of values.
19506
19507 @<Declare unary action procedures@>=
19508 void mp_pair_value (MP mp,scaled x, scaled y) {
19509   pointer p; /* a pair node */
19510   p=mp_get_node(mp, value_node_size); 
19511   mp_flush_cur_exp(mp, p); mp->cur_type=mp_pair_type;
19512   type(p)=mp_pair_type; name_type(p)=mp_capsule; mp_init_big_node(mp, p);
19513   p=value(p);
19514   type(x_part_loc(p))=mp_known; value(x_part_loc(p))=x;
19515   type(y_part_loc(p))=mp_known; value(y_part_loc(p))=y;
19516 }
19517
19518 @ @<Additional cases of unary operators@>=
19519 case ll_corner_op: 
19520   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ll_corner_op);
19521   else mp_pair_value(mp, minx,miny);
19522   break;
19523 case lr_corner_op: 
19524   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, lr_corner_op);
19525   else mp_pair_value(mp, maxx,miny);
19526   break;
19527 case ul_corner_op: 
19528   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ul_corner_op);
19529   else mp_pair_value(mp, minx,maxy);
19530   break;
19531 case ur_corner_op: 
19532   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ur_corner_op);
19533   else mp_pair_value(mp, maxx,maxy);
19534   break;
19535
19536 @ Here is a function that sets |minx|, |maxx|, |miny|, |maxy| to the bounding
19537 box of the current expression.  The boolean result is |false| if the expression
19538 has the wrong type.
19539
19540 @<Declare unary action procedures@>=
19541 boolean mp_get_cur_bbox (MP mp) { 
19542   switch (mp->cur_type) {
19543   case mp_picture_type: 
19544     mp_set_bbox(mp, mp->cur_exp,true);
19545     if ( minx_val(mp->cur_exp)>maxx_val(mp->cur_exp) ) {
19546       minx=0; maxx=0; miny=0; maxy=0;
19547     } else { 
19548       minx=minx_val(mp->cur_exp);
19549       maxx=maxx_val(mp->cur_exp);
19550       miny=miny_val(mp->cur_exp);
19551       maxy=maxy_val(mp->cur_exp);
19552     }
19553     break;
19554   case mp_path_type: 
19555     mp_path_bbox(mp, mp->cur_exp);
19556     break;
19557   case mp_pen_type: 
19558     mp_pen_bbox(mp, mp->cur_exp);
19559     break;
19560   default: 
19561     return false;
19562   }
19563   return true;
19564 }
19565
19566 @ @<Additional cases of unary operators@>=
19567 case read_from_op:
19568 case close_from_op: 
19569   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19570   else mp_do_read_or_close(mp,c);
19571   break;
19572
19573 @ Here is a routine that interprets |cur_exp| as a file name and tries to read
19574 a line from the file or to close the file.
19575
19576 @d close_file 46 /* go here when closing the file */
19577
19578 @<Declare unary action procedures@>=
19579 void mp_do_read_or_close (MP mp,quarterword c) {
19580   readf_index n,n0; /* indices for searching |rd_fname| */
19581   @<Find the |n| where |rd_fname[n]=cur_exp|; if |cur_exp| must be inserted,
19582     call |start_read_input| and |goto found| or |not_found|@>;
19583   mp_begin_file_reading(mp);
19584   name=is_read;
19585   if ( mp_input_ln(mp, mp->rd_file[n],true) ) 
19586     goto FOUND;
19587   mp_end_file_reading(mp);
19588 NOT_FOUND:
19589   @<Record the end of file and set |cur_exp| to a dummy value@>;
19590   return;
19591 CLOSE_FILE:
19592   mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous; 
19593   return;
19594 FOUND:
19595   mp_flush_cur_exp(mp, 0);
19596   mp_finish_read(mp);
19597 }
19598
19599 @ Free slots in the |rd_file| and |rd_fname| arrays are marked with NULL's in
19600 |rd_fname|.
19601
19602 @<Find the |n| where |rd_fname[n]=cur_exp|...@>=
19603 {   
19604   char *fn;
19605   n=mp->read_files;
19606   n0=mp->read_files;
19607   fn = str(mp->cur_exp);
19608   while (mp_xstrcmp(fn,mp->rd_fname[n])!=0) { 
19609     if ( n>0 ) {
19610       decr(n);
19611     } else if ( c==close_from_op ) {
19612       goto CLOSE_FILE;
19613     } else {
19614       if ( n0==mp->read_files ) {
19615         if ( mp->read_files<mp->max_read_files ) {
19616           incr(mp->read_files);
19617         } else {
19618           FILE **rd_file;
19619           char **rd_fname;
19620               readf_index l,k;
19621           l = mp->max_read_files + (mp->max_read_files>>2);
19622           rd_file = xmalloc((l+1), sizeof(FILE *));
19623           rd_fname = xmalloc((l+1), sizeof(char *));
19624               for (k=0;k<=l;k++) {
19625             if (k<=mp->max_read_files) {
19626                   rd_file[k]=mp->rd_file[k]; 
19627               rd_fname[k]=mp->rd_fname[k];
19628             } else {
19629                   rd_file[k]=0; 
19630               rd_fname[k]=NULL;
19631             }
19632           }
19633               xfree(mp->rd_file); xfree(mp->rd_fname);
19634           mp->max_read_files = l;
19635           mp->rd_file = rd_file;
19636           mp->rd_fname = rd_fname;
19637         }
19638       }
19639       n=n0;
19640       if ( mp_start_read_input(mp,fn,n) ) 
19641         goto FOUND;
19642       else 
19643         goto NOT_FOUND;
19644     }
19645     if ( mp->rd_fname[n]==NULL ) { n0=n; }
19646   } 
19647   if ( c==close_from_op ) { 
19648     fclose(mp->rd_file[n]); 
19649     goto NOT_FOUND; 
19650   }
19651 }
19652
19653 @ @<Record the end of file and set |cur_exp| to a dummy value@>=
19654 xfree(mp->rd_fname[n]);
19655 mp->rd_fname[n]=NULL;
19656 if ( n==mp->read_files-1 ) mp->read_files=n;
19657 if ( c==close_from_op ) 
19658   goto CLOSE_FILE;
19659 mp_flush_cur_exp(mp, mp->eof_line);
19660 mp->cur_type=mp_string_type
19661
19662 @ The string denoting end-of-file is a one-byte string at position zero, by definition
19663
19664 @<Glob...@>=
19665 str_number eof_line;
19666
19667 @ @<Set init...@>=
19668 mp->eof_line=0;
19669
19670 @ Finally, we have the operations that combine a capsule~|p|
19671 with the current expression.
19672
19673 @c @<Declare binary action procedures@>;
19674 void mp_do_binary (MP mp,pointer p, quarterword c) {
19675   pointer q,r,rr; /* for list manipulation */
19676   pointer old_p,old_exp; /* capsules to recycle */
19677   integer v; /* for numeric manipulation */
19678   check_arith;
19679   if ( mp->internal[tracing_commands]>two ) {
19680     @<Trace the current binary operation@>;
19681   }
19682   @<Sidestep |independent| cases in capsule |p|@>;
19683   @<Sidestep |independent| cases in the current expression@>;
19684   switch (c) {
19685   case plus: case minus:
19686     @<Add or subtract the current expression from |p|@>;
19687     break;
19688   @<Additional cases of binary operators@>;
19689   }; /* there are no other cases */
19690   mp_recycle_value(mp, p); 
19691   mp_free_node(mp, p,value_node_size); /* |return| to avoid this */
19692   check_arith; 
19693   @<Recycle any sidestepped |independent| capsules@>;
19694 }
19695
19696 @ @<Declare binary action...@>=
19697 void mp_bad_binary (MP mp,pointer p, quarterword c) { 
19698   mp_disp_err(mp, p,"");
19699   exp_err("Not implemented: ");
19700 @.Not implemented...@>
19701   if ( c>=min_of ) mp_print_op(mp, c);
19702   mp_print_known_or_unknown_type(mp, type(p),p);
19703   if ( c>=min_of ) mp_print(mp, "of"); else mp_print_op(mp, c);
19704   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
19705   help3("I'm afraid I don't know how to apply that operation to that")
19706        ("combination of types. Continue, and I'll return the second")
19707       ("argument (see above) as the result of the operation.");
19708   mp_put_get_error(mp);
19709 }
19710
19711 @ @<Trace the current binary operation@>=
19712
19713   mp_begin_diagnostic(mp); mp_print_nl(mp, "{(");
19714   mp_print_exp(mp,p,0); /* show the operand, but not verbosely */
19715   mp_print_char(mp,')'); mp_print_op(mp,c); mp_print_char(mp,'(');
19716   mp_print_exp(mp,null,0); mp_print(mp,")}"); 
19717   mp_end_diagnostic(mp, false);
19718 }
19719
19720 @ Several of the binary operations are potentially complicated by the
19721 fact that |independent| values can sneak into capsules. For example,
19722 we've seen an instance of this difficulty in the unary operation
19723 of negation. In order to reduce the number of cases that need to be
19724 handled, we first change the two operands (if necessary)
19725 to rid them of |independent| components. The original operands are
19726 put into capsules called |old_p| and |old_exp|, which will be
19727 recycled after the binary operation has been safely carried out.
19728
19729 @<Recycle any sidestepped |independent| capsules@>=
19730 if ( old_p!=null ) { 
19731   mp_recycle_value(mp, old_p); mp_free_node(mp, old_p,value_node_size);
19732 }
19733 if ( old_exp!=null ) {
19734   mp_recycle_value(mp, old_exp); mp_free_node(mp, old_exp,value_node_size);
19735 }
19736
19737 @ A big node is considered to be ``tarnished'' if it contains at least one
19738 independent component. We will define a simple function called `|tarnished|'
19739 that returns |null| if and only if its argument is not tarnished.
19740
19741 @<Sidestep |independent| cases in capsule |p|@>=
19742 switch (type(p)) {
19743 case mp_transform_type:
19744 case mp_color_type:
19745 case mp_cmykcolor_type:
19746 case mp_pair_type: 
19747   old_p=mp_tarnished(mp, p);
19748   break;
19749 case mp_independent: old_p=diov; break;
19750 default: old_p=null; break;
19751 };
19752 if ( old_p!=null ) {
19753   q=mp_stash_cur_exp(mp); old_p=p; mp_make_exp_copy(mp, old_p);
19754   p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
19755 }
19756
19757 @ @<Sidestep |independent| cases in the current expression@>=
19758 switch (mp->cur_type) {
19759 case mp_transform_type:
19760 case mp_color_type:
19761 case mp_cmykcolor_type:
19762 case mp_pair_type: 
19763   old_exp=mp_tarnished(mp, mp->cur_exp);
19764   break;
19765 case mp_independent:old_exp=diov; break;
19766 default: old_exp=null; break;
19767 };
19768 if ( old_exp!=null ) {
19769   old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
19770 }
19771
19772 @ @<Declare binary action...@>=
19773 pointer mp_tarnished (MP mp,pointer p) {
19774   pointer q; /* beginning of the big node */
19775   pointer r; /* current position in the big node */
19776   q=value(p); r=q+mp->big_node_size[type(p)];
19777   do {  
19778    r=r-2;
19779    if ( type(r)==mp_independent ) return diov; 
19780   } while (r!=q);
19781   return null;
19782 }
19783
19784 @ @<Add or subtract the current expression from |p|@>=
19785 if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
19786   mp_bad_binary(mp, p,c);
19787 } else  {
19788   if ((mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
19789     mp_add_or_subtract(mp, p,null,c);
19790   } else {
19791     if ( mp->cur_type!=type(p) )  {
19792       mp_bad_binary(mp, p,c);
19793     } else { 
19794       q=value(p); r=value(mp->cur_exp);
19795       rr=r+mp->big_node_size[mp->cur_type];
19796       while ( r<rr ) { 
19797         mp_add_or_subtract(mp, q,r,c);
19798         q=q+2; r=r+2;
19799       }
19800     }
19801   }
19802 }
19803
19804 @ The first argument to |add_or_subtract| is the location of a value node
19805 in a capsule or pair node that will soon be recycled. The second argument
19806 is either a location within a pair or transform node of |cur_exp|,
19807 or it is null (which means that |cur_exp| itself should be the second
19808 argument).  The third argument is either |plus| or |minus|.
19809
19810 The sum or difference of the numeric quantities will replace the second
19811 operand.  Arithmetic overflow may go undetected; users aren't supposed to
19812 be monkeying around with really big values.
19813
19814 @<Declare binary action...@>=
19815 @<Declare the procedure called |dep_finish|@>;
19816 void mp_add_or_subtract (MP mp,pointer p, pointer q, quarterword c) {
19817   small_number s,t; /* operand types */
19818   pointer r; /* list traverser */
19819   integer v; /* second operand value */
19820   if ( q==null ) { 
19821     t=mp->cur_type;
19822     if ( t<mp_dependent ) v=mp->cur_exp; else v=dep_list(mp->cur_exp);
19823   } else { 
19824     t=type(q);
19825     if ( t<mp_dependent ) v=value(q); else v=dep_list(q);
19826   }
19827   if ( t==mp_known ) {
19828     if ( c==minus ) negate(v);
19829     if ( type(p)==mp_known ) {
19830       v=mp_slow_add(mp, value(p),v);
19831       if ( q==null ) mp->cur_exp=v; else value(q)=v;
19832       return;
19833     }
19834     @<Add a known value to the constant term of |dep_list(p)|@>;
19835   } else  { 
19836     if ( c==minus ) mp_negate_dep_list(mp, v);
19837     @<Add operand |p| to the dependency list |v|@>;
19838   }
19839 }
19840
19841 @ @<Add a known value to the constant term of |dep_list(p)|@>=
19842 r=dep_list(p);
19843 while ( info(r)!=null ) r=link(r);
19844 value(r)=mp_slow_add(mp, value(r),v);
19845 if ( q==null ) {
19846   q=mp_get_node(mp, value_node_size); mp->cur_exp=q; mp->cur_type=type(p);
19847   name_type(q)=mp_capsule;
19848 }
19849 dep_list(q)=dep_list(p); type(q)=type(p);
19850 prev_dep(q)=prev_dep(p); link(prev_dep(p))=q;
19851 type(p)=mp_known; /* this will keep the recycler from collecting non-garbage */
19852
19853 @ We prefer |dependent| lists to |mp_proto_dependent| ones, because it is
19854 nice to retain the extra accuracy of |fraction| coefficients.
19855 But we have to handle both kinds, and mixtures too.
19856
19857 @<Add operand |p| to the dependency list |v|@>=
19858 if ( type(p)==mp_known ) {
19859   @<Add the known |value(p)| to the constant term of |v|@>;
19860 } else { 
19861   s=type(p); r=dep_list(p);
19862   if ( t==mp_dependent ) {
19863     if ( s==mp_dependent ) {
19864       if ( mp_max_coef(mp, r)+mp_max_coef(mp, v)<coef_bound )
19865         v=mp_p_plus_q(mp, v,r,mp_dependent); goto DONE;
19866       } /* |fix_needed| will necessarily be false */
19867       t=mp_proto_dependent; 
19868       v=mp_p_over_v(mp, v,unity,mp_dependent,mp_proto_dependent);
19869     }
19870     if ( s==mp_proto_dependent ) v=mp_p_plus_q(mp, v,r,mp_proto_dependent);
19871     else v=mp_p_plus_fq(mp, v,unity,r,mp_proto_dependent,mp_dependent);
19872  DONE:  
19873     @<Output the answer, |v| (which might have become |known|)@>;
19874   }
19875
19876 @ @<Add the known |value(p)| to the constant term of |v|@>=
19877
19878   while ( info(v)!=null ) v=link(v);
19879   value(v)=mp_slow_add(mp, value(p),value(v));
19880 }
19881
19882 @ @<Output the answer, |v| (which might have become |known|)@>=
19883 if ( q!=null ) mp_dep_finish(mp, v,q,t);
19884 else  { mp->cur_type=t; mp_dep_finish(mp, v,null,t); }
19885
19886 @ Here's the current situation: The dependency list |v| of type |t|
19887 should either be put into the current expression (if |q=null|) or
19888 into location |q| within a pair node (otherwise). The destination (|cur_exp|
19889 or |q|) formerly held a dependency list with the same
19890 final pointer as the list |v|.
19891
19892 @<Declare the procedure called |dep_finish|@>=
19893 void mp_dep_finish (MP mp, pointer v, pointer q, small_number t) {
19894   pointer p; /* the destination */
19895   scaled vv; /* the value, if it is |known| */
19896   if ( q==null ) p=mp->cur_exp; else p=q;
19897   dep_list(p)=v; type(p)=t;
19898   if ( info(v)==null ) { 
19899     vv=value(v);
19900     if ( q==null ) { 
19901       mp_flush_cur_exp(mp, vv);
19902     } else  { 
19903       mp_recycle_value(mp, p); type(q)=mp_known; value(q)=vv; 
19904     }
19905   } else if ( q==null ) {
19906     mp->cur_type=t;
19907   }
19908   if ( mp->fix_needed ) mp_fix_dependencies(mp);
19909 }
19910
19911 @ Let's turn now to the six basic relations of comparison.
19912
19913 @<Additional cases of binary operators@>=
19914 case less_than: case less_or_equal: case greater_than:
19915 case greater_or_equal: case equal_to: case unequal_to:
19916   check_arith; /* at this point |arith_error| should be |false|? */
19917   if ( (mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
19918     mp_add_or_subtract(mp, p,null,minus); /* |cur_exp:=(p)-cur_exp| */
19919   } else if ( mp->cur_type!=type(p) ) {
19920     mp_bad_binary(mp, p,c); goto DONE; 
19921   } else if ( mp->cur_type==mp_string_type ) {
19922     mp_flush_cur_exp(mp, mp_str_vs_str(mp, value(p),mp->cur_exp));
19923   } else if ((mp->cur_type==mp_unknown_string)||
19924            (mp->cur_type==mp_unknown_boolean) ) {
19925     @<Check if unknowns have been equated@>;
19926   } else if ( (mp->cur_type<=mp_pair_type)&&(mp->cur_type>=mp_transform_type)) {
19927     @<Reduce comparison of big nodes to comparison of scalars@>;
19928   } else if ( mp->cur_type==mp_boolean_type ) {
19929     mp_flush_cur_exp(mp, mp->cur_exp-value(p));
19930   } else { 
19931     mp_bad_binary(mp, p,c); goto DONE;
19932   }
19933   @<Compare the current expression with zero@>;
19934 DONE:  
19935   mp->arith_error=false; /* ignore overflow in comparisons */
19936   break;
19937
19938 @ @<Compare the current expression with zero@>=
19939 if ( mp->cur_type!=mp_known ) {
19940   if ( mp->cur_type<mp_known ) {
19941     mp_disp_err(mp, p,"");
19942     help1("The quantities shown above have not been equated.")
19943   } else  {
19944     help2("Oh dear. I can\'t decide if the expression above is positive,")
19945      ("negative, or zero. So this comparison test won't be `true'.");
19946   }
19947   exp_err("Unknown relation will be considered false");
19948 @.Unknown relation...@>
19949   mp_put_get_flush_error(mp, false_code);
19950 } else {
19951   switch (c) {
19952   case less_than: boolean_reset(mp->cur_exp<0); break;
19953   case less_or_equal: boolean_reset(mp->cur_exp<=0); break;
19954   case greater_than: boolean_reset(mp->cur_exp>0); break;
19955   case greater_or_equal: boolean_reset(mp->cur_exp>=0); break;
19956   case equal_to: boolean_reset(mp->cur_exp==0); break;
19957   case unequal_to: boolean_reset(mp->cur_exp!=0); break;
19958   }; /* there are no other cases */
19959 }
19960 mp->cur_type=mp_boolean_type
19961
19962 @ When two unknown strings are in the same ring, we know that they are
19963 equal. Otherwise, we don't know whether they are equal or not, so we
19964 make no change.
19965
19966 @<Check if unknowns have been equated@>=
19967
19968   q=value(mp->cur_exp);
19969   while ( (q!=mp->cur_exp)&&(q!=p) ) q=value(q);
19970   if ( q==p ) mp_flush_cur_exp(mp, 0);
19971 }
19972
19973 @ @<Reduce comparison of big nodes to comparison of scalars@>=
19974
19975   q=value(p); r=value(mp->cur_exp);
19976   rr=r+mp->big_node_size[mp->cur_type]-2;
19977   while (1) { mp_add_or_subtract(mp, q,r,minus);
19978     if ( type(r)!=mp_known ) break;
19979     if ( value(r)!=0 ) break;
19980     if ( r==rr ) break;
19981     q=q+2; r=r+2;
19982   }
19983   mp_take_part(mp, name_type(r)+x_part-mp_x_part_sector);
19984 }
19985
19986 @ Here we use the sneaky fact that |and_op-false_code=or_op-true_code|.
19987
19988 @<Additional cases of binary operators@>=
19989 case and_op:
19990 case or_op: 
19991   if ( (type(p)!=mp_boolean_type)||(mp->cur_type!=mp_boolean_type) )
19992     mp_bad_binary(mp, p,c);
19993   else if ( value(p)==c+false_code-and_op ) mp->cur_exp=value(p);
19994   break;
19995
19996 @ @<Additional cases of binary operators@>=
19997 case times: 
19998   if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
19999    mp_bad_binary(mp, p,times);
20000   } else if ( (mp->cur_type==mp_known)||(type(p)==mp_known) ) {
20001     @<Multiply when at least one operand is known@>;
20002   } else if ( (mp_nice_color_or_pair(mp, p,type(p))&&(mp->cur_type>mp_pair_type))
20003       ||(mp_nice_color_or_pair(mp, mp->cur_exp,mp->cur_type)&&
20004           (type(p)>mp_pair_type)) ) {
20005     mp_hard_times(mp, p); return;
20006   } else {
20007     mp_bad_binary(mp, p,times);
20008   }
20009   break;
20010
20011 @ @<Multiply when at least one operand is known@>=
20012
20013   if ( type(p)==mp_known ) {
20014     v=value(p); mp_free_node(mp, p,value_node_size); 
20015   } else {
20016     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20017   }
20018   if ( mp->cur_type==mp_known ) {
20019     mp->cur_exp=mp_take_scaled(mp, mp->cur_exp,v);
20020   } else if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_color_type)||
20021               (mp->cur_type==mp_cmykcolor_type) ) {
20022     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20023     do {  
20024        p=p-2; mp_dep_mult(mp, p,v,true);
20025     } while (p!=value(mp->cur_exp));
20026   } else {
20027     mp_dep_mult(mp, null,v,true);
20028   }
20029   return;
20030 }
20031
20032 @ @<Declare binary action...@>=
20033 void mp_dep_mult (MP mp,pointer p, integer v, boolean v_is_scaled) {
20034   pointer q; /* the dependency list being multiplied by |v| */
20035   small_number s,t; /* its type, before and after */
20036   if ( p==null ) {
20037     q=mp->cur_exp;
20038   } else if ( type(p)!=mp_known ) {
20039     q=p;
20040   } else { 
20041     if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
20042     else value(p)=mp_take_fraction(mp, value(p),v);
20043     return;
20044   };
20045   t=type(q); q=dep_list(q); s=t;
20046   if ( t==mp_dependent ) if ( v_is_scaled )
20047     if (mp_ab_vs_cd(mp, mp_max_coef(mp,q),abs(v),coef_bound-1,unity)>=0 ) 
20048       t=mp_proto_dependent;
20049   q=mp_p_times_v(mp, q,v,s,t,v_is_scaled); 
20050   mp_dep_finish(mp, q,p,t);
20051 }
20052
20053 @ Here is a routine that is similar to |times|; but it is invoked only
20054 internally, when |v| is a |fraction| whose magnitude is at most~1,
20055 and when |cur_type>=mp_color_type|.
20056
20057 @c void mp_frac_mult (MP mp,scaled n, scaled d) {
20058   /* multiplies |cur_exp| by |n/d| */
20059   pointer p; /* a pair node */
20060   pointer old_exp; /* a capsule to recycle */
20061   fraction v; /* |n/d| */
20062   if ( mp->internal[tracing_commands]>two ) {
20063     @<Trace the fraction multiplication@>;
20064   }
20065   switch (mp->cur_type) {
20066   case mp_transform_type:
20067   case mp_color_type:
20068   case mp_cmykcolor_type:
20069   case mp_pair_type:
20070    old_exp=mp_tarnished(mp, mp->cur_exp);
20071    break;
20072   case mp_independent: old_exp=diov; break;
20073   default: old_exp=null; break;
20074   }
20075   if ( old_exp!=null ) { 
20076      old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20077   }
20078   v=mp_make_fraction(mp, n,d);
20079   if ( mp->cur_type==mp_known ) {
20080     mp->cur_exp=mp_take_fraction(mp, mp->cur_exp,v);
20081   } else if ( mp->cur_type<=mp_pair_type ) { 
20082     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20083     do {  
20084       p=p-2;
20085       mp_dep_mult(mp, p,v,false);
20086     } while (p!=value(mp->cur_exp));
20087   } else {
20088     mp_dep_mult(mp, null,v,false);
20089   }
20090   if ( old_exp!=null ) {
20091     mp_recycle_value(mp, old_exp); 
20092     mp_free_node(mp, old_exp,value_node_size);
20093   }
20094 }
20095
20096 @ @<Trace the fraction multiplication@>=
20097
20098   mp_begin_diagnostic(mp); 
20099   mp_print_nl(mp, "{("); mp_print_scaled(mp,n); mp_print_char(mp,'/');
20100   mp_print_scaled(mp,d); mp_print(mp,")*("); mp_print_exp(mp,null,0); 
20101   mp_print(mp,")}");
20102   mp_end_diagnostic(mp, false);
20103 }
20104
20105 @ The |hard_times| routine multiplies a nice color or pair by a dependency list.
20106
20107 @<Declare binary action procedures@>=
20108 void mp_hard_times (MP mp,pointer p) {
20109   pointer q; /* a copy of the dependent variable |p| */
20110   pointer r; /* a component of the big node for the nice color or pair */
20111   scaled v; /* the known value for |r| */
20112   if ( type(p)<=mp_pair_type ) { 
20113      q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); p=q;
20114   }; /* now |cur_type=mp_pair_type| or |cur_type=mp_color_type| */
20115   r=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20116   while (1) { 
20117     r=r-2;
20118     v=value(r);
20119     type(r)=type(p);
20120     if ( r==value(mp->cur_exp) ) 
20121       break;
20122     mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(p)));
20123     mp_dep_mult(mp, r,v,true);
20124   }
20125   mp->mem[value_loc(r)]=mp->mem[value_loc(p)];
20126   link(prev_dep(p))=r;
20127   mp_free_node(mp, p,value_node_size);
20128   mp_dep_mult(mp, r,v,true);
20129 }
20130
20131 @ @<Additional cases of binary operators@>=
20132 case over: 
20133   if ( (mp->cur_type!=mp_known)||(type(p)<mp_color_type) ) {
20134     mp_bad_binary(mp, p,over);
20135   } else { 
20136     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20137     if ( v==0 ) {
20138       @<Squeal about division by zero@>;
20139     } else { 
20140       if ( mp->cur_type==mp_known ) {
20141         mp->cur_exp=mp_make_scaled(mp, mp->cur_exp,v);
20142       } else if ( mp->cur_type<=mp_pair_type ) { 
20143         p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20144         do {  
20145           p=p-2;  mp_dep_div(mp, p,v);
20146         } while (p!=value(mp->cur_exp));
20147       } else {
20148         mp_dep_div(mp, null,v);
20149       }
20150     }
20151     return;
20152   }
20153   break;
20154
20155 @ @<Declare binary action...@>=
20156 void mp_dep_div (MP mp,pointer p, scaled v) {
20157   pointer q; /* the dependency list being divided by |v| */
20158   small_number s,t; /* its type, before and after */
20159   if ( p==null ) q=mp->cur_exp;
20160   else if ( type(p)!=mp_known ) q=p;
20161   else { value(p)=mp_make_scaled(mp, value(p),v); return; };
20162   t=type(q); q=dep_list(q); s=t;
20163   if ( t==mp_dependent )
20164     if ( mp_ab_vs_cd(mp, mp_max_coef(mp,q),unity,coef_bound-1,abs(v))>=0 ) 
20165       t=mp_proto_dependent;
20166   q=mp_p_over_v(mp, q,v,s,t); 
20167   mp_dep_finish(mp, q,p,t);
20168 }
20169
20170 @ @<Squeal about division by zero@>=
20171
20172   exp_err("Division by zero");
20173 @.Division by zero@>
20174   help2("You're trying to divide the quantity shown above the error")
20175     ("message by zero. I'm going to divide it by one instead.");
20176   mp_put_get_error(mp);
20177 }
20178
20179 @ @<Additional cases of binary operators@>=
20180 case pythag_add:
20181 case pythag_sub: 
20182    if ( (mp->cur_type==mp_known)&&(type(p)==mp_known) ) {
20183      if ( c==pythag_add ) mp->cur_exp=mp_pyth_add(mp, value(p),mp->cur_exp);
20184      else mp->cur_exp=mp_pyth_sub(mp, value(p),mp->cur_exp);
20185    } else mp_bad_binary(mp, p,c);
20186    break;
20187
20188 @ The next few sections of the program deal with affine transformations
20189 of coordinate data.
20190
20191 @<Additional cases of binary operators@>=
20192 case rotated_by: case slanted_by:
20193 case scaled_by: case shifted_by: case transformed_by:
20194 case x_scaled: case y_scaled: case z_scaled:
20195   if ( type(p)==mp_path_type ) { 
20196     path_trans(c,p); return;
20197   } else if ( type(p)==mp_pen_type ) { 
20198     pen_trans(c,p);
20199     mp->cur_exp=mp_convex_hull(mp, mp->cur_exp); 
20200       /* rounding error could destroy convexity */
20201     return;
20202   } else if ( (type(p)==mp_pair_type)||(type(p)==mp_transform_type) ) {
20203     mp_big_trans(mp, p,c);
20204   } else if ( type(p)==mp_picture_type ) {
20205     mp_do_edges_trans(mp, p,c); return;
20206   } else {
20207     mp_bad_binary(mp, p,c);
20208   }
20209   break;
20210
20211 @ Let |c| be one of the eight transform operators. The procedure call
20212 |set_up_trans(c)| first changes |cur_exp| to a transform that corresponds to
20213 |c| and the original value of |cur_exp|. (In particular, |cur_exp| doesn't
20214 change at all if |c=transformed_by|.)
20215
20216 Then, if all components of the resulting transform are |known|, they are
20217 moved to the global variables |txx|, |txy|, |tyx|, |tyy|, |tx|, |ty|;
20218 and |cur_exp| is changed to the known value zero.
20219
20220 @<Declare binary action...@>=
20221 void mp_set_up_trans (MP mp,quarterword c) {
20222   pointer p,q,r; /* list manipulation registers */
20223   if ( (c!=transformed_by)||(mp->cur_type!=mp_transform_type) ) {
20224     @<Put the current transform into |cur_exp|@>;
20225   }
20226   @<If the current transform is entirely known, stash it in global variables;
20227     otherwise |return|@>;
20228 }
20229
20230 @ @<Glob...@>=
20231 scaled txx;
20232 scaled txy;
20233 scaled tyx;
20234 scaled tyy;
20235 scaled tx;
20236 scaled ty; /* current transform coefficients */
20237
20238 @ @<Put the current transform...@>=
20239
20240   p=mp_stash_cur_exp(mp); 
20241   mp->cur_exp=mp_id_transform(mp); 
20242   mp->cur_type=mp_transform_type;
20243   q=value(mp->cur_exp);
20244   switch (c) {
20245   @<For each of the eight cases, change the relevant fields of |cur_exp|
20246     and |goto done|;
20247     but do nothing if capsule |p| doesn't have the appropriate type@>;
20248   }; /* there are no other cases */
20249   mp_disp_err(mp, p,"Improper transformation argument");
20250 @.Improper transformation argument@>
20251   help3("The expression shown above has the wrong type,")
20252        ("so I can\'t transform anything using it.")
20253        ("Proceed, and I'll omit the transformation.");
20254   mp_put_get_error(mp);
20255 DONE: 
20256   mp_recycle_value(mp, p); 
20257   mp_free_node(mp, p,value_node_size);
20258 }
20259
20260 @ @<If the current transform is entirely known, ...@>=
20261 q=value(mp->cur_exp); r=q+transform_node_size;
20262 do {  
20263   r=r-2;
20264   if ( type(r)!=mp_known ) return;
20265 } while (r!=q);
20266 mp->txx=value(xx_part_loc(q));
20267 mp->txy=value(xy_part_loc(q));
20268 mp->tyx=value(yx_part_loc(q));
20269 mp->tyy=value(yy_part_loc(q));
20270 mp->tx=value(x_part_loc(q));
20271 mp->ty=value(y_part_loc(q));
20272 mp_flush_cur_exp(mp, 0)
20273
20274 @ @<For each of the eight cases...@>=
20275 case rotated_by:
20276   if ( type(p)==mp_known )
20277     @<Install sines and cosines, then |goto done|@>;
20278   break;
20279 case slanted_by:
20280   if ( type(p)>mp_pair_type ) { 
20281    mp_install(mp, xy_part_loc(q),p); goto DONE;
20282   };
20283   break;
20284 case scaled_by:
20285   if ( type(p)>mp_pair_type ) { 
20286     mp_install(mp, xx_part_loc(q),p); mp_install(mp, yy_part_loc(q),p); 
20287     goto DONE;
20288   };
20289   break;
20290 case shifted_by:
20291   if ( type(p)==mp_pair_type ) {
20292     r=value(p); mp_install(mp, x_part_loc(q),x_part_loc(r));
20293     mp_install(mp, y_part_loc(q),y_part_loc(r)); goto DONE;
20294   };
20295   break;
20296 case x_scaled:
20297   if ( type(p)>mp_pair_type ) {
20298     mp_install(mp, xx_part_loc(q),p); goto DONE;
20299   };
20300   break;
20301 case y_scaled:
20302   if ( type(p)>mp_pair_type ) {
20303     mp_install(mp, yy_part_loc(q),p); goto DONE;
20304   };
20305   break;
20306 case z_scaled:
20307   if ( type(p)==mp_pair_type )
20308     @<Install a complex multiplier, then |goto done|@>;
20309   break;
20310 case transformed_by:
20311   break;
20312   
20313
20314 @ @<Install sines and cosines, then |goto done|@>=
20315 { mp_n_sin_cos(mp, (value(p) % three_sixty_units)*16);
20316   value(xx_part_loc(q))=mp_round_fraction(mp, mp->n_cos);
20317   value(yx_part_loc(q))=mp_round_fraction(mp, mp->n_sin);
20318   value(xy_part_loc(q))=-value(yx_part_loc(q));
20319   value(yy_part_loc(q))=value(xx_part_loc(q));
20320   goto DONE;
20321 }
20322
20323 @ @<Install a complex multiplier, then |goto done|@>=
20324
20325   r=value(p);
20326   mp_install(mp, xx_part_loc(q),x_part_loc(r));
20327   mp_install(mp, yy_part_loc(q),x_part_loc(r));
20328   mp_install(mp, yx_part_loc(q),y_part_loc(r));
20329   if ( type(y_part_loc(r))==mp_known ) negate(value(y_part_loc(r)));
20330   else mp_negate_dep_list(mp, dep_list(y_part_loc(r)));
20331   mp_install(mp, xy_part_loc(q),y_part_loc(r));
20332   goto DONE;
20333 }
20334
20335 @ Procedure |set_up_known_trans| is like |set_up_trans|, but it
20336 insists that the transformation be entirely known.
20337
20338 @<Declare binary action...@>=
20339 void mp_set_up_known_trans (MP mp,quarterword c) { 
20340   mp_set_up_trans(mp, c);
20341   if ( mp->cur_type!=mp_known ) {
20342     exp_err("Transform components aren't all known");
20343 @.Transform components...@>
20344     help3("I'm unable to apply a partially specified transformation")
20345       ("except to a fully known pair or transform.")
20346       ("Proceed, and I'll omit the transformation.");
20347     mp_put_get_flush_error(mp, 0);
20348     mp->txx=unity; mp->txy=0; mp->tyx=0; mp->tyy=unity; 
20349     mp->tx=0; mp->ty=0;
20350   }
20351 }
20352
20353 @ Here's a procedure that applies the transform |txx..ty| to a pair of
20354 coordinates in locations |p| and~|q|.
20355
20356 @<Declare binary action...@>= 
20357 void mp_trans (MP mp,pointer p, pointer q) {
20358   scaled v; /* the new |x| value */
20359   v=mp_take_scaled(mp, mp->mem[p].sc,mp->txx)+
20360   mp_take_scaled(mp, mp->mem[q].sc,mp->txy)+mp->tx;
20361   mp->mem[q].sc=mp_take_scaled(mp, mp->mem[p].sc,mp->tyx)+
20362   mp_take_scaled(mp, mp->mem[q].sc,mp->tyy)+mp->ty;
20363   mp->mem[p].sc=v;
20364 }
20365
20366 @ The simplest transformation procedure applies a transform to all
20367 coordinates of a path.  The |path_trans(c)(p)| macro applies
20368 a transformation defined by |cur_exp| and the transform operator |c|
20369 to the path~|p|.
20370
20371 @d path_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20372                      mp_unstash_cur_exp(mp, (B)); 
20373                      mp_do_path_trans(mp, mp->cur_exp); }
20374
20375 @<Declare binary action...@>=
20376 void mp_do_path_trans (MP mp,pointer p) {
20377   pointer q; /* list traverser */
20378   q=p;
20379   do { 
20380     if ( left_type(q)!=endpoint ) 
20381       mp_trans(mp, q+3,q+4); /* that's |left_x| and |left_y| */
20382     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20383     if ( right_type(q)!=endpoint ) 
20384       mp_trans(mp, q+5,q+6); /* that's |right_x| and |right_y| */
20385 @^data structure assumptions@>
20386     q=link(q);
20387   } while (q!=p);
20388 }
20389
20390 @ Transforming a pen is very similar, except that there are no |left_type|
20391 and |right_type| fields.
20392
20393 @d pen_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20394                     mp_unstash_cur_exp(mp, (B)); 
20395                     mp_do_pen_trans(mp, mp->cur_exp); }
20396
20397 @<Declare binary action...@>=
20398 void mp_do_pen_trans (MP mp,pointer p) {
20399   pointer q; /* list traverser */
20400   if ( pen_is_elliptical(p) ) {
20401     mp_trans(mp, p+3,p+4); /* that's |left_x| and |left_y| */
20402     mp_trans(mp, p+5,p+6); /* that's |right_x| and |right_y| */
20403   };
20404   q=p;
20405   do { 
20406     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20407 @^data structure assumptions@>
20408     q=link(q);
20409   } while (q!=p);
20410 }
20411
20412 @ The next transformation procedure applies to edge structures. It will do
20413 any transformation, but the results may be substandard if the picture contains
20414 text that uses downloaded bitmap fonts.  The binary action procedure is
20415 |do_edges_trans|, but we also need a function that just scales a picture.
20416 That routine is |scale_edges|.  Both it and the underlying routine |edges_trans|
20417 should be thought of as procedures that update an edge structure |h|, except
20418 that they have to return a (possibly new) structure because of the need to call
20419 |private_edges|.
20420
20421 @<Declare binary action...@>=
20422 pointer mp_edges_trans (MP mp, pointer h) {
20423   pointer q; /* the object being transformed */
20424   pointer r,s; /* for list manipulation */
20425   scaled sx,sy; /* saved transformation parameters */
20426   scaled sqdet; /* square root of determinant for |dash_scale| */
20427   integer sgndet; /* sign of the determinant */
20428   scaled v; /* a temporary value */
20429   h=mp_private_edges(mp, h);
20430   sqdet=mp_sqrt_det(mp, mp->txx,mp->txy,mp->tyx,mp->tyy);
20431   sgndet=mp_ab_vs_cd(mp, mp->txx,mp->tyy,mp->txy,mp->tyx);
20432   if ( dash_list(h)!=null_dash ) {
20433     @<Try to transform the dash list of |h|@>;
20434   }
20435   @<Make the bounding box of |h| unknown if it can't be updated properly
20436     without scanning the whole structure@>;  
20437   q=link(dummy_loc(h));
20438   while ( q!=null ) { 
20439     @<Transform graphical object |q|@>;
20440     q=link(q);
20441   }
20442   return h;
20443 }
20444 void mp_do_edges_trans (MP mp,pointer p, quarterword c) { 
20445   mp_set_up_known_trans(mp, c);
20446   value(p)=mp_edges_trans(mp, value(p));
20447   mp_unstash_cur_exp(mp, p);
20448 }
20449 void mp_scale_edges (MP mp) { 
20450   mp->txx=mp->se_sf; mp->tyy=mp->se_sf;
20451   mp->txy=0; mp->tyx=0; mp->tx=0; mp->ty=0;
20452   mp->se_pic=mp_edges_trans(mp, mp->se_pic);
20453 }
20454
20455 @ @<Try to transform the dash list of |h|@>=
20456 if ( (mp->txy!=0)||(mp->tyx!=0)||
20457      (mp->ty!=0)||(abs(mp->txx)!=abs(mp->tyy))) {
20458   mp_flush_dash_list(mp, h);
20459 } else { 
20460   if ( mp->txx<0 ) { @<Reverse the dash list of |h|@>; } 
20461   @<Scale the dash list by |txx| and shift it by |tx|@>;
20462   dash_y(h)=mp_take_scaled(mp, dash_y(h),abs(mp->tyy));
20463 }
20464
20465 @ @<Reverse the dash list of |h|@>=
20466
20467   r=dash_list(h);
20468   dash_list(h)=null_dash;
20469   while ( r!=null_dash ) {
20470     s=r; r=link(r);
20471     v=start_x(s); start_x(s)=stop_x(s); stop_x(s)=v;
20472     link(s)=dash_list(h);
20473     dash_list(h)=s;
20474   }
20475 }
20476
20477 @ @<Scale the dash list by |txx| and shift it by |tx|@>=
20478 r=dash_list(h);
20479 while ( r!=null_dash ) {
20480   start_x(r)=mp_take_scaled(mp, start_x(r),mp->txx)+mp->tx;
20481   stop_x(r)=mp_take_scaled(mp, stop_x(r),mp->txx)+mp->tx;
20482   r=link(r);
20483 }
20484
20485 @ @<Make the bounding box of |h| unknown if it can't be updated properly...@>=
20486 if ( (mp->txx==0)&&(mp->tyy==0) ) {
20487   @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>;
20488 } else if ( (mp->txy!=0)||(mp->tyx!=0) ) {
20489   mp_init_bbox(mp, h);
20490   goto DONE1;
20491 }
20492 if ( minx_val(h)<=maxx_val(h) ) {
20493   @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift by
20494    |(tx,ty)|@>;
20495 }
20496 DONE1:
20497
20498
20499
20500 @ @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>=
20501
20502   v=minx_val(h); minx_val(h)=miny_val(h); miny_val(h)=v;
20503   v=maxx_val(h); maxx_val(h)=maxy_val(h); maxy_val(h)=v;
20504 }
20505
20506 @ The sum ``|txx+txy|'' is whichever of |txx| or |txy| is nonzero.  The other
20507 sum is similar.
20508
20509 @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift...@>=
20510
20511   minx_val(h)=mp_take_scaled(mp, minx_val(h),mp->txx+mp->txy)+mp->tx;
20512   maxx_val(h)=mp_take_scaled(mp, maxx_val(h),mp->txx+mp->txy)+mp->tx;
20513   miny_val(h)=mp_take_scaled(mp, miny_val(h),mp->tyx+mp->tyy)+mp->ty;
20514   maxy_val(h)=mp_take_scaled(mp, maxy_val(h),mp->tyx+mp->tyy)+mp->ty;
20515   if ( mp->txx+mp->txy<0 ) {
20516     v=minx_val(h); minx_val(h)=maxx_val(h); maxx_val(h)=v;
20517   }
20518   if ( mp->tyx+mp->tyy<0 ) {
20519     v=miny_val(h); miny_val(h)=maxy_val(h); maxy_val(h)=v;
20520   }
20521 }
20522
20523 @ Now we ready for the main task of transforming the graphical objects in edge
20524 structure~|h|.
20525
20526 @<Transform graphical object |q|@>=
20527 switch (type(q)) {
20528 case fill_code: case stroked_code: 
20529   mp_do_path_trans(mp, path_p(q));
20530   @<Transform |pen_p(q)|, making sure polygonal pens stay counter-clockwise@>;
20531   break;
20532 case mp_start_clip_code: case mp_start_bounds_code: 
20533   mp_do_path_trans(mp, path_p(q));
20534   break;
20535 case text_code: 
20536   r=text_tx_loc(q);
20537   @<Transform the compact transformation starting at |r|@>;
20538   break;
20539 case mp_stop_clip_code: case mp_stop_bounds_code: 
20540   break;
20541 } /* there are no other cases */
20542
20543 @ Note that the shift parameters |(tx,ty)| apply only to the path being stroked.
20544 The |dash_scale| has to be adjusted  to scale the dash lengths in |dash_p(q)|
20545 since the \ps\ output procedures will try to compensate for the transformation
20546 we are applying to |pen_p(q)|.  Since this compensation is based on the square
20547 root of the determinant, |sqdet| is the appropriate factor.
20548
20549 @<Transform |pen_p(q)|, making sure...@>=
20550 if ( pen_p(q)!=null ) {
20551   sx=mp->tx; sy=mp->ty;
20552   mp->tx=0; mp->ty=0;
20553   mp_do_pen_trans(mp, pen_p(q));
20554   if ( ((type(q)==stroked_code)&&(dash_p(q)!=null)) )
20555     dash_scale(q)=mp_take_scaled(mp, dash_scale(q),sqdet);
20556   if ( ! pen_is_elliptical(pen_p(q)) )
20557     if ( sgndet<0 )
20558       pen_p(q)=mp_make_pen(mp, mp_copy_path(mp, pen_p(q)),true); 
20559          /* this unreverses the pen */
20560   mp->tx=sx; mp->ty=sy;
20561 }
20562
20563 @ This uses the fact that transformations are stored in the order
20564 |(tx,ty,txx,txy,tyx,tyy)|.
20565 @^data structure assumptions@>
20566
20567 @<Transform the compact transformation starting at |r|@>=
20568 mp_trans(mp, r,r+1);
20569 sx=mp->tx; sy=mp->ty;
20570 mp->tx=0; mp->ty=0;
20571 mp_trans(mp, r+2,r+4);
20572 mp_trans(mp, r+3,r+5);
20573 mp->tx=sx; mp->ty=sy
20574
20575 @ The hard cases of transformation occur when big nodes are involved,
20576 and when some of their components are unknown.
20577
20578 @<Declare binary action...@>=
20579 @<Declare subroutines needed by |big_trans|@>;
20580 void mp_big_trans (MP mp,pointer p, quarterword c) {
20581   pointer q,r,pp,qq; /* list manipulation registers */
20582   small_number s; /* size of a big node */
20583   s=mp->big_node_size[type(p)]; q=value(p); r=q+s;
20584   do {  
20585     r=r-2;
20586     if ( type(r)!=mp_known ) {
20587       @<Transform an unknown big node and |return|@>;
20588     }
20589   } while (r!=q);
20590   @<Transform a known big node@>;
20591 }; /* node |p| will now be recycled by |do_binary| */
20592
20593 @ @<Transform an unknown big node and |return|@>=
20594
20595   mp_set_up_known_trans(mp, c); mp_make_exp_copy(mp, p); 
20596   r=value(mp->cur_exp);
20597   if ( mp->cur_type==mp_transform_type ) {
20598     mp_bilin1(mp, yy_part_loc(r),mp->tyy,xy_part_loc(q),mp->tyx,0);
20599     mp_bilin1(mp, yx_part_loc(r),mp->tyy,xx_part_loc(q),mp->tyx,0);
20600     mp_bilin1(mp, xy_part_loc(r),mp->txx,yy_part_loc(q),mp->txy,0);
20601     mp_bilin1(mp, xx_part_loc(r),mp->txx,yx_part_loc(q),mp->txy,0);
20602   }
20603   mp_bilin1(mp, y_part_loc(r),mp->tyy,x_part_loc(q),mp->tyx,mp->ty);
20604   mp_bilin1(mp, x_part_loc(r),mp->txx,y_part_loc(q),mp->txy,mp->tx);
20605   return;
20606 }
20607
20608 @ Let |p| point to a two-word value field inside a big node of |cur_exp|,
20609 and let |q| point to a another value field. The |bilin1| procedure
20610 replaces |p| by $p\cdot t+q\cdot u+\delta$.
20611
20612 @<Declare subroutines needed by |big_trans|@>=
20613 void mp_bilin1 (MP mp, pointer p, scaled t, pointer q, 
20614                 scaled u, scaled delta) {
20615   pointer r; /* list traverser */
20616   if ( t!=unity ) mp_dep_mult(mp, p,t,true);
20617   if ( u!=0 ) {
20618     if ( type(q)==mp_known ) {
20619       delta+=mp_take_scaled(mp, value(q),u);
20620     } else { 
20621       @<Ensure that |type(p)=mp_proto_dependent|@>;
20622       dep_list(p)=mp_p_plus_fq(mp, dep_list(p),u,dep_list(q),
20623                                mp_proto_dependent,type(q));
20624     }
20625   }
20626   if ( type(p)==mp_known ) {
20627     value(p)+=delta;
20628   } else {
20629     r=dep_list(p);
20630     while ( info(r)!=null ) r=link(r);
20631     delta+=value(r);
20632     if ( r!=dep_list(p) ) value(r)=delta;
20633     else { mp_recycle_value(mp, p); type(p)=mp_known; value(p)=delta; };
20634   }
20635   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20636 }
20637
20638 @ @<Ensure that |type(p)=mp_proto_dependent|@>=
20639 if ( type(p)!=mp_proto_dependent ) {
20640   if ( type(p)==mp_known ) 
20641     mp_new_dep(mp, p,mp_const_dependency(mp, value(p)));
20642   else 
20643     dep_list(p)=mp_p_times_v(mp, dep_list(p),unity,mp_dependent,
20644                              mp_proto_dependent,true);
20645   type(p)=mp_proto_dependent;
20646 }
20647
20648 @ @<Transform a known big node@>=
20649 mp_set_up_trans(mp, c);
20650 if ( mp->cur_type==mp_known ) {
20651   @<Transform known by known@>;
20652 } else { 
20653   pp=mp_stash_cur_exp(mp); qq=value(pp);
20654   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20655   if ( mp->cur_type==mp_transform_type ) {
20656     mp_bilin2(mp, yy_part_loc(r),yy_part_loc(qq),
20657       value(xy_part_loc(q)),yx_part_loc(qq),null);
20658     mp_bilin2(mp, yx_part_loc(r),yy_part_loc(qq),
20659       value(xx_part_loc(q)),yx_part_loc(qq),null);
20660     mp_bilin2(mp, xy_part_loc(r),xx_part_loc(qq),
20661       value(yy_part_loc(q)),xy_part_loc(qq),null);
20662     mp_bilin2(mp, xx_part_loc(r),xx_part_loc(qq),
20663       value(yx_part_loc(q)),xy_part_loc(qq),null);
20664   };
20665   mp_bilin2(mp, y_part_loc(r),yy_part_loc(qq),
20666     value(x_part_loc(q)),yx_part_loc(qq),y_part_loc(qq));
20667   mp_bilin2(mp, x_part_loc(r),xx_part_loc(qq),
20668     value(y_part_loc(q)),xy_part_loc(qq),x_part_loc(qq));
20669   mp_recycle_value(mp, pp); mp_free_node(mp, pp,value_node_size);
20670 }
20671
20672 @ Let |p| be a |mp_proto_dependent| value whose dependency list ends
20673 at |dep_final|. The following procedure adds |v| times another
20674 numeric quantity to~|p|.
20675
20676 @<Declare subroutines needed by |big_trans|@>=
20677 void mp_add_mult_dep (MP mp,pointer p, scaled v, pointer r) { 
20678   if ( type(r)==mp_known ) {
20679     value(mp->dep_final)+=mp_take_scaled(mp, value(r),v);
20680   } else  { 
20681     dep_list(p)=mp_p_plus_fq(mp, dep_list(p),v,dep_list(r),
20682                                                          mp_proto_dependent,type(r));
20683     if ( mp->fix_needed ) mp_fix_dependencies(mp);
20684   }
20685 }
20686
20687 @ The |bilin2| procedure is something like |bilin1|, but with known
20688 and unknown quantities reversed. Parameter |p| points to a value field
20689 within the big node for |cur_exp|; and |type(p)=mp_known|. Parameters
20690 |t| and~|u| point to value fields elsewhere; so does parameter~|q|,
20691 unless it is |null| (which stands for zero). Location~|p| will be
20692 replaced by $p\cdot t+v\cdot u+q$.
20693
20694 @<Declare subroutines needed by |big_trans|@>=
20695 void mp_bilin2 (MP mp,pointer p, pointer t, scaled v, 
20696                 pointer u, pointer q) {
20697   scaled vv; /* temporary storage for |value(p)| */
20698   vv=value(p); type(p)=mp_proto_dependent;
20699   mp_new_dep(mp, p,mp_const_dependency(mp, 0)); /* this sets |dep_final| */
20700   if ( vv!=0 ) 
20701     mp_add_mult_dep(mp, p,vv,t); /* |dep_final| doesn't change */
20702   if ( v!=0 ) mp_add_mult_dep(mp, p,v,u);
20703   if ( q!=null ) mp_add_mult_dep(mp, p,unity,q);
20704   if ( dep_list(p)==mp->dep_final ) {
20705     vv=value(mp->dep_final); mp_recycle_value(mp, p);
20706     type(p)=mp_known; value(p)=vv;
20707   }
20708 }
20709
20710 @ @<Transform known by known@>=
20711
20712   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
20713   if ( mp->cur_type==mp_transform_type ) {
20714     mp_bilin3(mp, yy_part_loc(r),mp->tyy,value(xy_part_loc(q)),mp->tyx,0);
20715     mp_bilin3(mp, yx_part_loc(r),mp->tyy,value(xx_part_loc(q)),mp->tyx,0);
20716     mp_bilin3(mp, xy_part_loc(r),mp->txx,value(yy_part_loc(q)),mp->txy,0);
20717     mp_bilin3(mp, xx_part_loc(r),mp->txx,value(yx_part_loc(q)),mp->txy,0);
20718   }
20719   mp_bilin3(mp, y_part_loc(r),mp->tyy,value(x_part_loc(q)),mp->tyx,mp->ty);
20720   mp_bilin3(mp, x_part_loc(r),mp->txx,value(y_part_loc(q)),mp->txy,mp->tx);
20721 }
20722
20723 @ Finally, in |bilin3| everything is |known|.
20724
20725 @<Declare subroutines needed by |big_trans|@>=
20726 void mp_bilin3 (MP mp,pointer p, scaled t, 
20727                scaled v, scaled u, scaled delta) { 
20728   if ( t!=unity )
20729     delta+=mp_take_scaled(mp, value(p),t);
20730   else 
20731     delta+=value(p);
20732   if ( u!=0 ) value(p)=delta+mp_take_scaled(mp, v,u);
20733   else value(p)=delta;
20734 }
20735
20736 @ @<Additional cases of binary operators@>=
20737 case concatenate: 
20738   if ( (mp->cur_type==mp_string_type)&&(type(p)==mp_string_type) ) mp_cat(mp, p);
20739   else mp_bad_binary(mp, p,concatenate);
20740   break;
20741 case substring_of: 
20742   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_string_type) )
20743     mp_chop_string(mp, value(p));
20744   else mp_bad_binary(mp, p,substring_of);
20745   break;
20746 case subpath_of: 
20747   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20748   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_path_type) )
20749     mp_chop_path(mp, value(p));
20750   else mp_bad_binary(mp, p,subpath_of);
20751   break;
20752
20753 @ @<Declare binary action...@>=
20754 void mp_cat (MP mp,pointer p) {
20755   str_number a,b; /* the strings being concatenated */
20756   pool_pointer k; /* index into |str_pool| */
20757   a=value(p); b=mp->cur_exp; str_room(length(a)+length(b));
20758   for (k=mp->str_start[a];k<=str_stop(a)-1;k++) {
20759     append_char(mp->str_pool[k]);
20760   }
20761   for (k=mp->str_start[b];k<=str_stop(b)-1;k++) {
20762     append_char(mp->str_pool[k]);
20763   }
20764   mp->cur_exp=mp_make_string(mp); delete_str_ref(b);
20765 }
20766
20767 @ @<Declare binary action...@>=
20768 void mp_chop_string (MP mp,pointer p) {
20769   integer a, b; /* start and stop points */
20770   integer l; /* length of the original string */
20771   integer k; /* runs from |a| to |b| */
20772   str_number s; /* the original string */
20773   boolean reversed; /* was |a>b|? */
20774   a=mp_round_unscaled(mp, value(x_part_loc(p)));
20775   b=mp_round_unscaled(mp, value(y_part_loc(p)));
20776   if ( a<=b ) reversed=false;
20777   else  { reversed=true; k=a; a=b; b=k; };
20778   s=mp->cur_exp; l=length(s);
20779   if ( a<0 ) { 
20780     a=0;
20781     if ( b<0 ) b=0;
20782   }
20783   if ( b>l ) { 
20784     b=l;
20785     if ( a>l ) a=l;
20786   }
20787   str_room(b-a);
20788   if ( reversed ) {
20789     for (k=mp->str_start[s]+b-1;k>=mp->str_start[s]+a;k--)  {
20790       append_char(mp->str_pool[k]);
20791     }
20792   } else  {
20793     for (k=mp->str_start[s]+a;k<=mp->str_start[s]+b-1;k++)  {
20794       append_char(mp->str_pool[k]);
20795     }
20796   }
20797   mp->cur_exp=mp_make_string(mp); delete_str_ref(s);
20798 }
20799
20800 @ @<Declare binary action...@>=
20801 void mp_chop_path (MP mp,pointer p) {
20802   pointer q; /* a knot in the original path */
20803   pointer pp,qq,rr,ss; /* link variables for copies of path nodes */
20804   scaled a,b,k,l; /* indices for chopping */
20805   boolean reversed; /* was |a>b|? */
20806   l=mp_path_length(mp); a=value(x_part_loc(p)); b=value(y_part_loc(p));
20807   if ( a<=b ) reversed=false;
20808   else  { reversed=true; k=a; a=b; b=k; };
20809   @<Dispense with the cases |a<0| and/or |b>l|@>;
20810   q=mp->cur_exp;
20811   while ( a>=unity ) {
20812     q=link(q); a=a-unity; b=b-unity;
20813   }
20814   if ( b==a ) {
20815     @<Construct a path from |pp| to |qq| of length zero@>; 
20816   } else { 
20817     @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>; 
20818   }
20819   left_type(pp)=endpoint; right_type(qq)=endpoint; link(qq)=pp;
20820   mp_toss_knot_list(mp, mp->cur_exp);
20821   if ( reversed ) {
20822     mp->cur_exp=link(mp_htap_ypoc(mp, pp)); mp_toss_knot_list(mp, pp);
20823   } else {
20824     mp->cur_exp=pp;
20825   }
20826 }
20827
20828 @ @<Dispense with the cases |a<0| and/or |b>l|@>=
20829 if ( a<0 ) {
20830   if ( left_type(mp->cur_exp)==endpoint ) {
20831     a=0; if ( b<0 ) b=0;
20832   } else  {
20833     do {  a=a+l; b=b+l; } while (a<0); /* a cycle always has length |l>0| */
20834   }
20835 }
20836 if ( b>l ) {
20837   if ( left_type(mp->cur_exp)==endpoint ) {
20838     b=l; if ( a>l ) a=l;
20839   } else {
20840     while ( a>=l ) { 
20841       a=a-l; b=b-l;
20842     }
20843   }
20844 }
20845
20846 @ @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>=
20847
20848   pp=mp_copy_knot(mp, q); qq=pp;
20849   do {  
20850     q=link(q); rr=qq; qq=mp_copy_knot(mp, q); link(rr)=qq; b=b-unity;
20851   } while (b>0);
20852   if ( a>0 ) {
20853     ss=pp; pp=link(pp);
20854     mp_split_cubic(mp, ss,a*010000); pp=link(ss);
20855     mp_free_node(mp, ss,knot_node_size);
20856     if ( rr==ss ) {
20857       b=mp_make_scaled(mp, b,unity-a); rr=pp;
20858     }
20859   }
20860   if ( b<0 ) {
20861     mp_split_cubic(mp, rr,(b+unity)*010000);
20862     mp_free_node(mp, qq,knot_node_size);
20863     qq=link(rr);
20864   }
20865 }
20866
20867 @ @<Construct a path from |pp| to |qq| of length zero@>=
20868
20869   if ( a>0 ) { mp_split_cubic(mp, q,a*010000); q=link(q); };
20870   pp=mp_copy_knot(mp, q); qq=pp;
20871 }
20872
20873 @ @<Additional cases of binary operators@>=
20874 case point_of: case precontrol_of: case postcontrol_of: 
20875   if ( mp->cur_type==mp_pair_type )
20876      mp_pair_to_path(mp);
20877   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
20878     mp_find_point(mp, value(p),c);
20879   else 
20880     mp_bad_binary(mp, p,c);
20881   break;
20882 case pen_offset_of: 
20883   if ( (mp->cur_type==mp_pen_type)&& mp_nice_pair(mp, p,type(p)) )
20884     mp_set_up_offset(mp, value(p));
20885   else 
20886     mp_bad_binary(mp, p,pen_offset_of);
20887   break;
20888 case direction_time_of: 
20889   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20890   if ( (mp->cur_type==mp_path_type)&& mp_nice_pair(mp, p,type(p)) )
20891     mp_set_up_direction_time(mp, value(p));
20892   else 
20893     mp_bad_binary(mp, p,direction_time_of);
20894   break;
20895
20896 @ @<Declare binary action...@>=
20897 void mp_set_up_offset (MP mp,pointer p) { 
20898   mp_find_offset(mp, value(x_part_loc(p)),value(y_part_loc(p)),mp->cur_exp);
20899   mp_pair_value(mp, mp->cur_x,mp->cur_y);
20900 }
20901 void mp_set_up_direction_time (MP mp,pointer p) { 
20902   mp_flush_cur_exp(mp, mp_find_direction_time(mp, value(x_part_loc(p)),
20903   value(y_part_loc(p)),mp->cur_exp));
20904 }
20905
20906 @ @<Declare binary action...@>=
20907 void mp_find_point (MP mp,scaled v, quarterword c) {
20908   pointer p; /* the path */
20909   scaled n; /* its length */
20910   p=mp->cur_exp;
20911   if ( left_type(p)==endpoint ) n=-unity; else n=0;
20912   do {  p=link(p); n=n+unity; } while (p!=mp->cur_exp);
20913   if ( n==0 ) { 
20914     v=0; 
20915   } else if ( v<0 ) {
20916     if ( left_type(p)==endpoint ) v=0;
20917     else v=n-1-((-v-1) % n);
20918   } else if ( v>n ) {
20919     if ( left_type(p)==endpoint ) v=n;
20920     else v=v % n;
20921   }
20922   p=mp->cur_exp;
20923   while ( v>=unity ) { p=link(p); v=v-unity;  };
20924   if ( v!=0 ) {
20925      @<Insert a fractional node by splitting the cubic@>;
20926   }
20927   @<Set the current expression to the desired path coordinates@>;
20928 }
20929
20930 @ @<Insert a fractional node...@>=
20931 { mp_split_cubic(mp, p,v*010000); p=link(p); }
20932
20933 @ @<Set the current expression to the desired path coordinates...@>=
20934 switch (c) {
20935 case point_of: 
20936   mp_pair_value(mp, x_coord(p),y_coord(p));
20937   break;
20938 case precontrol_of: 
20939   if ( left_type(p)==endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
20940   else mp_pair_value(mp, left_x(p),left_y(p));
20941   break;
20942 case postcontrol_of: 
20943   if ( right_type(p)==endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
20944   else mp_pair_value(mp, right_x(p),right_y(p));
20945   break;
20946 } /* there are no other cases */
20947
20948 @ @<Additional cases of binary operators@>=
20949 case arc_time_of: 
20950   if ( mp->cur_type==mp_pair_type )
20951      mp_pair_to_path(mp);
20952   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
20953     mp_flush_cur_exp(mp, mp_get_arc_time(mp, mp->cur_exp,value(p)));
20954   else 
20955     mp_bad_binary(mp, p,c);
20956   break;
20957
20958 @ @<Additional cases of bin...@>=
20959 case intersect: 
20960   if ( type(p)==mp_pair_type ) {
20961     q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p);
20962     mp_pair_to_path(mp); p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
20963   };
20964   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
20965   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_path_type) ) {
20966     mp_path_intersection(mp, value(p),mp->cur_exp);
20967     mp_pair_value(mp, mp->cur_t,mp->cur_tt);
20968   } else {
20969     mp_bad_binary(mp, p,intersect);
20970   }
20971   break;
20972
20973 @ @<Additional cases of bin...@>=
20974 case in_font:
20975   if ( (mp->cur_type!=mp_string_type)||(type(p)!=mp_string_type)) 
20976     mp_bad_binary(mp, p,in_font);
20977   else { mp_do_infont(mp, p); return; }
20978   break;
20979
20980 @ Function |new_text_node| owns the reference count for its second argument
20981 (the text string) but not its first (the font name).
20982
20983 @<Declare binary action...@>=
20984 void mp_do_infont (MP mp,pointer p) {
20985   pointer q;
20986   q=mp_get_node(mp, edge_header_size);
20987   mp_init_edges(mp, q);
20988   link(obj_tail(q))=mp_new_text_node(mp, str(mp->cur_exp),value(p));
20989   obj_tail(q)=link(obj_tail(q));
20990   mp_free_node(mp, p,value_node_size);
20991   mp_flush_cur_exp(mp, q);
20992   mp->cur_type=mp_picture_type;
20993 }
20994
20995 @* \[40] Statements and commands.
20996 The chief executive of \MP\ is the |do_statement| routine, which
20997 contains the master switch that causes all the various pieces of \MP\
20998 to do their things, in the right order.
20999
21000 In a sense, this is the grand climax of the program: It applies all the
21001 tools that we have worked so hard to construct. In another sense, this is
21002 the messiest part of the program: It necessarily refers to other pieces
21003 of code all over the place, so that a person can't fully understand what is
21004 going on without paging back and forth to be reminded of conventions that
21005 are defined elsewhere. We are now at the hub of the web.
21006
21007 The structure of |do_statement| itself is quite simple.  The first token
21008 of the statement is fetched using |get_x_next|.  If it can be the first
21009 token of an expression, we look for an equation, an assignment, or a
21010 title. Otherwise we use a \&{case} construction to branch at high speed to
21011 the appropriate routine for various and sundry other types of commands,
21012 each of which has an ``action procedure'' that does the necessary work.
21013
21014 The program uses the fact that
21015 $$\hbox{|min_primary_command=max_statement_command=type_name|}$$
21016 to interpret a statement that starts with, e.g., `\&{string}',
21017 as a type declaration rather than a boolean expression.
21018
21019 @c void mp_do_statement (MP mp) { /* governs \MP's activities */
21020   mp->cur_type=mp_vacuous; mp_get_x_next(mp);
21021   if ( mp->cur_cmd>max_primary_command ) {
21022     @<Worry about bad statement@>;
21023   } else if ( mp->cur_cmd>max_statement_command ) {
21024     @<Do an equation, assignment, title, or
21025      `$\langle\,$expression$\,\rangle\,$\&{endgroup}'@>;
21026   } else {
21027     @<Do a statement that doesn't begin with an expression@>;
21028   }
21029   if ( mp->cur_cmd<semicolon )
21030     @<Flush unparsable junk that was found after the statement@>;
21031   mp->error_count=0;
21032 }
21033
21034 @ @<Declarations@>=
21035 @<Declare action procedures for use by |do_statement|@>;
21036
21037 @ The only command codes |>max_primary_command| that can be present
21038 at the beginning of a statement are |semicolon| and higher; these
21039 occur when the statement is null.
21040
21041 @<Worry about bad statement@>=
21042
21043   if ( mp->cur_cmd<semicolon ) {
21044     print_err("A statement can't begin with `");
21045 @.A statement can't begin with x@>
21046     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); mp_print_char(mp, '\'');
21047     help5("I was looking for the beginning of a new statement.")
21048       ("If you just proceed without changing anything, I'll ignore")
21049       ("everything up to the next `;'. Please insert a semicolon")
21050       ("now in front of anything that you don't want me to delete.")
21051       ("(See Chapter 27 of The METAFONTbook for an example.)");
21052 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21053     mp_back_error(mp); mp_get_x_next(mp);
21054   }
21055 }
21056
21057 @ The help message printed here says that everything is flushed up to
21058 a semicolon, but actually the commands |end_group| and |stop| will
21059 also terminate a statement.
21060
21061 @<Flush unparsable junk that was found after the statement@>=
21062
21063   print_err("Extra tokens will be flushed");
21064 @.Extra tokens will be flushed@>
21065   help6("I've just read as much of that statement as I could fathom,")
21066        ("so a semicolon should have been next. It's very puzzling...")
21067        ("but I'll try to get myself back together, by ignoring")
21068        ("everything up to the next `;'. Please insert a semicolon")
21069        ("now in front of anything that you don't want me to delete.")
21070        ("(See Chapter 27 of The METAFONTbook for an example.)");
21071 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21072   mp_back_error(mp); mp->scanner_status=flushing;
21073   do {  
21074     get_t_next;
21075     @<Decrease the string reference count...@>;
21076   } while (! end_of_statement); /* |cur_cmd=semicolon|, |end_group|, or |stop| */
21077   mp->scanner_status=normal;
21078 }
21079
21080 @ If |do_statement| ends with |cur_cmd=end_group|, we should have
21081 |cur_type=mp_vacuous| unless the statement was simply an expression;
21082 in the latter case, |cur_type| and |cur_exp| should represent that
21083 expression.
21084
21085 @<Do a statement that doesn't...@>=
21086
21087   if ( mp->internal[tracing_commands]>0 ) 
21088     show_cur_cmd_mod;
21089   switch (mp->cur_cmd ) {
21090   case type_name:mp_do_type_declaration(mp); break;
21091   case macro_def:
21092     if ( mp->cur_mod>var_def ) mp_make_op_def(mp);
21093     else if ( mp->cur_mod>end_def ) mp_scan_def(mp);
21094      break;
21095   @<Cases of |do_statement| that invoke particular commands@>;
21096   } /* there are no other cases */
21097   mp->cur_type=mp_vacuous;
21098 }
21099
21100 @ The most important statements begin with expressions.
21101
21102 @<Do an equation, assignment, title, or...@>=
21103
21104   mp->var_flag=assignment; mp_scan_expression(mp);
21105   if ( mp->cur_cmd<end_group ) {
21106     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21107     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21108     else if ( mp->cur_type==mp_string_type ) {@<Do a title@> ; }
21109     else if ( mp->cur_type!=mp_vacuous ){ 
21110       exp_err("Isolated expression");
21111 @.Isolated expression@>
21112       help3("I couldn't find an `=' or `:=' after the")
21113         ("expression that is shown above this error message,")
21114         ("so I guess I'll just ignore it and carry on.");
21115       mp_put_get_error(mp);
21116     }
21117     mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous;
21118   }
21119 }
21120
21121 @ @<Do a title@>=
21122
21123   if ( mp->internal[tracing_titles]>0 ) {
21124     mp_print_nl(mp, "");  mp_print_str(mp, mp->cur_exp); update_terminal;
21125   }
21126 }
21127
21128 @ Equations and assignments are performed by the pair of mutually recursive
21129 @^recursion@>
21130 routines |do_equation| and |do_assignment|. These routines are called when
21131 |cur_cmd=equals| and when |cur_cmd=assignment|, respectively; the left-hand
21132 side is in |cur_type| and |cur_exp|, while the right-hand side is yet
21133 to be scanned. After the routines are finished, |cur_type| and |cur_exp|
21134 will be equal to the right-hand side (which will normally be equal
21135 to the left-hand side).
21136
21137 @<Declare action procedures for use by |do_statement|@>=
21138 @<Declare the procedure called |try_eq|@>;
21139 @<Declare the procedure called |make_eq|@>;
21140 void mp_do_equation (MP mp) ;
21141
21142 @ @c
21143 void mp_do_equation (MP mp) {
21144   pointer lhs; /* capsule for the left-hand side */
21145   pointer p; /* temporary register */
21146   lhs=mp_stash_cur_exp(mp); mp_get_x_next(mp); 
21147   mp->var_flag=assignment; mp_scan_expression(mp);
21148   if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21149   else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21150   if ( mp->internal[tracing_commands]>two ) 
21151     @<Trace the current equation@>;
21152   if ( mp->cur_type==mp_unknown_path ) if ( type(lhs)==mp_pair_type ) {
21153     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, lhs); lhs=p;
21154   }; /* in this case |make_eq| will change the pair to a path */
21155   mp_make_eq(mp, lhs); /* equate |lhs| to |(cur_type,cur_exp)| */
21156 }
21157
21158 @ And |do_assignment| is similar to |do_expression|:
21159
21160 @<Declarations@>=
21161 void mp_do_assignment (MP mp);
21162
21163 @ @<Declare action procedures for use by |do_statement|@>=
21164 void mp_do_assignment (MP mp) ;
21165
21166 @ @c
21167 void mp_do_assignment (MP mp) {
21168   pointer lhs; /* token list for the left-hand side */
21169   pointer p; /* where the left-hand value is stored */
21170   pointer q; /* temporary capsule for the right-hand value */
21171   if ( mp->cur_type!=mp_token_list ) { 
21172     exp_err("Improper `:=' will be changed to `='");
21173 @.Improper `:='@>
21174     help2("I didn't find a variable name at the left of the `:=',")
21175       ("so I'm going to pretend that you said `=' instead.");
21176     mp_error(mp); mp_do_equation(mp);
21177   } else { 
21178     lhs=mp->cur_exp; mp->cur_type=mp_vacuous;
21179     mp_get_x_next(mp); mp->var_flag=assignment; mp_scan_expression(mp);
21180     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21181     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21182     if ( mp->internal[tracing_commands]>two ) 
21183       @<Trace the current assignment@>;
21184     if ( info(lhs)>hash_end ) {
21185       @<Assign the current expression to an internal variable@>;
21186     } else  {
21187       @<Assign the current expression to the variable |lhs|@>;
21188     }
21189     mp_flush_node_list(mp, lhs);
21190   }
21191 }
21192
21193 @ @<Trace the current equation@>=
21194
21195   mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp,lhs,0);
21196   mp_print(mp,")=("); mp_print_exp(mp,null,0); 
21197   mp_print(mp,")}"); mp_end_diagnostic(mp, false);
21198 }
21199
21200 @ @<Trace the current assignment@>=
21201
21202   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
21203   if ( info(lhs)>hash_end ) 
21204      mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21205   else 
21206      mp_show_token_list(mp, lhs,null,1000,0);
21207   mp_print(mp, ":="); mp_print_exp(mp, null,0); 
21208   mp_print_char(mp, '}'); mp_end_diagnostic(mp, false);
21209 }
21210
21211 @ @<Assign the current expression to an internal variable@>=
21212 if ( mp->cur_type==mp_known )  {
21213   mp->internal[info(lhs)-(hash_end)]=mp->cur_exp;
21214 } else { 
21215   exp_err("Internal quantity `");
21216 @.Internal quantity...@>
21217   mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21218   mp_print(mp, "' must receive a known value");
21219   help2("I can\'t set an internal quantity to anything but a known")
21220     ("numeric value, so I'll have to ignore this assignment.");
21221   mp_put_get_error(mp);
21222 }
21223
21224 @ @<Assign the current expression to the variable |lhs|@>=
21225
21226   p=mp_find_variable(mp, lhs);
21227   if ( p!=null ) {
21228     q=mp_stash_cur_exp(mp); mp->cur_type=mp_und_type(mp, p); 
21229     mp_recycle_value(mp, p);
21230     type(p)=mp->cur_type; value(p)=null; mp_make_exp_copy(mp, p);
21231     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); mp_make_eq(mp, p);
21232   } else  { 
21233     mp_obliterated(mp, lhs); mp_put_get_error(mp);
21234   }
21235 }
21236
21237
21238 @ And now we get to the nitty-gritty. The |make_eq| procedure is given
21239 a pointer to a capsule that is to be equated to the current expression.
21240
21241 @<Declare the procedure called |make_eq|@>=
21242 void mp_make_eq (MP mp,pointer lhs) ;
21243
21244
21245
21246 @c void mp_make_eq (MP mp,pointer lhs) {
21247   small_number t; /* type of the left-hand side */
21248   pointer p,q; /* pointers inside of big nodes */
21249   integer v=0; /* value of the left-hand side */
21250 RESTART: 
21251   t=type(lhs);
21252   if ( t<=mp_pair_type ) v=value(lhs);
21253   switch (t) {
21254   @<For each type |t|, make an equation and |goto done| unless |cur_type|
21255     is incompatible with~|t|@>;
21256   } /* all cases have been listed */
21257   @<Announce that the equation cannot be performed@>;
21258 DONE:
21259   check_arith; mp_recycle_value(mp, lhs); 
21260   mp_free_node(mp, lhs,value_node_size);
21261 }
21262
21263 @ @<Announce that the equation cannot be performed@>=
21264 mp_disp_err(mp, lhs,""); 
21265 exp_err("Equation cannot be performed (");
21266 @.Equation cannot be performed@>
21267 if ( type(lhs)<=mp_pair_type ) mp_print_type(mp, type(lhs));
21268 else mp_print(mp, "numeric");
21269 mp_print_char(mp, '=');
21270 if ( mp->cur_type<=mp_pair_type ) mp_print_type(mp, mp->cur_type);
21271 else mp_print(mp, "numeric");
21272 mp_print_char(mp, ')');
21273 help2("I'm sorry, but I don't know how to make such things equal.")
21274      ("(See the two expressions just above the error message.)");
21275 mp_put_get_error(mp)
21276
21277 @ @<For each type |t|, make an equation and |goto done| unless...@>=
21278 case mp_boolean_type: case mp_string_type: case mp_pen_type:
21279 case mp_path_type: case mp_picture_type:
21280   if ( mp->cur_type==t+unknown_tag ) { 
21281     mp_nonlinear_eq(mp, v,mp->cur_exp,false); goto DONE;
21282   } else if ( mp->cur_type==t ) {
21283     @<Report redundant or inconsistent equation and |goto done|@>;
21284   }
21285   break;
21286 case unknown_types:
21287   if ( mp->cur_type==t-unknown_tag ) { 
21288     mp_nonlinear_eq(mp, mp->cur_exp,lhs,true); goto DONE;
21289   } else if ( mp->cur_type==t ) { 
21290     mp_ring_merge(mp, lhs,mp->cur_exp); goto DONE;
21291   } else if ( mp->cur_type==mp_pair_type ) {
21292     if ( t==mp_unknown_path ) { 
21293      mp_pair_to_path(mp); goto RESTART;
21294     };
21295   }
21296   break;
21297 case mp_transform_type: case mp_color_type:
21298 case mp_cmykcolor_type: case mp_pair_type:
21299   if ( mp->cur_type==t ) {
21300     @<Do multiple equations and |goto done|@>;
21301   }
21302   break;
21303 case mp_known: case mp_dependent:
21304 case mp_proto_dependent: case mp_independent:
21305   if ( mp->cur_type>=mp_known ) { 
21306     mp_try_eq(mp, lhs,null); goto DONE;
21307   };
21308   break;
21309 case mp_vacuous:
21310   break;
21311
21312 @ @<Report redundant or inconsistent equation and |goto done|@>=
21313
21314   if ( mp->cur_type<=mp_string_type ) {
21315     if ( mp->cur_type==mp_string_type ) {
21316       if ( mp_str_vs_str(mp, v,mp->cur_exp)!=0 ) {
21317         goto NOT_FOUND;
21318       }
21319     } else if ( v!=mp->cur_exp ) {
21320       goto NOT_FOUND;
21321     }
21322     @<Exclaim about a redundant equation@>; goto DONE;
21323   }
21324   print_err("Redundant or inconsistent equation");
21325 @.Redundant or inconsistent equation@>
21326   help2("An equation between already-known quantities can't help.")
21327        ("But don't worry; continue and I'll just ignore it.");
21328   mp_put_get_error(mp); goto DONE;
21329 NOT_FOUND: 
21330   print_err("Inconsistent equation");
21331 @.Inconsistent equation@>
21332   help2("The equation I just read contradicts what was said before.")
21333        ("But don't worry; continue and I'll just ignore it.");
21334   mp_put_get_error(mp); goto DONE;
21335 }
21336
21337 @ @<Do multiple equations and |goto done|@>=
21338
21339   p=v+mp->big_node_size[t]; 
21340   q=value(mp->cur_exp)+mp->big_node_size[t];
21341   do {  
21342     p=p-2; q=q-2; mp_try_eq(mp, p,q);
21343   } while (p!=v);
21344   goto DONE;
21345 }
21346
21347 @ The first argument to |try_eq| is the location of a value node
21348 in a capsule that will soon be recycled. The second argument is
21349 either a location within a pair or transform node pointed to by
21350 |cur_exp|, or it is |null| (which means that |cur_exp| itself
21351 serves as the second argument). The idea is to leave |cur_exp| unchanged,
21352 but to equate the two operands.
21353
21354 @<Declare the procedure called |try_eq|@>=
21355 void mp_try_eq (MP mp,pointer l, pointer r) ;
21356
21357
21358 @c void mp_try_eq (MP mp,pointer l, pointer r) {
21359   pointer p; /* dependency list for right operand minus left operand */
21360   int t; /* the type of list |p| */
21361   pointer q; /* the constant term of |p| is here */
21362   pointer pp; /* dependency list for right operand */
21363   int tt; /* the type of list |pp| */
21364   boolean copied; /* have we copied a list that ought to be recycled? */
21365   @<Remove the left operand from its container, negate it, and
21366     put it into dependency list~|p| with constant term~|q|@>;
21367   @<Add the right operand to list |p|@>;
21368   if ( info(p)==null ) {
21369     @<Deal with redundant or inconsistent equation@>;
21370   } else { 
21371     mp_linear_eq(mp, p,t);
21372     if ( r==null ) if ( mp->cur_type!=mp_known ) {
21373       if ( type(mp->cur_exp)==mp_known ) {
21374         pp=mp->cur_exp; mp->cur_exp=value(mp->cur_exp); mp->cur_type=mp_known;
21375         mp_free_node(mp, pp,value_node_size);
21376       }
21377     }
21378   }
21379 }
21380
21381 @ @<Remove the left operand from its container, negate it, and...@>=
21382 t=type(l);
21383 if ( t==mp_known ) { 
21384   t=mp_dependent; p=mp_const_dependency(mp, -value(l)); q=p;
21385 } else if ( t==mp_independent ) {
21386   t=mp_dependent; p=mp_single_dependency(mp, l); negate(value(p));
21387   q=mp->dep_final;
21388 } else { 
21389   p=dep_list(l); q=p;
21390   while (1) { 
21391     negate(value(q));
21392     if ( info(q)==null ) break;
21393     q=link(q);
21394   }
21395   link(prev_dep(l))=link(q); prev_dep(link(q))=prev_dep(l);
21396   type(l)=mp_known;
21397 }
21398
21399 @ @<Deal with redundant or inconsistent equation@>=
21400
21401   if ( abs(value(p))>64 ) { /* off by .001 or more */
21402     print_err("Inconsistent equation");
21403 @.Inconsistent equation@>
21404     mp_print(mp, " (off by "); mp_print_scaled(mp, value(p)); 
21405     mp_print_char(mp, ')');
21406     help2("The equation I just read contradicts what was said before.")
21407       ("But don't worry; continue and I'll just ignore it.");
21408     mp_put_get_error(mp);
21409   } else if ( r==null ) {
21410     @<Exclaim about a redundant equation@>;
21411   }
21412   mp_free_node(mp, p,dep_node_size);
21413 }
21414
21415 @ @<Add the right operand to list |p|@>=
21416 if ( r==null ) {
21417   if ( mp->cur_type==mp_known ) {
21418     value(q)=value(q)+mp->cur_exp; goto DONE1;
21419   } else { 
21420     tt=mp->cur_type;
21421     if ( tt==mp_independent ) pp=mp_single_dependency(mp, mp->cur_exp);
21422     else pp=dep_list(mp->cur_exp);
21423   } 
21424 } else {
21425   if ( type(r)==mp_known ) {
21426     value(q)=value(q)+value(r); goto DONE1;
21427   } else { 
21428     tt=type(r);
21429     if ( tt==mp_independent ) pp=mp_single_dependency(mp, r);
21430     else pp=dep_list(r);
21431   }
21432 }
21433 if ( tt!=mp_independent ) copied=false;
21434 else  { copied=true; tt=mp_dependent; };
21435 @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>;
21436 if ( copied ) mp_flush_node_list(mp, pp);
21437 DONE1:
21438
21439 @ @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>=
21440 mp->watch_coefs=false;
21441 if ( t==tt ) {
21442   p=mp_p_plus_q(mp, p,pp,t);
21443 } else if ( t==mp_proto_dependent ) {
21444   p=mp_p_plus_fq(mp, p,unity,pp,mp_proto_dependent,mp_dependent);
21445 } else { 
21446   q=p;
21447   while ( info(q)!=null ) {
21448     value(q)=mp_round_fraction(mp, value(q)); q=link(q);
21449   }
21450   t=mp_proto_dependent; p=mp_p_plus_q(mp, p,pp,t);
21451 }
21452 mp->watch_coefs=true;
21453
21454 @ Our next goal is to process type declarations. For this purpose it's
21455 convenient to have a procedure that scans a $\langle\,$declared
21456 variable$\,\rangle$ and returns the corresponding token list. After the
21457 following procedure has acted, the token after the declared variable
21458 will have been scanned, so it will appear in |cur_cmd|, |cur_mod|,
21459 and~|cur_sym|.
21460
21461 @<Declare the function called |scan_declared_variable|@>=
21462 pointer mp_scan_declared_variable (MP mp) {
21463   pointer x; /* hash address of the variable's root */
21464   pointer h,t; /* head and tail of the token list to be returned */
21465   pointer l; /* hash address of left bracket */
21466   mp_get_symbol(mp); x=mp->cur_sym;
21467   if ( mp->cur_cmd!=tag_token ) mp_clear_symbol(mp, x,false);
21468   h=mp_get_avail(mp); info(h)=x; t=h;
21469   while (1) { 
21470     mp_get_x_next(mp);
21471     if ( mp->cur_sym==0 ) break;
21472     if ( mp->cur_cmd!=tag_token ) if ( mp->cur_cmd!=internal_quantity)  {
21473       if ( mp->cur_cmd==left_bracket ) {
21474         @<Descend past a collective subscript@>;
21475       } else {
21476         break;
21477       }
21478     }
21479     link(t)=mp_get_avail(mp); t=link(t); info(t)=mp->cur_sym;
21480   }
21481   if ( eq_type(x)!=tag_token ) mp_clear_symbol(mp, x,false);
21482   if ( equiv(x)==null ) mp_new_root(mp, x);
21483   return h;
21484 }
21485
21486 @ If the subscript isn't collective, we don't accept it as part of the
21487 declared variable.
21488
21489 @<Descend past a collective subscript@>=
21490
21491   l=mp->cur_sym; mp_get_x_next(mp);
21492   if ( mp->cur_cmd!=right_bracket ) {
21493     mp_back_input(mp); mp->cur_sym=l; mp->cur_cmd=left_bracket; break;
21494   } else {
21495     mp->cur_sym=collective_subscript;
21496   }
21497 }
21498
21499 @ Type declarations are introduced by the following primitive operations.
21500
21501 @<Put each...@>=
21502 mp_primitive(mp, "numeric",type_name,mp_numeric_type);
21503 @:numeric_}{\&{numeric} primitive@>
21504 mp_primitive(mp, "string",type_name,mp_string_type);
21505 @:string_}{\&{string} primitive@>
21506 mp_primitive(mp, "boolean",type_name,mp_boolean_type);
21507 @:boolean_}{\&{boolean} primitive@>
21508 mp_primitive(mp, "path",type_name,mp_path_type);
21509 @:path_}{\&{path} primitive@>
21510 mp_primitive(mp, "pen",type_name,mp_pen_type);
21511 @:pen_}{\&{pen} primitive@>
21512 mp_primitive(mp, "picture",type_name,mp_picture_type);
21513 @:picture_}{\&{picture} primitive@>
21514 mp_primitive(mp, "transform",type_name,mp_transform_type);
21515 @:transform_}{\&{transform} primitive@>
21516 mp_primitive(mp, "color",type_name,mp_color_type);
21517 @:color_}{\&{color} primitive@>
21518 mp_primitive(mp, "rgbcolor",type_name,mp_color_type);
21519 @:color_}{\&{rgbcolor} primitive@>
21520 mp_primitive(mp, "cmykcolor",type_name,mp_cmykcolor_type);
21521 @:color_}{\&{cmykcolor} primitive@>
21522 mp_primitive(mp, "pair",type_name,mp_pair_type);
21523 @:pair_}{\&{pair} primitive@>
21524
21525 @ @<Cases of |print_cmd...@>=
21526 case type_name: mp_print_type(mp, m); break;
21527
21528 @ Now we are ready to handle type declarations, assuming that a
21529 |type_name| has just been scanned.
21530
21531 @<Declare action procedures for use by |do_statement|@>=
21532 void mp_do_type_declaration (MP mp) ;
21533
21534 @ @c
21535 void mp_do_type_declaration (MP mp) {
21536   small_number t; /* the type being declared */
21537   pointer p; /* token list for a declared variable */
21538   pointer q; /* value node for the variable */
21539   if ( mp->cur_mod>=mp_transform_type ) 
21540     t=mp->cur_mod;
21541   else 
21542     t=mp->cur_mod+unknown_tag;
21543   do {  
21544     p=mp_scan_declared_variable(mp);
21545     mp_flush_variable(mp, equiv(info(p)),link(p),false);
21546     q=mp_find_variable(mp, p);
21547     if ( q!=null ) { 
21548       type(q)=t; value(q)=null; 
21549     } else  { 
21550       print_err("Declared variable conflicts with previous vardef");
21551 @.Declared variable conflicts...@>
21552       help2("You can't use, e.g., `numeric foo[]' after `vardef foo'.")
21553            ("Proceed, and I'll ignore the illegal redeclaration.");
21554       mp_put_get_error(mp);
21555     }
21556     mp_flush_list(mp, p);
21557     if ( mp->cur_cmd<comma ) {
21558       @<Flush spurious symbols after the declared variable@>;
21559     }
21560   } while (! end_of_statement);
21561 }
21562
21563 @ @<Flush spurious symbols after the declared variable@>=
21564
21565   print_err("Illegal suffix of declared variable will be flushed");
21566 @.Illegal suffix...flushed@>
21567   help5("Variables in declarations must consist entirely of")
21568     ("names and collective subscripts, e.g., `x[]a'.")
21569     ("Are you trying to use a reserved word in a variable name?")
21570     ("I'm going to discard the junk I found here,")
21571     ("up to the next comma or the end of the declaration.");
21572   if ( mp->cur_cmd==numeric_token )
21573     mp->help_line[2]="Explicit subscripts like `x15a' aren't permitted.";
21574   mp_put_get_error(mp); mp->scanner_status=flushing;
21575   do {  
21576     get_t_next;
21577     @<Decrease the string reference count...@>;
21578   } while (mp->cur_cmd<comma); /* either |end_of_statement| or |cur_cmd=comma| */
21579   mp->scanner_status=normal;
21580 }
21581
21582 @ \MP's |main_control| procedure just calls |do_statement| repeatedly
21583 until coming to the end of the user's program.
21584 Each execution of |do_statement| concludes with
21585 |cur_cmd=semicolon|, |end_group|, or |stop|.
21586
21587 @c void mp_main_control (MP mp) { 
21588   do {  
21589     mp_do_statement(mp);
21590     if ( mp->cur_cmd==end_group ) {
21591       print_err("Extra `endgroup'");
21592 @.Extra `endgroup'@>
21593       help2("I'm not currently working on a `begingroup',")
21594         ("so I had better not try to end anything.");
21595       mp_flush_error(mp, 0);
21596     }
21597   } while (mp->cur_cmd!=stop);
21598 }
21599 int mp_run (MP mp) {
21600   mp_main_control(mp); /* come to life */
21601   mp_final_cleanup(mp); /* prepare for death */
21602   mp_close_files_and_terminate(mp);
21603   return mp->history;
21604 }
21605 char * mp_mplib_version (MP mp) {
21606   assert(mp);
21607   return mplib_version;
21608 }
21609 char * mp_metapost_version (MP mp) {
21610   assert(mp);
21611   return metapost_version;
21612 }
21613
21614 @ @<Exported function headers@>=
21615 int mp_run (MP mp);
21616 char * mp_mplib_version (MP mp);
21617 char * mp_metapost_version (MP mp);
21618
21619 @ @<Put each...@>=
21620 mp_primitive(mp, "end",stop,0);
21621 @:end_}{\&{end} primitive@>
21622 mp_primitive(mp, "dump",stop,1);
21623 @:dump_}{\&{dump} primitive@>
21624
21625 @ @<Cases of |print_cmd...@>=
21626 case stop:
21627   if ( m==0 ) mp_print(mp, "end");
21628   else mp_print(mp, "dump");
21629   break;
21630
21631 @* \[41] Commands.
21632 Let's turn now to statements that are classified as ``commands'' because
21633 of their imperative nature. We'll begin with simple ones, so that it
21634 will be clear how to hook command processing into the |do_statement| routine;
21635 then we'll tackle the tougher commands.
21636
21637 Here's one of the simplest:
21638
21639 @<Cases of |do_statement|...@>=
21640 case random_seed: mp_do_random_seed(mp);  break;
21641
21642 @ @<Declare action procedures for use by |do_statement|@>=
21643 void mp_do_random_seed (MP mp) ;
21644
21645 @ @c void mp_do_random_seed (MP mp) { 
21646   mp_get_x_next(mp);
21647   if ( mp->cur_cmd!=assignment ) {
21648     mp_missing_err(mp, ":=");
21649 @.Missing `:='@>
21650     help1("Always say `randomseed:=<numeric expression>'.");
21651     mp_back_error(mp);
21652   };
21653   mp_get_x_next(mp); mp_scan_expression(mp);
21654   if ( mp->cur_type!=mp_known ) {
21655     exp_err("Unknown value will be ignored");
21656 @.Unknown value...ignored@>
21657     help2("Your expression was too random for me to handle,")
21658       ("so I won't change the random seed just now.");
21659     mp_put_get_flush_error(mp, 0);
21660   } else {
21661    @<Initialize the random seed to |cur_exp|@>;
21662   }
21663 }
21664
21665 @ @<Initialize the random seed to |cur_exp|@>=
21666
21667   mp_init_randoms(mp, mp->cur_exp);
21668   if ( mp->selector>=log_only && mp->selector<write_file) {
21669     mp->old_setting=mp->selector; mp->selector=log_only;
21670     mp_print_nl(mp, "{randomseed:="); 
21671     mp_print_scaled(mp, mp->cur_exp); 
21672     mp_print_char(mp, '}');
21673     mp_print_nl(mp, ""); mp->selector=mp->old_setting;
21674   }
21675 }
21676
21677 @ And here's another simple one (somewhat different in flavor):
21678
21679 @<Cases of |do_statement|...@>=
21680 case mode_command: 
21681   mp_print_ln(mp); mp->interaction=mp->cur_mod;
21682   @<Initialize the print |selector| based on |interaction|@>;
21683   if ( mp->log_opened ) mp->selector=mp->selector+2;
21684   mp_get_x_next(mp);
21685   break;
21686
21687 @ @<Put each...@>=
21688 mp_primitive(mp, "batchmode",mode_command,mp_batch_mode);
21689 @:mp_batch_mode_}{\&{batchmode} primitive@>
21690 mp_primitive(mp, "nonstopmode",mode_command,mp_nonstop_mode);
21691 @:mp_nonstop_mode_}{\&{nonstopmode} primitive@>
21692 mp_primitive(mp, "scrollmode",mode_command,mp_scroll_mode);
21693 @:mp_scroll_mode_}{\&{scrollmode} primitive@>
21694 mp_primitive(mp, "errorstopmode",mode_command,mp_error_stop_mode);
21695 @:mp_error_stop_mode_}{\&{errorstopmode} primitive@>
21696
21697 @ @<Cases of |print_cmd_mod|...@>=
21698 case mode_command: 
21699   switch (m) {
21700   case mp_batch_mode: mp_print(mp, "batchmode"); break;
21701   case mp_nonstop_mode: mp_print(mp, "nonstopmode"); break;
21702   case mp_scroll_mode: mp_print(mp, "scrollmode"); break;
21703   default: mp_print(mp, "errorstopmode"); break;
21704   }
21705   break;
21706
21707 @ The `\&{inner}' and `\&{outer}' commands are only slightly harder.
21708
21709 @<Cases of |do_statement|...@>=
21710 case protection_command: mp_do_protection(mp); break;
21711
21712 @ @<Put each...@>=
21713 mp_primitive(mp, "inner",protection_command,0);
21714 @:inner_}{\&{inner} primitive@>
21715 mp_primitive(mp, "outer",protection_command,1);
21716 @:outer_}{\&{outer} primitive@>
21717
21718 @ @<Cases of |print_cmd...@>=
21719 case protection_command: 
21720   if ( m==0 ) mp_print(mp, "inner");
21721   else mp_print(mp, "outer");
21722   break;
21723
21724 @ @<Declare action procedures for use by |do_statement|@>=
21725 void mp_do_protection (MP mp) ;
21726
21727 @ @c void mp_do_protection (MP mp) {
21728   int m; /* 0 to unprotect, 1 to protect */
21729   halfword t; /* the |eq_type| before we change it */
21730   m=mp->cur_mod;
21731   do {  
21732     mp_get_symbol(mp); t=eq_type(mp->cur_sym);
21733     if ( m==0 ) { 
21734       if ( t>=outer_tag ) 
21735         eq_type(mp->cur_sym)=t-outer_tag;
21736     } else if ( t<outer_tag ) {
21737       eq_type(mp->cur_sym)=t+outer_tag;
21738     }
21739     mp_get_x_next(mp);
21740   } while (mp->cur_cmd==comma);
21741 }
21742
21743 @ \MP\ never defines the tokens `\.(' and `\.)' to be primitives, but
21744 plain \MP\ begins with the declaration `\&{delimiters} \.{()}'. Such a
21745 declaration assigns the command code |left_delimiter| to `\.{(}' and
21746 |right_delimiter| to `\.{)}'; the |equiv| of each delimiter is the
21747 hash address of its mate.
21748
21749 @<Cases of |do_statement|...@>=
21750 case delimiters: mp_def_delims(mp); break;
21751
21752 @ @<Declare action procedures for use by |do_statement|@>=
21753 void mp_def_delims (MP mp) ;
21754
21755 @ @c void mp_def_delims (MP mp) {
21756   pointer l_delim,r_delim; /* the new delimiter pair */
21757   mp_get_clear_symbol(mp); l_delim=mp->cur_sym;
21758   mp_get_clear_symbol(mp); r_delim=mp->cur_sym;
21759   eq_type(l_delim)=left_delimiter; equiv(l_delim)=r_delim;
21760   eq_type(r_delim)=right_delimiter; equiv(r_delim)=l_delim;
21761   mp_get_x_next(mp);
21762 }
21763
21764 @ Here is a procedure that is called when \MP\ has reached a point
21765 where some right delimiter is mandatory.
21766
21767 @<Declare the procedure called |check_delimiter|@>=
21768 void mp_check_delimiter (MP mp,pointer l_delim, pointer r_delim) {
21769   if ( mp->cur_cmd==right_delimiter ) 
21770     if ( mp->cur_mod==l_delim ) 
21771       return;
21772   if ( mp->cur_sym!=r_delim ) {
21773      mp_missing_err(mp, str(text(r_delim)));
21774 @.Missing `)'@>
21775     help2("I found no right delimiter to match a left one. So I've")
21776       ("put one in, behind the scenes; this may fix the problem.");
21777     mp_back_error(mp);
21778   } else { 
21779     print_err("The token `"); mp_print_text(r_delim);
21780 @.The token...delimiter@>
21781     mp_print(mp, "' is no longer a right delimiter");
21782     help3("Strange: This token has lost its former meaning!")
21783       ("I'll read it as a right delimiter this time;")
21784       ("but watch out, I'll probably miss it later.");
21785     mp_error(mp);
21786   }
21787 }
21788
21789 @ The next four commands save or change the values associated with tokens.
21790
21791 @<Cases of |do_statement|...@>=
21792 case save_command: 
21793   do {  
21794     mp_get_symbol(mp); mp_save_variable(mp, mp->cur_sym); mp_get_x_next(mp);
21795   } while (mp->cur_cmd==comma);
21796   break;
21797 case interim_command: mp_do_interim(mp); break;
21798 case let_command: mp_do_let(mp); break;
21799 case new_internal: mp_do_new_internal(mp); break;
21800
21801 @ @<Declare action procedures for use by |do_statement|@>=
21802 void mp_do_statement (MP mp);
21803 void mp_do_interim (MP mp);
21804
21805 @ @c void mp_do_interim (MP mp) { 
21806   mp_get_x_next(mp);
21807   if ( mp->cur_cmd!=internal_quantity ) {
21808      print_err("The token `");
21809 @.The token...quantity@>
21810     if ( mp->cur_sym==0 ) mp_print(mp, "(%CAPSULE)");
21811     else mp_print_text(mp->cur_sym);
21812     mp_print(mp, "' isn't an internal quantity");
21813     help1("Something like `tracingonline' should follow `interim'.");
21814     mp_back_error(mp);
21815   } else { 
21816     mp_save_internal(mp, mp->cur_mod); mp_back_input(mp);
21817   }
21818   mp_do_statement(mp);
21819 }
21820
21821 @ The following procedure is careful not to undefine the left-hand symbol
21822 too soon, lest commands like `{\tt let x=x}' have a surprising effect.
21823
21824 @<Declare action procedures for use by |do_statement|@>=
21825 void mp_do_let (MP mp) ;
21826
21827 @ @c void mp_do_let (MP mp) {
21828   pointer l; /* hash location of the left-hand symbol */
21829   mp_get_symbol(mp); l=mp->cur_sym; mp_get_x_next(mp);
21830   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
21831      mp_missing_err(mp, "=");
21832 @.Missing `='@>
21833     help3("You should have said `let symbol = something'.")
21834       ("But don't worry; I'll pretend that an equals sign")
21835       ("was present. The next token I read will be `something'.");
21836     mp_back_error(mp);
21837   }
21838   mp_get_symbol(mp);
21839   switch (mp->cur_cmd) {
21840   case defined_macro: case secondary_primary_macro:
21841   case tertiary_secondary_macro: case expression_tertiary_macro: 
21842     add_mac_ref(mp->cur_mod);
21843     break;
21844   default: 
21845     break;
21846   }
21847   mp_clear_symbol(mp, l,false); eq_type(l)=mp->cur_cmd;
21848   if ( mp->cur_cmd==tag_token ) equiv(l)=null;
21849   else equiv(l)=mp->cur_mod;
21850   mp_get_x_next(mp);
21851 }
21852
21853 @ @<Declarations@>=
21854 void mp_grow_internals (MP mp, int l);
21855 void mp_do_new_internal (MP mp) ;
21856
21857 @ @c
21858 void mp_grow_internals (MP mp, int l) {
21859   scaled *internal;
21860   char * *int_name; 
21861   int k;
21862   if ( hash_end+l>max_halfword ) {
21863     mp_confusion(mp, "out of memory space"); /* can't be reached */
21864   }
21865   int_name = xmalloc ((l+1),sizeof(char *));
21866   internal = xmalloc ((l+1),sizeof(scaled));
21867   for (k=0;k<=l; k++ ) { 
21868     if (k<=mp->max_internal) {
21869       internal[k]=mp->internal[k]; 
21870       int_name[k]=mp->int_name[k]; 
21871     } else {
21872       internal[k]=0; 
21873       int_name[k]=NULL; 
21874     }
21875   }
21876   xfree(mp->internal); xfree(mp->int_name);
21877   mp->int_name = int_name;
21878   mp->internal = internal;
21879   mp->max_internal = l;
21880 }
21881
21882
21883 void mp_do_new_internal (MP mp) { 
21884   do {  
21885     if ( mp->int_ptr==mp->max_internal ) {
21886       mp_grow_internals(mp, (mp->max_internal + (mp->max_internal>>2)));
21887     }
21888     mp_get_clear_symbol(mp); incr(mp->int_ptr);
21889     eq_type(mp->cur_sym)=internal_quantity; 
21890     equiv(mp->cur_sym)=mp->int_ptr;
21891     if(mp->int_name[mp->int_ptr]!=NULL)
21892       xfree(mp->int_name[mp->int_ptr]);
21893     mp->int_name[mp->int_ptr]=str(text(mp->cur_sym)); 
21894     mp->internal[mp->int_ptr]=0;
21895     mp_get_x_next(mp);
21896   } while (mp->cur_cmd==comma);
21897 }
21898
21899 @ @<Dealloc variables@>=
21900 for (k=0;k<=mp->max_internal;k++) {
21901    xfree(mp->int_name[k]);
21902 }
21903 xfree(mp->internal); 
21904 xfree(mp->int_name); 
21905
21906
21907 @ The various `\&{show}' commands are distinguished by modifier fields
21908 in the usual way.
21909
21910 @d show_token_code 0 /* show the meaning of a single token */
21911 @d show_stats_code 1 /* show current memory and string usage */
21912 @d show_code 2 /* show a list of expressions */
21913 @d show_var_code 3 /* show a variable and its descendents */
21914 @d show_dependencies_code 4 /* show dependent variables in terms of independents */
21915
21916 @<Put each...@>=
21917 mp_primitive(mp, "showtoken",show_command,show_token_code);
21918 @:show_token_}{\&{showtoken} primitive@>
21919 mp_primitive(mp, "showstats",show_command,show_stats_code);
21920 @:show_stats_}{\&{showstats} primitive@>
21921 mp_primitive(mp, "show",show_command,show_code);
21922 @:show_}{\&{show} primitive@>
21923 mp_primitive(mp, "showvariable",show_command,show_var_code);
21924 @:show_var_}{\&{showvariable} primitive@>
21925 mp_primitive(mp, "showdependencies",show_command,show_dependencies_code);
21926 @:show_dependencies_}{\&{showdependencies} primitive@>
21927
21928 @ @<Cases of |print_cmd...@>=
21929 case show_command: 
21930   switch (m) {
21931   case show_token_code:mp_print(mp, "showtoken"); break;
21932   case show_stats_code:mp_print(mp, "showstats"); break;
21933   case show_code:mp_print(mp, "show"); break;
21934   case show_var_code:mp_print(mp, "showvariable"); break;
21935   default: mp_print(mp, "showdependencies"); break;
21936   }
21937   break;
21938
21939 @ @<Cases of |do_statement|...@>=
21940 case show_command:mp_do_show_whatever(mp); break;
21941
21942 @ The value of |cur_mod| controls the |verbosity| in the |print_exp| routine:
21943 if it's |show_code|, complicated structures are abbreviated, otherwise
21944 they aren't.
21945
21946 @<Declare action procedures for use by |do_statement|@>=
21947 void mp_do_show (MP mp) ;
21948
21949 @ @c void mp_do_show (MP mp) { 
21950   do {  
21951     mp_get_x_next(mp); mp_scan_expression(mp);
21952     mp_print_nl(mp, ">> ");
21953 @.>>@>
21954     mp_print_exp(mp, null,2); mp_flush_cur_exp(mp, 0);
21955   } while (mp->cur_cmd==comma);
21956 }
21957
21958 @ @<Declare action procedures for use by |do_statement|@>=
21959 void mp_disp_token (MP mp) ;
21960
21961 @ @c void mp_disp_token (MP mp) { 
21962   mp_print_nl(mp, "> ");
21963 @.>\relax@>
21964   if ( mp->cur_sym==0 ) {
21965     @<Show a numeric or string or capsule token@>;
21966   } else { 
21967     mp_print_text(mp->cur_sym); mp_print_char(mp, '=');
21968     if ( eq_type(mp->cur_sym)>=outer_tag ) mp_print(mp, "(outer) ");
21969     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod);
21970     if ( mp->cur_cmd==defined_macro ) {
21971       mp_print_ln(mp); mp_show_macro(mp, mp->cur_mod,null,100000);
21972     } /* this avoids recursion between |show_macro| and |print_cmd_mod| */
21973 @^recursion@>
21974   }
21975 }
21976
21977 @ @<Show a numeric or string or capsule token@>=
21978
21979   if ( mp->cur_cmd==numeric_token ) {
21980     mp_print_scaled(mp, mp->cur_mod);
21981   } else if ( mp->cur_cmd==capsule_token ) {
21982     mp->g_pointer=mp->cur_mod; mp_print_capsule(mp);
21983   } else  { 
21984     mp_print_char(mp, '"'); 
21985     mp_print_str(mp, mp->cur_mod); mp_print_char(mp, '"');
21986     delete_str_ref(mp->cur_mod);
21987   }
21988 }
21989
21990 @ The following cases of |print_cmd_mod| might arise in connection
21991 with |disp_token|, although they don't correspond to any
21992 primitive tokens.
21993
21994 @<Cases of |print_cmd_...@>=
21995 case left_delimiter:
21996 case right_delimiter: 
21997   if ( c==left_delimiter ) mp_print(mp, "left");
21998   else mp_print(mp, "right");
21999   mp_print(mp, " delimiter that matches "); 
22000   mp_print_text(m);
22001   break;
22002 case tag_token:
22003   if ( m==null ) mp_print(mp, "tag");
22004    else mp_print(mp, "variable");
22005    break;
22006 case defined_macro: 
22007    mp_print(mp, "macro:");
22008    break;
22009 case secondary_primary_macro:
22010 case tertiary_secondary_macro:
22011 case expression_tertiary_macro:
22012   mp_print_cmd_mod(mp, macro_def,c); 
22013   mp_print(mp, "'d macro:");
22014   mp_print_ln(mp); mp_show_token_list(mp, link(link(m)),null,1000,0);
22015   break;
22016 case repeat_loop:
22017   mp_print(mp, "[repeat the loop]");
22018   break;
22019 case internal_quantity:
22020   mp_print(mp, mp->int_name[m]);
22021   break;
22022
22023 @ @<Declare action procedures for use by |do_statement|@>=
22024 void mp_do_show_token (MP mp) ;
22025
22026 @ @c void mp_do_show_token (MP mp) { 
22027   do {  
22028     get_t_next; mp_disp_token(mp);
22029     mp_get_x_next(mp);
22030   } while (mp->cur_cmd==comma);
22031 }
22032
22033 @ @<Declare action procedures for use by |do_statement|@>=
22034 void mp_do_show_stats (MP mp) ;
22035
22036 @ @c void mp_do_show_stats (MP mp) { 
22037   mp_print_nl(mp, "Memory usage ");
22038 @.Memory usage...@>
22039   mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used);
22040   if ( false )
22041     mp_print(mp, "unknown");
22042   mp_print(mp, " ("); mp_print_int(mp, mp->hi_mem_min-mp->lo_mem_max-1);
22043   mp_print(mp, " still untouched)"); mp_print_ln(mp);
22044   mp_print_nl(mp, "String usage ");
22045   mp_print_int(mp, mp->strs_in_use-mp->init_str_use);
22046   mp_print_char(mp, '&'); mp_print_int(mp, mp->pool_in_use-mp->init_pool_ptr);
22047   if ( false )
22048     mp_print(mp, "unknown");
22049   mp_print(mp, " (");
22050   mp_print_int(mp, mp->max_strings-1-mp->strs_used_up); mp_print_char(mp, '&');
22051   mp_print_int(mp, mp->pool_size-mp->pool_ptr); 
22052   mp_print(mp, " now untouched)"); mp_print_ln(mp);
22053   mp_get_x_next(mp);
22054 }
22055
22056 @ Here's a recursive procedure that gives an abbreviated account
22057 of a variable, for use by |do_show_var|.
22058
22059 @<Declare action procedures for use by |do_statement|@>=
22060 void mp_disp_var (MP mp,pointer p) ;
22061
22062 @ @c void mp_disp_var (MP mp,pointer p) {
22063   pointer q; /* traverses attributes and subscripts */
22064   int n; /* amount of macro text to show */
22065   if ( type(p)==mp_structured )  {
22066     @<Descend the structure@>;
22067   } else if ( type(p)>=mp_unsuffixed_macro ) {
22068     @<Display a variable macro@>;
22069   } else if ( type(p)!=undefined ){ 
22070     mp_print_nl(mp, ""); mp_print_variable_name(mp, p); 
22071     mp_print_char(mp, '=');
22072     mp_print_exp(mp, p,0);
22073   }
22074 }
22075
22076 @ @<Descend the structure@>=
22077
22078   q=attr_head(p);
22079   do {  mp_disp_var(mp, q); q=link(q); } while (q!=end_attr);
22080   q=subscr_head(p);
22081   while ( name_type(q)==mp_subscr ) { 
22082     mp_disp_var(mp, q); q=link(q);
22083   }
22084 }
22085
22086 @ @<Display a variable macro@>=
22087
22088   mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22089   if ( type(p)>mp_unsuffixed_macro ) 
22090     mp_print(mp, "@@#"); /* |suffixed_macro| */
22091   mp_print(mp, "=macro:");
22092   if ( (int)mp->file_offset>=mp->max_print_line-20 ) n=5;
22093   else n=mp->max_print_line-mp->file_offset-15;
22094   mp_show_macro(mp, value(p),null,n);
22095 }
22096
22097 @ @<Declare action procedures for use by |do_statement|@>=
22098 void mp_do_show_var (MP mp) ;
22099
22100 @ @c void mp_do_show_var (MP mp) { 
22101   do {  
22102     get_t_next;
22103     if ( mp->cur_sym>0 ) if ( mp->cur_sym<=hash_end )
22104       if ( mp->cur_cmd==tag_token ) if ( mp->cur_mod!=null ) {
22105       mp_disp_var(mp, mp->cur_mod); goto DONE;
22106     }
22107    mp_disp_token(mp);
22108   DONE:
22109    mp_get_x_next(mp);
22110   } while (mp->cur_cmd==comma);
22111 }
22112
22113 @ @<Declare action procedures for use by |do_statement|@>=
22114 void mp_do_show_dependencies (MP mp) ;
22115
22116 @ @c void mp_do_show_dependencies (MP mp) {
22117   pointer p; /* link that runs through all dependencies */
22118   p=link(dep_head);
22119   while ( p!=dep_head ) {
22120     if ( mp_interesting(mp, p) ) {
22121       mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22122       if ( type(p)==mp_dependent ) mp_print_char(mp, '=');
22123       else mp_print(mp, " = "); /* extra spaces imply proto-dependency */
22124       mp_print_dependency(mp, dep_list(p),type(p));
22125     }
22126     p=dep_list(p);
22127     while ( info(p)!=null ) p=link(p);
22128     p=link(p);
22129   }
22130   mp_get_x_next(mp);
22131 }
22132
22133 @ Finally we are ready for the procedure that governs all of the
22134 show commands.
22135
22136 @<Declare action procedures for use by |do_statement|@>=
22137 void mp_do_show_whatever (MP mp) ;
22138
22139 @ @c void mp_do_show_whatever (MP mp) { 
22140   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
22141   switch (mp->cur_mod) {
22142   case show_token_code:mp_do_show_token(mp); break;
22143   case show_stats_code:mp_do_show_stats(mp); break;
22144   case show_code:mp_do_show(mp); break;
22145   case show_var_code:mp_do_show_var(mp); break;
22146   case show_dependencies_code:mp_do_show_dependencies(mp); break;
22147   } /* there are no other cases */
22148   if ( mp->internal[showstopping]>0 ){ 
22149     print_err("OK");
22150 @.OK@>
22151     if ( mp->interaction<mp_error_stop_mode ) { 
22152       help0; decr(mp->error_count);
22153     } else {
22154       help1("This isn't an error message; I'm just showing something.");
22155     }
22156     if ( mp->cur_cmd==semicolon ) mp_error(mp);
22157      else mp_put_get_error(mp);
22158   }
22159 }
22160
22161 @ The `\&{addto}' command needs the following additional primitives:
22162
22163 @d double_path_code 0 /* command modifier for `\&{doublepath}' */
22164 @d contour_code 1 /* command modifier for `\&{contour}' */
22165 @d also_code 2 /* command modifier for `\&{also}' */
22166
22167 @ Pre and postscripts need two new identifiers:
22168
22169 @d with_pre_script 11
22170 @d with_post_script 13
22171
22172 @<Put each...@>=
22173 mp_primitive(mp, "doublepath",thing_to_add,double_path_code);
22174 @:double_path_}{\&{doublepath} primitive@>
22175 mp_primitive(mp, "contour",thing_to_add,contour_code);
22176 @:contour_}{\&{contour} primitive@>
22177 mp_primitive(mp, "also",thing_to_add,also_code);
22178 @:also_}{\&{also} primitive@>
22179 mp_primitive(mp, "withpen",with_option,mp_pen_type);
22180 @:with_pen_}{\&{withpen} primitive@>
22181 mp_primitive(mp, "dashed",with_option,mp_picture_type);
22182 @:dashed_}{\&{dashed} primitive@>
22183 mp_primitive(mp, "withprescript",with_option,with_pre_script);
22184 @:with_pre_script_}{\&{withprescript} primitive@>
22185 mp_primitive(mp, "withpostscript",with_option,with_post_script);
22186 @:with_post_script_}{\&{withpostscript} primitive@>
22187 mp_primitive(mp, "withoutcolor",with_option,no_model);
22188 @:with_color_}{\&{withoutcolor} primitive@>
22189 mp_primitive(mp, "withgreyscale",with_option,grey_model);
22190 @:with_color_}{\&{withgreyscale} primitive@>
22191 mp_primitive(mp, "withcolor",with_option,uninitialized_model);
22192 @:with_color_}{\&{withcolor} primitive@>
22193 /*  \&{withrgbcolor} is an alias for \&{withcolor} */
22194 mp_primitive(mp, "withrgbcolor",with_option,rgb_model);
22195 @:with_color_}{\&{withrgbcolor} primitive@>
22196 mp_primitive(mp, "withcmykcolor",with_option,cmyk_model);
22197 @:with_color_}{\&{withcmykcolor} primitive@>
22198
22199 @ @<Cases of |print_cmd...@>=
22200 case thing_to_add:
22201   if ( m==contour_code ) mp_print(mp, "contour");
22202   else if ( m==double_path_code ) mp_print(mp, "doublepath");
22203   else mp_print(mp, "also");
22204   break;
22205 case with_option:
22206   if ( m==mp_pen_type ) mp_print(mp, "withpen");
22207   else if ( m==with_pre_script ) mp_print(mp, "withprescript");
22208   else if ( m==with_post_script ) mp_print(mp, "withpostscript");
22209   else if ( m==no_model ) mp_print(mp, "withoutcolor");
22210   else if ( m==rgb_model ) mp_print(mp, "withrgbcolor");
22211   else if ( m==uninitialized_model ) mp_print(mp, "withcolor");
22212   else if ( m==cmyk_model ) mp_print(mp, "withcmykcolor");
22213   else if ( m==grey_model ) mp_print(mp, "withgreyscale");
22214   else mp_print(mp, "dashed");
22215   break;
22216
22217 @ The |scan_with_list| procedure parses a $\langle$with list$\rangle$ and
22218 updates the list of graphical objects starting at |p|.  Each $\langle$with
22219 clause$\rangle$ updates all graphical objects whose |type| is compatible.
22220 Other objects are ignored.
22221
22222 @<Declare action procedures for use by |do_statement|@>=
22223 void mp_scan_with_list (MP mp,pointer p) ;
22224
22225 @ @c void mp_scan_with_list (MP mp,pointer p) {
22226   small_number t; /* |cur_mod| of the |with_option| (should match |cur_type|) */
22227   pointer q; /* for list manipulation */
22228   int old_setting; /* saved |selector| setting */
22229   pointer k; /* for finding the near-last item in a list  */
22230   str_number s; /* for string cleanup after combining  */
22231   pointer cp,pp,dp,ap,bp;
22232     /* objects being updated; |void| initially; |null| to suppress update */
22233   cp=diov; pp=diov; dp=diov; ap=diov; bp=diov;
22234   k=0;
22235   while ( mp->cur_cmd==with_option ){ 
22236     t=mp->cur_mod;
22237     mp_get_x_next(mp);
22238     if ( t!=no_model ) mp_scan_expression(mp);
22239     if (((t==with_pre_script)&&(mp->cur_type!=mp_string_type))||
22240      ((t==with_post_script)&&(mp->cur_type!=mp_string_type))||
22241      ((t==uninitialized_model)&&
22242         ((mp->cur_type!=mp_cmykcolor_type)&&(mp->cur_type!=mp_color_type)
22243           &&(mp->cur_type!=mp_known)&&(mp->cur_type!=mp_boolean_type)))||
22244      ((t==cmyk_model)&&(mp->cur_type!=mp_cmykcolor_type))||
22245      ((t==rgb_model)&&(mp->cur_type!=mp_color_type))||
22246      ((t==grey_model)&&(mp->cur_type!=mp_known))||
22247      ((t==mp_pen_type)&&(mp->cur_type!=t))||
22248      ((t==mp_picture_type)&&(mp->cur_type!=t)) ) {
22249       @<Complain about improper type@>;
22250     } else if ( t==uninitialized_model ) {
22251       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22252       if ( cp!=null )
22253         @<Transfer a color from the current expression to object~|cp|@>;
22254       mp_flush_cur_exp(mp, 0);
22255     } else if ( t==rgb_model ) {
22256       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22257       if ( cp!=null )
22258         @<Transfer a rgbcolor from the current expression to object~|cp|@>;
22259       mp_flush_cur_exp(mp, 0);
22260     } else if ( t==cmyk_model ) {
22261       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22262       if ( cp!=null )
22263         @<Transfer a cmykcolor from the current expression to object~|cp|@>;
22264       mp_flush_cur_exp(mp, 0);
22265     } else if ( t==grey_model ) {
22266       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22267       if ( cp!=null )
22268         @<Transfer a greyscale from the current expression to object~|cp|@>;
22269       mp_flush_cur_exp(mp, 0);
22270     } else if ( t==no_model ) {
22271       if ( cp==diov ) @<Make |cp| a colored object in object list~|p|@>;
22272       if ( cp!=null )
22273         @<Transfer a noncolor from the current expression to object~|cp|@>;
22274     } else if ( t==mp_pen_type ) {
22275       if ( pp==diov ) @<Make |pp| an object in list~|p| that needs a pen@>;
22276       if ( pp!=null ) {
22277         if ( pen_p(pp)!=null ) mp_toss_knot_list(mp, pen_p(pp));
22278         pen_p(pp)=mp->cur_exp; mp->cur_type=mp_vacuous;
22279       }
22280     } else if ( t==with_pre_script ) {
22281       if ( ap==diov )
22282         ap=p;
22283       while ( (ap!=null)&&(! has_color(ap)) )
22284          ap=link(ap);
22285       if ( ap!=null ) {
22286         if ( pre_script(ap)!=null ) { /*  build a new,combined string  */
22287           s=pre_script(ap);
22288           old_setting=mp->selector;
22289               mp->selector=new_string;
22290           str_room(length(pre_script(ap))+length(mp->cur_exp)+2);
22291               mp_print_str(mp, mp->cur_exp);
22292           append_char(13);  /* a forced \ps\ newline  */
22293           mp_print_str(mp, pre_script(ap));
22294           pre_script(ap)=mp_make_string(mp);
22295           delete_str_ref(s);
22296           mp->selector=old_setting;
22297         } else {
22298           pre_script(ap)=mp->cur_exp;
22299         }
22300         mp->cur_type=mp_vacuous;
22301       }
22302     } else if ( t==with_post_script ) {
22303       if ( bp==diov )
22304         k=p; 
22305       bp=k;
22306       while ( link(k)!=null ) {
22307         k=link(k);
22308         if ( has_color(k) ) bp=k;
22309       }
22310       if ( bp!=null ) {
22311          if ( post_script(bp)!=null ) {
22312            s=post_script(bp);
22313            old_setting=mp->selector;
22314                mp->selector=new_string;
22315            str_room(length(post_script(bp))+length(mp->cur_exp)+2);
22316            mp_print_str(mp, post_script(bp));
22317            append_char(13); /* a forced \ps\ newline  */
22318            mp_print_str(mp, mp->cur_exp);
22319            post_script(bp)=mp_make_string(mp);
22320            delete_str_ref(s);
22321            mp->selector=old_setting;
22322          } else {
22323            post_script(bp)=mp->cur_exp;
22324          }
22325          mp->cur_type=mp_vacuous;
22326        }
22327     } else { 
22328       if ( dp==diov ) 
22329         @<Make |dp| a stroked node in list~|p|@>;
22330       if ( dp!=null ) {
22331         if ( dash_p(dp)!=null ) delete_edge_ref(dash_p(dp));
22332         dash_p(dp)=mp_make_dashes(mp, mp->cur_exp);
22333         dash_scale(dp)=unity;
22334         mp->cur_type=mp_vacuous;
22335       }
22336     }
22337   }
22338   @<Copy the information from objects |cp|, |pp|, and |dp| into the rest
22339     of the list@>;
22340 };
22341
22342 @ @<Complain about improper type@>=
22343 { exp_err("Improper type");
22344 @.Improper type@>
22345 help2("Next time say `withpen <known pen expression>';")
22346   ("I'll ignore the bad `with' clause and look for another.");
22347 if ( t==with_pre_script )
22348   mp->help_line[1]="Next time say `withprescript <known string expression>';";
22349 else if ( t==with_post_script )
22350   mp->help_line[1]="Next time say `withpostscript <known string expression>';";
22351 else if ( t==mp_picture_type )
22352   mp->help_line[1]="Next time say `dashed <known picture expression>';";
22353 else if ( t==uninitialized_model )
22354   mp->help_line[1]="Next time say `withcolor <known color expression>';";
22355 else if ( t==rgb_model )
22356   mp->help_line[1]="Next time say `withrgbcolor <known color expression>';";
22357 else if ( t==cmyk_model )
22358   mp->help_line[1]="Next time say `withcmykcolor <known cmykcolor expression>';";
22359 else if ( t==grey_model )
22360   mp->help_line[1]="Next time say `withgreyscale <known numeric expression>';";;
22361 mp_put_get_flush_error(mp, 0);
22362 }
22363
22364 @ Forcing the color to be between |0| and |unity| here guarantees that no
22365 picture will ever contain a color outside the legal range for \ps\ graphics.
22366
22367 @<Transfer a color from the current expression to object~|cp|@>=
22368 { if ( mp->cur_type==mp_color_type )
22369    @<Transfer a rgbcolor from the current expression to object~|cp|@>
22370 else if ( mp->cur_type==mp_cmykcolor_type )
22371    @<Transfer a cmykcolor from the current expression to object~|cp|@>
22372 else if ( mp->cur_type==mp_known )
22373    @<Transfer a greyscale from the current expression to object~|cp|@>
22374 else if ( mp->cur_exp==false_code )
22375    @<Transfer a noncolor from the current expression to object~|cp|@>;
22376 }
22377
22378 @ @<Transfer a rgbcolor from the current expression to object~|cp|@>=
22379 { q=value(mp->cur_exp);
22380 cyan_val(cp)=0;
22381 magenta_val(cp)=0;
22382 yellow_val(cp)=0;
22383 black_val(cp)=0;
22384 red_val(cp)=value(red_part_loc(q));
22385 green_val(cp)=value(green_part_loc(q));
22386 blue_val(cp)=value(blue_part_loc(q));
22387 color_model(cp)=rgb_model;
22388 if ( red_val(cp)<0 ) red_val(cp)=0;
22389 if ( green_val(cp)<0 ) green_val(cp)=0;
22390 if ( blue_val(cp)<0 ) blue_val(cp)=0;
22391 if ( red_val(cp)>unity ) red_val(cp)=unity;
22392 if ( green_val(cp)>unity ) green_val(cp)=unity;
22393 if ( blue_val(cp)>unity ) blue_val(cp)=unity;
22394 }
22395
22396 @ @<Transfer a cmykcolor from the current expression to object~|cp|@>=
22397 { q=value(mp->cur_exp);
22398 cyan_val(cp)=value(cyan_part_loc(q));
22399 magenta_val(cp)=value(magenta_part_loc(q));
22400 yellow_val(cp)=value(yellow_part_loc(q));
22401 black_val(cp)=value(black_part_loc(q));
22402 color_model(cp)=cmyk_model;
22403 if ( cyan_val(cp)<0 ) cyan_val(cp)=0;
22404 if ( magenta_val(cp)<0 ) magenta_val(cp)=0;
22405 if ( yellow_val(cp)<0 ) yellow_val(cp)=0;
22406 if ( black_val(cp)<0 ) black_val(cp)=0;
22407 if ( cyan_val(cp)>unity ) cyan_val(cp)=unity;
22408 if ( magenta_val(cp)>unity ) magenta_val(cp)=unity;
22409 if ( yellow_val(cp)>unity ) yellow_val(cp)=unity;
22410 if ( black_val(cp)>unity ) black_val(cp)=unity;
22411 }
22412
22413 @ @<Transfer a greyscale from the current expression to object~|cp|@>=
22414 { q=mp->cur_exp;
22415 cyan_val(cp)=0;
22416 magenta_val(cp)=0;
22417 yellow_val(cp)=0;
22418 black_val(cp)=0;
22419 grey_val(cp)=q;
22420 color_model(cp)=grey_model;
22421 if ( grey_val(cp)<0 ) grey_val(cp)=0;
22422 if ( grey_val(cp)>unity ) grey_val(cp)=unity;
22423 }
22424
22425 @ @<Transfer a noncolor from the current expression to object~|cp|@>=
22426 {
22427 cyan_val(cp)=0;
22428 magenta_val(cp)=0;
22429 yellow_val(cp)=0;
22430 black_val(cp)=0;
22431 grey_val(cp)=0;
22432 color_model(cp)=no_model;
22433 }
22434
22435 @ @<Make |cp| a colored object in object list~|p|@>=
22436 { cp=p;
22437   while ( cp!=null ){ 
22438     if ( has_color(cp) ) break;
22439     cp=link(cp);
22440   }
22441 }
22442
22443 @ @<Make |pp| an object in list~|p| that needs a pen@>=
22444 { pp=p;
22445   while ( pp!=null ) {
22446     if ( has_pen(pp) ) break;
22447     pp=link(pp);
22448   }
22449 }
22450
22451 @ @<Make |dp| a stroked node in list~|p|@>=
22452 { dp=p;
22453   while ( dp!=null ) {
22454     if ( type(dp)==stroked_code ) break;
22455     dp=link(dp);
22456   }
22457 }
22458
22459 @ @<Copy the information from objects |cp|, |pp|, and |dp| into...@>=
22460 @<Copy |cp|'s color into the colored objects linked to~|cp|@>;
22461 if ( pp>diov )
22462   @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>;
22463 if ( dp>diov ) @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>
22464
22465 @ @<Copy |cp|'s color into the colored objects linked to~|cp|@>=
22466 { q=link(cp);
22467   while ( q!=null ) { 
22468     if ( has_color(q) ) {
22469       red_val(q)=red_val(cp);
22470       green_val(q)=green_val(cp);
22471       blue_val(q)=blue_val(cp);
22472       black_val(q)=black_val(cp);
22473       color_model(q)=color_model(cp);
22474     }
22475     q=link(q);
22476   }
22477 }
22478
22479 @ @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>=
22480 { q=link(pp);
22481   while ( q!=null ) {
22482     if ( has_pen(q) ) {
22483       if ( pen_p(q)!=null ) mp_toss_knot_list(mp, pen_p(q));
22484       pen_p(q)=copy_pen(pen_p(pp));
22485     }
22486     q=link(q);
22487   }
22488 }
22489
22490 @ @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>=
22491 { q=link(dp);
22492   while ( q!=null ) {
22493     if ( type(q)==stroked_code ) {
22494       if ( dash_p(q)!=null ) delete_edge_ref(dash_p(q));
22495       dash_p(q)=dash_p(dp);
22496       dash_scale(q)=unity;
22497       if ( dash_p(q)!=null ) add_edge_ref(dash_p(q));
22498     }
22499     q=link(q);
22500   }
22501 }
22502
22503 @ One of the things we need to do when we've parsed an \&{addto} or
22504 similar command is find the header of a supposed \&{picture} variable, given
22505 a token list for that variable.  Since the edge structure is about to be
22506 updated, we use |private_edges| to make sure that this is possible.
22507
22508 @<Declare action procedures for use by |do_statement|@>=
22509 pointer mp_find_edges_var (MP mp, pointer t) ;
22510
22511 @ @c pointer mp_find_edges_var (MP mp, pointer t) {
22512   pointer p;
22513   pointer cur_edges; /* the return value */
22514   p=mp_find_variable(mp, t); cur_edges=null;
22515   if ( p==null ) { 
22516     mp_obliterated(mp, t); mp_put_get_error(mp);
22517   } else if ( type(p)!=mp_picture_type )  { 
22518     print_err("Variable "); mp_show_token_list(mp, t,null,1000,0);
22519 @.Variable x is the wrong type@>
22520     mp_print(mp, " is the wrong type ("); 
22521     mp_print_type(mp, type(p)); mp_print_char(mp, ')');
22522     help2("I was looking for a \"known\" picture variable.")
22523          ("So I'll not change anything just now."); 
22524     mp_put_get_error(mp);
22525   } else { 
22526     value(p)=mp_private_edges(mp, value(p));
22527     cur_edges=value(p);
22528   }
22529   mp_flush_node_list(mp, t);
22530   return cur_edges;
22531 };
22532
22533 @ @<Cases of |do_statement|...@>=
22534 case add_to_command: mp_do_add_to(mp); break;
22535 case bounds_command:mp_do_bounds(mp); break;
22536
22537 @ @<Put each...@>=
22538 mp_primitive(mp, "clip",bounds_command,mp_start_clip_code);
22539 @:clip_}{\&{clip} primitive@>
22540 mp_primitive(mp, "setbounds",bounds_command,mp_start_bounds_code);
22541 @:set_bounds_}{\&{setbounds} primitive@>
22542
22543 @ @<Cases of |print_cmd...@>=
22544 case bounds_command: 
22545   if ( m==mp_start_clip_code ) mp_print(mp, "clip");
22546   else mp_print(mp, "setbounds");
22547   break;
22548
22549 @ The following function parses the beginning of an \&{addto} or \&{clip}
22550 command: it expects a variable name followed by a token with |cur_cmd=sep|
22551 and then an expression.  The function returns the token list for the variable
22552 and stores the command modifier for the separator token in the global variable
22553 |last_add_type|.  We must be careful because this variable might get overwritten
22554 any time we call |get_x_next|.
22555
22556 @<Glob...@>=
22557 quarterword last_add_type;
22558   /* command modifier that identifies the last \&{addto} command */
22559
22560 @ @<Declare action procedures for use by |do_statement|@>=
22561 pointer mp_start_draw_cmd (MP mp,quarterword sep) ;
22562
22563 @ @c pointer mp_start_draw_cmd (MP mp,quarterword sep) {
22564   pointer lhv; /* variable to add to left */
22565   quarterword add_type=0; /* value to be returned in |last_add_type| */
22566   lhv=null;
22567   mp_get_x_next(mp); mp->var_flag=sep; mp_scan_primary(mp);
22568   if ( mp->cur_type!=mp_token_list ) {
22569     @<Abandon edges command because there's no variable@>;
22570   } else  { 
22571     lhv=mp->cur_exp; add_type=mp->cur_mod;
22572     mp->cur_type=mp_vacuous; mp_get_x_next(mp); mp_scan_expression(mp);
22573   }
22574   mp->last_add_type=add_type;
22575   return lhv;
22576 }
22577
22578 @ @<Abandon edges command because there's no variable@>=
22579 { exp_err("Not a suitable variable");
22580 @.Not a suitable variable@>
22581   help4("At this point I needed to see the name of a picture variable.")
22582     ("(Or perhaps you have indeed presented me with one; I might")
22583     ("have missed it, if it wasn't followed by the proper token.)")
22584     ("So I'll not change anything just now.");
22585   mp_put_get_flush_error(mp, 0);
22586 }
22587
22588 @ Here is an example of how to use |start_draw_cmd|.
22589
22590 @<Declare action procedures for use by |do_statement|@>=
22591 void mp_do_bounds (MP mp) ;
22592
22593 @ @c void mp_do_bounds (MP mp) {
22594   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22595   pointer p; /* for list manipulation */
22596   integer m; /* initial value of |cur_mod| */
22597   m=mp->cur_mod;
22598   lhv=mp_start_draw_cmd(mp, to_token);
22599   if ( lhv!=null ) {
22600     lhe=mp_find_edges_var(mp, lhv);
22601     if ( lhe==null ) {
22602       mp_flush_cur_exp(mp, 0);
22603     } else if ( mp->cur_type!=mp_path_type ) {
22604       exp_err("Improper `clip'");
22605 @.Improper `addto'@>
22606       help2("This expression should have specified a known path.")
22607         ("So I'll not change anything just now."); 
22608       mp_put_get_flush_error(mp, 0);
22609     } else if ( left_type(mp->cur_exp)==endpoint ) {
22610       @<Complain about a non-cycle@>;
22611     } else {
22612       @<Make |cur_exp| into a \&{setbounds} or clipping path and add it to |lhe|@>;
22613     }
22614   }
22615 }
22616
22617 @ @<Complain about a non-cycle@>=
22618 { print_err("Not a cycle");
22619 @.Not a cycle@>
22620   help2("That contour should have ended with `..cycle' or `&cycle'.")
22621     ("So I'll not change anything just now."); mp_put_get_error(mp);
22622 }
22623
22624 @ @<Make |cur_exp| into a \&{setbounds} or clipping path and add...@>=
22625 { p=mp_new_bounds_node(mp, mp->cur_exp,m);
22626   link(p)=link(dummy_loc(lhe));
22627   link(dummy_loc(lhe))=p;
22628   if ( obj_tail(lhe)==dummy_loc(lhe) ) obj_tail(lhe)=p;
22629   p=mp_get_node(mp, mp->gr_object_size[stop_type(m)]);
22630   type(p)=stop_type(m);
22631   link(obj_tail(lhe))=p;
22632   obj_tail(lhe)=p;
22633   mp_init_bbox(mp, lhe);
22634 }
22635
22636 @ The |do_add_to| procedure is a little like |do_clip| but there are a lot more
22637 cases to deal with.
22638
22639 @<Declare action procedures for use by |do_statement|@>=
22640 void mp_do_add_to (MP mp) ;
22641
22642 @ @c void mp_do_add_to (MP mp) {
22643   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
22644   pointer p; /* the graphical object or list for |scan_with_list| to update */
22645   pointer e; /* an edge structure to be merged */
22646   quarterword add_type; /* |also_code|, |contour_code|, or |double_path_code| */
22647   lhv=mp_start_draw_cmd(mp, thing_to_add); add_type=mp->last_add_type;
22648   if ( lhv!=null ) {
22649     if ( add_type==also_code ) {
22650       @<Make sure the current expression is a suitable picture and set |e| and |p|
22651        appropriately@>;
22652     } else {
22653       @<Create a graphical object |p| based on |add_type| and the current
22654         expression@>;
22655     }
22656     mp_scan_with_list(mp, p);
22657     @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>;
22658   }
22659 }
22660
22661 @ Setting |p:=null| causes the $\langle$with list$\rangle$ to be ignored;
22662 setting |e:=null| prevents anything from being added to |lhe|.
22663
22664 @ @<Make sure the current expression is a suitable picture and set |e|...@>=
22665
22666   p=null; e=null;
22667   if ( mp->cur_type!=mp_picture_type ) {
22668     exp_err("Improper `addto'");
22669 @.Improper `addto'@>
22670     help2("This expression should have specified a known picture.")
22671       ("So I'll not change anything just now."); mp_put_get_flush_error(mp, 0);
22672   } else { 
22673     e=mp_private_edges(mp, mp->cur_exp); mp->cur_type=mp_vacuous;
22674     p=link(dummy_loc(e));
22675   }
22676 }
22677
22678 @ In this case |add_type<>also_code| so setting |p:=null| suppresses future
22679 attempts to add to the edge structure.
22680
22681 @<Create a graphical object |p| based on |add_type| and the current...@>=
22682 { e=null; p=null;
22683   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
22684   if ( mp->cur_type!=mp_path_type ) {
22685     exp_err("Improper `addto'");
22686 @.Improper `addto'@>
22687     help2("This expression should have specified a known path.")
22688       ("So I'll not change anything just now."); 
22689     mp_put_get_flush_error(mp, 0);
22690   } else if ( add_type==contour_code ) {
22691     if ( left_type(mp->cur_exp)==endpoint ) {
22692       @<Complain about a non-cycle@>;
22693     } else { 
22694       p=mp_new_fill_node(mp, mp->cur_exp);
22695       mp->cur_type=mp_vacuous;
22696     }
22697   } else { 
22698     p=mp_new_stroked_node(mp, mp->cur_exp);
22699     mp->cur_type=mp_vacuous;
22700   }
22701 }
22702
22703 @ @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>=
22704 lhe=mp_find_edges_var(mp, lhv);
22705 if ( lhe==null ) {
22706   if ( (e==null)&&(p!=null) ) e=mp_toss_gr_object(mp, p);
22707   if ( e!=null ) delete_edge_ref(e);
22708 } else if ( add_type==also_code ) {
22709   if ( e!=null ) {
22710     @<Merge |e| into |lhe| and delete |e|@>;
22711   } else { 
22712     do_nothing;
22713   }
22714 } else if ( p!=null ) {
22715   link(obj_tail(lhe))=p;
22716   obj_tail(lhe)=p;
22717   if ( add_type==double_path_code )
22718     if ( pen_p(p)==null ) 
22719       pen_p(p)=mp_get_pen_circle(mp, 0);
22720 }
22721
22722 @ @<Merge |e| into |lhe| and delete |e|@>=
22723 { if ( link(dummy_loc(e))!=null ) {
22724     link(obj_tail(lhe))=link(dummy_loc(e));
22725     obj_tail(lhe)=obj_tail(e);
22726     obj_tail(e)=dummy_loc(e);
22727     link(dummy_loc(e))=null;
22728     mp_flush_dash_list(mp, lhe);
22729   }
22730   mp_toss_edges(mp, e);
22731 }
22732
22733 @ @<Cases of |do_statement|...@>=
22734 case ship_out_command: mp_do_ship_out(mp); break;
22735
22736 @ @<Declare action procedures for use by |do_statement|@>=
22737 @<Declare the function called |tfm_check|@>;
22738 @<Declare the \ps\ output procedures@>;
22739 void mp_do_ship_out (MP mp) ;
22740
22741 @ @c void mp_do_ship_out (MP mp) {
22742   integer c; /* the character code */
22743   mp_get_x_next(mp); mp_scan_expression(mp);
22744   if ( mp->cur_type!=mp_picture_type ) {
22745     @<Complain that it's not a known picture@>;
22746   } else { 
22747     c=mp_round_unscaled(mp, mp->internal[char_code]) % 256;
22748     if ( c<0 ) c=c+256;
22749     @<Store the width information for character code~|c|@>;
22750     mp_ship_out(mp, mp->cur_exp);
22751     mp_flush_cur_exp(mp, 0);
22752   }
22753 }
22754
22755 @ @<Complain that it's not a known picture@>=
22756
22757   exp_err("Not a known picture");
22758   help1("I can only output known pictures.");
22759   mp_put_get_flush_error(mp, 0);
22760 }
22761
22762 @ The \&{everyjob} command simply assigns a nonzero value to the global variable
22763 |start_sym|.
22764
22765 @<Cases of |do_statement|...@>=
22766 case every_job_command: 
22767   mp_get_symbol(mp); mp->start_sym=mp->cur_sym; mp_get_x_next(mp);
22768   break;
22769
22770 @ @<Glob...@>=
22771 halfword start_sym; /* a symbolic token to insert at beginning of job */
22772
22773 @ @<Set init...@>=
22774 mp->start_sym=0;
22775
22776 @ Finally, we have only the ``message'' commands remaining.
22777
22778 @d message_code 0
22779 @d err_message_code 1
22780 @d err_help_code 2
22781 @d filename_template_code 3
22782 @d print_with_leading_zeroes(A)  g = mp->pool_ptr;
22783               mp_print_int(mp, (A)); g = mp->pool_ptr-g;
22784               if ( f>g ) {
22785                 mp->pool_ptr = mp->pool_ptr - g;
22786                 while ( f>g ) {
22787                   mp_print_char(mp, '0');
22788                   decr(f);
22789                   };
22790                 mp_print_int(mp, (A));
22791               };
22792               f = 0
22793
22794 @<Put each...@>=
22795 mp_primitive(mp, "message",message_command,message_code);
22796 @:message_}{\&{message} primitive@>
22797 mp_primitive(mp, "errmessage",message_command,err_message_code);
22798 @:err_message_}{\&{errmessage} primitive@>
22799 mp_primitive(mp, "errhelp",message_command,err_help_code);
22800 @:err_help_}{\&{errhelp} primitive@>
22801 mp_primitive(mp, "filenametemplate",message_command,filename_template_code);
22802 @:filename_template_}{\&{filenametemplate} primitive@>
22803
22804 @ @<Cases of |print_cmd...@>=
22805 case message_command: 
22806   if ( m<err_message_code ) mp_print(mp, "message");
22807   else if ( m==err_message_code ) mp_print(mp, "errmessage");
22808   else if ( m==filename_template_code ) mp_print(mp, "filenametemplate");
22809   else mp_print(mp, "errhelp");
22810   break;
22811
22812 @ @<Cases of |do_statement|...@>=
22813 case message_command: mp_do_message(mp); break;
22814
22815 @ @<Declare action procedures for use by |do_statement|@>=
22816 @<Declare a procedure called |no_string_err|@>;
22817 void mp_do_message (MP mp) ;
22818
22819
22820 @c void mp_do_message (MP mp) {
22821   int m; /* the type of message */
22822   m=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
22823   if ( mp->cur_type!=mp_string_type )
22824     mp_no_string_err(mp, "A message should be a known string expression.");
22825   else {
22826     switch (m) {
22827     case message_code: 
22828       mp_print_nl(mp, ""); mp_print_str(mp, mp->cur_exp);
22829       break;
22830     case err_message_code:
22831       @<Print string |cur_exp| as an error message@>;
22832       break;
22833     case err_help_code:
22834       @<Save string |cur_exp| as the |err_help|@>;
22835       break;
22836     case filename_template_code:
22837       @<Save the filename template@>;
22838       break;
22839     } /* there are no other cases */
22840   }
22841   mp_flush_cur_exp(mp, 0);
22842 }
22843
22844 @ @<Declare a procedure called |no_string_err|@>=
22845 void mp_no_string_err (MP mp,char *s) { 
22846    exp_err("Not a string");
22847 @.Not a string@>
22848   help1(s);
22849   mp_put_get_error(mp);
22850 }
22851
22852 @ The global variable |err_help| is zero when the user has most recently
22853 given an empty help string, or if none has ever been given.
22854
22855 @<Save string |cur_exp| as the |err_help|@>=
22856
22857   if ( mp->err_help!=0 ) delete_str_ref(mp->err_help);
22858   if ( length(mp->cur_exp)==0 ) mp->err_help=0;
22859   else  { mp->err_help=mp->cur_exp; add_str_ref(mp->err_help); }
22860 }
22861
22862 @ If \&{errmessage} occurs often in |mp_scroll_mode|, without user-defined
22863 \&{errhelp}, we don't want to give a long help message each time. So we
22864 give a verbose explanation only once.
22865
22866 @<Glob...@>=
22867 boolean long_help_seen; /* has the long \.{\\errmessage} help been used? */
22868
22869 @ @<Set init...@>=mp->long_help_seen=false;
22870
22871 @ @<Print string |cur_exp| as an error message@>=
22872
22873   print_err(""); mp_print_str(mp, mp->cur_exp);
22874   if ( mp->err_help!=0 ) {
22875     mp->use_err_help=true;
22876   } else if ( mp->long_help_seen ) { 
22877     help1("(That was another `errmessage'.)") ; 
22878   } else  { 
22879    if ( mp->interaction<mp_error_stop_mode ) mp->long_help_seen=true;
22880     help4("This error message was generated by an `errmessage'")
22881      ("command, so I can\'t give any explicit help.")
22882      ("Pretend that you're Miss Marple: Examine all clues,")
22883 @^Marple, Jane@>
22884      ("and deduce the truth by inspired guesses.");
22885   }
22886   mp_put_get_error(mp); mp->use_err_help=false;
22887 }
22888
22889 @ @<Cases of |do_statement|...@>=
22890 case write_command: mp_do_write(mp); break;
22891
22892 @ @<Declare action procedures for use by |do_statement|@>=
22893 void mp_do_write (MP mp) ;
22894
22895 @ @c void mp_do_write (MP mp) {
22896   str_number t; /* the line of text to be written */
22897   write_index n,n0; /* for searching |wr_fname| and |wr_file| arrays */
22898   int old_setting; /* for saving |selector| during output */
22899   mp_get_x_next(mp);
22900   mp_scan_expression(mp);
22901   if ( mp->cur_type!=mp_string_type ) {
22902     mp_no_string_err(mp, "The text to be written should be a known string expression");
22903   } else if ( mp->cur_cmd!=to_token ) { 
22904     print_err("Missing `to' clause");
22905     help1("A write command should end with `to <filename>'");
22906     mp_put_get_error(mp);
22907   } else { 
22908     t=mp->cur_exp; mp->cur_type=mp_vacuous;
22909     mp_get_x_next(mp);
22910     mp_scan_expression(mp);
22911     if ( mp->cur_type!=mp_string_type )
22912       mp_no_string_err(mp, "I can\'t write to that file name.  It isn't a known string");
22913     else {
22914       @<Write |t| to the file named by |cur_exp|@>;
22915     }
22916     delete_str_ref(t);
22917   }
22918   mp_flush_cur_exp(mp, 0);
22919 }
22920
22921 @ @<Write |t| to the file named by |cur_exp|@>=
22922
22923   @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if
22924     |cur_exp| must be inserted@>;
22925   if ( mp_str_vs_str(mp, t,mp->eof_line)==0 ) {
22926     @<Record the end of file on |wr_file[n]|@>;
22927   } else { 
22928     old_setting=mp->selector;
22929     mp->selector=n+write_file;
22930     mp_print_str(mp, t); mp_print_ln(mp);
22931     mp->selector = old_setting;
22932   }
22933 }
22934
22935 @ @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if...@>=
22936 {
22937   char *fn = str(mp->cur_exp);
22938   n=mp->write_files;
22939   n0=mp->write_files;
22940   while (mp_xstrcmp(fn,mp->wr_fname[n])!=0) { 
22941     if ( n==0 ) { /* bottom reached */
22942           if ( n0==mp->write_files ) {
22943         if ( mp->write_files<mp->max_write_files ) {
22944           incr(mp->write_files);
22945         } else {
22946           FILE **wr_file;
22947           char **wr_fname;
22948               write_index l,k;
22949           l = mp->max_write_files + (mp->max_write_files>>2);
22950           wr_file = xmalloc((l+1),sizeof(FILE *));
22951           wr_fname = xmalloc((l+1),sizeof(char *));
22952               for (k=0;k<=l;k++) {
22953             if (k<=mp->max_write_files) {
22954                   wr_file[k]=mp->wr_file[k]; 
22955               wr_fname[k]=mp->wr_fname[k];
22956             } else {
22957                   wr_file[k]=0; 
22958               wr_fname[k]=NULL;
22959             }
22960           }
22961               xfree(mp->wr_file); xfree(mp->wr_fname);
22962           mp->max_write_files = l;
22963           mp->wr_file = wr_file;
22964           mp->wr_fname = wr_fname;
22965         }
22966       }
22967       n=n0;
22968       mp_open_write_file(mp, fn ,n);
22969     } else { 
22970       decr(n);
22971           if ( mp->wr_fname[n]==NULL )  n0=n; 
22972     }
22973   }
22974 }
22975
22976 @ @<Record the end of file on |wr_file[n]|@>=
22977 { fclose(mp->wr_file[n]);
22978   xfree(mp->wr_fname[n]);
22979   mp->wr_fname[n]=NULL;
22980   if ( n==mp->write_files-1 ) mp->write_files=n;
22981 }
22982
22983
22984 @* \[42] Writing font metric data.
22985 \TeX\ gets its knowledge about fonts from font metric files, also called
22986 \.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
22987 but other programs know about them too. One of \MP's duties is to
22988 write \.{TFM} files so that the user's fonts can readily be
22989 applied to typesetting.
22990 @:TFM files}{\.{TFM} files@>
22991 @^font metric files@>
22992
22993 The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
22994 Since the number of bytes is always a multiple of~4, we could
22995 also regard the file as a sequence of 32-bit words, but \MP\ uses the
22996 byte interpretation. The format of \.{TFM} files was designed by
22997 Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
22998 @^Ramshaw, Lyle Harold@>
22999 of information in a compact but useful form.
23000
23001 @<Glob...@>=
23002 FILE * tfm_file; /* the font metric output goes here */
23003 char * metric_file_name; /* full name of the font metric file */
23004
23005 @ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
23006 integers that give the lengths of the various subsequent portions
23007 of the file. These twelve integers are, in order:
23008 $$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
23009 |lf|&length of the entire file, in words;\cr
23010 |lh|&length of the header data, in words;\cr
23011 |bc|&smallest character code in the font;\cr
23012 |ec|&largest character code in the font;\cr
23013 |nw|&number of words in the width table;\cr
23014 |nh|&number of words in the height table;\cr
23015 |nd|&number of words in the depth table;\cr
23016 |ni|&number of words in the italic correction table;\cr
23017 |nl|&number of words in the lig/kern table;\cr
23018 |nk|&number of words in the kern table;\cr
23019 |ne|&number of words in the extensible character table;\cr
23020 |np|&number of font parameter words.\cr}}$$
23021 They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
23022 |ne<=256|, and
23023 $$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
23024 Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
23025 and as few as 0 characters (if |bc=ec+1|).
23026
23027 Incidentally, when two or more 8-bit bytes are combined to form an integer of
23028 16 or more bits, the most significant bytes appear first in the file.
23029 This is called BigEndian order.
23030 @^BigEndian order@>
23031
23032 @ The rest of the \.{TFM} file may be regarded as a sequence of ten data
23033 arrays.
23034
23035 The most important data type used here is a |fix_word|, which is
23036 a 32-bit representation of a binary fraction. A |fix_word| is a signed
23037 quantity, with the two's complement of the entire word used to represent
23038 negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
23039 binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
23040 the smallest is $-2048$. We will see below, however, that all but two of
23041 the |fix_word| values must lie between $-16$ and $+16$.
23042
23043 @ The first data array is a block of header information, which contains
23044 general facts about the font. The header must contain at least two words,
23045 |header[0]| and |header[1]|, whose meaning is explained below.  Additional
23046 header information of use to other software routines might also be
23047 included, and \MP\ will generate it if the \.{headerbyte} command occurs.
23048 For example, 16 more words of header information are in use at the Xerox
23049 Palo Alto Research Center; the first ten specify the character coding
23050 scheme used (e.g., `\.{XEROX TEXT}' or `\.{TEX MATHSY}'), the next five
23051 give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
23052 last gives the ``face byte.''
23053
23054 \yskip\hang|header[0]| is a 32-bit check sum that \MP\ will copy into
23055 the \.{GF} output file. This helps ensure consistency between files,
23056 since \TeX\ records the check sums from the \.{TFM}'s it reads, and these
23057 should match the check sums on actual fonts that are used.  The actual
23058 relation between this check sum and the rest of the \.{TFM} file is not
23059 important; the check sum is simply an identification number with the
23060 property that incompatible fonts almost always have distinct check sums.
23061 @^check sum@>
23062
23063 \yskip\hang|header[1]| is a |fix_word| containing the design size of the
23064 font, in units of \TeX\ points. This number must be at least 1.0; it is
23065 fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
23066 font, i.e., a font that was designed to look best at a 10-point size,
23067 whatever that really means. When a \TeX\ user asks for a font `\.{at}
23068 $\delta$ \.{pt}', the effect is to override the design size and replace it
23069 by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in
23070 the font image by a factor of $\delta$ divided by the design size.  {\sl
23071 All other dimensions in the\/ \.{TFM} file are |fix_word|\kern-1pt\
23072 numbers in design-size units.} Thus, for example, the value of |param[6]|,
23073 which defines the \.{em} unit, is often the |fix_word| value $2^{20}=1.0$,
23074 since many fonts have a design size equal to one em.  The other dimensions
23075 must be less than 16 design-size units in absolute value; thus,
23076 |header[1]| and |param[1]| are the only |fix_word| entries in the whole
23077 \.{TFM} file whose first byte might be something besides 0 or 255.
23078
23079 @ Next comes the |char_info| array, which contains one |char_info_word|
23080 per character. Each word in this part of the file contains six fields
23081 packed into four bytes as follows.
23082
23083 \yskip\hang first byte: |width_index| (8 bits)\par
23084 \hang second byte: |height_index| (4 bits) times 16, plus |depth_index|
23085   (4~bits)\par
23086 \hang third byte: |italic_index| (6 bits) times 4, plus |tag|
23087   (2~bits)\par
23088 \hang fourth byte: |remainder| (8 bits)\par
23089 \yskip\noindent
23090 The actual width of a character is \\{width}|[width_index]|, in design-size
23091 units; this is a device for compressing information, since many characters
23092 have the same width. Since it is quite common for many characters
23093 to have the same height, depth, or italic correction, the \.{TFM} format
23094 imposes a limit of 16 different heights, 16 different depths, and
23095 64 different italic corrections.
23096
23097 Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
23098 \\{italic}[0]=0$ should always hold, so that an index of zero implies a
23099 value of zero.  The |width_index| should never be zero unless the
23100 character does not exist in the font, since a character is valid if and
23101 only if it lies between |bc| and |ec| and has a nonzero |width_index|.
23102
23103 @ The |tag| field in a |char_info_word| has four values that explain how to
23104 interpret the |remainder| field.
23105
23106 \yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
23107 \hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
23108 program starting at location |remainder| in the |lig_kern| array.\par
23109 \hang|tag=2| (|list_tag|) means that this character is part of a chain of
23110 characters of ascending sizes, and not the largest in the chain.  The
23111 |remainder| field gives the character code of the next larger character.\par
23112 \hang|tag=3| (|ext_tag|) means that this character code represents an
23113 extensible character, i.e., a character that is built up of smaller pieces
23114 so that it can be made arbitrarily large. The pieces are specified in
23115 |exten[remainder]|.\par
23116 \yskip\noindent
23117 Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
23118 unless they are used in special circumstances in math formulas. For example,
23119 \TeX's \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
23120 operation looks for both |list_tag| and |ext_tag|.
23121
23122 @d no_tag 0 /* vanilla character */
23123 @d lig_tag 1 /* character has a ligature/kerning program */
23124 @d list_tag 2 /* character has a successor in a charlist */
23125 @d ext_tag 3 /* character is extensible */
23126
23127 @ The |lig_kern| array contains instructions in a simple programming language
23128 that explains what to do for special letter pairs. Each word in this array is a
23129 |lig_kern_command| of four bytes.
23130
23131 \yskip\hang first byte: |skip_byte|, indicates that this is the final program
23132   step if the byte is 128 or more, otherwise the next step is obtained by
23133   skipping this number of intervening steps.\par
23134 \hang second byte: |next_char|, ``if |next_char| follows the current character,
23135   then perform the operation and stop, otherwise continue.''\par
23136 \hang third byte: |op_byte|, indicates a ligature step if less than~128,
23137   a kern step otherwise.\par
23138 \hang fourth byte: |remainder|.\par
23139 \yskip\noindent
23140 In a kern step, an
23141 additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
23142 between the current character and |next_char|. This amount is
23143 often negative, so that the characters are brought closer together
23144 by kerning; but it might be positive.
23145
23146 There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
23147 $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
23148 |remainder| is inserted between the current character and |next_char|;
23149 then the current character is deleted if $b=0$, and |next_char| is
23150 deleted if $c=0$; then we pass over $a$~characters to reach the next
23151 current character (which may have a ligature/kerning program of its own).
23152
23153 If the very first instruction of the |lig_kern| array has |skip_byte=255|,
23154 the |next_char| byte is the so-called right boundary character of this font;
23155 the value of |next_char| need not lie between |bc| and~|ec|.
23156 If the very last instruction of the |lig_kern| array has |skip_byte=255|,
23157 there is a special ligature/kerning program for a left boundary character,
23158 beginning at location |256*op_byte+remainder|.
23159 The interpretation is that \TeX\ puts implicit boundary characters
23160 before and after each consecutive string of characters from the same font.
23161 These implicit characters do not appear in the output, but they can affect
23162 ligatures and kerning.
23163
23164 If the very first instruction of a character's |lig_kern| program has
23165 |skip_byte>128|, the program actually begins in location
23166 |256*op_byte+remainder|. This feature allows access to large |lig_kern|
23167 arrays, because the first instruction must otherwise
23168 appear in a location |<=255|.
23169
23170 Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
23171 the condition
23172 $$\hbox{|256*op_byte+remainder<nl|.}$$
23173 If such an instruction is encountered during
23174 normal program execution, it denotes an unconditional halt; no ligature
23175 command is performed.
23176
23177 @d stop_flag (128)
23178   /* value indicating `\.{STOP}' in a lig/kern program */
23179 @d kern_flag (128) /* op code for a kern step */
23180 @d skip_byte(A) mp->lig_kern[(A)].b0
23181 @d next_char(A) mp->lig_kern[(A)].b1
23182 @d op_byte(A) mp->lig_kern[(A)].b2
23183 @d rem_byte(A) mp->lig_kern[(A)].b3
23184
23185 @ Extensible characters are specified by an |extensible_recipe|, which
23186 consists of four bytes called |top|, |mid|, |bot|, and |rep| (in this
23187 order). These bytes are the character codes of individual pieces used to
23188 build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
23189 present in the built-up result. For example, an extensible vertical line is
23190 like an extensible bracket, except that the top and bottom pieces are missing.
23191
23192 Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
23193 if the piece isn't present. Then the extensible characters have the form
23194 $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
23195 in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
23196 The width of the extensible character is the width of $R$; and the
23197 height-plus-depth is the sum of the individual height-plus-depths of the
23198 components used, since the pieces are butted together in a vertical list.
23199
23200 @d ext_top(A) mp->exten[(A)].b0 /* |top| piece in a recipe */
23201 @d ext_mid(A) mp->exten[(A)].b1 /* |mid| piece in a recipe */
23202 @d ext_bot(A) mp->exten[(A)].b2 /* |bot| piece in a recipe */
23203 @d ext_rep(A) mp->exten[(A)].b3 /* |rep| piece in a recipe */
23204
23205 @ The final portion of a \.{TFM} file is the |param| array, which is another
23206 sequence of |fix_word| values.
23207
23208 \yskip\hang|param[1]=slant| is the amount of italic slant, which is used
23209 to help position accents. For example, |slant=.25| means that when you go
23210 up one unit, you also go .25 units to the right. The |slant| is a pure
23211 number; it is the only |fix_word| other than the design size itself that is
23212 not scaled by the design size.
23213
23214 \hang|param[2]=space| is the normal spacing between words in text.
23215 Note that character 040 in the font need not have anything to do with
23216 blank spaces.
23217
23218 \hang|param[3]=space_stretch| is the amount of glue stretching between words.
23219
23220 \hang|param[4]=space_shrink| is the amount of glue shrinking between words.
23221
23222 \hang|param[5]=x_height| is the size of one ex in the font; it is also
23223 the height of letters for which accents don't have to be raised or lowered.
23224
23225 \hang|param[6]=quad| is the size of one em in the font.
23226
23227 \hang|param[7]=extra_space| is the amount added to |param[2]| at the
23228 ends of sentences.
23229
23230 \yskip\noindent
23231 If fewer than seven parameters are present, \TeX\ sets the missing parameters
23232 to zero.
23233
23234 @d slant_code 1
23235 @d space_code 2
23236 @d space_stretch_code 3
23237 @d space_shrink_code 4
23238 @d x_height_code 5
23239 @d quad_code 6
23240 @d extra_space_code 7
23241
23242 @ So that is what \.{TFM} files hold. One of \MP's duties is to output such
23243 information, and it does this all at once at the end of a job.
23244 In order to prepare for such frenetic activity, it squirrels away the
23245 necessary facts in various arrays as information becomes available.
23246
23247 Character dimensions (\&{charwd}, \&{charht}, \&{chardp}, and \&{charic})
23248 are stored respectively in |tfm_width|, |tfm_height|, |tfm_depth|, and
23249 |tfm_ital_corr|. Other information about a character (e.g., about
23250 its ligatures or successors) is accessible via the |char_tag| and
23251 |char_remainder| arrays. Other information about the font as a whole
23252 is kept in additional arrays called |header_byte|, |lig_kern|,
23253 |kern|, |exten|, and |param|.
23254
23255 @d max_tfm_int 32510
23256 @d undefined_label max_tfm_int /* an undefined local label */
23257
23258 @<Glob...@>=
23259 #define TFM_ITEMS 257
23260 eight_bits bc;
23261 eight_bits ec; /* smallest and largest character codes shipped out */
23262 scaled tfm_width[TFM_ITEMS]; /* \&{charwd} values */
23263 scaled tfm_height[TFM_ITEMS]; /* \&{charht} values */
23264 scaled tfm_depth[TFM_ITEMS]; /* \&{chardp} values */
23265 scaled tfm_ital_corr[TFM_ITEMS]; /* \&{charic} values */
23266 boolean char_exists[TFM_ITEMS]; /* has this code been shipped out? */
23267 int char_tag[TFM_ITEMS]; /* |remainder| category */
23268 int char_remainder[TFM_ITEMS]; /* the |remainder| byte */
23269 char *header_byte; /* bytes of the \.{TFM} header */
23270 int header_last; /* last initialized \.{TFM} header byte */
23271 int header_size; /* size of the \.{TFM} header */
23272 four_quarters *lig_kern; /* the ligature/kern table */
23273 short nl; /* the number of ligature/kern steps so far */
23274 scaled *kern; /* distinct kerning amounts */
23275 short nk; /* the number of distinct kerns so far */
23276 four_quarters exten[TFM_ITEMS]; /* extensible character recipes */
23277 short ne; /* the number of extensible characters so far */
23278 scaled *param; /* \&{fontinfo} parameters */
23279 short np; /* the largest \&{fontinfo} parameter specified so far */
23280 short nw;short nh;short nd;short ni; /* sizes of \.{TFM} subtables */
23281 short skip_table[TFM_ITEMS]; /* local label status */
23282 boolean lk_started; /* has there been a lig/kern step in this command yet? */
23283 integer bchar; /* right boundary character */
23284 short bch_label; /* left boundary starting location */
23285 short ll;short lll; /* registers used for lig/kern processing */
23286 short label_loc[257]; /* lig/kern starting addresses */
23287 eight_bits label_char[257]; /* characters for |label_loc| */
23288 short label_ptr; /* highest position occupied in |label_loc| */
23289
23290 @ @<Allocate or initialize ...@>=
23291 mp->header_last = 0; mp->header_size = 128; /* just for init */
23292 mp->header_byte = xmalloc(mp->header_size, sizeof(char));
23293 mp->lig_kern = NULL; /* allocated when needed */
23294 mp->kern = NULL; /* allocated when needed */ 
23295 mp->param = NULL; /* allocated when needed */
23296
23297 @ @<Dealloc variables@>=
23298 xfree(mp->header_byte);
23299 xfree(mp->lig_kern);
23300 xfree(mp->kern);
23301 xfree(mp->param);
23302
23303 @ @<Set init...@>=
23304 for (k=0;k<= 255;k++ ) {
23305   mp->tfm_width[k]=0; mp->tfm_height[k]=0; mp->tfm_depth[k]=0; mp->tfm_ital_corr[k]=0;
23306   mp->char_exists[k]=false; mp->char_tag[k]=no_tag; mp->char_remainder[k]=0;
23307   mp->skip_table[k]=undefined_label;
23308 };
23309 memset(mp->header_byte,0,mp->header_size);
23310 mp->bc=255; mp->ec=0; mp->nl=0; mp->nk=0; mp->ne=0; mp->np=0;
23311 mp->internal[boundary_char]=-unity;
23312 mp->bch_label=undefined_label;
23313 mp->label_loc[0]=-1; mp->label_ptr=0;
23314
23315 @ @<Declarations@>=
23316 scaled mp_tfm_check (MP mp,small_number m) ;
23317
23318 @ @<Declare the function called |tfm_check|@>=
23319 scaled mp_tfm_check (MP mp,small_number m) {
23320   if ( abs(mp->internal[m])>=fraction_half ) {
23321     print_err("Enormous "); mp_print(mp, mp->int_name[m]);
23322 @.Enormous charwd...@>
23323 @.Enormous chardp...@>
23324 @.Enormous charht...@>
23325 @.Enormous charic...@>
23326 @.Enormous designsize...@>
23327     mp_print(mp, " has been reduced");
23328     help1("Font metric dimensions must be less than 2048pt.");
23329     mp_put_get_error(mp);
23330     if ( mp->internal[m]>0 ) return (fraction_half-1);
23331     else return (1-fraction_half);
23332   } else {
23333     return mp->internal[m];
23334   }
23335 }
23336
23337 @ @<Store the width information for character code~|c|@>=
23338 if ( c<mp->bc ) mp->bc=c;
23339 if ( c>mp->ec ) mp->ec=c;
23340 mp->char_exists[c]=true;
23341 mp->tfm_width[c]=mp_tfm_check(mp, char_wd);
23342 mp->tfm_height[c]=mp_tfm_check(mp, char_ht);
23343 mp->tfm_depth[c]=mp_tfm_check(mp, char_dp);
23344 mp->tfm_ital_corr[c]=mp_tfm_check(mp, char_ic)
23345
23346 @ Now let's consider \MP's special \.{TFM}-oriented commands.
23347
23348 @<Cases of |do_statement|...@>=
23349 case tfm_command: mp_do_tfm_command(mp); break;
23350
23351 @ @d char_list_code 0
23352 @d lig_table_code 1
23353 @d extensible_code 2
23354 @d header_byte_code 3
23355 @d font_dimen_code 4
23356
23357 @<Put each...@>=
23358 mp_primitive(mp, "charlist",tfm_command,char_list_code);
23359 @:char_list_}{\&{charlist} primitive@>
23360 mp_primitive(mp, "ligtable",tfm_command,lig_table_code);
23361 @:lig_table_}{\&{ligtable} primitive@>
23362 mp_primitive(mp, "extensible",tfm_command,extensible_code);
23363 @:extensible_}{\&{extensible} primitive@>
23364 mp_primitive(mp, "headerbyte",tfm_command,header_byte_code);
23365 @:header_byte_}{\&{headerbyte} primitive@>
23366 mp_primitive(mp, "fontdimen",tfm_command,font_dimen_code);
23367 @:font_dimen_}{\&{fontdimen} primitive@>
23368
23369 @ @<Cases of |print_cmd...@>=
23370 case tfm_command: 
23371   switch (m) {
23372   case char_list_code:mp_print(mp, "charlist"); break;
23373   case lig_table_code:mp_print(mp, "ligtable"); break;
23374   case extensible_code:mp_print(mp, "extensible"); break;
23375   case header_byte_code:mp_print(mp, "headerbyte"); break;
23376   default: mp_print(mp, "fontdimen"); break;
23377   }
23378   break;
23379
23380 @ @<Declare action procedures for use by |do_statement|@>=
23381 eight_bits mp_get_code (MP mp) ;
23382
23383 @ @c eight_bits mp_get_code (MP mp) { /* scans a character code value */
23384   integer c; /* the code value found */
23385   mp_get_x_next(mp); mp_scan_expression(mp);
23386   if ( mp->cur_type==mp_known ) { 
23387     c=mp_round_unscaled(mp, mp->cur_exp);
23388     if ( c>=0 ) if ( c<256 ) return c;
23389   } else if ( mp->cur_type==mp_string_type ) {
23390     if ( length(mp->cur_exp)==1 )  { 
23391       c=mp->str_pool[mp->str_start[mp->cur_exp]];
23392       return c;
23393     }
23394   }
23395   exp_err("Invalid code has been replaced by 0");
23396 @.Invalid code...@>
23397   help2("I was looking for a number between 0 and 255, or for a")
23398        ("string of length 1. Didn't find it; will use 0 instead.");
23399   mp_put_get_flush_error(mp, 0); c=0;
23400   return c;
23401 };
23402
23403 @ @<Declare action procedures for use by |do_statement|@>=
23404 void mp_set_tag (MP mp,halfword c, small_number t, halfword r) ;
23405
23406 @ @c void mp_set_tag (MP mp,halfword c, small_number t, halfword r) { 
23407   if ( mp->char_tag[c]==no_tag ) {
23408     mp->char_tag[c]=t; mp->char_remainder[c]=r;
23409     if ( t==lig_tag ){ 
23410       incr(mp->label_ptr); mp->label_loc[mp->label_ptr]=r; 
23411       mp->label_char[mp->label_ptr]=c;
23412     }
23413   } else {
23414     @<Complain about a character tag conflict@>;
23415   }
23416 }
23417
23418 @ @<Complain about a character tag conflict@>=
23419
23420   print_err("Character ");
23421   if ( (c>' ')&&(c<127) ) mp_print_char(mp,c);
23422   else if ( c==256 ) mp_print(mp, "||");
23423   else  { mp_print(mp, "code "); mp_print_int(mp, c); };
23424   mp_print(mp, " is already ");
23425 @.Character c is already...@>
23426   switch (mp->char_tag[c]) {
23427   case lig_tag: mp_print(mp, "in a ligtable"); break;
23428   case list_tag: mp_print(mp, "in a charlist"); break;
23429   case ext_tag: mp_print(mp, "extensible"); break;
23430   } /* there are no other cases */
23431   help2("It's not legal to label a character more than once.")
23432     ("So I'll not change anything just now.");
23433   mp_put_get_error(mp); 
23434 }
23435
23436 @ @<Declare action procedures for use by |do_statement|@>=
23437 void mp_do_tfm_command (MP mp) ;
23438
23439 @ @c void mp_do_tfm_command (MP mp) {
23440   int c,cc; /* character codes */
23441   int k; /* index into the |kern| array */
23442   int j; /* index into |header_byte| or |param| */
23443   switch (mp->cur_mod) {
23444   case char_list_code: 
23445     c=mp_get_code(mp);
23446      /* we will store a list of character successors */
23447     while ( mp->cur_cmd==colon )   { 
23448       cc=mp_get_code(mp); mp_set_tag(mp, c,list_tag,cc); c=cc;
23449     };
23450     break;
23451   case lig_table_code: 
23452     if (mp->lig_kern==NULL) 
23453        mp->lig_kern = xmalloc((max_tfm_int+1),sizeof(four_quarters));
23454     if (mp->kern==NULL) 
23455        mp->kern = xmalloc((max_tfm_int+1),sizeof(scaled));
23456     @<Store a list of ligature/kern steps@>;
23457     break;
23458   case extensible_code: 
23459     @<Define an extensible recipe@>;
23460     break;
23461   case header_byte_code: 
23462   case font_dimen_code: 
23463     c=mp->cur_mod; mp_get_x_next(mp);
23464     mp_scan_expression(mp);
23465     if ( (mp->cur_type!=mp_known)||(mp->cur_exp<half_unit) ) {
23466       exp_err("Improper location");
23467 @.Improper location@>
23468       help2("I was looking for a known, positive number.")
23469        ("For safety's sake I'll ignore the present command.");
23470       mp_put_get_error(mp);
23471     } else  { 
23472       j=mp_round_unscaled(mp, mp->cur_exp);
23473       if ( mp->cur_cmd!=colon ) {
23474         mp_missing_err(mp, ":");
23475 @.Missing `:'@>
23476         help1("A colon should follow a headerbyte or fontinfo location.");
23477         mp_back_error(mp);
23478       }
23479       if ( c==header_byte_code ) { 
23480         @<Store a list of header bytes@>;
23481       } else {     
23482         if (mp->param==NULL) 
23483           mp->param = xmalloc((max_tfm_int+1),sizeof(scaled));
23484         @<Store a list of font dimensions@>;
23485       }
23486     }
23487     break;
23488   } /* there are no other cases */
23489 };
23490
23491 @ @<Store a list of ligature/kern steps@>=
23492
23493   mp->lk_started=false;
23494 CONTINUE: 
23495   mp_get_x_next(mp);
23496   if ((mp->cur_cmd==skip_to)&& mp->lk_started )
23497     @<Process a |skip_to| command and |goto done|@>;
23498   if ( mp->cur_cmd==bchar_label ) { c=256; mp->cur_cmd=colon; }
23499   else { mp_back_input(mp); c=mp_get_code(mp); };
23500   if ((mp->cur_cmd==colon)||(mp->cur_cmd==double_colon)) {
23501     @<Record a label in a lig/kern subprogram and |goto continue|@>;
23502   }
23503   if ( mp->cur_cmd==lig_kern_token ) { 
23504     @<Compile a ligature/kern command@>; 
23505   } else  { 
23506     print_err("Illegal ligtable step");
23507 @.Illegal ligtable step@>
23508     help1("I was looking for `=:' or `kern' here.");
23509     mp_back_error(mp); next_char(mp->nl)=qi(0); 
23510     op_byte(mp->nl)=qi(0); rem_byte(mp->nl)=qi(0);
23511     skip_byte(mp->nl)=stop_flag+1; /* this specifies an unconditional stop */
23512   }
23513   if ( mp->nl==max_tfm_int) mp_fatal_error(mp, "ligtable too large");
23514   incr(mp->nl);
23515   if ( mp->cur_cmd==comma ) goto CONTINUE;
23516   if ( skip_byte(mp->nl-1)<stop_flag ) skip_byte(mp->nl-1)=stop_flag;
23517 }
23518 DONE:
23519
23520 @ @<Put each...@>=
23521 mp_primitive(mp, "=:",lig_kern_token,0);
23522 @:=:_}{\.{=:} primitive@>
23523 mp_primitive(mp, "=:|",lig_kern_token,1);
23524 @:=:/_}{\.{=:\char'174} primitive@>
23525 mp_primitive(mp, "=:|>",lig_kern_token,5);
23526 @:=:/>_}{\.{=:\char'174>} primitive@>
23527 mp_primitive(mp, "|=:",lig_kern_token,2);
23528 @:=:/_}{\.{\char'174=:} primitive@>
23529 mp_primitive(mp, "|=:>",lig_kern_token,6);
23530 @:=:/>_}{\.{\char'174=:>} primitive@>
23531 mp_primitive(mp, "|=:|",lig_kern_token,3);
23532 @:=:/_}{\.{\char'174=:\char'174} primitive@>
23533 mp_primitive(mp, "|=:|>",lig_kern_token,7);
23534 @:=:/>_}{\.{\char'174=:\char'174>} primitive@>
23535 mp_primitive(mp, "|=:|>>",lig_kern_token,11);
23536 @:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
23537 mp_primitive(mp, "kern",lig_kern_token,128);
23538 @:kern_}{\&{kern} primitive@>
23539
23540 @ @<Cases of |print_cmd...@>=
23541 case lig_kern_token: 
23542   switch (m) {
23543   case 0:mp_print(mp, "=:"); break;
23544   case 1:mp_print(mp, "=:|"); break;
23545   case 2:mp_print(mp, "|=:"); break;
23546   case 3:mp_print(mp, "|=:|"); break;
23547   case 5:mp_print(mp, "=:|>"); break;
23548   case 6:mp_print(mp, "|=:>"); break;
23549   case 7:mp_print(mp, "|=:|>"); break;
23550   case 11:mp_print(mp, "|=:|>>"); break;
23551   default: mp_print(mp, "kern"); break;
23552   }
23553   break;
23554
23555 @ Local labels are implemented by maintaining the |skip_table| array,
23556 where |skip_table[c]| is either |undefined_label| or the address of the
23557 most recent lig/kern instruction that skips to local label~|c|. In the
23558 latter case, the |skip_byte| in that instruction will (temporarily)
23559 be zero if there were no prior skips to this label, or it will be the
23560 distance to the prior skip.
23561
23562 We may need to cancel skips that span more than 127 lig/kern steps.
23563
23564 @d cancel_skips(A) mp->ll=(A);
23565   do {  
23566     mp->lll=qo(skip_byte(mp->ll)); 
23567     skip_byte(mp->ll)=stop_flag; mp->ll=mp->ll-mp->lll;
23568   } while (mp->lll!=0)
23569 @d skip_error(A) { print_err("Too far to skip");
23570 @.Too far to skip@>
23571   help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
23572   mp_error(mp); cancel_skips((A));
23573   }
23574
23575 @<Process a |skip_to| command and |goto done|@>=
23576
23577   c=mp_get_code(mp);
23578   if ( mp->nl-mp->skip_table[c]>128 ) { /* |skip_table[c]<<nl<=undefined_label| */
23579     skip_error(mp->skip_table[c]); mp->skip_table[c]=undefined_label;
23580   }
23581   if ( mp->skip_table[c]==undefined_label ) skip_byte(mp->nl-1)=qi(0);
23582   else skip_byte(mp->nl-1)=qi(mp->nl-mp->skip_table[c]-1);
23583   mp->skip_table[c]=mp->nl-1; goto DONE;
23584 }
23585
23586 @ @<Record a label in a lig/kern subprogram and |goto continue|@>=
23587
23588   if ( mp->cur_cmd==colon ) {
23589     if ( c==256 ) mp->bch_label=mp->nl;
23590     else mp_set_tag(mp, c,lig_tag,mp->nl);
23591   } else if ( mp->skip_table[c]<undefined_label ) {
23592     mp->ll=mp->skip_table[c]; mp->skip_table[c]=undefined_label;
23593     do {  
23594       mp->lll=qo(skip_byte(mp->ll));
23595       if ( mp->nl-mp->ll>128 ) {
23596         skip_error(mp->ll); goto CONTINUE;
23597       }
23598       skip_byte(mp->ll)=qi(mp->nl-mp->ll-1); mp->ll=mp->ll-mp->lll;
23599     } while (mp->lll!=0);
23600   }
23601   goto CONTINUE;
23602 }
23603
23604 @ @<Compile a ligature/kern...@>=
23605
23606   next_char(mp->nl)=qi(c); skip_byte(mp->nl)=qi(0);
23607   if ( mp->cur_mod<128 ) { /* ligature op */
23608     op_byte(mp->nl)=qi(mp->cur_mod); rem_byte(mp->nl)=qi(mp_get_code(mp));
23609   } else { 
23610     mp_get_x_next(mp); mp_scan_expression(mp);
23611     if ( mp->cur_type!=mp_known ) {
23612       exp_err("Improper kern");
23613 @.Improper kern@>
23614       help2("The amount of kern should be a known numeric value.")
23615         ("I'm zeroing this one. Proceed, with fingers crossed.");
23616       mp_put_get_flush_error(mp, 0);
23617     }
23618     mp->kern[mp->nk]=mp->cur_exp;
23619     k=0; 
23620     while ( mp->kern[k]!=mp->cur_exp ) incr(k);
23621     if ( k==mp->nk ) {
23622       if ( mp->nk==max_tfm_int ) mp_fatal_error(mp, "too many TFM kerns");
23623       incr(mp->nk);
23624     }
23625     op_byte(mp->nl)=kern_flag+(k / 256);
23626     rem_byte(mp->nl)=qi((k % 256));
23627   }
23628   mp->lk_started=true;
23629 }
23630
23631 @ @d missing_extensible_punctuation(A) 
23632   { mp_missing_err(mp, (A));
23633 @.Missing `\char`\#'@>
23634   help1("I'm processing `extensible c: t,m,b,r'."); mp_back_error(mp);
23635   }
23636
23637 @<Define an extensible recipe@>=
23638
23639   if ( mp->ne==256 ) mp_fatal_error(mp, "too many extensible recipies");
23640   c=mp_get_code(mp); mp_set_tag(mp, c,ext_tag,mp->ne);
23641   if ( mp->cur_cmd!=colon ) missing_extensible_punctuation(":");
23642   ext_top(mp->ne)=qi(mp_get_code(mp));
23643   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23644   ext_mid(mp->ne)=qi(mp_get_code(mp));
23645   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23646   ext_bot(mp->ne)=qi(mp_get_code(mp));
23647   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
23648   ext_rep(mp->ne)=qi(mp_get_code(mp));
23649   incr(mp->ne);
23650 }
23651
23652 @ The header could contain ASCII zeroes, so can't use |strdup|.
23653
23654 @<Store a list of header bytes@>=
23655 do {  
23656   if ( j>=mp->header_size ) {
23657     int l = mp->header_size + (mp->header_size >> 2);
23658     char *t = xmalloc(l,sizeof(char));
23659     memset(t,0,l); 
23660     memcpy(t,mp->header_byte,mp->header_size);
23661     xfree (mp->header_byte);
23662     mp->header_byte = t;
23663     mp->header_size = l;
23664   }
23665   mp->header_byte[j]=mp_get_code(mp); 
23666   incr(j); incr(mp->header_last);
23667 } while (mp->cur_cmd==comma)
23668
23669 @ @<Store a list of font dimensions@>=
23670 do {  
23671   if ( j>max_tfm_int ) mp_fatal_error(mp, "too many fontdimens");
23672   while ( j>mp->np ) { incr(mp->np); mp->param[mp->np]=0; };
23673   mp_get_x_next(mp); mp_scan_expression(mp);
23674   if ( mp->cur_type!=mp_known ){ 
23675     exp_err("Improper font parameter");
23676 @.Improper font parameter@>
23677     help1("I'm zeroing this one. Proceed, with fingers crossed.");
23678     mp_put_get_flush_error(mp, 0);
23679   }
23680   mp->param[j]=mp->cur_exp; incr(j);
23681 } while (mp->cur_cmd==comma)
23682
23683 @ OK: We've stored all the data that is needed for the \.{TFM} file.
23684 All that remains is to output it in the correct format.
23685
23686 An interesting problem needs to be solved in this connection, because
23687 the \.{TFM} format allows at most 256~widths, 16~heights, 16~depths,
23688 and 64~italic corrections. If the data has more distinct values than
23689 this, we want to meet the necessary restrictions by perturbing the
23690 given values as little as possible.
23691
23692 \MP\ solves this problem in two steps. First the values of a given
23693 kind (widths, heights, depths, or italic corrections) are sorted;
23694 then the list of sorted values is perturbed, if necessary.
23695
23696 The sorting operation is facilitated by having a special node of
23697 essentially infinite |value| at the end of the current list.
23698
23699 @<Initialize table entries...@>=
23700 value(inf_val)=fraction_four;
23701
23702 @ Straight linear insertion is good enough for sorting, since the lists
23703 are usually not terribly long. As we work on the data, the current list
23704 will start at |link(temp_head)| and end at |inf_val|; the nodes in this
23705 list will be in increasing order of their |value| fields.
23706
23707 Given such a list, the |sort_in| function takes a value and returns a pointer
23708 to where that value can be found in the list. The value is inserted in
23709 the proper place, if necessary.
23710
23711 At the time we need to do these operations, most of \MP's work has been
23712 completed, so we will have plenty of memory to play with. The value nodes
23713 that are allocated for sorting will never be returned to free storage.
23714
23715 @d clear_the_list link(temp_head)=inf_val
23716
23717 @c pointer mp_sort_in (MP mp,scaled v) {
23718   pointer p,q,r; /* list manipulation registers */
23719   p=temp_head;
23720   while (1) { 
23721     q=link(p);
23722     if ( v<=value(q) ) break;
23723     p=q;
23724   }
23725   if ( v<value(q) ) {
23726     r=mp_get_node(mp, value_node_size); value(r)=v; link(r)=q; link(p)=r;
23727   }
23728   return link(p);
23729 }
23730
23731 @ Now we come to the interesting part, where we reduce the list if necessary
23732 until it has the required size. The |min_cover| routine is basic to this
23733 process; it computes the minimum number~|m| such that the values of the
23734 current sorted list can be covered by |m|~intervals of width~|d|. It
23735 also sets the global value |perturbation| to the smallest value $d'>d$
23736 such that the covering found by this algorithm would be different.
23737
23738 In particular, |min_cover(0)| returns the number of distinct values in the
23739 current list and sets |perturbation| to the minimum distance between
23740 adjacent values.
23741
23742 @c integer mp_min_cover (MP mp,scaled d) {
23743   pointer p; /* runs through the current list */
23744   scaled l; /* the least element covered by the current interval */
23745   integer m; /* lower bound on the size of the minimum cover */
23746   m=0; p=link(temp_head); mp->perturbation=el_gordo;
23747   while ( p!=inf_val ){ 
23748     incr(m); l=value(p);
23749     do {  p=link(p); } while (value(p)<=l+d);
23750     if ( value(p)-l<mp->perturbation ) 
23751       mp->perturbation=value(p)-l;
23752   }
23753   return m;
23754 }
23755
23756 @ @<Glob...@>=
23757 scaled perturbation; /* quantity related to \.{TFM} rounding */
23758 integer excess; /* the list is this much too long */
23759
23760 @ The smallest |d| such that a given list can be covered with |m| intervals
23761 is determined by the |threshold| routine, which is sort of an inverse
23762 to |min_cover|. The idea is to increase the interval size rapidly until
23763 finding the range, then to go sequentially until the exact borderline has
23764 been discovered.
23765
23766 @c scaled mp_threshold (MP mp,integer m) {
23767   scaled d; /* lower bound on the smallest interval size */
23768   mp->excess=mp_min_cover(mp, 0)-m;
23769   if ( mp->excess<=0 ) {
23770     return 0;
23771   } else  { 
23772     do {  
23773       d=mp->perturbation;
23774     } while (mp_min_cover(mp, d+d)>m);
23775     while ( mp_min_cover(mp, d)>m ) 
23776       d=mp->perturbation;
23777     return d;
23778   }
23779 }
23780
23781 @ The |skimp| procedure reduces the current list to at most |m| entries,
23782 by changing values if necessary. It also sets |info(p):=k| if |value(p)|
23783 is the |k|th distinct value on the resulting list, and it sets
23784 |perturbation| to the maximum amount by which a |value| field has
23785 been changed. The size of the resulting list is returned as the
23786 value of |skimp|.
23787
23788 @c integer mp_skimp (MP mp,integer m) {
23789   scaled d; /* the size of intervals being coalesced */
23790   pointer p,q,r; /* list manipulation registers */
23791   scaled l; /* the least value in the current interval */
23792   scaled v; /* a compromise value */
23793   d=mp_threshold(mp, m); mp->perturbation=0;
23794   q=temp_head; m=0; p=link(temp_head);
23795   while ( p!=inf_val ) {
23796     incr(m); l=value(p); info(p)=m;
23797     if ( value(link(p))<=l+d ) {
23798       @<Replace an interval of values by its midpoint@>;
23799     }
23800     q=p; p=link(p);
23801   }
23802   return m;
23803 }
23804
23805 @ @<Replace an interval...@>=
23806
23807   do {  
23808     p=link(p); info(p)=m;
23809     decr(mp->excess); if ( mp->excess==0 ) d=0;
23810   } while (value(link(p))<=l+d);
23811   v=l+halfp(value(p)-l);
23812   if ( value(p)-v>mp->perturbation ) 
23813     mp->perturbation=value(p)-v;
23814   r=q;
23815   do {  
23816     r=link(r); value(r)=v;
23817   } while (r!=p);
23818   link(q)=p; /* remove duplicate values from the current list */
23819 }
23820
23821 @ A warning message is issued whenever something is perturbed by
23822 more than 1/16\thinspace pt.
23823
23824 @c void mp_tfm_warning (MP mp,small_number m) { 
23825   mp_print_nl(mp, "(some "); 
23826   mp_print(mp, mp->int_name[m]);
23827 @.some charwds...@>
23828 @.some chardps...@>
23829 @.some charhts...@>
23830 @.some charics...@>
23831   mp_print(mp, " values had to be adjusted by as much as ");
23832   mp_print_scaled(mp, mp->perturbation); mp_print(mp, "pt)");
23833 }
23834
23835 @ Here's an example of how we use these routines.
23836 The width data needs to be perturbed only if there are 256 distinct
23837 widths, but \MP\ must check for this case even though it is
23838 highly unusual.
23839
23840 An integer variable |k| will be defined when we use this code.
23841 The |dimen_head| array will contain pointers to the sorted
23842 lists of dimensions.
23843
23844 @<Massage the \.{TFM} widths@>=
23845 clear_the_list;
23846 for (k=mp->bc;k<=mp->ec;k++)  {
23847   if ( mp->char_exists[k] )
23848     mp->tfm_width[k]=mp_sort_in(mp, mp->tfm_width[k]);
23849 }
23850 mp->nw=mp_skimp(mp, 255)+1; mp->dimen_head[1]=link(temp_head);
23851 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_wd)
23852
23853 @ @<Glob...@>=
23854 pointer dimen_head[5]; /* lists of \.{TFM} dimensions */
23855
23856 @ Heights, depths, and italic corrections are different from widths
23857 not only because their list length is more severely restricted, but
23858 also because zero values do not need to be put into the lists.
23859
23860 @<Massage the \.{TFM} heights, depths, and italic corrections@>=
23861 clear_the_list;
23862 for (k=mp->bc;k<=mp->ec;k++) {
23863   if ( mp->char_exists[k] ) {
23864     if ( mp->tfm_height[k]==0 ) mp->tfm_height[k]=zero_val;
23865     else mp->tfm_height[k]=mp_sort_in(mp, mp->tfm_height[k]);
23866   }
23867 }
23868 mp->nh=mp_skimp(mp, 15)+1; mp->dimen_head[2]=link(temp_head);
23869 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_ht);
23870 clear_the_list;
23871 for (k=mp->bc;k<=mp->ec;k++) {
23872   if ( mp->char_exists[k] ) {
23873     if ( mp->tfm_depth[k]==0 ) mp->tfm_depth[k]=zero_val;
23874     else mp->tfm_depth[k]=mp_sort_in(mp, mp->tfm_depth[k]);
23875   }
23876 }
23877 mp->nd=mp_skimp(mp, 15)+1; mp->dimen_head[3]=link(temp_head);
23878 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_dp);
23879 clear_the_list;
23880 for (k=mp->bc;k<=mp->ec;k++) {
23881   if ( mp->char_exists[k] ) {
23882     if ( mp->tfm_ital_corr[k]==0 ) mp->tfm_ital_corr[k]=zero_val;
23883     else mp->tfm_ital_corr[k]=mp_sort_in(mp, mp->tfm_ital_corr[k]);
23884   }
23885 }
23886 mp->ni=mp_skimp(mp, 63)+1; mp->dimen_head[4]=link(temp_head);
23887 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, char_ic)
23888
23889 @ @<Initialize table entries...@>=
23890 value(zero_val)=0; info(zero_val)=0;
23891
23892 @ Bytes 5--8 of the header are set to the design size, unless the user has
23893 some crazy reason for specifying them differently.
23894
23895 Error messages are not allowed at the time this procedure is called,
23896 so a warning is printed instead.
23897
23898 The value of |max_tfm_dimen| is calculated so that
23899 $$\hbox{|make_scaled(16*max_tfm_dimen,internal[design_size])|}
23900  < \\{three\_bytes}.$$
23901
23902 @d three_bytes 0100000000 /* $2^{24}$ */
23903
23904 @c 
23905 void mp_fix_design_size (MP mp) {
23906   scaled d; /* the design size */
23907   d=mp->internal[design_size];
23908   if ( (d<unity)||(d>=fraction_half) ) {
23909     if ( d!=0 )
23910       mp_print_nl(mp, "(illegal design size has been changed to 128pt)");
23911 @.illegal design size...@>
23912     d=040000000; mp->internal[design_size]=d;
23913   }
23914   if ( mp->header_byte[4]<0 ) if ( mp->header_byte[5]<0 )
23915     if ( mp->header_byte[6]<0 ) if ( mp->header_byte[7]<0 ) {
23916      mp->header_byte[4]=d / 04000000;
23917      mp->header_byte[5]=(d / 4096) % 256;
23918      mp->header_byte[6]=(d / 16) % 256;
23919      mp->header_byte[7]=(d % 16)*16;
23920   };
23921   mp->max_tfm_dimen=16*mp->internal[design_size]-mp->internal[design_size] / 010000000;
23922   if ( mp->max_tfm_dimen>=fraction_half ) mp->max_tfm_dimen=fraction_half-1;
23923 }
23924
23925 @ The |dimen_out| procedure computes a |fix_word| relative to the
23926 design size. If the data was out of range, it is corrected and the
23927 global variable |tfm_changed| is increased by~one.
23928
23929 @c integer mp_dimen_out (MP mp,scaled x) { 
23930   if ( abs(x)>mp->max_tfm_dimen ) {
23931     incr(mp->tfm_changed);
23932     if ( x>0 ) x=three_bytes-1; else x=1-three_bytes;
23933   } else {
23934     x=mp_make_scaled(mp, x*16,mp->internal[design_size]);
23935   }
23936   return x;
23937 }
23938
23939 @ @<Glob...@>=
23940 scaled max_tfm_dimen; /* bound on widths, heights, kerns, etc. */
23941 integer tfm_changed; /* the number of data entries that were out of bounds */
23942
23943 @ If the user has not specified any of the first four header bytes,
23944 the |fix_check_sum| procedure replaces them by a ``check sum'' computed
23945 from the |tfm_width| data relative to the design size.
23946 @^check sum@>
23947
23948 @c void mp_fix_check_sum (MP mp) {
23949   eight_bits k; /* runs through character codes */
23950   eight_bits B1,B2,B3,B4; /* bytes of the check sum */
23951   integer x;  /* hash value used in check sum computation */
23952   if ( mp->header_byte[0]==0 && mp->header_byte[1]==0 &&
23953        mp->header_byte[2]==0 && mp->header_byte[3]==0 ) {
23954     @<Compute a check sum in |(b1,b2,b3,b4)|@>;
23955     mp->header_byte[0]=B1; mp->header_byte[1]=B2;
23956     mp->header_byte[2]=B3; mp->header_byte[3]=B4; 
23957     return;
23958   }
23959 }
23960
23961 @ @<Compute a check sum in |(b1,b2,b3,b4)|@>=
23962 B1=mp->bc; B2=mp->ec; B3=mp->bc; B4=mp->ec; mp->tfm_changed=0;
23963 for (k=mp->bc;k<=mp->ec;k++) { 
23964   if ( mp->char_exists[k] ) {
23965     x=mp_dimen_out(mp, value(mp->tfm_width[k]))+(k+4)*020000000; /* this is positive */
23966     B1=(B1+B1+x) % 255;
23967     B2=(B2+B2+x) % 253;
23968     B3=(B3+B3+x) % 251;
23969     B4=(B4+B4+x) % 247;
23970   }
23971 }
23972
23973 @ Finally we're ready to actually write the \.{TFM} information.
23974 Here are some utility routines for this purpose.
23975
23976 @d tfm_out(A) fputc((A),mp->tfm_file) /* output one byte to |tfm_file| */
23977
23978 @c void mp_tfm_two (MP mp,integer x) { /* output two bytes to |tfm_file| */
23979   tfm_out(x / 256); tfm_out(x % 256);
23980 }
23981 void mp_tfm_four (MP mp,integer x) { /* output four bytes to |tfm_file| */
23982   if ( x>=0 ) tfm_out(x / three_bytes);
23983   else { 
23984     x=x+010000000000; /* use two's complement for negative values */
23985     x=x+010000000000;
23986     tfm_out((x / three_bytes) + 128);
23987   };
23988   x=x % three_bytes; tfm_out(x / unity);
23989   x=x % unity; tfm_out(x / 0400);
23990   tfm_out(x % 0400);
23991 }
23992 void mp_tfm_qqqq (MP mp,four_quarters x) { /* output four quarterwords to |tfm_file| */
23993   tfm_out(qo(x.b0)); tfm_out(qo(x.b1)); 
23994   tfm_out(qo(x.b2)); tfm_out(qo(x.b3));
23995 }
23996
23997 @ @<Finish the \.{TFM} file@>=
23998 if ( mp->job_name==NULL ) mp_open_log_file(mp);
23999 mp_pack_job_name(mp, ".tfm");
24000 while ( ! mp_b_open_out(mp, &mp->tfm_file, mp_filetype_metrics) )
24001   mp_prompt_file_name(mp, "file name for font metrics",".tfm");
24002 mp->metric_file_name=xstrdup(mp->name_of_file);
24003 @<Output the subfile sizes and header bytes@>;
24004 @<Output the character information bytes, then
24005   output the dimensions themselves@>;
24006 @<Output the ligature/kern program@>;
24007 @<Output the extensible character recipes and the font metric parameters@>;
24008   if ( mp->internal[tracing_stats]>0 )
24009   @<Log the subfile sizes of the \.{TFM} file@>;
24010 mp_print_nl(mp, "Font metrics written on "); 
24011 mp_print(mp, mp->metric_file_name); mp_print_char(mp, '.');
24012 @.Font metrics written...@>
24013 fclose(mp->tfm_file)
24014
24015 @ Integer variables |lh|, |k|, and |lk_offset| will be defined when we use
24016 this code.
24017
24018 @<Output the subfile sizes and header bytes@>=
24019 k=mp->header_last;
24020 LH=(k+3) / 4; /* this is the number of header words */
24021 if ( mp->bc>mp->ec ) mp->bc=1; /* if there are no characters, |ec=0| and |bc=1| */
24022 @<Compute the ligature/kern program offset and implant the
24023   left boundary label@>;
24024 mp_tfm_two(mp,6+LH+(mp->ec-mp->bc+1)+mp->nw+mp->nh+mp->nd+mp->ni+mp->nl
24025      +lk_offset+mp->nk+mp->ne+mp->np);
24026   /* this is the total number of file words that will be output */
24027 mp_tfm_two(mp, LH); mp_tfm_two(mp, mp->bc); mp_tfm_two(mp, mp->ec); 
24028 mp_tfm_two(mp, mp->nw); mp_tfm_two(mp, mp->nh);
24029 mp_tfm_two(mp, mp->nd); mp_tfm_two(mp, mp->ni); mp_tfm_two(mp, mp->nl+lk_offset); 
24030 mp_tfm_two(mp, mp->nk); mp_tfm_two(mp, mp->ne);
24031 mp_tfm_two(mp, mp->np);
24032 for (k=0;k< 4*LH;k++)   { 
24033   tfm_out(mp->header_byte[k]);
24034 }
24035
24036 @ @<Output the character information bytes...@>=
24037 for (k=mp->bc;k<=mp->ec;k++) {
24038   if ( ! mp->char_exists[k] ) {
24039     mp_tfm_four(mp, 0);
24040   } else { 
24041     tfm_out(info(mp->tfm_width[k])); /* the width index */
24042     tfm_out((info(mp->tfm_height[k]))*16+info(mp->tfm_depth[k]));
24043     tfm_out((info(mp->tfm_ital_corr[k]))*4+mp->char_tag[k]);
24044     tfm_out(mp->char_remainder[k]);
24045   };
24046 }
24047 mp->tfm_changed=0;
24048 for (k=1;k<=4;k++) { 
24049   mp_tfm_four(mp, 0); p=mp->dimen_head[k];
24050   while ( p!=inf_val ) {
24051     mp_tfm_four(mp, mp_dimen_out(mp, value(p))); p=link(p);
24052   }
24053 }
24054
24055
24056 @ We need to output special instructions at the beginning of the
24057 |lig_kern| array in order to specify the right boundary character
24058 and/or to handle starting addresses that exceed 255. The |label_loc|
24059 and |label_char| arrays have been set up to record all the
24060 starting addresses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
24061 \le|label_loc|[|label_ptr]|$.
24062
24063 @<Compute the ligature/kern program offset...@>=
24064 mp->bchar=mp_round_unscaled(mp, mp->internal[boundary_char]);
24065 if ((mp->bchar<0)||(mp->bchar>255))
24066   { mp->bchar=-1; mp->lk_started=false; lk_offset=0; }
24067 else { mp->lk_started=true; lk_offset=1; };
24068 @<Find the minimum |lk_offset| and adjust all remainders@>;
24069 if ( mp->bch_label<undefined_label )
24070   { skip_byte(mp->nl)=qi(255); next_char(mp->nl)=qi(0);
24071   op_byte(mp->nl)=qi(((mp->bch_label+lk_offset)/ 256));
24072   rem_byte(mp->nl)=qi(((mp->bch_label+lk_offset)% 256));
24073   incr(mp->nl); /* possibly |nl=lig_table_size+1| */
24074   }
24075
24076 @ @<Find the minimum |lk_offset|...@>=
24077 k=mp->label_ptr; /* pointer to the largest unallocated label */
24078 if ( mp->label_loc[k]+lk_offset>255 ) {
24079   lk_offset=0; mp->lk_started=false; /* location 0 can do double duty */
24080   do {  
24081     mp->char_remainder[mp->label_char[k]]=lk_offset;
24082     while ( mp->label_loc[k-1]==mp->label_loc[k] ) {
24083        decr(k); mp->char_remainder[mp->label_char[k]]=lk_offset;
24084     }
24085     incr(lk_offset); decr(k);
24086   } while (! (lk_offset+mp->label_loc[k]<256));
24087     /* N.B.: |lk_offset=256| satisfies this when |k=0| */
24088 };
24089 if ( lk_offset>0 ) {
24090   while ( k>0 ) {
24091     mp->char_remainder[mp->label_char[k]]
24092      =mp->char_remainder[mp->label_char[k]]+lk_offset;
24093     decr(k);
24094   }
24095 }
24096
24097 @ @<Output the ligature/kern program@>=
24098 for (k=0;k<= 255;k++ ) {
24099   if ( mp->skip_table[k]<undefined_label ) {
24100      mp_print_nl(mp, "(local label "); mp_print_int(mp, k); mp_print(mp, ":: was missing)");
24101 @.local label l:: was missing@>
24102     cancel_skips(mp->skip_table[k]);
24103   }
24104 }
24105 if ( mp->lk_started ) { /* |lk_offset=1| for the special |bchar| */
24106   tfm_out(255); tfm_out(mp->bchar); mp_tfm_two(mp, 0);
24107 } else {
24108   for (k=1;k<=lk_offset;k++) {/* output the redirection specs */
24109     mp->ll=mp->label_loc[mp->label_ptr];
24110     if ( mp->bchar<0 ) { tfm_out(254); tfm_out(0);   }
24111     else { tfm_out(255); tfm_out(mp->bchar);   };
24112     mp_tfm_two(mp, mp->ll+lk_offset);
24113     do {  
24114       decr(mp->label_ptr);
24115     } while (! (mp->label_loc[mp->label_ptr]<mp->ll));
24116   }
24117 }
24118 for (k=0;k<=mp->nl-1;k++) mp_tfm_qqqq(mp, mp->lig_kern[k]);
24119 for (k=0;k<=mp->nk-1;k++) mp_tfm_four(mp, mp_dimen_out(mp, mp->kern[k]))
24120
24121 @ @<Output the extensible character recipes...@>=
24122 for (k=0;k<=mp->ne-1;k++) 
24123   mp_tfm_qqqq(mp, mp->exten[k]);
24124 for (k=1;k<=mp->np;k++) {
24125   if ( k==1 ) {
24126     if ( abs(mp->param[1])<fraction_half ) {
24127       mp_tfm_four(mp, mp->param[1]*16);
24128     } else  { 
24129       incr(mp->tfm_changed);
24130       if ( mp->param[1]>0 ) mp_tfm_four(mp, el_gordo);
24131       else mp_tfm_four(mp, -el_gordo);
24132     }
24133   } else {
24134     mp_tfm_four(mp, mp_dimen_out(mp, mp->param[k]));
24135   }
24136 }
24137 if ( mp->tfm_changed>0 )  { 
24138   if ( mp->tfm_changed==1 ) mp_print_nl(mp, "(a font metric dimension");
24139 @.a font metric dimension...@>
24140   else  { 
24141     mp_print_nl(mp, "("); mp_print_int(mp, mp->tfm_changed);
24142 @.font metric dimensions...@>
24143     mp_print(mp, " font metric dimensions");
24144   }
24145   mp_print(mp, " had to be decreased)");
24146 }
24147
24148 @ @<Log the subfile sizes of the \.{TFM} file@>=
24149
24150   char s[200];
24151   wlog_ln(" ");
24152   if ( mp->bch_label<undefined_label ) decr(mp->nl);
24153   snprintf(s,128,"(You used %iw,%ih,%id,%ii,%il,%ik,%ie,%ip metric file positions)",
24154                  mp->nw, mp->nh, mp->nd, mp->ni, mp->nl, mp->nk, mp->ne,mp->np);
24155   wlog_ln(s);
24156 }
24157
24158 @* \[43] Reading font metric data.
24159
24160 \MP\ isn't a typesetting program but it does need to find the bounding box
24161 of a sequence of typeset characters.  Thus it needs to read \.{TFM} files as
24162 well as write them.
24163
24164 @<Glob...@>=
24165 FILE * tfm_infile;
24166
24167 @ All the width, height, and depth information is stored in an array called
24168 |font_info|.  This array is allocated sequentially and each font is stored
24169 as a series of |char_info| words followed by the width, height, and depth
24170 tables.  Since |font_name| entries are permanent, their |str_ref| values are
24171 set to |max_str_ref|.
24172
24173 @<Types...@>=
24174 typedef unsigned int font_number; /* |0..font_max| */
24175
24176 @ The |font_info| array is indexed via a group directory arrays.
24177 For example, the |char_info| data for character~|c| in font~|f| will be
24178 in |font_info[char_base[f]+c].qqqq|.
24179
24180 @<Glob...@>=
24181 font_number font_max; /* maximum font number for included text fonts */
24182 size_t      font_mem_size; /* number of words for \.{TFM} information for text fonts */
24183 memory_word *font_info; /* height, width, and depth data */
24184 char        **font_enc_name; /* encoding names, if any */
24185 boolean     *font_ps_name_fixed; /* are the postscript names fixed already?  */
24186 int         next_fmem; /* next unused entry in |font_info| */
24187 font_number last_fnum; /* last font number used so far */
24188 scaled      *font_dsize;  /* 16 times the ``design'' size in \ps\ points */
24189 char        **font_name;  /* name as specified in the \&{infont} command */
24190 char        **font_ps_name;  /* PostScript name for use when |internal[prologues]>0| */
24191 font_number last_ps_fnum; /* last valid |font_ps_name| index */
24192 eight_bits  *font_bc;
24193 eight_bits  *font_ec;  /* first and last character code */
24194 int         *char_base;  /* base address for |char_info| */
24195 int         *width_base; /* index for zeroth character width */
24196 int         *height_base; /* index for zeroth character height */
24197 int         *depth_base; /* index for zeroth character depth */
24198 pointer     *font_sizes;
24199
24200 @ @<Allocate or initialize ...@>=
24201 mp->font_mem_size = 10000; 
24202 mp->font_info = xmalloc ((mp->font_mem_size+1),sizeof(memory_word));
24203 memset (mp->font_info,0,sizeof(memory_word)*(mp->font_mem_size+1));
24204 mp->font_enc_name = NULL;
24205 mp->font_ps_name_fixed = NULL;
24206 mp->font_dsize = NULL;
24207 mp->font_name = NULL;
24208 mp->font_ps_name = NULL;
24209 mp->font_bc = NULL;
24210 mp->font_ec = NULL;
24211 mp->last_fnum = null_font;
24212 mp->char_base = NULL;
24213 mp->width_base = NULL;
24214 mp->height_base = NULL;
24215 mp->depth_base = NULL;
24216 mp->font_sizes = null;
24217
24218 @ @<Dealloc variables@>=
24219 xfree(mp->font_info);
24220 xfree(mp->font_enc_name);
24221 xfree(mp->font_ps_name_fixed);
24222 xfree(mp->font_dsize);
24223 xfree(mp->font_name);
24224 xfree(mp->font_ps_name);
24225 xfree(mp->font_bc);
24226 xfree(mp->font_ec);
24227 xfree(mp->char_base);
24228 xfree(mp->width_base);
24229 xfree(mp->height_base);
24230 xfree(mp->depth_base);
24231 xfree(mp->font_sizes);
24232
24233
24234 @c 
24235 void mp_reallocate_fonts (MP mp, font_number l) {
24236   font_number f;
24237   XREALLOC(mp->font_enc_name,      l, char *);
24238   XREALLOC(mp->font_ps_name_fixed, l, boolean);
24239   XREALLOC(mp->font_dsize,         l, scaled);
24240   XREALLOC(mp->font_name,          l, char *);
24241   XREALLOC(mp->font_ps_name,       l, char *);
24242   XREALLOC(mp->font_bc,            l, eight_bits);
24243   XREALLOC(mp->font_ec,            l, eight_bits);
24244   XREALLOC(mp->char_base,          l, int);
24245   XREALLOC(mp->width_base,         l, int);
24246   XREALLOC(mp->height_base,        l, int);
24247   XREALLOC(mp->depth_base,         l, int);
24248   XREALLOC(mp->font_sizes,         l, pointer);
24249   for (f=(mp->last_fnum+1);f<=l;f++) {
24250     mp->font_enc_name[f]=NULL;
24251     mp->font_ps_name_fixed[f] = false;
24252     mp->font_name[f]=NULL;
24253     mp->font_ps_name[f]=NULL;
24254     mp->font_sizes[f]=null;
24255   }
24256   mp->font_max = l;
24257 }
24258
24259 @ @<Declare |mp_reallocate| functions@>=
24260 void mp_reallocate_fonts (MP mp, font_number l);
24261
24262
24263 @ A |null_font| containing no characters is useful for error recovery.  Its
24264 |font_name| entry starts out empty but is reset each time an erroneous font is
24265 found.  This helps to cut down on the number of duplicate error messages without
24266 wasting a lot of space.
24267
24268 @d null_font 0 /* the |font_number| for an empty font */
24269
24270 @<Set initial...@>=
24271 mp->font_dsize[null_font]=0;
24272 mp->font_bc[null_font]=1;
24273 mp->font_ec[null_font]=0;
24274 mp->char_base[null_font]=0;
24275 mp->width_base[null_font]=0;
24276 mp->height_base[null_font]=0;
24277 mp->depth_base[null_font]=0;
24278 mp->next_fmem=0;
24279 mp->last_fnum=null_font;
24280 mp->last_ps_fnum=null_font;
24281 mp->font_name[null_font]="nullfont";
24282 mp->font_ps_name[null_font]="";
24283
24284 @ Each |char_info| word is of type |four_quarters|.  The |b0| field contains
24285 the |width index|; the |b1| field contains the height
24286 index; the |b2| fields contains the depth index, and the |b3| field used only
24287 for temporary storage. (It is used to keep track of which characters occur in
24288 an edge structure that is being shipped out.)
24289 The corresponding words in the width, height, and depth tables are stored as
24290 |scaled| values in units of \ps\ points.
24291
24292 With the macros below, the |char_info| word for character~|c| in font~|f| is
24293 |char_info(f)(c)| and the width is
24294 $$\hbox{|char_width(f)(char_info(f)(c)).sc|.}$$
24295
24296 @d char_info_end(A) (A)].qqqq
24297 @d char_info(A) mp->font_info[mp->char_base[(A)]+char_info_end
24298 @d char_width_end(A) (A).b0].sc
24299 @d char_width(A) mp->font_info[mp->width_base[(A)]+char_width_end
24300 @d char_height_end(A) (A).b1].sc
24301 @d char_height(A) mp->font_info[mp->height_base[(A)]+char_height_end
24302 @d char_depth_end(A) (A).b2].sc
24303 @d char_depth(A) mp->font_info[mp->depth_base[(A)]+char_depth_end
24304 @d ichar_exists(A) ((A).b0>0)
24305
24306 @ The |font_ps_name| for a built-in font should be what PostScript expects.
24307 A preliminary name is obtained here from the \.{TFM} name as given in the
24308 |fname| argument.  This gets updated later from an external table if necessary.
24309
24310 @<Declare text measuring subroutines@>=
24311 @<Declare subroutines for parsing file names@>;
24312 font_number mp_read_font_info (MP mp, char*fname) {
24313   boolean file_opened; /* has |tfm_infile| been opened? */
24314   font_number n; /* the number to return */
24315   halfword lf,tfm_lh,bc,ec,nw,nh,nd; /* subfile size parameters */
24316   size_t whd_size; /* words needed for heights, widths, and depths */
24317   int i,ii; /* |font_info| indices */
24318   int jj; /* counts bytes to be ignored */
24319   scaled z; /* used to compute the design size */
24320   fraction d;
24321   /* height, width, or depth as a fraction of design size times $2^{-8}$ */
24322   eight_bits h_and_d; /* height and depth indices being unpacked */
24323   int tfbyte; /* a byte read from the file */
24324   n=null_font;
24325   @<Open |tfm_infile| for input@>;
24326   @<Read data from |tfm_infile|; if there is no room, say so and |goto done|;
24327     otherwise |goto bad_tfm| or |goto done| as appropriate@>;
24328 BAD_TFM:
24329   @<Complain that the \.{TFM} file is bad@>;
24330 DONE:
24331   if ( file_opened ) fclose(mp->tfm_infile);
24332   if ( n!=null_font ) { 
24333     mp->font_ps_name[n]=fname;
24334     mp->font_name[n]=fname;
24335   }
24336   return n;
24337 }
24338
24339 @ \MP\ doesn't bother to check the entire \.{TFM} file for errors or explain
24340 precisely what is wrong if it does find a problem.  Programs called \.{TFtoPL}
24341 @.TFtoPL@> @.PLtoTF@>
24342 and \.{PLtoTF} can be used to debug \.{TFM} files.
24343
24344 @<Complain that the \.{TFM} file is bad@>=
24345 print_err("Font ");
24346 mp_print(mp, fname);
24347 if ( file_opened ) mp_print(mp, " not usable: TFM file is bad");
24348 else mp_print(mp, " not usable: TFM file not found");
24349 help3("I wasn't able to read the size data for this font so this")
24350   ("`infont' operation won't produce anything. If the font name")
24351   ("is right, you might ask an expert to make a TFM file");
24352 if ( file_opened )
24353   mp->help_line[0]="is right, try asking an expert to fix the TFM file";
24354 mp_error(mp)
24355
24356 @ @<Read data from |tfm_infile|; if there is no room, say so...@>=
24357 @<Read the \.{TFM} size fields@>;
24358 @<Use the size fields to allocate space in |font_info|@>;
24359 @<Read the \.{TFM} header@>;
24360 @<Read the character data and the width, height, and depth tables and
24361   |goto done|@>
24362
24363 @ A bad \.{TFM} file can be shorter than it claims to be.  The code given here
24364 might try to read past the end of the file if this happens.  Changes will be
24365 needed if it causes a system error to refer to |tfm_infile^| or call
24366 |get_tfm_infile| when |eof(tfm_infile)| is true.  For example, the definition
24367 @^system dependencies@>
24368 of |tfget| could be changed to
24369 ``|begin get(tfm_infile); if eof(tfm_infile) then goto bad_tfm; end|.''
24370
24371 @d tfget {tfbyte = fgetc(mp->tfm_infile); }
24372 @d read_two(A) { (A)=tfbyte;
24373   if ( (A)>127 ) goto BAD_TFM;
24374   tfget; (A)=(A)*0400+tfbyte;
24375   }
24376 @d tf_ignore(A) { for (jj=(A);jj>=1;jj--) tfget; }
24377
24378 @<Read the \.{TFM} size fields@>=
24379 tfget; read_two(lf);
24380 tfget; read_two(tfm_lh);
24381 tfget; read_two(bc);
24382 tfget; read_two(ec);
24383 if ( (bc>1+ec)||(ec>255) ) goto BAD_TFM;
24384 tfget; read_two(nw);
24385 tfget; read_two(nh);
24386 tfget; read_two(nd);
24387 whd_size=(ec+1-bc)+nw+nh+nd;
24388 if ( lf<(int)(6+tfm_lh+whd_size) ) goto BAD_TFM;
24389 tf_ignore(10)
24390
24391 @ Offsets are added to |char_base[n]| and |width_base[n]| so that is not
24392 necessary to apply the |so|  and |qo| macros when looking up the width of a
24393 character in the string pool.  In order to ensure nonnegative |char_base|
24394 values when |bc>0|, it may be necessary to reserve a few unused |font_info|
24395 elements.
24396
24397 @<Use the size fields to allocate space in |font_info|@>=
24398 if ( mp->next_fmem<bc) mp->next_fmem=bc;  /* ensure nonnegative |char_base| */
24399 if (mp->last_fnum==mp->font_max)
24400   mp_reallocate_fonts(mp,(mp->font_max+(mp->font_max>>2)));
24401 while (mp->next_fmem+whd_size>=mp->font_mem_size) {
24402   size_t l = mp->font_mem_size+(mp->font_mem_size>>2);
24403   memory_word *font_info;
24404   font_info = xmalloc ((l+1),sizeof(memory_word));
24405   memset (font_info,0,sizeof(memory_word)*(l+1));
24406   memcpy (font_info,mp->font_info,sizeof(memory_word)*(mp->font_mem_size+1));
24407   xfree(mp->font_info);
24408   mp->font_info = font_info;
24409   mp->font_mem_size = l;
24410 }
24411 incr(mp->last_fnum);
24412 n=mp->last_fnum;
24413 mp->font_bc[n]=bc;
24414 mp->font_ec[n]=ec;
24415 mp->char_base[n]=mp->next_fmem-bc;
24416 mp->width_base[n]=mp->next_fmem+ec-bc+1;
24417 mp->height_base[n]=mp->width_base[n]+nw;
24418 mp->depth_base[n]=mp->height_base[n]+nh;
24419 mp->next_fmem=mp->next_fmem+whd_size;
24420
24421
24422 @ @<Read the \.{TFM} header@>=
24423 if ( tfm_lh<2 ) goto BAD_TFM;
24424 tf_ignore(4);
24425 tfget; read_two(z);
24426 tfget; z=z*0400+tfbyte;
24427 tfget; z=z*0400+tfbyte; /* now |z| is 16 times the design size */
24428 mp->font_dsize[n]=mp_take_fraction(mp, z,267432584);
24429   /* times ${72\over72.27}2^{28}$ to convert from \TeX\ points */
24430 tf_ignore(4*(tfm_lh-2))
24431
24432 @ @<Read the character data and the width, height, and depth tables...@>=
24433 ii=mp->width_base[n];
24434 i=mp->char_base[n]+bc;
24435 while ( i<ii ) { 
24436   tfget; mp->font_info[i].qqqq.b0=qi(tfbyte);
24437   tfget; h_and_d=tfbyte;
24438   mp->font_info[i].qqqq.b1=h_and_d / 16;
24439   mp->font_info[i].qqqq.b2=h_and_d % 16;
24440   tfget; tfget;
24441   incr(i);
24442 }
24443 while ( i<mp->next_fmem ) {
24444   @<Read a four byte dimension, scale it by the design size, store it in
24445     |font_info[i]|, and increment |i|@>;
24446 }
24447 if (feof(mp->tfm_infile) ) goto BAD_TFM;
24448 goto DONE
24449
24450 @ The raw dimension read into |d| should have magnitude at most $2^{24}$ when
24451 interpreted as an integer, and this includes a scale factor of $2^{20}$.  Thus
24452 we can multiply it by sixteen and think of it as a |fraction| that has been
24453 divided by sixteen.  This cancels the extra scale factor contained in
24454 |font_dsize[n|.
24455
24456 @<Read a four byte dimension, scale it by the design size, store it in...@>=
24457
24458 tfget; d=tfbyte;
24459 if ( d>=0200 ) d=d-0400;
24460 tfget; d=d*0400+tfbyte;
24461 tfget; d=d*0400+tfbyte;
24462 tfget; d=d*0400+tfbyte;
24463 mp->font_info[i].sc=mp_take_fraction(mp, d*16,mp->font_dsize[n]);
24464 incr(i);
24465 }
24466
24467 @ This function does no longer use the file name parser, because |fname| is
24468 a C string already.
24469 @<Open |tfm_infile| for input@>=
24470 file_opened=false;
24471 mp_ptr_scan_file(mp, fname);
24472 if ( strlen(mp->cur_area)==0 ) { xfree(mp->cur_area); mp->cur_area=xstrdup(MP_font_area);}
24473 if ( strlen(mp->cur_ext)==0 )  { xfree(mp->cur_ext); mp->cur_ext=xstrdup(".tfm"); }
24474 pack_cur_name;
24475 mp->tfm_infile = mp_open_file(mp, mp->name_of_file, "rb",mp_filetype_metrics);
24476 if ( !mp->tfm_infile  ) goto BAD_TFM;
24477 file_opened=true
24478
24479 @ When we have a font name and we don't know whether it has been loaded yet,
24480 we scan the |font_name| array before calling |read_font_info|.
24481
24482 @<Declare text measuring subroutines@>=
24483 font_number mp_find_font (MP mp, char *f) {
24484   font_number n;
24485   for (n=0;n<=mp->last_fnum;n++) {
24486     if (mp_xstrcmp(f,mp->font_name[n])==0 )
24487       return n;
24488   }
24489   return mp_read_font_info(mp, f);
24490 }
24491
24492 @ One simple application of |find_font| is the implementation of the |font_size|
24493 operator that gets the design size for a given font name.
24494
24495 @<Find the design size of the font whose name is |cur_exp|@>=
24496 mp_flush_cur_exp(mp, (mp->font_dsize[mp_find_font(mp, str(mp->cur_exp))]+8) / 16)
24497
24498 @ If we discover that the font doesn't have a requested character, we omit it
24499 from the bounding box computation and expect the \ps\ interpreter to drop it.
24500 This routine issues a warning message if the user has asked for it.
24501
24502 @<Declare text measuring subroutines@>=
24503 void mp_lost_warning (MP mp,font_number f, pool_pointer k) { 
24504   if ( mp->internal[tracing_lost_chars]>0 ) { 
24505     mp_begin_diagnostic(mp);
24506     if ( mp->selector==log_only ) incr(mp->selector);
24507     mp_print_nl(mp, "Missing character: There is no ");
24508 @.Missing character@>
24509     mp_print_str(mp, mp->str_pool[k]); 
24510     mp_print(mp, " in font ");
24511     mp_print(mp, mp->font_name[f]); mp_print_char(mp, '!'); 
24512     mp_end_diagnostic(mp, false);
24513   }
24514 }
24515
24516 @ The whole purpose of saving the height, width, and depth information is to be
24517 able to find the bounding box of an item of text in an edge structure.  The
24518 |set_text_box| procedure takes a text node and adds this information.
24519
24520 @<Declare text measuring subroutines@>=
24521 void mp_set_text_box (MP mp,pointer p) {
24522   font_number f; /* |font_n(p)| */
24523   ASCII_code bc,ec; /* range of valid characters for font |f| */
24524   pool_pointer k,kk; /* current character and character to stop at */
24525   four_quarters cc; /* the |char_info| for the current character */
24526   scaled h,d; /* dimensions of the current character */
24527   width_val(p)=0;
24528   height_val(p)=-el_gordo;
24529   depth_val(p)=-el_gordo;
24530   f=font_n(p);
24531   bc=mp->font_bc[f];
24532   ec=mp->font_ec[f];
24533   kk=str_stop(text_p(p));
24534   k=mp->str_start[text_p(p)];
24535   while ( k<kk ) {
24536     @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>;
24537   }
24538   @<Set the height and depth to zero if the bounding box is empty@>;
24539 }
24540
24541 @ @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>=
24542
24543   if ( (mp->str_pool[k]<bc)||(mp->str_pool[k]>ec) ) {
24544     mp_lost_warning(mp, f,k);
24545   } else { 
24546     cc=char_info(f)(mp->str_pool[k]);
24547     if ( ! ichar_exists(cc) ) {
24548       mp_lost_warning(mp, f,k);
24549     } else { 
24550       width_val(p)=width_val(p)+char_width(f)(cc);
24551       h=char_height(f)(cc);
24552       d=char_depth(f)(cc);
24553       if ( h>height_val(p) ) height_val(p)=h;
24554       if ( d>depth_val(p) ) depth_val(p)=d;
24555     }
24556   }
24557   incr(k);
24558 }
24559
24560 @ Let's hope modern compilers do comparisons correctly when the difference would
24561 overflow.
24562
24563 @<Set the height and depth to zero if the bounding box is empty@>=
24564 if ( height_val(p)<-depth_val(p) ) { 
24565   height_val(p)=0;
24566   depth_val(p)=0;
24567 }
24568
24569 @ The new primitives fontmapfile and fontmapline.
24570
24571 @<Declare action procedures for use by |do_statement|@>=
24572 void mp_do_mapfile (MP mp) ;
24573 void mp_do_mapline (MP mp) ;
24574
24575 @ @c void mp_do_mapfile (MP mp) { 
24576   mp_get_x_next(mp); mp_scan_expression(mp);
24577   if ( mp->cur_type!=mp_string_type ) {
24578     @<Complain about improper map operation@>;
24579   } else {
24580     mp_map_file(mp,mp->cur_exp);
24581   }
24582 }
24583 void mp_do_mapline (MP mp) { 
24584   mp_get_x_next(mp); mp_scan_expression(mp);
24585   if ( mp->cur_type!=mp_string_type ) {
24586      @<Complain about improper map operation@>;
24587   } else { 
24588      mp_map_line(mp,mp->cur_exp);
24589   }
24590 }
24591
24592 @ @<Complain about improper map operation@>=
24593
24594   exp_err("Unsuitable expression");
24595   help1("Only known strings can be map files or map lines.");
24596   mp_put_get_error(mp);
24597 }
24598
24599 @ This is temporary.
24600
24601 @d ps_room(A) mp_ps_room(mp,A)
24602
24603 @<Declare the \ps\ output procedures@>=
24604 void mp_ps_print_cmd (MP mp, char *l, char *s) {
24605   if ( mp->internal[mpprocset]>0 ) { ps_room(strlen(s)); mp_print(mp,s); }
24606   else { ps_room(strlen(l)); mp_print(mp, l); };
24607 }
24608 void mp_print_cmd (MP mp,char *l, char *s) {
24609   if ( mp->internal[mpprocset]>0 ) mp_print(mp, s); 
24610   else mp_print(mp, l);
24611 }
24612
24613 @ To print |scaled| value to PDF output we need some subroutines to ensure
24614 accurary.
24615
24616 @d max_integer   0x7FFFFFFF /* $2^{31}-1$ */
24617
24618 @<Glob...@>=
24619 scaled one_bp; /* scaled value corresponds to 1bp */
24620 scaled one_hundred_bp; /* scaled value corresponds to 100bp */
24621 scaled one_hundred_inch; /* scaled value corresponds to 100in */
24622 integer ten_pow[10]; /* $10^0..10^9$ */
24623 integer scaled_out; /* amount of |scaled| that was taken out in |divide_scaled| */
24624
24625 @ @<Set init...@>=
24626 mp->one_bp = 65782; /* 65781.76 */
24627 mp->one_hundred_bp = 6578176;
24628 mp->one_hundred_inch = 473628672;
24629 mp->ten_pow[0] = 1;
24630 for (i = 1;i<= 9; i++ ) {
24631   mp->ten_pow[i] = 10*mp->ten_pow[i - 1];
24632 }
24633
24634 @ The following function divides |s| by |m|. |dd| is number of decimal digits.
24635
24636 @c scaled mp_divide_scaled (MP mp,scaled s, scaled m, integer  dd) {
24637   scaled q,r;
24638   integer sign,i;
24639   sign = 1;
24640   if ( s < 0 ) { sign = -sign; s = -s; }
24641   if ( m < 0 ) { sign = -sign; m = -m; }
24642   if ( m == 0 )
24643     mp_confusion(mp, "arithmetic: divided by zero");
24644   else if ( m >= (max_integer / 10) )
24645     mp_confusion(mp, "arithmetic: number too big");
24646   q = s / m;
24647   r = s % m;
24648   for (i = 1;i<=dd;i++) {
24649     q = 10*q + (10*r) / m;
24650     r = (10*r) % m;
24651   }
24652   if ( 2*r >= m ) { incr(q); r = r - m; }
24653   mp->scaled_out = sign*(s - (r / mp->ten_pow[dd]));
24654   return (sign*q);
24655 }
24656
24657 @* \[44] Shipping pictures out.
24658 The |ship_out| procedure, to be described below, is given a pointer to
24659 an edge structure. Its mission is to output a file containing the \ps\
24660 description of an edge structure.
24661
24662 @ Each time an edge structure is shipped out we write a new \ps\ output
24663 file named according to the current \&{charcode}.
24664 @:char_code_}{\&{charcode} primitive@>
24665
24666 @<Declare the \ps\ output procedures@>=
24667 void mp_open_output_file (MP mp) ;
24668
24669 @ @c void mp_open_output_file (MP mp) {
24670   integer c; /* \&{charcode} rounded to the nearest integer */
24671   int old_setting; /* previous |selector| setting */
24672   pool_pointer i; /*  indexes into |filename_template|  */
24673   integer cc; /* a temporary integer for template building  */
24674   integer f,g=0; /* field widths */
24675   if ( mp->job_name==NULL ) mp_open_log_file(mp);
24676   c=mp_round_unscaled(mp, mp->internal[char_code]);
24677   if ( mp->filename_template==0 ) {
24678     char *s; /* a file extension derived from |c| */
24679     if ( c<0 ) 
24680       s=xstrdup(".ps");
24681     else 
24682       @<Use |c| to compute the file extension |s|@>;
24683     mp_pack_job_name(mp, s);
24684     xfree(s);
24685     while ( ! mp_a_open_out(mp, &mp->ps_file, mp_filetype_postscript) )
24686       mp_prompt_file_name(mp, "file name for output",s);
24687   } else { /* initializations */
24688     str_number s, n; /* a file extension derived from |c| */
24689     old_setting=mp->selector; 
24690     mp->selector=new_string;
24691     f = 0;
24692     i = mp->str_start[mp->filename_template];
24693     n = rts(""); /* initialize */
24694     while ( i<str_stop(mp->filename_template) ) {
24695        if ( mp->str_pool[i]=='%' ) {
24696       CONTINUE:
24697         incr(i);
24698         if ( i<str_stop(mp->filename_template) ) {
24699           if ( mp->str_pool[i]=='j' ) {
24700             mp_print(mp, mp->job_name);
24701           } else if ( mp->str_pool[i]=='d' ) {
24702              cc= mp_round_unscaled(mp, mp->internal[day]);
24703              print_with_leading_zeroes(cc);
24704           } else if ( mp->str_pool[i]=='m' ) {
24705              cc= mp_round_unscaled(mp, mp->internal[month]);
24706              print_with_leading_zeroes(cc);
24707           } else if ( mp->str_pool[i]=='y' ) {
24708              cc= mp_round_unscaled(mp, mp->internal[year]);
24709              print_with_leading_zeroes(cc);
24710           } else if ( mp->str_pool[i]=='H' ) {
24711              cc= mp_round_unscaled(mp, mp->internal[mp_time]) / 60;
24712              print_with_leading_zeroes(cc);
24713           }  else if ( mp->str_pool[i]=='M' ) {
24714              cc= mp_round_unscaled(mp, mp->internal[mp_time]) % 60;
24715              print_with_leading_zeroes(cc);
24716           } else if ( mp->str_pool[i]=='c' ) {
24717             if ( c<0 ) mp_print(mp, "ps");
24718             else print_with_leading_zeroes(c);
24719           } else if ( (mp->str_pool[i]>='0') && 
24720                       (mp->str_pool[i]<='9') ) {
24721             if ( (f<10)  )
24722               f = (f*10) + mp->str_pool[i]-'0';
24723             goto CONTINUE;
24724           } else {
24725             mp_print_str(mp, mp->str_pool[i]);
24726           }
24727         }
24728       } else {
24729         if ( mp->str_pool[i]=='.' )
24730           if (length(n)==0)
24731             n = mp_make_string(mp);
24732         mp_print_str(mp, mp->str_pool[i]);
24733       };
24734       incr(i);
24735     };
24736     s = mp_make_string(mp);
24737     mp->selector= old_setting;
24738     if (length(n)==0) {
24739        n=s;
24740        s=rts("");
24741     };
24742     mp_pack_file_name(mp, str(n),"",str(s));
24743     while ( ! mp_a_open_out(mp, &mp->ps_file, mp_filetype_postscript) )
24744       mp_prompt_file_name(mp, "file name for output",str(s));
24745     delete_str_ref(n);
24746     delete_str_ref(s);
24747   }
24748   @<Store the true output file name if appropriate@>;
24749   @<Begin the progress report for the output of picture~|c|@>;
24750 }
24751
24752 @ The file extension created here could be up to five characters long in
24753 extreme cases so it may have to be shortened on some systems.
24754 @^system dependencies@>
24755
24756 @<Use |c| to compute the file extension |s|@>=
24757
24758   s = xmalloc(7,1);
24759   snprintf(s,7,".%i",(int)c);
24760 }
24761
24762 @ The user won't want to see all the output file names so we only save the
24763 first and last ones and a count of how many there were.  For this purpose
24764 files are ordered primarily by \&{charcode} and secondarily by order of
24765 creation.
24766 @:char_code_}{\&{charcode} primitive@>
24767
24768 @<Store the true output file name if appropriate@>=
24769 if ((c<mp->first_output_code)&&(mp->first_output_code>=0)) {
24770   mp->first_output_code=c;
24771   xfree(mp->first_file_name);
24772   mp->first_file_name=xstrdup(mp->name_of_file);
24773 }
24774 if ( c>=mp->last_output_code ) {
24775   mp->last_output_code=c;
24776   xfree(mp->last_file_name);
24777   mp->last_file_name=xstrdup(mp->name_of_file);
24778 }
24779
24780 @ @<Glob...@>=
24781 char * first_file_name;
24782 char * last_file_name; /* full file names */
24783 integer first_output_code;integer last_output_code; /* rounded \&{charcode} values */
24784 @:char_code_}{\&{charcode} primitive@>
24785 integer total_shipped; /* total number of |ship_out| operations completed */
24786
24787 @ @<Set init...@>=
24788 mp->first_file_name=xstrdup("");
24789 mp->last_file_name=xstrdup("");
24790 mp->first_output_code=32768;
24791 mp->last_output_code=-32768;
24792 mp->total_shipped=0;
24793
24794 @ @<Dealloc variables@>=
24795 xfree(mp->first_file_name);
24796 xfree(mp->last_file_name);
24797
24798 @ @<Begin the progress report for the output of picture~|c|@>=
24799 if ( (int)mp->term_offset>mp->max_print_line-6 ) mp_print_ln(mp);
24800 else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, ' ');
24801 mp_print_char(mp, '[');
24802 if ( c>=0 ) mp_print_int(mp, c)
24803
24804 @ @<End progress report@>=
24805 mp_print_char(mp, ']');
24806 update_terminal;
24807 incr(mp->total_shipped)
24808
24809 @ @<Explain what output files were written@>=
24810 if ( mp->total_shipped>0 ) { 
24811   mp_print_nl(mp, "");
24812   mp_print_int(mp, mp->total_shipped);
24813   mp_print(mp, " output file");
24814   if ( mp->total_shipped>1 ) mp_print_char(mp, 's');
24815   mp_print(mp, " written: ");
24816   mp_print(mp, mp->first_file_name);
24817   if ( mp->total_shipped>1 ) {
24818     if ( 31+strlen(mp->first_file_name)+
24819          strlen(mp->last_file_name)> (unsigned)mp->max_print_line) 
24820       mp_print_ln(mp);
24821     mp_print(mp, " .. ");
24822     mp_print(mp, mp->last_file_name);
24823   }
24824 }
24825
24826
24827 @ The most important output procedure is the one that gives the \ps\ version of
24828 a \MP\ path.
24829
24830 @<Declare the \ps\ output procedures@>=
24831 void mp_ps_path_out (MP mp,pointer h) {
24832   pointer p,q; /* for scanning the path */
24833   scaled d; /* a temporary value */
24834   boolean curved; /* |true| unless the cubic is almost straight */
24835   ps_room(40);
24836   if ( mp->need_newpath ) 
24837     mp_print_cmd(mp, "newpath ","n ");
24838   mp->need_newpath=true;
24839   mp_ps_pair_out(mp, x_coord(h),y_coord(h));
24840   mp_print_cmd(mp, "moveto","m");
24841   p=h;
24842   do {  
24843     if ( right_type(p)==endpoint ) { 
24844       if ( p==h ) mp_ps_print_cmd(mp, " 0 0 rlineto"," 0 0 r");
24845       return;
24846     }
24847     q=link(p);
24848     @<Start a new line and print the \ps\ commands for the curve from
24849       |p| to~|q|@>;
24850     p=q;
24851   } while (p!=h);
24852   mp_ps_print_cmd(mp, " closepath"," p");
24853 }
24854
24855 @ @<Glob...@>=
24856 boolean need_newpath;
24857   /* will |ps_path_out| need to issue a \&{newpath} command next time */
24858 @:newpath_}{\&{newpath} command@>
24859
24860 @ @<Start a new line and print the \ps\ commands for the curve from...@>=
24861 curved=true;
24862 @<Set |curved:=false| if the cubic from |p| to |q| is almost straight@>;
24863 mp_print_ln(mp);
24864 if ( curved ){ 
24865   mp_ps_pair_out(mp, right_x(p),right_y(p));
24866   mp_ps_pair_out(mp, left_x(q),left_y(q));
24867   mp_ps_pair_out(mp, x_coord(q),y_coord(q));
24868   mp_ps_print_cmd(mp, "curveto","c");
24869 } else if ( q!=h ){ 
24870   mp_ps_pair_out(mp, x_coord(q),y_coord(q));
24871   mp_ps_print_cmd(mp, "lineto","l");
24872 }
24873
24874 @ Two types of straight lines come up often in \MP\ paths:
24875 cubics with zero initial and final velocity as created by |make_path| or
24876 |make_envelope|, and cubics with control points uniformly spaced on a line
24877 as created by |make_choices|.
24878
24879 @d bend_tolerance 131 /* allow rounding error of $2\cdot10^{-3}$ */
24880
24881 @<Set |curved:=false| if the cubic from |p| to |q| is almost straight@>=
24882 if ( right_x(p)==x_coord(p) )
24883   if ( right_y(p)==y_coord(p) )
24884     if ( left_x(q)==x_coord(q) )
24885       if ( left_y(q)==y_coord(q) ) curved=false;
24886 d=left_x(q)-right_x(p);
24887 if ( abs(right_x(p)-x_coord(p)-d)<=bend_tolerance )
24888   if ( abs(x_coord(q)-left_x(q)-d)<=bend_tolerance )
24889     { d=left_y(q)-right_y(p);
24890     if ( abs(right_y(p)-y_coord(p)-d)<=bend_tolerance )
24891       if ( abs(y_coord(q)-left_y(q)-d)<=bend_tolerance ) curved=false;
24892     }
24893
24894 @ We need to keep track of several parameters from the \ps\ graphics state.
24895 @^graphics state@>
24896 This allows us to be sure that \ps\ has the correct values when they are
24897 needed without wasting time and space setting them unnecessarily.
24898
24899 @d gs_node_size 10
24900 @d gs_red        mp->mem[mp->gs_state+1].sc
24901 @d gs_green      mp->mem[mp->gs_state+2].sc
24902 @d gs_blue       mp->mem[mp->gs_state+3].sc
24903 @d gs_black      mp->mem[mp->gs_state+4].sc
24904    /* color from the last \&{setcmykcolor} or \&{setrgbcolor} or \&{setgray} command */
24905 @d gs_colormodel mp->mem[mp->gs_state+5].qqqq.b0
24906    /* the current colormodel */
24907 @d gs_ljoin      mp->mem[mp->gs_state+5].qqqq.b1
24908 @d gs_lcap       mp->mem[mp->gs_state+5].qqqq.b2
24909    /* values from the last \&{setlinejoin} and \&{setlinecap} commands */
24910 @d gs_adj_wx     mp->mem[mp->gs_state+5].qqqq.b3
24911    /* what resolution-dependent adjustment applies to the width */
24912 @d gs_miterlim   mp->mem[mp->gs_state+6].sc
24913    /* the value from the last \&{setmiterlimit} command */
24914 @d gs_dash_p     mp->mem[mp->gs_state+7].hh.lh
24915    /* edge structure for last \&{setdash} command */
24916 @d gs_previous   mp->mem[mp->gs_state+7].hh.rh
24917    /* backlink to the previous |gs_state| structure */
24918 @d gs_dash_sc    mp->mem[mp->gs_state+8].sc
24919    /* scale factor used with |gs_dash_p| */
24920 @d gs_width      mp->mem[mp->gs_state+9].sc
24921    /* width setting or $-1$ if no \&{setlinewidth} command so far */
24922
24923 @<Glob...@>=
24924 pointer gs_state;
24925
24926 @ @<Set init...@>=
24927 mp->gs_state=null;
24928
24929 @ To avoid making undue assumptions about the initial graphics state, these
24930 parameters are given special values that are guaranteed not to match anything
24931 in the edge structure being shipped out.  On the other hand, the initial color
24932 should be black so that the translation of an all-black picture will have no
24933 \&{setcolor} commands.  (These would be undesirable in a font application.)
24934 Hence we use |c=0| when initializing the graphics state and we use |c<0|
24935 to recover from a situation where we have lost track of the graphics state.
24936
24937 @<Declare the \ps\ output procedures@>=
24938 void mp_unknown_graphics_state (MP mp,scaled c) ;
24939
24940 @ @c void mp_unknown_graphics_state (MP mp,scaled c) {
24941   pointer p; /* to shift graphic states around */
24942   quarterword k; /* a loop index for copying the |gs_state| */
24943   if ( (c==0)||(c==-1) ) {
24944     if ( mp->gs_state==null ) {
24945       mp->gs_state = mp_get_node(mp, gs_node_size);
24946       gs_previous=null;
24947     } else {
24948       while ( gs_previous!=null ) {
24949         p = gs_previous;
24950         mp_free_node(mp, mp->gs_state,gs_node_size);
24951         mp->gs_state=p;
24952       }
24953     }
24954     gs_red=c; gs_green=c; gs_blue=c; gs_black=c;
24955     gs_colormodel=uninitialized_model;
24956     gs_ljoin=3;
24957     gs_lcap=3;
24958     gs_miterlim=0;
24959     gs_dash_p=diov;
24960     gs_dash_sc=0;
24961     gs_width=-1;
24962   } else if ( c==1 ) {
24963     p= mp->gs_state;
24964     mp->gs_state = mp_get_node(mp, gs_node_size);
24965     for (k=1;k<=gs_node_size-1;k++)
24966       mp->mem[mp->gs_state+k]=mp->mem[p+k];
24967     gs_previous = p;
24968   } else if ( c==2 ) {
24969     p = gs_previous;
24970     mp_free_node(mp, mp->gs_state,gs_node_size);
24971     mp->gs_state=p;
24972   }
24973 }
24974
24975 @ When it is time to output a graphical object, |fix_graphics_state| ensures
24976 that \ps's idea of the graphics state agrees with what is stored in the object.
24977
24978 @<Declare the \ps\ output procedures@>=
24979 @<Declare subroutines needed by |fix_graphics_state|@>;
24980 void mp_fix_graphics_state (MP mp, pointer p) ;
24981
24982 @ @c 
24983 void mp_fix_graphics_state (MP mp, pointer p) {
24984   /* get ready to output graphical object |p| */
24985   pointer hh,pp; /* for list manipulation */
24986   scaled wx,wy,ww; /* dimensions of pen bounding box */
24987   boolean adj_wx; /* whether pixel rounding should be based on |wx| or |wy| */
24988   integer tx,ty; /* temporaries for computing |adj_wx| */
24989   scaled scf; /* a scale factor for the dash pattern */
24990   if ( has_color(p) )
24991     @<Make sure \ps\ will use the right color for object~|p|@>;
24992   if ( (type(p)==fill_code)||(type(p)==stroked_code) )
24993     if ( pen_p(p)!=null )
24994       if ( pen_is_elliptical(pen_p(p)) ) {
24995         @<Generate \ps\ code that sets the stroke width to the
24996           appropriate rounded value@>;
24997         @<Make sure \ps\ will use the right dash pattern for |dash_p(p)|@>;
24998         @<Decide whether the line cap parameter matters and set it if necessary@>;
24999         @<Set the other numeric parameters as needed for object~|p|@>;
25000       }
25001   if ( mp->ps_offset>0 ) mp_print_ln(mp);
25002 }
25003
25004 @ @<Decide whether the line cap parameter matters and set it if necessary@>=
25005 if ( type(p)==stroked_code )
25006   if ( (left_type(path_p(p))==endpoint)||(dash_p(p)!=null) )
25007     if ( gs_lcap!=lcap_val(p) ) {
25008       ps_room(13);
25009       mp_print_char(mp, ' ');
25010       mp_print_char(mp, '0'+lcap_val(p)); 
25011       mp_print_cmd(mp, " setlinecap"," lc");
25012       gs_lcap=lcap_val(p);
25013     }
25014
25015 @ @<Set the other numeric parameters as needed for object~|p|@>=
25016 if ( gs_ljoin!=ljoin_val(p) ) {
25017   ps_room(14);
25018   mp_print_char(mp, ' ');
25019   mp_print_char(mp, '0'+ljoin_val(p)); mp_print_cmd(mp, " setlinejoin"," lj");
25020   gs_ljoin=ljoin_val(p);
25021 }
25022 if ( gs_miterlim!=miterlim_val(p) ) {
25023   ps_room(27);
25024   mp_print_char(mp, ' ');
25025   mp_print_scaled(mp, miterlim_val(p)); mp_print_cmd(mp, " setmiterlimit"," ml");
25026   gs_miterlim=miterlim_val(p);
25027 }
25028
25029 @ @<Make sure \ps\ will use the right color for object~|p|@>=
25030 {
25031   if ( (color_model(p)==rgb_model)||
25032      ((color_model(p)==uninitialized_model)&&
25033      ((mp->internal[default_color_model] / unity)==rgb_model)) ) {
25034   if ( (gs_colormodel!=rgb_model)||(gs_red!=red_val(p))||
25035       (gs_green!=green_val(p))||(gs_blue!=blue_val(p)) ) {
25036       gs_red=red_val(p);
25037       gs_green=green_val(p);
25038       gs_blue=blue_val(p);
25039       gs_black= -1;
25040       gs_colormodel=rgb_model;
25041       { ps_room(36);
25042         mp_print_char(mp, ' ');
25043         mp_print_scaled(mp, gs_red); mp_print_char(mp, ' ');
25044         mp_print_scaled(mp, gs_green); mp_print_char(mp, ' ');
25045         mp_print_scaled(mp, gs_blue);
25046         mp_print_cmd(mp, " setrgbcolor", " R");
25047       }
25048     }
25049   } else if ( (color_model(p)==cmyk_model)||
25050      ((color_model(p)==uninitialized_model)&&
25051      ((mp->internal[default_color_model] / unity)==cmyk_model)) ) {
25052    if ( (gs_red!=cyan_val(p))||(gs_green!=magenta_val(p))||
25053       (gs_blue!=yellow_val(p))||(gs_black!=black_val(p))||
25054       (gs_colormodel!=cmyk_model) ) {
25055       if ( color_model(p)==uninitialized_model ) {
25056         gs_red=0;
25057         gs_green=0;
25058         gs_blue=0;
25059         gs_black=unity;
25060       } else {
25061         gs_red=cyan_val(p);
25062         gs_green=magenta_val(p);
25063         gs_blue=yellow_val(p);
25064         gs_black=black_val(p);
25065       }
25066       gs_colormodel=cmyk_model;
25067       { ps_room(45);
25068         mp_print_char(mp, ' ');
25069         mp_print_scaled(mp, gs_red); mp_print_char(mp, ' ');
25070         mp_print_scaled(mp, gs_green); mp_print_char(mp, ' ');
25071         mp_print_scaled(mp, gs_blue); mp_print_char(mp, ' ');
25072         mp_print_scaled(mp, gs_black);
25073         mp_print_cmd(mp, " setcmykcolor"," C");
25074       }
25075     }
25076   } else if ( (color_model(p)==grey_model)||
25077     ((color_model(p)==uninitialized_model)&&
25078      ((mp->internal[default_color_model] / unity)==grey_model)) ) {
25079    if ( (gs_red!=grey_val(p))||(gs_colormodel!=grey_model) ) {
25080       gs_red = grey_val(p);
25081       gs_green= -1;
25082       gs_blue= -1;
25083       gs_black= -1;
25084       gs_colormodel=grey_model;
25085       { ps_room(16);
25086         mp_print_char(mp, ' ');
25087         mp_print_scaled(mp, gs_red);
25088         mp_print_cmd(mp, " setgray"," G");
25089       }
25090     }
25091   }
25092   if ( color_model(p)==no_model )
25093     gs_colormodel=no_model;
25094 }
25095
25096 @ In order to get consistent widths for horizontal and vertical pen strokes, we
25097 want \ps\ to use an integer number of pixels for the \&{setwidth} parameter.
25098 @:setwidth}{\&{setwidth}command@>
25099 We set |gs_width| to the ideal horizontal or vertical stroke width and then
25100 generate \ps\ code that computes the rounded value.  For non-circular pens, the
25101 pen shape will be rescaled so that horizontal or vertical parts of the stroke
25102 have the computed width.
25103
25104 Rounding the width to whole pixels is not likely to improve the appearance of
25105 diagonal or curved strokes, but we do it anyway for consistency.  The
25106 \&{truncate} command generated here tends to make all the strokes a little
25107 @:truncate}{\&{truncate} command@>
25108 thinner, but this is appropriate for \ps's scan-conversion rules.  Even with
25109 truncation, an ideal with of $w$~pixels gets mapped into $\lfloor w\rfloor+1$.
25110 It would be better to have $\lceil w\rceil$ but that is ridiculously expensive
25111 to compute in \ps.
25112
25113 @<Generate \ps\ code that sets the stroke width...@>=
25114 @<Set |wx| and |wy| to the width and height of the bounding box for
25115   |pen_p(p)|@>;
25116 @<Use |pen_p(p)| and |path_p(p)| to decide whether |wx| or |wy| is more
25117   important and set |adj_wx| and |ww| accordingly@>;
25118 if ( (ww!=gs_width) || (adj_wx!=gs_adj_wx) ) {
25119   if ( adj_wx ) {
25120     ps_room(13);
25121     mp_print_char(mp, ' '); mp_print_scaled(mp, ww);
25122     mp_ps_print_cmd(mp, 
25123       " 0 dtransform exch truncate exch idtransform pop setlinewidth"," hlw");
25124   } else {
25125     if ( mp->internal[mpprocset]>0 ) {
25126       ps_room(13);
25127       mp_print_char(mp, ' ');
25128       mp_print_scaled(mp, ww);
25129       mp_ps_print(mp, " vlw");
25130     } else { 
25131       ps_room(15);
25132       mp_print(mp, " 0 "); mp_print_scaled(mp, ww);
25133       mp_ps_print(mp, " dtransform truncate idtransform setlinewidth pop");
25134     }
25135   }
25136   gs_width = ww;
25137   gs_adj_wx = adj_wx;
25138 }
25139
25140 @ @<Set |wx| and |wy| to the width and height of the bounding box for...@>=
25141 pp=pen_p(p);
25142 if ( (right_x(pp)==x_coord(pp)) && (left_y(pp)==y_coord(pp)) ) {
25143   wx = abs(left_x(pp) - x_coord(pp));
25144   wy = abs(right_y(pp) - y_coord(pp));
25145 } else {
25146   wx = mp_pyth_add(mp, left_x(pp)-x_coord(pp), right_x(pp)-x_coord(pp));
25147   wy = mp_pyth_add(mp, left_y(pp)-y_coord(pp), right_y(pp)-y_coord(pp));
25148 }
25149
25150 @ The path is considered ``essentially horizontal'' if its range of
25151 $y$~coordinates is less than the $y$~range |wy| for the pen.  ``Essentially
25152 vertical'' paths are detected similarly.  This code ensures that no component
25153 of the pen transformation is more that |aspect_bound*(ww+1)|.
25154
25155 @d aspect_bound 10 /* ``less important'' of |wx|, |wy| cannot exceed the other by
25156     more than this factor */
25157
25158 @<Use |pen_p(p)| and |path_p(p)| to decide whether |wx| or |wy| is more...@>=
25159 tx=1; ty=1;
25160 if ( mp_coord_rangeOK(mp, path_p(p), y_loc(0), wy) ) tx=aspect_bound;
25161 else if ( mp_coord_rangeOK(mp, path_p(p), x_loc(0), wx) ) ty=aspect_bound;
25162 if ( wy / ty>=wx / tx ) { ww=wy; adj_wx=false; }
25163 else { ww=wx; adj_wx=true;  }
25164
25165 @ This routine quickly tests if path |h| is ``essentially horizontal'' or
25166 ``essentially vertical,'' where |zoff| is |x_loc(0)| or |y_loc(0)| and |dz| is
25167 allowable range for $x$ or~$y$.  We do not need and cannot afford a full
25168 bounding-box computation.
25169
25170 @<Declare subroutines needed by |fix_graphics_state|@>=
25171 boolean mp_coord_rangeOK (MP mp,pointer h, 
25172                           small_number  zoff, scaled dz) {
25173   pointer p; /* for scanning the path form |h| */
25174   scaled zlo,zhi; /* coordinate range so far */
25175   scaled z; /* coordinate currently being tested */
25176   zlo=knot_coord(h+zoff);
25177   zhi=zlo;
25178   p=h;
25179   while ( right_type(p)!=endpoint ) {
25180     z=right_coord(p+zoff);
25181     @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>;
25182     p=link(p);
25183     z=left_coord(p+zoff);
25184     @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>;
25185     z=knot_coord(p+zoff);
25186     @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>;
25187     if ( p==h ) break;
25188   }
25189   return true;
25190 }
25191
25192 @ @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>=
25193 if ( z<zlo ) zlo=z;
25194 else if ( z>zhi ) zhi=z;
25195 if ( zhi-zlo>dz ) return false
25196
25197 @ Filling with an elliptical pen is implemented via a combination of \&{stroke}
25198 and \&{fill} commands and a nontrivial dash pattern would interfere with this.
25199 @:stroke}{\&{stroke} command@>
25200 @:fill}{\&{fill} command@>
25201 Note that we don't use |delete_edge_ref| because |gs_dash_p| is not counted as
25202 a reference.
25203
25204 @<Make sure \ps\ will use the right dash pattern for |dash_p(p)|@>=
25205 if ( type(p)==fill_code ) {
25206   hh=null;
25207 } else { 
25208   hh=dash_p(p);
25209   scf=mp_get_pen_scale(mp, pen_p(p));
25210   if ( scf==0 ) {
25211     if ( gs_width==0 ) scf=dash_scale(p);  else hh=null;
25212   } else { 
25213     scf=mp_make_scaled(mp, gs_width,scf);
25214     scf=mp_take_scaled(mp, scf,dash_scale(p));
25215   }
25216 }
25217 if ( hh==null ) {
25218   if ( gs_dash_p!=null ) {
25219     mp_ps_print_cmd(mp, " [] 0 setdash"," rd");
25220     gs_dash_p=null;
25221   }
25222 } else if ( (gs_dash_sc!=scf) || ! mp_same_dashes(mp, gs_dash_p,hh) ) {
25223   @<Set the dash pattern from |dash_list(hh)| scaled by |scf|@>;
25224 }
25225
25226 @ Translating a dash list into \ps\ is very similar to printing it symbolically
25227 in |print_edges|.  A dash pattern with |dash_y(hh)=0| has length zero and is
25228 ignored.  The same fate applies in the bizarre case of a dash pattern that
25229 cannot be printed without overflow.
25230
25231 @<Set the dash pattern from |dash_list(hh)| scaled by |scf|@>=
25232 { gs_dash_p=hh;
25233   gs_dash_sc=scf;
25234   if ( (dash_y(hh)==0) || (abs(dash_y(hh)) / unity >= el_gordo / scf)){
25235     mp_ps_print_cmd(mp, " [] 0 setdash"," rd");
25236   } else { 
25237     pp=dash_list(hh);
25238     start_x(null_dash)=start_x(pp)+dash_y(hh);
25239     ps_room(28);
25240     mp_print(mp, " [");
25241     while ( pp!=null_dash ) {
25242       mp_ps_pair_out(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf),
25243                          mp_take_scaled(mp, start_x(link(pp))-stop_x(pp),scf));
25244       pp=link(pp);
25245     }
25246     ps_room(22);
25247     mp_print(mp, "] ");
25248     mp_print_scaled(mp, mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
25249     mp_print_cmd(mp, " setdash"," sd");
25250   }
25251 }
25252
25253 @ @<Declare subroutines needed by |fix_graphics_state|@>=
25254 boolean mp_same_dashes (MP mp,pointer h, pointer hh) ;
25255
25256 @ @c
25257 boolean mp_same_dashes (MP mp,pointer h, pointer hh) {
25258   /* do |h| and |hh| represent the same dash pattern? */
25259   pointer p,pp; /* dash nodes being compared */
25260   if ( h==hh ) return true;
25261   else if ( (h<=diov)||(hh<=diov) ) return false;
25262   else if ( dash_y(h)!=dash_y(hh) ) return false;
25263   else { @<Compare |dash_list(h)| and |dash_list(hh)|@>; }
25264   return false; /* can't happen */
25265 }
25266
25267 @ @<Compare |dash_list(h)| and |dash_list(hh)|@>=
25268 { p=dash_list(h);
25269   pp=dash_list(hh);
25270   while ( (p!=null_dash)&&(pp!=null_dash) ) {
25271     if ( (start_x(p)!=start_x(pp))||(stop_x(p)!=stop_x(pp)) ) {
25272       break;
25273     } else { 
25274       p=link(p);
25275       pp=link(pp);
25276     }
25277   }
25278   return (p==pp);
25279 }
25280
25281 @ When stroking a path with an elliptical pen, it is necessary to transform
25282 the coordinate system so that a unit circular pen will have the desired shape.
25283 To keep this transformation local, we enclose it in a
25284 $$\&{gsave}\ldots\&{grestore}$$
25285 block. Any translation component must be applied to the path being stroked
25286 while the rest of the transformation must apply only to the pen.
25287 If |fill_also=true|, the path is to be filled as well as stroked so we must
25288 insert commands to do this after giving the path.
25289
25290 @<Declare the \ps\ output procedures@>=
25291 void mp_stroke_ellipse (MP mp,pointer h, boolean fill_also) ;
25292
25293
25294 @c void mp_stroke_ellipse (MP mp,pointer h, boolean fill_also) {
25295   /* generate an elliptical pen stroke from object |h| */
25296   scaled txx,txy,tyx,tyy; /* transformation parameters */
25297   pointer p; /* the pen to stroke with */
25298   scaled d1,det; /* for tweaking transformation parameters */
25299   integer s; /* also for tweaking transformation paramters */
25300   boolean transformed; /* keeps track of whether gsave/grestore are needed */
25301   transformed=false;
25302   @<Use |pen_p(h)| to set the transformation parameters and give the initial
25303     translation@>;
25304   @<Tweak the transformation parameters so the transformation is nonsingular@>;
25305   mp_ps_path_out(mp, path_p(h));
25306   if ( mp->internal[mpprocset]==0 ) {
25307     if ( fill_also ) mp_print_nl(mp, "gsave fill grestore");
25308     @<Issue \ps\ commands to transform the coordinate system@>;
25309     mp_ps_print(mp, " stroke");
25310     if ( transformed ) mp_ps_print(mp, " grestore");
25311   } else {
25312     if ( fill_also ) mp_print_nl(mp, "B"); else mp_print_ln(mp);
25313     if ( (txy!=0)||(tyx!=0) ) {
25314       mp_print(mp, " [");
25315       mp_ps_pair_out(mp, txx,tyx);
25316       mp_ps_pair_out(mp, txy,tyy);
25317       mp_ps_print(mp, "0 0] t");
25318     } else if ((txx!=unity)||(tyy!=unity) )  {
25319       mp_ps_pair_out(mp,txx,tyy);
25320       mp_print(mp, " s");
25321     };
25322     mp_ps_print(mp, " S");
25323     if ( transformed ) mp_ps_print(mp, " Q");
25324   }
25325   mp_print_ln(mp);
25326 }
25327
25328 @ @<Use |pen_p(h)| to set the transformation parameters and give the...@>=
25329 p=pen_p(h);
25330 txx=left_x(p);
25331 tyx=left_y(p);
25332 txy=right_x(p);
25333 tyy=right_y(p);
25334 if ( (x_coord(p)!=0)||(y_coord(p)!=0) ) {
25335   mp_print_nl(mp, ""); mp_print_cmd(mp, "gsave ","q ");
25336   mp_ps_pair_out(mp, x_coord(p),y_coord(p));
25337   mp_ps_print(mp, "translate ");
25338   txx-=x_coord(p);
25339   tyx-=y_coord(p);
25340   txy-=x_coord(p);
25341   tyy-=y_coord(p);
25342   transformed=true;
25343 } else {
25344   mp_print_nl(mp, "");
25345 }
25346 @<Adjust the transformation to account for |gs_width| and output the
25347   initial \&{gsave} if |transformed| should be |true|@>
25348
25349 @ @<Adjust the transformation to account for |gs_width| and output the...@>=
25350 if ( gs_width!=unity ) {
25351   if ( gs_width==0 ) { 
25352     txx=unity; tyy=unity;
25353   } else { 
25354     txx=mp_make_scaled(mp, txx,gs_width);
25355     txy=mp_make_scaled(mp, txy,gs_width);
25356     tyx=mp_make_scaled(mp, tyx,gs_width);
25357     tyy=mp_make_scaled(mp, tyy,gs_width);
25358   };
25359 }
25360 if ( (txy!=0)||(tyx!=0)||(txx!=unity)||(tyy!=unity) ) {
25361   if ( (! transformed) ){ 
25362     mp_ps_print_cmd(mp, "gsave ","q ");
25363     transformed=true;
25364   }
25365 }
25366
25367 @ @<Issue \ps\ commands to transform the coordinate system@>=
25368 if ( (txy!=0)||(tyx!=0) ){ 
25369   mp_print_ln(mp);
25370   mp_print_char(mp, '[');
25371   mp_ps_pair_out(mp, txx,tyx);
25372   mp_ps_pair_out(mp, txy,tyy);
25373   mp_ps_print(mp, "0 0] concat");
25374 } else if ( (txx!=unity)||(tyy!=unity) ){ 
25375   mp_print_ln(mp);
25376   mp_ps_pair_out(mp, txx,tyy);
25377   mp_print(mp, "scale");
25378 }
25379
25380 @ The \ps\ interpreter will probably abort if it encounters a singular
25381 transformation matrix.  The determinant must be large enough to ensure that
25382 the printed representation will be nonsingular.  Since the printed
25383 representation is always within $2^{-17}$ of the internal |scaled| value, the
25384 total error is at most $4T_{\rm max}2^{-17}$, where $T_{\rm max}$ is a bound on
25385 the magnitudes of |txx/65536|, |txy/65536|, etc.
25386
25387 The |aspect_bound*(gs_width+1)| bound on the components of the pen
25388 transformation allows $T_{\rm max}$ to be at most |2*aspect_bound|.
25389
25390 @<Tweak the transformation parameters so the transformation is nonsingular@>=
25391 det=mp_take_scaled(mp, txx,tyy) - mp_take_scaled(mp, txy,tyx);
25392 d1=4*aspect_bound+1;
25393 if ( abs(det)<d1 ) { 
25394   if ( det>=0 ) { d1=d1-det; s=1;  }
25395   else { d1=-d1-det; s=-1;  };
25396   d1=d1*unity;
25397   if ( abs(txx)+abs(tyy)>=abs(txy)+abs(tyy) ) {
25398     if ( abs(txx)>abs(tyy) ) tyy=tyy+(d1+s*abs(txx)) / txx;
25399     else txx=txx+(d1+s*abs(tyy)) / tyy;
25400   } else {
25401     if ( abs(txy)>abs(tyx) ) tyx=tyx+(d1+s*abs(txy)) / txy;
25402     else txy=txy+(d1+s*abs(tyx)) / tyx;
25403   }
25404 }
25405
25406 @ Here is a simple routine that just fills a cycle.
25407
25408 @<Declare the \ps\ output procedures@>=
25409 void mp_ps_fill_out (MP mp,pointer p) ;
25410
25411 @ @c
25412 void mp_ps_fill_out (MP mp,pointer p) { /* fill cyclic path~|p| */
25413   mp_ps_path_out(mp, p);
25414   mp_ps_print_cmd(mp, " fill"," F");
25415   mp_print_ln(mp);
25416 }
25417
25418 @ Given a cyclic path~|p| and a graphical object~|h|, the |do_outer_envelope|
25419 procedure fills the cycle generated by |make_envelope|.  It need not do
25420 anything unless some region has positive winding number with respect to~|p|,
25421 but it does not seem worthwhile to for test this.
25422
25423 @<Declare the \ps\ output procedures@>=
25424 void mp_do_outer_envelope (MP mp,pointer p, pointer h) ;
25425
25426 @ @c
25427 void mp_do_outer_envelope (MP mp,pointer p, pointer h) {
25428   p=mp_make_envelope(mp, p, pen_p(h), ljoin_val(h), 0, miterlim_val(h));
25429   mp_ps_fill_out(mp, p);
25430   mp_toss_knot_list(mp, p);
25431 }
25432
25433 @ A text node may specify an arbitrary transformation but the usual case
25434 involves only shifting, scaling, and occasionally rotation.  The purpose
25435 of |choose_scale| is to select a scale factor so that the remaining
25436 transformation is as ``nice'' as possible.  The definition of ``nice''
25437 is somewhat arbitrary but shifting and $90^\circ$ rotation are especially
25438 nice because they work out well for bitmap fonts.  The code here selects
25439 a scale factor equal to $1/\sqrt2$ times the Frobenius norm of the
25440 non-shifting part of the transformation matrix.  It is careful to avoid
25441 additions that might cause undetected overflow.
25442
25443 @<Declare the \ps\ output procedures@>=
25444 scaled mp_choose_scale (MP mp,pointer p) ;
25445
25446 @ @c scaled mp_choose_scale (MP mp,pointer p) {
25447   /* |p| should point to a text node */
25448   scaled a,b,c,d,ad,bc; /* temporary values */
25449   a=txx_val(p);
25450   b=txy_val(p);
25451   c=tyx_val(p);
25452   d=tyy_val(p);
25453   if ( (a<0) ) negate(a);
25454   if ( (b<0) ) negate(b);
25455   if ( (c<0) ) negate(c);
25456   if ( (d<0) ) negate(d);
25457   ad=half(a-d);
25458   bc=half(b-c);
25459   return mp_pyth_add(mp, mp_pyth_add(mp, d+ad,ad), mp_pyth_add(mp, c+bc,bc));
25460 }
25461
25462 @ @<Declare the \ps\ output procedures@>= 
25463 void mp_mark_string_chars (MP mp,font_number f, str_number s) ;
25464
25465 @ @c
25466 void mp_mark_string_chars (MP mp,font_number f, str_number s) {
25467   integer b; /* |char_base[f]| */
25468   ASCII_code bc,ec; /* only characters between these bounds are marked */
25469   pool_pointer k; /* an index into string |s| */
25470   b=mp->char_base[f];
25471   bc=mp->font_bc[f];
25472   ec=mp->font_ec[f];
25473   k=str_stop(s);
25474   while ( k>mp->str_start[s] ){ 
25475     decr(k);
25476     if ( (mp->str_pool[k]>=bc)&&(mp->str_pool[k]<=ec) )
25477       mp->font_info[b+mp->str_pool[k]].qqqq.b3=used;
25478   }
25479 }
25480
25481 @ There may be many sizes of one font and we need to keep track of the
25482 characters used for each size.  This is done by keeping a linked list of
25483 sizes for each font with a counter in each text node giving the appropriate
25484 position in the size list for its font.
25485
25486 @d sc_factor(A) mp->mem[(A)+1].sc /* the scale factor stored in a font size node */
25487 @d font_size_size 2 /* size of a font size node */
25488
25489 @ @<Exported...@>=
25490 boolean mp_has_font_size(MP mp, font_number f );
25491
25492 @ @c 
25493 boolean mp_has_font_size(MP mp, font_number f ) {
25494   return (mp->font_sizes[f]!=null);
25495 }
25496
25497
25498 @ The overflow here is caused by the fact the returned value
25499 has to fit in a |name_type|, which is a quarterword. 
25500
25501 @d fscale_tolerance 65 /* that's $.001\times2^{16}$ */
25502
25503 @<Declare the \ps\ output procedures@>=
25504 quarterword mp_size_index (MP mp, font_number f, scaled s) {
25505   pointer p,q; /* the previous and current font size nodes */
25506   quarterword i; /* the size index for |q| */
25507   q=mp->font_sizes[f];
25508   i=0;
25509   while ( q!=null ) {
25510     if ( abs(s-sc_factor(q))<=fscale_tolerance ) 
25511       return i;
25512     else 
25513       { p=q; q=link(q); incr(i); };
25514     if ( i==max_quarterword )
25515       mp_overflow(mp, "sizes per font",max_quarterword);
25516 @:MetaPost capacity exceeded sizes per font}{\quad sizes per font@>
25517   }
25518   q=mp_get_node(mp, font_size_size);
25519   sc_factor(q)=s;
25520   if ( i==0 ) mp->font_sizes[f]=q;  else link(p)=q;
25521   return i;
25522 }
25523
25524 @ @<Declare the \ps\ output procedures@>=
25525 scaled mp_indexed_size (MP mp,font_number f, quarterword j) {
25526   pointer p; /* a font size node */
25527   quarterword i; /* the size index for |p| */
25528   p=mp->font_sizes[f];
25529   i=0;
25530   if ( p==null ) mp_confusion(mp, "size");
25531   while ( (i!=j) ) { 
25532     incr(i); p=link(p);
25533     if ( p==null ) mp_confusion(mp, "size");
25534   }
25535   return sc_factor(p);
25536 }
25537
25538 @ @<Declare the \ps\ output procedures@>=
25539 void mp_clear_sizes (MP mp) ;
25540
25541 @ @c void mp_clear_sizes (MP mp) {
25542   font_number f;  /* the font whose size list is being cleared */
25543   pointer p;  /* current font size nodes */
25544   for (f=null_font+1;f<=mp->last_fnum;f++) {
25545     while ( mp->font_sizes[f]!=null ) {
25546       p=mp->font_sizes[f];
25547       mp->font_sizes[f]=link(p);
25548       mp_free_node(mp, p,font_size_size);
25549     }
25550   }
25551 }
25552
25553 @ The \&{special} command saves up lines of text to be printed during the next
25554 |ship_out| operation.  The saved items are stored as a list of capsule tokens.
25555
25556 @<Glob...@>=
25557 pointer last_pending; /* the last token in a list of pending specials */
25558
25559 @ @<Set init...@>=
25560 mp->last_pending=spec_head;
25561
25562 @ @<Cases of |do_statement|...@>=
25563 case special_command: 
25564   if ( mp->cur_mod==0 ) mp_do_special(mp); else 
25565   if ( mp->cur_mod==1 ) mp_do_mapfile(mp); else 
25566   mp_do_mapline(mp);
25567   break;
25568
25569 @ @<Declare action procedures for use by |do_statement|@>=
25570 void mp_do_special (MP mp) ;
25571
25572 @ @c void mp_do_special (MP mp) { 
25573   mp_get_x_next(mp); mp_scan_expression(mp);
25574   if ( mp->cur_type!=mp_string_type ) {
25575     @<Complain about improper special operation@>;
25576   } else { 
25577     link(mp->last_pending)=mp_stash_cur_exp(mp);
25578     mp->last_pending=link(mp->last_pending);
25579     link(mp->last_pending)=null;
25580   }
25581 }
25582
25583 @ @<Complain about improper special operation@>=
25584
25585   exp_err("Unsuitable expression");
25586   help1("Only known strings are allowed for output as specials.");
25587   mp_put_get_error(mp);
25588 }
25589
25590 @ @<Print any pending specials@>=
25591 t=link(spec_head);
25592 while ( t!=null ) {
25593   mp_print_str(mp, value(t));
25594   mp_print_ln(mp);
25595   t=link(t);
25596 }
25597 mp_flush_token_list(mp, link(spec_head));
25598 link(spec_head)=null;
25599 mp->last_pending=spec_head
25600
25601 @ We are now ready for the main output procedure.  Note that the |selector|
25602 setting is saved in a global variable so that |begin_diagnostic| can access it.
25603
25604 @<Declare the \ps\ output procedures@>=
25605 void mp_ship_out (MP mp, pointer h) ;
25606
25607 @ @c
25608 void mp_ship_out (MP mp, pointer h) { /* output edge structure |h| */
25609   pointer p; /* the current graphical object */
25610   pointer q; /* something that |p| points to */
25611   integer t; /* a temporary value */
25612   font_number f; /* fonts used in a text node or as loop counters */
25613   font_number ldf;
25614   scaled ds,scf; /* design size and scale factor for a text node */
25615   boolean transformed; /* is the coordinate system being transformed? */
25616   mp_open_output_file(mp);
25617   mp->non_ps_setting=mp->selector; mp->selector=ps_file_only;
25618   if ( (mp->internal[prologues]==two)||(mp->internal[prologues]==three) ) {
25619     @<Print improved initial comment and bounding box for edge structure~|h|@>;
25620     @<Scan all the text nodes and mark the used characters@>;
25621     mp_load_encodings(mp,mp->last_fnum);
25622     @<Update encoding names@>;
25623     @<Print the improved prologue and setup@>;
25624   } else {
25625     @<Print the initial comment and give the bounding box for edge structure~|h|@>;
25626     if ( (mp->internal[prologues]>0) && (mp->last_ps_fnum<mp->last_fnum) )
25627       mp_read_psname_table(mp);
25628     mp_print_prologue(mp, (mp->internal[prologues]>>16), (mp->internal[mpprocset]>>16), ldf);
25629   }
25630   @<Print any pending specials@>;
25631   mp_unknown_graphics_state(mp, 0);
25632   mp->need_newpath=true;
25633   p=link(dummy_loc(h));
25634   while ( p!=null ) { 
25635     if ( has_color(p) ) {
25636       if ( (pre_script(p))!=null ) {
25637         mp_print_nl (mp, str(pre_script(p))); mp_print_ln(mp);
25638       }
25639     }
25640     mp_fix_graphics_state(mp, p);
25641     switch (type(p)) {
25642     @<Cases for translating graphical object~|p| into \ps@>;
25643     case mp_start_bounds_code:
25644     case mp_stop_bounds_code:
25645           break;
25646     } /* all cases are enumerated */
25647     p=link(p);
25648   }
25649   mp_print_cmd(mp, "showpage","P"); mp_print_ln(mp);
25650   mp_print(mp, "%%EOF"); mp_print_ln(mp);
25651   fclose(mp->ps_file);
25652   mp->selector=mp->non_ps_setting;
25653   if ( mp->internal[prologues]<=0 ) mp_clear_sizes(mp);
25654   @<End progress report@>;
25655   if ( mp->internal[tracing_output]>0 ) 
25656    mp_print_edges(mp, h," (just shipped out)",true);
25657 }
25658
25659 @ @<Exported...@>=
25660 void mp_apply_mark_string_chars(MP mp, pointer h, int next_size);
25661
25662 @ @c
25663 void mp_apply_mark_string_chars(MP mp, pointer h, int next_size) {
25664   pointer p;
25665   p=link(dummy_loc(h));
25666   while ( p!=null ) {
25667     if ( type(p)==text_code )
25668       if ( font_n(p)!=null_font )
25669         if ( name_type(p)==next_size )
25670           mp_mark_string_chars(mp, font_n(p),text_p(p));
25671     p=link(p);
25672   }
25673 }
25674
25675 @
25676 @<Print the improved prologue and setup@>=
25677 {
25678   mp_print_improved_prologue(mp, (mp->internal[prologues]>>16),(mp->internal[mpprocset]>>16),
25679                             (mp->internal[gtroffmode]>>16), null, h);
25680 }
25681
25682 @
25683 @<Print improved initial comment and bounding box for edge...@>=
25684 mp_print(mp, "%!PS-Adobe-3.0 EPSF-3.0");
25685 mp_print_nl(mp, "%%BoundingBox: ");
25686 mp_set_bbox(mp, h,true);
25687 if ( minx_val(h)>maxx_val(h) ) {
25688   mp_print(mp, "0 0 0 0");
25689 } else { 
25690   mp_ps_pair_out(mp, mp_floor_scaled(mp, minx_val(h)),mp_floor_scaled(mp, miny_val(h)));
25691   mp_ps_pair_out(mp, -mp_floor_scaled(mp, -maxx_val(h)),-mp_floor_scaled(mp, -maxy_val(h)));
25692 };
25693 mp_print_nl(mp, "%%HiResBoundingBox: ");
25694 if ( minx_val(h)>maxx_val(h) ) {
25695   mp_print(mp, "0 0 0 0");
25696 } else {
25697   mp_ps_pair_out(mp, minx_val(h),miny_val(h));
25698   mp_ps_pair_out(mp, maxx_val(h),maxy_val(h));
25699 }
25700 mp_print_nl(mp, "%%Creator: MetaPost ");
25701 mp_print(mp, metapost_version);
25702 mp_print_nl(mp, "%%CreationDate: ");
25703 mp_print_int(mp, mp_round_unscaled(mp, mp->internal[year])); mp_print_char(mp, '.');
25704 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[month])); mp_print_char(mp, '.');
25705 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[day])); mp_print_char(mp, ':');
25706 t=mp_round_unscaled(mp, mp->internal[mp_time]);
25707 mp_print_dd(mp, t / 60); mp_print_dd(mp, t % 60);
25708 mp_print_nl(mp, "%%Pages: 1");
25709
25710 @
25711
25712 @ @<Scan all the text nodes and mark the used ...@>=
25713 for (f=null_font+1;f<=mp->last_fnum;f++) {
25714   if ( mp->font_sizes[f]!=null ) {
25715     mp_unmark_font(mp, f);
25716     mp->font_sizes[f]=null;
25717   }
25718   if ( mp->font_enc_name[f]!=NULL )
25719      xfree(mp->font_enc_name[f]);
25720   mp->font_enc_name[f] = NULL;
25721 }
25722 for (f=null_font+1;f<=mp->last_fnum;f++) {
25723   p=link(dummy_loc(h));
25724   while ( p!=null ) {
25725     if ( type(p)==text_code ) {
25726       if ( font_n(p)!=null_font ) {
25727         mp->font_sizes[font_n(p)] = diov;
25728         mp_mark_string_chars(mp, font_n(p),text_p(p));
25729             if ( mp_has_fm_entry(mp,font_n(p),NULL) )
25730           mp->font_ps_name[font_n(p)] = mp_fm_font_name(mp,font_n(p));
25731       }
25732     }
25733     p=link(p);
25734   }
25735 }
25736
25737 @ @<Update encoding names@>=
25738 for (f=null_font+1;f<=mp->last_fnum;f++) {
25739   p=link(dummy_loc(h));
25740   while ( p!=null ) {
25741     if ( type(p)==text_code )
25742       if ( font_n(p)!=null_font )
25743             if ( mp_has_fm_entry(mp,font_n(p),NULL) )
25744           if ( mp->font_enc_name[font_n(p)]==NULL )
25745             mp->font_enc_name[font_n(p)] = mp_fm_encoding_name(mp,font_n(p));
25746     p=link(p);
25747   }
25748 }
25749
25750 @ These special comments described in the {\sl PostScript Language Reference
25751 Manual}, 2nd.~edition are understood by some \ps-reading programs.
25752 We can't normally output ``conforming'' \ps\ because
25753 the structuring conventions don't allow us to say ``Please make sure the
25754 following characters are downloaded and define the \.{fshow} macro to access
25755 them.''
25756
25757 The exact bounding box is written out if |prologues<0|, although this
25758 is not standard \ps, since it allows \TeX\ to calculate the box dimensions
25759 accurately. (Overfull boxes are avoided if an illustration is made to
25760 match a given \.{\char`\\hsize}.)
25761
25762 @<Print the initial comment and give the bounding box for edge...@>=
25763 mp_print(mp, "%!PS");
25764 if ( mp->internal[prologues]>0 ) mp_print(mp, "-Adobe-3.0 EPSF-3.0");
25765 mp_print_nl(mp, "%%BoundingBox: ");
25766 mp_set_bbox(mp, h,true);
25767 if ( minx_val(h)>maxx_val(h) ) mp_print(mp, "0 0 0 0");
25768 else if ( mp->internal[prologues]<0 ) {
25769   mp_ps_pair_out(mp, minx_val(h),miny_val(h));
25770   mp_ps_pair_out(mp, maxx_val(h),maxy_val(h));
25771 } else { 
25772   mp_ps_pair_out(mp, mp_floor_scaled(mp, minx_val(h)),mp_floor_scaled(mp, miny_val(h)));
25773   mp_ps_pair_out(mp, -mp_floor_scaled(mp, -maxx_val(h)),-mp_floor_scaled(mp, -maxy_val(h)));
25774 }
25775 mp_print_nl(mp, "%%HiResBoundingBox: ");
25776 if ( minx_val(h)>maxx_val(h) ) mp_print(mp, "0 0 0 0");
25777 else {
25778   mp_ps_pair_out(mp, minx_val(h),miny_val(h));
25779   mp_ps_pair_out(mp, maxx_val(h),maxy_val(h));
25780 }
25781 mp_print_nl(mp, "%%Creator: MetaPost ");
25782 mp_print(mp, metapost_version);
25783 mp_print_nl(mp, "%%CreationDate: ");
25784 mp_print_int(mp, mp_round_unscaled(mp, mp->internal[year])); mp_print_char(mp, '.');
25785 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[month])); mp_print_char(mp, '.');
25786 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[day])); mp_print_char(mp, ':');
25787 t=mp_round_unscaled(mp, mp->internal[mp_time]);
25788 mp_print_dd(mp, t / 60); mp_print_dd(mp, t % 60);
25789 mp_print_nl(mp, "%%Pages: 1");
25790 @<List all the fonts and magnifications for edge structure~|h|@>;
25791 mp_print_ln(mp)
25792
25793 @ @<List all the fonts and magnifications for edge structure~|h|@>=
25794 @<Scan all the text nodes and set the |font_sizes| lists;
25795   if |internal[prologues]<=0| list the sizes selected by |choose_scale|,
25796   apply |unmark_font| to each font encountered, and call |mark_string|
25797   whenever the size index is zero@>;
25798 ldf = mp_print_font_comments (mp, (mp->internal[prologues]>>16), null, h)
25799
25800 @ @<Scan all the text nodes and set the |font_sizes| lists;...@>=
25801 for (f=null_font+1;f<=mp->last_fnum;f++) 
25802   mp->font_sizes[f]=null;
25803 p=link(dummy_loc(h));
25804 while ( p!=null ) {
25805   if ( type(p)==text_code ) {
25806     if ( font_n(p)!=null_font ) {
25807       f=font_n(p);
25808       if ( mp->internal[prologues]>0 ) {
25809         mp->font_sizes[f]=diov;
25810       } else { 
25811         if ( mp->font_sizes[f]==null ) mp_unmark_font(mp, f);
25812         name_type(p)=mp_size_index(mp, f,mp_choose_scale(mp, p));
25813         if ( name_type(p)==0 )
25814           mp_mark_string_chars(mp, f,text_p(p));
25815       }
25816     }
25817   }
25818   p=link(p);
25819 }
25820
25821 @ @<Cases for translating graphical object~|p| into \ps@>=
25822 case mp_start_clip_code: 
25823   mp_print_nl(mp, ""); mp_print_cmd(mp, "gsave ","q ");
25824   mp_ps_path_out(mp, path_p(p));
25825   mp_ps_print_cmd(mp, " clip"," W");
25826   mp_print_ln(mp);
25827   if ( mp->internal[restore_clip_color]>0 )
25828     mp_unknown_graphics_state(mp, 1);
25829   break;
25830 case mp_stop_clip_code: 
25831   mp_print_nl(mp, ""); mp_print_cmd(mp, "grestore","Q");
25832   mp_print_ln(mp);
25833   if ( mp->internal[restore_clip_color]>0 )
25834     mp_unknown_graphics_state(mp, 2);
25835   else
25836     mp_unknown_graphics_state(mp, -1);
25837   break;
25838
25839 @ @<Cases for translating graphical object~|p| into \ps@>=
25840 case fill_code: 
25841   if ( pen_p(p)==null ) mp_ps_fill_out(mp, path_p(p));
25842   else if ( pen_is_elliptical(pen_p(p)) ) mp_stroke_ellipse(mp, p,true);
25843   else { 
25844     mp_do_outer_envelope(mp, mp_copy_path(mp, path_p(p)), p);
25845     mp_do_outer_envelope(mp, mp_htap_ypoc(mp, path_p(p)), p);
25846   }
25847   if ( (post_script(p))!=null ) {
25848     mp_print_nl (mp, str(post_script(p))); mp_print_ln(mp);
25849   };
25850   break;
25851 case stroked_code:
25852   if ( pen_is_elliptical(pen_p(p)) ) mp_stroke_ellipse(mp, p,false);
25853   else { 
25854     q=mp_copy_path(mp, path_p(p));
25855     t=lcap_val(p);
25856     @<Break the cycle and set |t:=1| if path |q| is cyclic@>;
25857     q=mp_make_envelope(mp, q,pen_p(p),ljoin_val(p),t,miterlim_val(p));
25858     mp_ps_fill_out(mp, q);
25859     mp_toss_knot_list(mp, q);
25860   };
25861   if ( (post_script(p))!=null ) {
25862     mp_print_nl (mp, str(post_script(p))); mp_print_ln(mp);
25863   };
25864   break;
25865
25866 @ The envelope of a cyclic path~|q| could be computed by calling
25867 |make_envelope| once for |q| and once for its reversal.  We don't do this
25868 because it would fail color regions that are covered by the pen regardless
25869 of where it is placed on~|q|.
25870
25871 @<Break the cycle and set |t:=1| if path |q| is cyclic@>=
25872 if ( left_type(q)!=endpoint ) { 
25873   left_type(mp_insert_knot(mp, q,x_coord(q),y_coord(q)))=endpoint;
25874   right_type(q)=endpoint;
25875   q=link(q);
25876   t=1;
25877 }
25878
25879 @ @<Cases for translating graphical object~|p| into \ps@>=
25880 case text_code: 
25881   if ( (font_n(p)!=null_font) && (length(text_p(p))>0) ) {
25882     if ( mp->internal[prologues]>0 )
25883       scf=mp_choose_scale(mp, p);
25884     else 
25885       scf=mp_indexed_size(mp, font_n(p), name_type(p));
25886     @<Shift or transform as necessary before outputting text node~|p| at scale
25887       factor~|scf|; set |transformed:=true| if the original transformation must
25888       be restored@>;
25889     mp_ps_string_out(mp, str(text_p(p)));
25890     mp_ps_name_out(mp, mp->font_name[font_n(p)],false);
25891     @<Print the size information and \ps\ commands for text node~|p|@>;
25892     mp_print_ln(mp);
25893   }
25894   if ( (post_script(p))!=null ) {
25895     mp_print_nl (mp, str(post_script(p))); mp_print_ln(mp);
25896   }
25897   break;
25898
25899 @ @<Print the size information and \ps\ commands for text node~|p|@>=
25900 ps_room(18);
25901 mp_print_char(mp, ' ');
25902 ds=(mp->font_dsize[font_n(p)]+8) / 16;
25903 mp_print_scaled(mp, mp_take_scaled(mp, ds,scf));
25904 mp_print(mp, " fshow");
25905 if ( transformed ) 
25906   mp_ps_print_cmd(mp, " grestore"," Q")
25907
25908 @ @<Shift or transform as necessary before outputting text node~|p| at...@>=
25909 transformed=(txx_val(p)!=scf)||(tyy_val(p)!=scf)||
25910             (txy_val(p)!=0)||(tyx_val(p)!=0);
25911 if ( transformed ) {
25912   mp_print_cmd(mp, "gsave [", "q [");
25913   mp_ps_pair_out(mp, mp_make_scaled(mp, txx_val(p),scf),
25914                      mp_make_scaled(mp, tyx_val(p),scf));
25915   mp_ps_pair_out(mp, mp_make_scaled(mp, txy_val(p),scf),
25916                      mp_make_scaled(mp, tyy_val(p),scf));
25917   mp_ps_pair_out(mp, tx_val(p),ty_val(p));
25918   mp_ps_print_cmd(mp, "] concat 0 0 moveto","] t 0 0 m");
25919 } else { 
25920   mp_ps_pair_out(mp, tx_val(p),ty_val(p));
25921   mp_ps_print_cmd(mp, "moveto","m");
25922 }
25923 mp_print_ln(mp)
25924
25925 @ Now that we've finished |ship_out|, let's look at the other commands
25926 by which a user can send things to the \.{GF} file.
25927
25928 @ @<Determine if a character has been shipped out@>=
25929
25930   mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256;
25931   if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
25932   boolean_reset(mp->char_exists[mp->cur_exp]);
25933   mp->cur_type=mp_boolean_type;
25934 }
25935
25936 @ @<Glob...@>=
25937 psout_data ps;
25938
25939 @ @<Allocate or initialize ...@>=
25940 mp_backend_initialize(mp);
25941
25942 @ @<Dealloc...@>=
25943 mp_backend_free(mp);
25944
25945
25946 @* \[45] Dumping and undumping the tables.
25947 After \.{INIMP} has seen a collection of macros, it
25948 can write all the necessary information on an auxiliary file so
25949 that production versions of \MP\ are able to initialize their
25950 memory at high speed. The present section of the program takes
25951 care of such output and input. We shall consider simultaneously
25952 the processes of storing and restoring,
25953 so that the inverse relation between them is clear.
25954 @.INIMP@>
25955
25956 The global variable |mem_ident| is a string that is printed right
25957 after the |banner| line when \MP\ is ready to start. For \.{INIMP} this
25958 string says simply `\.{(INIMP)}'; for other versions of \MP\ it says,
25959 for example, `\.{(mem=plain 90.4.14)}', showing the year,
25960 month, and day that the mem file was created. We have |mem_ident=0|
25961 before \MP's tables are loaded.
25962
25963 @<Glob...@>=
25964 char * mem_ident;
25965
25966 @ @<Set init...@>=
25967 mp->mem_ident=NULL;
25968
25969 @ @<Initialize table entries...@>=
25970 if (mp->ini_version) 
25971   mp->mem_ident=xstrdup(" (INIMP)");
25972
25973 @ @<Declare act...@>=
25974 void mp_store_mem_file (MP mp) ;
25975
25976 @ @c void mp_store_mem_file (MP mp) {
25977   integer k;  /* all-purpose index */
25978   pointer p,q; /* all-purpose pointers */
25979   integer x; /* something to dump */
25980   four_quarters w; /* four ASCII codes */
25981   memory_word WW;
25982   @<Create the |mem_ident|, open the mem file,
25983     and inform the user that dumping has begun@>;
25984   @<Dump constants for consistency check@>;
25985   @<Dump the string pool@>;
25986   @<Dump the dynamic memory@>;
25987   @<Dump the table of equivalents and the hash table@>;
25988   @<Dump a few more things and the closing check word@>;
25989   @<Close the mem file@>;
25990 }
25991
25992 @ Corresponding to the procedure that dumps a mem file, we also have a function
25993 that reads~one~in. The function returns |false| if the dumped mem is
25994 incompatible with the present \MP\ table sizes, etc.
25995
25996 @d off_base 6666 /* go here if the mem file is unacceptable */
25997 @d too_small(A) { wake_up_terminal;
25998   wterm_ln("---! Must increase the "); wterm((A));
25999 @.Must increase the x@>
26000   goto OFF_BASE;
26001   }
26002
26003 @c 
26004 boolean mp_load_mem_file (MP mp) {
26005   integer k; /* all-purpose index */
26006   pointer p,q; /* all-purpose pointers */
26007   integer x; /* something undumped */
26008   str_number s; /* some temporary string */
26009   four_quarters w; /* four ASCII codes */
26010   memory_word WW;
26011   @<Undump constants for consistency check@>;
26012   @<Undump the string pool@>;
26013   @<Undump the dynamic memory@>;
26014   @<Undump the table of equivalents and the hash table@>;
26015   @<Undump a few more things and the closing check word@>;
26016   return true; /* it worked! */
26017 OFF_BASE: 
26018   wake_up_terminal;
26019   wterm_ln("(Fatal mem file error; I'm stymied)\n");
26020 @.Fatal mem file error@>
26021    return false;
26022 }
26023
26024 @ @<Declarations@>=
26025 boolean mp_load_mem_file (MP mp) ;
26026
26027 @ Mem files consist of |memory_word| items, and we use the following
26028 macros to dump words of different types:
26029
26030 @d dump_wd(A)   { WW=(A);       fwrite(&WW,sizeof(WW),1,mp->mem_file); }
26031 @d dump_int(A)  { int cint=(A); fwrite(&cint,sizeof(cint),1,mp->mem_file); }
26032 @d dump_hh(A)   { WW.hh=(A);    fwrite(&WW,sizeof(WW),1,mp->mem_file); }
26033 @d dump_qqqq(A) { WW.qqqq=(A);  fwrite(&WW,sizeof(WW),1,mp->mem_file); }
26034 @d dump_string(A) { dump_int(strlen(A)+1);
26035                     fwrite(A,strlen(A)+1,1,mp->mem_file); }
26036
26037 @<Glob...@>=
26038 FILE * mem_file; /* for input or output of mem information */
26039
26040 @ The inverse macros are slightly more complicated, since we need to check
26041 the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
26042 read an integer value |x| that is supposed to be in the range |a<=x<=b|.
26043
26044 @d undump_wd(A)   { fread(&WW,sizeof(WW),1,mp->mem_file); (A)=WW; }
26045 @d undump_int(A)  { int cint; fread(&cint,sizeof(cint),1,mp->mem_file); (A)=cint; }
26046 @d undump_hh(A)   { fread(&WW,sizeof(WW),1,mp->mem_file); (A)=WW.hh; }
26047 @d undump_qqqq(A) { fread(&WW,sizeof(WW),1,mp->mem_file); (A)=WW.qqqq; }
26048 @d undump_strings(A,B,C) { 
26049    undump_int(x); if ( (x<(A)) || (x>(B)) ) goto OFF_BASE; else (C)=str(x); }
26050 @d undump(A,B,C) { undump_int(x); if ( (x<(A)) || (x>(int)(B)) ) goto OFF_BASE; else (C)=x; }
26051 @d undump_size(A,B,C,D) { undump_int(x);
26052                if (x<(A)) goto OFF_BASE; 
26053                if (x>(B)) { too_small((C)); } else {(D)=x;} }
26054 @d undump_string(A) { integer XX=0; undump_int(XX);
26055                       A = xmalloc(XX,sizeof(char));
26056                       fread(A,XX,1,mp->mem_file); }
26057
26058 @ The next few sections of the program should make it clear how we use the
26059 dump/undump macros.
26060
26061 @<Dump constants for consistency check@>=
26062 dump_int(mp->mem_top);
26063 dump_int(mp->hash_size);
26064 dump_int(mp->hash_prime)
26065 dump_int(mp->param_size);
26066 dump_int(mp->max_in_open);
26067
26068 @ Sections of a \.{WEB} program that are ``commented out'' still contribute
26069 strings to the string pool; therefore \.{INIMP} and \MP\ will have
26070 the same strings. (And it is, of course, a good thing that they do.)
26071 @.WEB@>
26072 @^string pool@>
26073
26074 @<Undump constants for consistency check@>=
26075 undump_int(x); mp->mem_top = x;
26076 undump_int(x); if (mp->hash_size != x) goto OFF_BASE;
26077 undump_int(x); if (mp->hash_prime != x) goto OFF_BASE;
26078 undump_int(x); if (mp->param_size != x) goto OFF_BASE;
26079 undump_int(x); if (mp->max_in_open != x) goto OFF_BASE
26080
26081 @ We do string pool compaction to avoid dumping unused strings.
26082
26083 @d dump_four_ASCII 
26084   w.b0=qi(mp->str_pool[k]); w.b1=qi(mp->str_pool[k+1]);
26085   w.b2=qi(mp->str_pool[k+2]); w.b3=qi(mp->str_pool[k+3]);
26086   dump_qqqq(w)
26087
26088 @<Dump the string pool@>=
26089 mp_do_compaction(mp, mp->pool_size);
26090 dump_int(mp->pool_ptr);
26091 dump_int(mp->max_str_ptr);
26092 dump_int(mp->str_ptr);
26093 k=0;
26094 while ( (mp->next_str[k]==k+1) && (k<=mp->max_str_ptr) ) 
26095   incr(k);
26096 dump_int(k);
26097 while ( k<=mp->max_str_ptr ) { 
26098   dump_int(mp->next_str[k]); incr(k);
26099 }
26100 k=0;
26101 while (1)  { 
26102   dump_int(mp->str_start[k]); /* TODO: valgrind warning here */
26103   if ( k==mp->str_ptr ) {
26104     break;
26105   } else { 
26106     k=mp->next_str[k]; 
26107   }
26108 };
26109 k=0;
26110 while (k+4<mp->pool_ptr ) { 
26111   dump_four_ASCII; k=k+4; 
26112 }
26113 k=mp->pool_ptr-4; dump_four_ASCII;
26114 mp_print_ln(mp); mp_print(mp, "at most "); mp_print_int(mp, mp->max_str_ptr);
26115 mp_print(mp, " strings of total length ");
26116 mp_print_int(mp, mp->pool_ptr)
26117
26118 @ @d undump_four_ASCII 
26119   undump_qqqq(w);
26120   mp->str_pool[k]=qo(w.b0); mp->str_pool[k+1]=qo(w.b1);
26121   mp->str_pool[k+2]=qo(w.b2); mp->str_pool[k+3]=qo(w.b3)
26122
26123 @<Undump the string pool@>=
26124 undump_int(mp->pool_ptr);
26125 mp_reallocate_pool(mp, mp->pool_ptr) ;
26126 undump_int(mp->max_str_ptr);
26127 mp_reallocate_strings (mp,mp->max_str_ptr) ;
26128 undump(0,mp->max_str_ptr,mp->str_ptr);
26129 undump(0,mp->max_str_ptr+1,s);
26130 for (k=0;k<=s-1;k++) 
26131   mp->next_str[k]=k+1;
26132 for (k=s;k<=mp->max_str_ptr;k++) 
26133   undump(s+1,mp->max_str_ptr+1,mp->next_str[k]);
26134 mp->fixed_str_use=0;
26135 k=0;
26136 while (1) { 
26137   undump(0,mp->pool_ptr,mp->str_start[k]);
26138   if ( k==mp->str_ptr ) break;
26139   mp->str_ref[k]=max_str_ref;
26140   incr(mp->fixed_str_use);
26141   mp->last_fixed_str=k; k=mp->next_str[k];
26142 }
26143 k=0;
26144 while ( k+4<mp->pool_ptr ) { 
26145   undump_four_ASCII; k=k+4;
26146 }
26147 k=mp->pool_ptr-4; undump_four_ASCII;
26148 mp->init_str_use=mp->fixed_str_use; mp->init_pool_ptr=mp->pool_ptr;
26149 mp->max_pool_ptr=mp->pool_ptr;
26150 mp->strs_used_up=mp->fixed_str_use;
26151 mp->pool_in_use=mp->str_start[mp->str_ptr]; mp->strs_in_use=mp->fixed_str_use;
26152 mp->max_pl_used=mp->pool_in_use; mp->max_strs_used=mp->strs_in_use;
26153 mp->pact_count=0; mp->pact_chars=0; mp->pact_strs=0;
26154
26155 @ By sorting the list of available spaces in the variable-size portion of
26156 |mem|, we are usually able to get by without having to dump very much
26157 of the dynamic memory.
26158
26159 We recompute |var_used| and |dyn_used|, so that \.{INIMP} dumps valid
26160 information even when it has not been gathering statistics.
26161
26162 @<Dump the dynamic memory@>=
26163 mp_sort_avail(mp); mp->var_used=0;
26164 dump_int(mp->lo_mem_max); dump_int(mp->rover);
26165 p=0; q=mp->rover; x=0;
26166 do {  
26167   for (k=p;k<= q+1;k++) 
26168     dump_wd(mp->mem[k]);
26169   x=x+q+2-p; mp->var_used=mp->var_used+q-p;
26170   p=q+node_size(q); q=rlink(q);
26171 } while (q!=mp->rover);
26172 mp->var_used=mp->var_used+mp->lo_mem_max-p; 
26173 mp->dyn_used=mp->mem_end+1-mp->hi_mem_min;
26174 for (k=p;k<= mp->lo_mem_max;k++ ) 
26175   dump_wd(mp->mem[k]);
26176 x=x+mp->lo_mem_max+1-p;
26177 dump_int(mp->hi_mem_min); dump_int(mp->avail);
26178 for (k=mp->hi_mem_min;k<=mp->mem_end;k++ ) 
26179   dump_wd(mp->mem[k]);
26180 x=x+mp->mem_end+1-mp->hi_mem_min;
26181 p=mp->avail;
26182 while ( p!=null ) { 
26183   decr(mp->dyn_used); p=link(p);
26184 }
26185 dump_int(mp->var_used); dump_int(mp->dyn_used);
26186 mp_print_ln(mp); mp_print_int(mp, x);
26187 mp_print(mp, " memory locations dumped; current usage is ");
26188 mp_print_int(mp, mp->var_used); mp_print_char(mp, '&'); mp_print_int(mp, mp->dyn_used)
26189
26190 @ @<Undump the dynamic memory@>=
26191 undump(lo_mem_stat_max+1000,hi_mem_stat_min-1,mp->lo_mem_max);
26192 undump(lo_mem_stat_max+1,mp->lo_mem_max,mp->rover);
26193 p=0; q=mp->rover;
26194 do {  
26195   for (k=p;k<= q+1; k++) 
26196     undump_wd(mp->mem[k]);
26197   p=q+node_size(q);
26198   if ( (p>mp->lo_mem_max)||((q>=rlink(q))&&(rlink(q)!=mp->rover)) ) 
26199     goto OFF_BASE;
26200   q=rlink(q);
26201 } while (q!=mp->rover);
26202 for (k=p;k<=mp->lo_mem_max;k++ ) 
26203   undump_wd(mp->mem[k]);
26204 undump(mp->lo_mem_max+1,hi_mem_stat_min,mp->hi_mem_min);
26205 undump(null,mp->mem_top,mp->avail); mp->mem_end=mp->mem_top;
26206 for (k=mp->hi_mem_min;k<= mp->mem_end;k++) 
26207   undump_wd(mp->mem[k]);
26208 undump_int(mp->var_used); undump_int(mp->dyn_used)
26209
26210 @ A different scheme is used to compress the hash table, since its lower region
26211 is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output three
26212 words: |p|, |hash[p]|, and |eqtb[p]|. The hash table is, of course, densely
26213 packed for |p>=hash_used|, so the remaining entries are output in~a~block.
26214
26215 @<Dump the table of equivalents and the hash table@>=
26216 dump_int(mp->hash_used); 
26217 mp->st_count=frozen_inaccessible-1-mp->hash_used;
26218 for (p=1;p<=mp->hash_used;p++) {
26219   if ( text(p)!=0 ) {
26220      dump_int(p); dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]); incr(mp->st_count);
26221   }
26222 }
26223 for (p=mp->hash_used+1;p<=(int)hash_end;p++) {
26224   dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]);
26225 }
26226 dump_int(mp->st_count);
26227 mp_print_ln(mp); mp_print_int(mp, mp->st_count); mp_print(mp, " symbolic tokens")
26228
26229 @ @<Undump the table of equivalents and the hash table@>=
26230 undump(1,frozen_inaccessible,mp->hash_used); 
26231 p=0;
26232 do {  
26233   undump(p+1,mp->hash_used,p); 
26234   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
26235 } while (p!=mp->hash_used);
26236 for (p=mp->hash_used+1;p<=(int)hash_end;p++ )  { 
26237   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
26238 }
26239 undump_int(mp->st_count)
26240
26241 @ We have already printed a lot of statistics, so we set |tracing_stats:=0|
26242 to prevent them appearing again.
26243
26244 @<Dump a few more things and the closing check word@>=
26245 dump_int(mp->max_internal);
26246 dump_int(mp->int_ptr);
26247 for (k=1;k<= mp->int_ptr;k++ ) { 
26248   dump_int(mp->internal[k]); 
26249   dump_string(mp->int_name[k]);
26250 }
26251 dump_int(mp->start_sym); 
26252 dump_int(mp->interaction); 
26253 dump_string(mp->mem_ident);
26254 dump_int(mp->bg_loc); dump_int(mp->eg_loc); dump_int(mp->serial_no); dump_int(69073);
26255 mp->internal[tracing_stats]=0
26256
26257 @ @<Undump a few more things and the closing check word@>=
26258 undump_int(x);
26259 if (x>mp->max_internal) mp_grow_internals(mp,x);
26260 undump_int(mp->int_ptr);
26261 for (k=1;k<= mp->int_ptr;k++) { 
26262   undump_int(mp->internal[k]);
26263   undump_string(mp->int_name[k]);
26264 }
26265 undump(0,frozen_inaccessible,mp->start_sym);
26266 if (mp->interaction==mp_unspecified_mode) {
26267   undump(mp_unspecified_mode,mp_error_stop_mode,mp->interaction);
26268 } else {
26269   undump(mp_unspecified_mode,mp_error_stop_mode,x);
26270 }
26271 undump_string(mp->mem_ident);
26272 undump(1,hash_end,mp->bg_loc);
26273 undump(1,hash_end,mp->eg_loc);
26274 undump_int(mp->serial_no);
26275 undump_int(x); 
26276 if ( (x!=69073)|| feof(mp->mem_file) ) goto OFF_BASE
26277
26278 @ @<Create the |mem_ident|...@>=
26279
26280   xfree(mp->mem_ident);
26281   mp->mem_ident = xmalloc(256,1);
26282   snprintf(mp->mem_ident,256," (mem=%s %i.%i.%i)", 
26283            mp->job_name,
26284            (int)(mp_round_unscaled(mp, mp->internal[year]) % 100),
26285            (int)mp_round_unscaled(mp, mp->internal[month]),
26286            (int)mp_round_unscaled(mp, mp->internal[day]));
26287   mp_pack_job_name(mp, mem_extension);
26288   while (! mp_w_open_out(mp, &mp->mem_file) )
26289     mp_prompt_file_name(mp, "mem file name", mem_extension);
26290   mp_print_nl(mp, "Beginning to dump on file ");
26291 @.Beginning to dump...@>
26292   mp_print(mp, mp->name_of_file); 
26293   mp_print_nl(mp, mp->mem_ident);
26294 }
26295
26296 @ @<Dealloc variables@>=
26297 xfree(mp->mem_ident);
26298
26299 @ @<Close the mem file@>=
26300 fclose(mp->mem_file)
26301
26302 @* \[46] The main program.
26303 This is it: the part of \MP\ that executes all those procedures we have
26304 written.
26305
26306 Well---almost. We haven't put the parsing subroutines into the
26307 program yet; and we'd better leave space for a few more routines that may
26308 have been forgotten.
26309
26310 @c @<Declare the basic parsing subroutines@>;
26311 @<Declare miscellaneous procedures that were declared |forward|@>;
26312 @<Last-minute procedures@>
26313
26314 @ We've noted that there are two versions of \MP. One, called \.{INIMP},
26315 @.INIMP@>
26316 has to be run first; it initializes everything from scratch, without
26317 reading a mem file, and it has the capability of dumping a mem file.
26318 The other one is called `\.{VIRMP}'; it is a ``virgin'' program that needs
26319 @.VIRMP@>
26320 to input a mem file in order to get started. \.{VIRMP} typically has
26321 a bit more memory capacity than \.{INIMP}, because it does not need the
26322 space consumed by the dumping/undumping routines and the numerous calls on
26323 |primitive|, etc.
26324
26325 The \.{VIRMP} program cannot read a mem file instantaneously, of course;
26326 the best implementations therefore allow for production versions of \MP\ that
26327 not only avoid the loading routine for \PASCAL\ object code, they also have
26328 a mem file pre-loaded. 
26329
26330 @<Glob...@>=
26331 boolean ini_version; /* are we iniMP? */
26332
26333 @ @<Option variables@>=
26334 boolean ini_version; /* are we iniMP? */
26335
26336 @ @<Set |ini_version|@>=
26337 mp->ini_version = (opt->ini_version ? true : false);
26338
26339 @ Here we do whatever is needed to complete \MP's job gracefully on the
26340 local operating system. The code here might come into play after a fatal
26341 error; it must therefore consist entirely of ``safe'' operations that
26342 cannot produce error messages. For example, it would be a mistake to call
26343 |str_room| or |make_string| at this time, because a call on |overflow|
26344 might lead to an infinite loop.
26345 @^system dependencies@>
26346
26347 This program doesn't bother to close the input files that may still be open.
26348
26349 @<Last-minute...@>=
26350 void mp_close_files_and_terminate (MP mp) {
26351   integer k; /* all-purpose index */
26352   integer LH; /* the length of the \.{TFM} header, in words */
26353   int lk_offset; /* extra words inserted at beginning of |lig_kern| array */
26354   pointer p; /* runs through a list of \.{TFM} dimensions */
26355   @<Close all open files in the |rd_file| and |wr_file| arrays@>;
26356   if ( mp->internal[tracing_stats]>0 )
26357     @<Output statistics about this job@>;
26358   wake_up_terminal; 
26359   @<Do all the finishing work on the \.{TFM} file@>;
26360   @<Explain what output files were written@>;
26361   if ( mp->log_opened ){ 
26362     wlog_cr;
26363     fclose(mp->log_file); mp->selector=mp->selector-2;
26364     if ( mp->selector==term_only ) {
26365       mp_print_nl(mp, "Transcript written on ");
26366 @.Transcript written...@>
26367       mp_print(mp, mp->log_name); mp_print_char(mp, '.');
26368     }
26369   }
26370   mp_print_ln(mp);
26371 }
26372
26373 @ @<Declarations@>=
26374 void mp_close_files_and_terminate (MP mp) ;
26375
26376 @ @<Close all open files in the |rd_file| and |wr_file| arrays@>=
26377 for (k=0;k<=(int)mp->read_files-1;k++ ) {
26378   if ( mp->rd_fname[k]!=NULL ) {
26379     fclose(mp->rd_file[k]);
26380   }
26381 }
26382 for (k=0;k<=(int)mp->write_files-1;k++) {
26383   if ( mp->wr_fname[k]!=NULL ) {
26384     fclose(mp->wr_file[k]);
26385   }
26386 }
26387
26388 @ @<Dealloc ...@>=
26389 for (k=0;k<(int)mp->max_read_files;k++ ) {
26390   if ( mp->rd_fname[k]!=NULL ) {
26391     fclose(mp->rd_file[k]);
26392     mp_xfree(mp->rd_fname[k]); 
26393   }
26394 }
26395 mp_xfree(mp->rd_file);
26396 mp_xfree(mp->rd_fname);
26397 for (k=0;k<(int)mp->max_write_files;k++) {
26398   if ( mp->wr_fname[k]!=NULL ) {
26399     fclose(mp->wr_file[k]);
26400     mp_xfree(mp->wr_fname[k]); 
26401   }
26402 }
26403 mp_xfree(mp->wr_file);
26404 mp_xfree(mp->wr_fname);
26405
26406
26407 @ We want to produce a \.{TFM} file if and only if |fontmaking| is positive.
26408
26409 We reclaim all of the variable-size memory at this point, so that
26410 there is no chance of another memory overflow after the memory capacity
26411 has already been exceeded.
26412
26413 @<Do all the finishing work on the \.{TFM} file@>=
26414 if ( mp->internal[fontmaking]>0 ) {
26415   @<Make the dynamic memory into one big available node@>;
26416   @<Massage the \.{TFM} widths@>;
26417   mp_fix_design_size(mp); mp_fix_check_sum(mp);
26418   @<Massage the \.{TFM} heights, depths, and italic corrections@>;
26419   mp->internal[fontmaking]=0; /* avoid loop in case of fatal error */
26420   @<Finish the \.{TFM} file@>;
26421 }
26422
26423 @ @<Make the dynamic memory into one big available node@>=
26424 mp->rover=lo_mem_stat_max+1; link(mp->rover)=empty_flag; mp->lo_mem_max=mp->hi_mem_min-1;
26425 if ( mp->lo_mem_max-mp->rover>max_halfword ) mp->lo_mem_max=max_halfword+mp->rover;
26426 node_size(mp->rover)=mp->lo_mem_max-mp->rover; 
26427 llink(mp->rover)=mp->rover; rlink(mp->rover)=mp->rover;
26428 link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null
26429
26430 @ The present section goes directly to the log file instead of using
26431 |print| commands, because there's no need for these strings to take
26432 up |str_pool| memory when a non-{\bf stat} version of \MP\ is being used.
26433
26434 @<Output statistics...@>=
26435 if ( mp->log_opened ) { 
26436   char s[128];
26437   wlog_ln(" ");
26438   wlog_ln("Here is how much of MetaPost's memory you used:");
26439 @.Here is how much...@>
26440   snprintf(s,128," %i string%s out of %i",(int)mp->max_strs_used-mp->init_str_use,
26441           (mp->max_strs_used!=mp->init_str_use+1 ? "s" : ""),
26442           (int)(mp->max_strings-1-mp->init_str_use));
26443   wlog_ln(s);
26444   snprintf(s,128," %i string characters out of %i",
26445            (int)mp->max_pl_used-mp->init_pool_ptr,
26446            (int)mp->pool_size-mp->init_pool_ptr);
26447   wlog_ln(s);
26448   snprintf(s,128," %i words of memory out of %i",
26449            (int)mp->lo_mem_max+mp->mem_end-mp->hi_mem_min+2,
26450            (int)mp->mem_end+1);
26451   wlog_ln(s);
26452   snprintf(s,128," %i symbolic tokens out of %i", (int)mp->st_count, (int)mp->hash_size);
26453   wlog_ln(s);
26454   snprintf(s,128," %ii, %in, %ip, %ib stack positions out of %ii, %in, %ip, %ib",
26455            (int)mp->max_in_stack,(int)mp->int_ptr,
26456            (int)mp->max_param_stack,(int)mp->max_buf_stack+1,
26457            (int)mp->stack_size,(int)mp->max_internal,(int)mp->param_size,(int)mp->buf_size);
26458   wlog_ln(s);
26459   snprintf(s,128," %i string compactions (moved %i characters, %i strings)",
26460           (int)mp->pact_count,(int)mp->pact_chars,(int)mp->pact_strs);
26461   wlog_ln(s);
26462 }
26463
26464 @ We get to the |final_cleanup| routine when \&{end} or \&{dump} has
26465 been scanned.
26466
26467 @<Last-minute...@>=
26468 void mp_final_cleanup (MP mp) {
26469   small_number c; /* 0 for \&{end}, 1 for \&{dump} */
26470   c=mp->cur_mod;
26471   if ( mp->job_name==NULL ) mp_open_log_file(mp);
26472   while ( mp->input_ptr>0 ) {
26473     if ( token_state ) mp_end_token_list(mp);
26474     else  mp_end_file_reading(mp);
26475   }
26476   while ( mp->loop_ptr!=null ) mp_stop_iteration(mp);
26477   while ( mp->open_parens>0 ) { 
26478     mp_print(mp, " )"); decr(mp->open_parens);
26479   };
26480   while ( mp->cond_ptr!=null ) {
26481     mp_print_nl(mp, "(end occurred when ");
26482 @.end occurred...@>
26483     mp_print_cmd_mod(mp, fi_or_else,mp->cur_if);
26484     /* `\.{if}' or `\.{elseif}' or `\.{else}' */
26485     if ( mp->if_line!=0 ) {
26486       mp_print(mp, " on line "); mp_print_int(mp, mp->if_line);
26487     }
26488     mp_print(mp, " was incomplete)");
26489     mp->if_line=if_line_field(mp->cond_ptr);
26490     mp->cur_if=name_type(mp->cond_ptr); mp->cond_ptr=link(mp->cond_ptr);
26491   }
26492   if ( mp->history!=spotless )
26493     if ( ((mp->history==warning_issued)||(mp->interaction<mp_error_stop_mode)) )
26494       if ( mp->selector==term_and_log ) {
26495     mp->selector=term_only;
26496     mp_print_nl(mp, "(see the transcript file for additional information)");
26497 @.see the transcript file...@>
26498     mp->selector=term_and_log;
26499   }
26500   if ( c==1 ) {
26501     if (mp->ini_version) {
26502       mp_store_mem_file(mp); return;
26503     }
26504     mp_print_nl(mp, "(dump is performed only by INIMP)"); return;
26505 @.dump...only by INIMP@>
26506   }
26507 }
26508
26509 @ @<Declarations@>=
26510 void mp_final_cleanup (MP mp) ;
26511 void mp_init_prim (MP mp) ;
26512 void mp_init_tab (MP mp) ;
26513
26514 @ @<Last-minute...@>=
26515 void mp_init_prim (MP mp) { /* initialize all the primitives */
26516   @<Put each...@>;
26517 }
26518 @#
26519 void mp_init_tab (MP mp) { /* initialize other tables */
26520   integer k; /* all-purpose index */
26521   @<Initialize table entries (done by \.{INIMP} only)@>;
26522 }
26523
26524
26525 @ When we begin the following code, \MP's tables may still contain garbage;
26526 the strings might not even be present. Thus we must proceed cautiously to get
26527 bootstrapped in.
26528
26529 But when we finish this part of the program, \MP\ is ready to call on the
26530 |main_control| routine to do its work.
26531
26532 @<Get the first line...@>=
26533
26534   @<Initialize the input routines@>;
26535   if ( (mp->mem_ident==NULL)||(mp->buffer[loc]=='&') ) {
26536     if ( mp->mem_ident!=NULL ) mp_initialize(mp); /* erase preloaded mem */
26537     if ( ! mp_open_mem_file(mp) ) return false;
26538     if ( ! mp_load_mem_file(mp) ) {
26539       fclose( mp->mem_file); return false;
26540     }
26541     fclose( mp->mem_file);
26542     while ( (loc<limit)&&(mp->buffer[loc]==' ') ) incr(loc);
26543   }
26544   mp->buffer[limit]='%';
26545   mp_fix_date_and_time(mp);
26546   mp->sys_random_seed = (mp->get_random_seed)(mp);
26547   mp_init_randoms(mp, mp->sys_random_seed);
26548   @<Initialize the print |selector|...@>;
26549   if ( loc<limit ) if ( mp->buffer[loc]!='\\' ) 
26550     mp_start_input(mp); /* \&{input} assumed */
26551 }
26552
26553 @ @<Run inimpost commands@>=
26554 {
26555   mp_get_strings_started(mp);
26556   mp_init_tab(mp); /* initialize the tables */
26557   mp_init_prim(mp); /* call |primitive| for each primitive */
26558   mp->init_str_use=mp->str_ptr; mp->init_pool_ptr=mp->pool_ptr;
26559   mp->max_str_ptr=mp->str_ptr; mp->max_pool_ptr=mp->pool_ptr;
26560   mp_fix_date_and_time(mp);
26561 }
26562
26563
26564 @* \[47] Debugging.
26565 Once \MP\ is working, you should be able to diagnose most errors with
26566 the \.{show} commands and other diagnostic features. But for the initial
26567 stages of debugging, and for the revelation of really deep mysteries, you
26568 can compile \MP\ with a few more aids, including the \PASCAL\ runtime
26569 checks and its debugger. An additional routine called |debug_help|
26570 will also come into play when you type `\.D' after an error message;
26571 |debug_help| also occurs just before a fatal error causes \MP\ to succumb.
26572 @^debugging@>
26573 @^system dependencies@>
26574
26575 The interface to |debug_help| is primitive, but it is good enough when used
26576 with a \PASCAL\ debugger that allows you to set breakpoints and to read
26577 variables and change their values. After getting the prompt `\.{debug \#}', you
26578 type either a negative number (this exits |debug_help|), or zero (this
26579 goes to a location where you can set a breakpoint, thereby entering into
26580 dialog with the \PASCAL\ debugger), or a positive number |m| followed by
26581 an argument |n|. The meaning of |m| and |n| will be clear from the
26582 program below. (If |m=13|, there is an additional argument, |l|.)
26583 @.debug \#@>
26584
26585 @<Last-minute...@>=
26586 void mp_debug_help (MP mp) { /* routine to display various things */
26587   integer k;
26588   int l,m,n;
26589   while (1) { 
26590     wake_up_terminal;
26591     mp_print_nl(mp, "debug # (-1 to exit):"); update_terminal;
26592 @.debug \#@>
26593     m = 0;
26594     fscanf(mp->term_in,"%i",&m);
26595     if ( m<=0 )
26596       return;
26597     n = 0 ;
26598     fscanf(mp->term_in,"%i",&n);
26599     switch (m) {
26600     @<Numbered cases for |debug_help|@>;
26601     default: mp_print(mp, "?"); break;
26602     }
26603   }
26604 }
26605
26606 @ @<Numbered cases...@>=
26607 case 1: mp_print_word(mp, mp->mem[n]); /* display |mem[n]| in all forms */
26608   break;
26609 case 2: mp_print_int(mp, info(n));
26610   break;
26611 case 3: mp_print_int(mp, link(n));
26612   break;
26613 case 4: mp_print_int(mp, eq_type(n)); mp_print_char(mp, ':'); mp_print_int(mp, equiv(n));
26614   break;
26615 case 5: mp_print_variable_name(mp, n);
26616   break;
26617 case 6: mp_print_int(mp, mp->internal[n]);
26618   break;
26619 case 7: mp_do_show_dependencies(mp);
26620   break;
26621 case 9: mp_show_token_list(mp, n,null,100000,0);
26622   break;
26623 case 10: mp_print_str(mp, n);
26624   break;
26625 case 11: mp_check_mem(mp, n>0); /* check wellformedness; print new busy locations if |n>0| */
26626   break;
26627 case 12: mp_search_mem(mp, n); /* look for pointers to |n| */
26628   break;
26629 case 13: l = 0;  fscanf(mp->term_in,"%i",&l); mp_print_cmd_mod(mp, n,l); 
26630   break;
26631 case 14: for (k=0;k<=n;k++) mp_print_str(mp, mp->buffer[k]);
26632   break;
26633 case 15: mp->panicking=! mp->panicking;
26634   break;
26635
26636
26637 @ Saving the filename template
26638
26639 @<Save the filename template@>=
26640
26641   if ( mp->filename_template!=0 ) delete_str_ref(mp->filename_template);
26642   if ( length(mp->cur_exp)==0 ) mp->filename_template=0;
26643   else { 
26644     mp->filename_template=mp->cur_exp; add_str_ref(mp->filename_template);
26645   }
26646 }
26647
26648 @* \[48] System-dependent changes.
26649 This section should be replaced, if necessary, by any special
26650 modification of the program
26651 that are necessary to make \MP\ work at a particular installation.
26652 It is usually best to design your change file so that all changes to
26653 previous sections preserve the section numbering; then everybody's version
26654 will be consistent with the published program. More extensive changes,
26655 which introduce new sections, can be inserted here; then only the index
26656 itself will get a new section number.
26657 @^system dependencies@>
26658
26659 @* \[49] Index.
26660 Here is where you can find all uses of each identifier in the program,
26661 with underlined entries pointing to where the identifier was defined.
26662 If the identifier is only one letter long, however, you get to see only
26663 the underlined entries. {\sl All references are to section numbers instead of
26664 page numbers.}
26665
26666 This index also lists error messages and other aspects of the program
26667 that you might want to look up some day. For example, the entry
26668 for ``system dependencies'' lists all sections that should receive
26669 special attention from people who are installing \MP\ in a new
26670 operating environment. A list of various things that can't happen appears
26671 under ``this can't happen''.
26672 Approximately 25 sections are listed under ``inner loop''; these account
26673 for more than 60\pct! of \MP's running time, exclusive of input and output.