remove sprintf call
[mplib] / src / texk / web2c / mpdir / mp.w
1 % $Id$
2 %
3 % Copyright 2008 Taco Hoekwater.
4 %
5 % This program is free software: you can redistribute it and/or modify
6 % it under the terms of the GNU General Public License as published by
7 % the Free Software Foundation, either version 2 of the License, or
8 % (at your option) any later version.
9 %
10 % This program is distributed in the hope that it will be useful,
11 % but WITHOUT ANY WARRANTY; without even the implied warranty of
12 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 % GNU General Public License for more details.
14 %
15 % You should have received a copy of the GNU General Public License
16 % along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 %
18 % TeX is a trademark of the American Mathematical Society.
19 % METAFONT is a trademark of Addison-Wesley Publishing Company.
20 % PostScript is a trademark of Adobe Systems Incorporated.
21
22 % Here is TeX material that gets inserted after \input webmac
23 \def\hang{\hangindent 3em\noindent\ignorespaces}
24 \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
25 \def\ps{PostScript}
26 \def\psqrt#1{\sqrt{\mathstrut#1}}
27 \def\k{_{k+1}}
28 \def\pct!{{\char`\%}} % percent sign in ordinary text
29 \font\tenlogo=logo10 % font used for the METAFONT logo
30 \font\logos=logosl10
31 \def\MF{{\tenlogo META}\-{\tenlogo FONT}}
32 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
33 \def\[#1]{\ignorespaces} % left over from pascal web
34 \def\<#1>{$\langle#1\rangle$}
35 \def\section{\mathhexbox278}
36 \let\swap=\leftrightarrow
37 \def\round{\mathop{\rm round}\nolimits}
38 \mathchardef\vb="026A % synonym for `\|'
39
40 \def\(#1){} % this is used to make section names sort themselves better
41 \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
42 \def\title{MetaPost}
43 \pdfoutput=1
44 \pageno=3
45
46 @* \[1] Introduction.
47
48 This is \MP\ by John Hobby, a graphics-language processor based on D. E. Knuth's \MF.
49
50 Much of the original Pascal version of this program was copied with
51 permission from MF.web Version 1.9. It interprets a language very
52 similar to D.E. Knuth's METAFONT, but with changes designed to make it
53 more suitable for PostScript output.
54
55 The main purpose of the following program is to explain the algorithms of \MP\
56 as clearly as possible. However, the program has been written so that it
57 can be tuned to run efficiently in a wide variety of operating environments
58 by making comparatively few changes. Such flexibility is possible because
59 the documentation that follows is written in the \.{WEB} language, which is
60 at a higher level than C.
61
62 A large piece of software like \MP\ has inherent complexity that cannot
63 be reduced below a certain level of difficulty, although each individual
64 part is fairly simple by itself. The \.{WEB} language is intended to make
65 the algorithms as readable as possible, by reflecting the way the
66 individual program pieces fit together and by providing the
67 cross-references that connect different parts. Detailed comments about
68 what is going on, and about why things were done in certain ways, have
69 been liberally sprinkled throughout the program.  These comments explain
70 features of the implementation, but they rarely attempt to explain the
71 \MP\ language itself, since the reader is supposed to be familiar with
72 {\sl The {\logos METAFONT\/}book} as well as the manual
73 @.WEB@>
74 @:METAFONTbook}{\sl The {\logos METAFONT\/}book}@>
75 {\sl A User's Manual for MetaPost}, Computing Science Technical Report 162,
76 AT\AM T Bell Laboratories.
77
78 @ The present implementation is a preliminary version, but the possibilities
79 for new features are limited by the desire to remain as nearly compatible
80 with \MF\ as possible.
81
82 On the other hand, the \.{WEB} description can be extended without changing
83 the core of the program, and it has been designed so that such
84 extensions are not extremely difficult to make.
85 The |banner| string defined here should be changed whenever \MP\
86 undergoes any modifications, so that it will be clear which version of
87 \MP\ might be the guilty party when a problem arises.
88 @^extensions to \MP@>
89 @^system dependencies@>
90
91 @d default_banner "This is MetaPost, Version 1.080" /* printed when \MP\ starts */
92 @d metapost_version "1.080"
93
94 @d true 1
95 @d false 0
96
97 @ The external library header for \MP\ is |mplib.h|. It contains a
98 few typedefs and the header defintions for the externally used
99 fuctions.
100
101 The most important of the typedefs is the definition of the structure 
102 |MP_options|, that acts as a small, configurable front-end to the fairly 
103 large |MP_instance| structure.
104  
105 @(mplib.h@>=
106 typedef struct MP_instance * MP;
107 @<Exported types@>
108 typedef struct MP_options {
109   @<Option variables@>
110 } MP_options;
111 @<Exported function headers@>
112
113 @ The internal header file is much longer: it not only lists the complete
114 |MP_instance|, but also a lot of functions that have to be available to
115 the \ps\ backend, that is defined in a separate \.{WEB} file. 
116
117 The variables from |MP_options| are included inside the |MP_instance| 
118 wholesale.
119
120 @(mpmp.h@>=
121 #include <setjmp.h>
122 typedef struct psout_data_struct * psout_data;
123 #ifndef HAVE_BOOLEAN
124 typedef int boolean;
125 #endif
126 #ifndef INTEGER_TYPE
127 typedef int integer;
128 #endif
129 @<Declare helpers@>
130 @<Types in the outer block@>
131 @<Constants in the outer block@>
132 #  ifndef LIBAVL_ALLOCATOR
133 #    define LIBAVL_ALLOCATOR
134     struct libavl_allocator {
135         void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
136         void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
137     };
138 #  endif
139 typedef struct MP_instance {
140   @<Option variables@>
141   @<Global variables@>
142 } MP_instance;
143 @<Internal library declarations@>
144
145 @ @c 
146 #include "config.h"
147 #include <stdio.h>
148 #include <stdlib.h>
149 #include <string.h>
150 #include <stdarg.h>
151 #include <assert.h>
152 #ifdef HAVE_UNISTD_H
153 #include <unistd.h> /* for access() */
154 #endif
155 #include <time.h> /* for struct tm \& co */
156 #include "mplib.h"
157 #include "psout.h" /* external header */
158 #include "mpmp.h" /* internal header */
159 #include "mppsout.h" /* internal header */
160 #include "mptfmin.h" /* mp_read_font_info */
161 @h
162 @<Declarations@>
163 @<Basic printing procedures@>
164 @<Error handling procedures@>
165
166 @ Here are the functions that set up the \MP\ instance.
167
168 @<Declarations@> =
169 MP_options *mp_options (void);
170 MP mp_initialize (MP_options *opt);
171
172 @ @c
173 MP_options *mp_options (void) {
174   MP_options *opt;
175   size_t l = sizeof(MP_options);
176   opt = malloc(l);
177   if (opt!=NULL) {
178     memset (opt,0,l);
179     opt->ini_version = true;
180   }
181   return opt;
182
183
184 @ @<Internal library declarations@>=
185 @<Declare subroutines for parsing file names@>
186
187 @ The whole instance structure is initialized with zeroes,
188 this greatly reduces the number of statements needed in 
189 the |Allocate or initialize variables| block.
190
191 @d set_callback_option(A) do { mp->A = mp_##A;
192   if (opt->A!=NULL) mp->A = opt->A;
193 } while (0)
194
195 @c
196 static MP mp_do_new (jmp_buf *buf) {
197   MP mp = malloc(sizeof(MP_instance));
198   if (mp==NULL)
199         return NULL;
200   memset(mp,0,sizeof(MP_instance));
201   mp->jump_buf = buf;
202   return mp;
203 }
204
205 @ @c
206 static void mp_free (MP mp) {
207   int k; /* loop variable */
208   @<Dealloc variables@>
209   if (mp->noninteractive) {
210     @<Finish non-interactive use@>;
211   }
212   xfree(mp);
213 }
214
215 @ @c
216 static void mp_do_initialize ( MP mp) {
217   @<Local variables for initialization@>
218   @<Set initial values of key variables@>
219 }
220
221 @ This procedure gets things started properly.
222 @c
223 MP mp_initialize (MP_options *opt) { 
224   MP mp;
225   jmp_buf *buf = malloc(sizeof(jmp_buf));
226   if (buf == NULL)  
227     return NULL;
228   if (setjmp(*buf) != 0) { return NULL; }
229   mp = mp_do_new(buf);
230   if (mp == NULL)
231     return NULL;
232   mp->userdata=opt->userdata;
233   @<Set |ini_version|@>;
234   mp->noninteractive=opt->noninteractive;
235   set_callback_option(find_file);
236   set_callback_option(open_file);
237   set_callback_option(read_ascii_file);
238   set_callback_option(read_binary_file);
239   set_callback_option(close_file);
240   set_callback_option(eof_file);
241   set_callback_option(flush_file);
242   set_callback_option(write_ascii_file);
243   set_callback_option(write_binary_file);
244   set_callback_option(shipout_backend);
245   if (opt->banner && *(opt->banner)) {
246     mp->banner = xstrdup(opt->banner);
247   } else {
248     mp->banner = xstrdup(default_banner);
249   }
250   if (opt->command_line && *(opt->command_line))
251     mp->command_line = xstrdup(opt->command_line);
252   if (mp->noninteractive) {
253     @<Prepare function pointers for non-interactive use@>;
254   } 
255   /* open the terminal for output */
256   t_open_out; 
257   @<Find constant sizes@>;
258   @<Allocate or initialize variables@>
259   mp_reallocate_memory(mp,mp->mem_max);
260   mp_reallocate_paths(mp,1000);
261   mp_reallocate_fonts(mp,8);
262   mp->history=mp_fatal_error_stop; /* in case we quit during initialization */
263   @<Check the ``constant'' values...@>;
264   if ( mp->bad>0 ) {
265         char ss[256];
266     mp_snprintf(ss,256,"Ouch---my internal constants have been clobbered!\n"
267                    "---case %i",(int)mp->bad);
268     do_fprintf(mp->err_out,(char *)ss);
269 @.Ouch...clobbered@>
270     return mp;
271   }
272   mp_do_initialize(mp); /* erase preloaded mem */
273   if (mp->ini_version) {
274     @<Run inimpost commands@>;
275   }
276   if (!mp->noninteractive) {
277     @<Initialize the output routines@>;
278     @<Get the first line of input and prepare to start@>;
279     @<Initializations after first line is read@>;
280   } else {
281     mp->history=mp_spotless;
282   }
283   return mp;
284 }
285
286 @ @<Initializations after first line is read@>=
287 mp_set_job_id(mp);
288 mp_init_map_file(mp, mp->troff_mode);
289 mp->history=mp_spotless; /* ready to go! */
290 if (mp->troff_mode) {
291   mp->internal[mp_gtroffmode]=unity; 
292   mp->internal[mp_prologues]=unity; 
293 }
294 if ( mp->start_sym>0 ) { /* insert the `\&{everyjob}' symbol */
295   mp->cur_sym=mp->start_sym; mp_back_input(mp);
296 }
297
298 @ @<Exported function headers@>=
299 extern MP_options *mp_options (void);
300 extern MP mp_initialize (MP_options *opt) ;
301 extern int mp_status(MP mp);
302 extern void *mp_userdata(MP mp);
303
304 @ @c
305 int mp_status(MP mp) { return mp->history; }
306
307 @ @c
308 void *mp_userdata(MP mp) { return mp->userdata; }
309
310 @ The overall \MP\ program begins with the heading just shown, after which
311 comes a bunch of procedure declarations and function declarations.
312 Finally we will get to the main program, which begins with the
313 comment `|start_here|'. If you want to skip down to the
314 main program now, you can look up `|start_here|' in the index.
315 But the author suggests that the best way to understand this program
316 is to follow pretty much the order of \MP's components as they appear in the
317 \.{WEB} description you are now reading, since the present ordering is
318 intended to combine the advantages of the ``bottom up'' and ``top down''
319 approaches to the problem of understanding a somewhat complicated system.
320
321 @ Some of the code below is intended to be used only when diagnosing the
322 strange behavior that sometimes occurs when \MP\ is being installed or
323 when system wizards are fooling around with \MP\ without quite knowing
324 what they are doing. Such code will not normally be compiled; it is
325 delimited by the preprocessor test `|#ifdef DEBUG .. #endif|'.
326
327 @ This program has two important variations: (1) There is a long and slow
328 version called \.{INIMP}, which does the extra calculations needed to
329 @.INIMP@>
330 initialize \MP's internal tables; and (2)~there is a shorter and faster
331 production version, which cuts the initialization to a bare minimum.
332
333 Which is which is decided at runtime.
334
335 @ The following parameters can be changed at compile time to extend or
336 reduce \MP's capacity. They may have different values in \.{INIMP} and
337 in production versions of \MP.
338 @.INIMP@>
339 @^system dependencies@>
340
341 @<Constants...@>=
342 #define file_name_size 255 /* file names shouldn't be longer than this */
343 #define bistack_size 1500 /* size of stack for bisection algorithms;
344   should probably be left at this value */
345
346 @ Like the preceding parameters, the following quantities can be changed
347 to extend or reduce \MP's capacity. But if they are changed,
348 it is necessary to rerun the initialization program \.{INIMP}
349 @.INIMP@>
350 to generate new tables for the production \MP\ program.
351 One can't simply make helter-skelter changes to the following constants,
352 since certain rather complex initialization
353 numbers are computed from them. 
354
355 @ @<Glob...@>=
356 int max_strings; /* maximum number of strings; must not exceed |max_halfword| */
357 int pool_size; /* maximum number of characters in strings, including all
358   error messages and help texts, and the names of all identifiers */
359 int mem_max; /* greatest index in \MP's internal |mem| array;
360   must be strictly less than |max_halfword|;
361   must be equal to |mem_top| in \.{INIMP}, otherwise |>=mem_top| */
362 int mem_top; /* largest index in the |mem| array dumped by \.{INIMP};
363   must not be greater than |mem_max| */
364 int hash_prime; /* a prime number equal to about 85\pct! of |hash_size| */
365
366 @ @<Option variables@>=
367 int error_line; /* width of context lines on terminal error messages */
368 int half_error_line; /* width of first lines of contexts in terminal
369   error messages; should be between 30 and |error_line-15| */
370 int max_print_line; /* width of longest text lines output; should be at least 60 */
371 unsigned hash_size; /* maximum number of symbolic tokens,
372   must be less than |max_halfword-3*param_size| */
373 int param_size; /* maximum number of simultaneous macro parameters */
374 int max_in_open; /* maximum number of input files and error insertions that
375   can be going on simultaneously */
376 int main_memory; /* only for options, to set up |mem_max| and |mem_top| */
377 void *userdata; /* this allows the calling application to setup local */
378 char *banner; /* the banner that is printed to the screen and log */
379
380 @ @<Dealloc variables@>=
381 xfree(mp->banner);
382
383
384 @d set_value(a,b,c) do { a=c; if (b>c) a=b; } while (0)
385
386 @<Allocate or ...@>=
387 mp->max_strings=500;
388 mp->pool_size=10000;
389 set_value(mp->error_line,opt->error_line,79);
390 set_value(mp->half_error_line,opt->half_error_line,50);
391 if (mp->half_error_line>mp->error_line-15 ) 
392   mp->half_error_line = mp->error_line-15;
393 set_value(mp->max_print_line,opt->max_print_line,100);
394
395 @ In case somebody has inadvertently made bad settings of the ``constants,''
396 \MP\ checks them using a global variable called |bad|.
397
398 This is the second of many sections of \MP\ where global variables are
399 defined.
400
401 @<Glob...@>=
402 integer bad; /* is some ``constant'' wrong? */
403
404 @ Later on we will say `\ignorespaces|if (mem_max>=max_halfword) bad=10;|',
405 or something similar. (We can't do that until |max_halfword| has been defined.)
406
407 In case you are wondering about the non-consequtive values of |bad|: some
408 of the things that used to be WEB constants are now runtime variables
409 with checking at assignment time.
410
411 @<Check the ``constant'' values for consistency@>=
412 mp->bad=0;
413 if ( mp->mem_top<=1100 ) mp->bad=4;
414
415 @ Some |goto| labels are used by the following definitions. The label
416 `|restart|' is occasionally used at the very beginning of a procedure; and
417 the label `|reswitch|' is occasionally used just prior to a |case|
418 statement in which some cases change the conditions and we wish to branch
419 to the newly applicable case.  Loops that are set up with the |loop|
420 construction defined below are commonly exited by going to `|done|' or to
421 `|found|' or to `|not_found|', and they are sometimes repeated by going to
422 `|continue|'.  If two or more parts of a subroutine start differently but
423 end up the same, the shared code may be gathered together at
424 `|common_ending|'.
425
426 @ Here are some macros for common programming idioms.
427
428 @d incr(A)   (A)=(A)+1 /* increase a variable by unity */
429 @d decr(A)   (A)=(A)-1 /* decrease a variable by unity */
430 @d negate(A) (A)=-(A) /* change the sign of a variable */
431 @d double(A) (A)=(A)+(A)
432 @d odd(A)   ((A)%2==1)
433 @d do_nothing   /* empty statement */
434
435 @* \[2] The character set.
436 In order to make \MP\ readily portable to a wide variety of
437 computers, all of its input text is converted to an internal eight-bit
438 code that includes standard ASCII, the ``American Standard Code for
439 Information Interchange.''  This conversion is done immediately when each
440 character is read in. Conversely, characters are converted from ASCII to
441 the user's external representation just before they are output to a
442 text file.
443 @^ASCII code@>
444
445 Such an internal code is relevant to users of \MP\ only with respect to
446 the \&{char} and \&{ASCII} operations, and the comparison of strings.
447
448 @ Characters of text that have been converted to \MP's internal form
449 are said to be of type |ASCII_code|, which is a subrange of the integers.
450
451 @<Types...@>=
452 typedef unsigned char ASCII_code; /* eight-bit numbers */
453
454 @ The present specification of \MP\ has been written under the assumption
455 that the character set contains at least the letters and symbols associated
456 with ASCII codes 040 through 0176; all of these characters are now
457 available on most computer terminals.
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)=(text_char)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=0;i<=255;i++) { 
501    xord(xchr(i))=0177;
502 }
503 for (i=0200;i<=0377;i++) { xord(xchr(i))=(ASCII_code)i;}
504 for (i=0;i<=0176;i++) { xord(xchr(i))=(ASCII_code)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
541 @ @<Exported types@>=
542 enum mp_filetype {
543   mp_filetype_terminal = 0, /* the terminal */
544   mp_filetype_error, /* the terminal */
545   mp_filetype_program , /* \MP\ language input */
546   mp_filetype_log,  /* the log file */
547   mp_filetype_postscript, /* the postscript output */
548   mp_filetype_memfile, /* memory dumps */
549   mp_filetype_metrics, /* TeX font metric files */
550   mp_filetype_fontmap, /* PostScript font mapping files */
551   mp_filetype_font, /*  PostScript type1 font programs */
552   mp_filetype_encoding, /*  PostScript font encoding files */
553   mp_filetype_text  /* first text file for readfrom and writeto primitives */
554 };
555 typedef char *(*mp_file_finder)(MP, const char *, const char *, int);
556 typedef void *(*mp_file_opener)(MP, const char *, const char *, int);
557 typedef char *(*mp_file_reader)(MP, void *, size_t *);
558 typedef void (*mp_binfile_reader)(MP, void *, void **, size_t *);
559 typedef void (*mp_file_closer)(MP, void *);
560 typedef int (*mp_file_eoftest)(MP, void *);
561 typedef void (*mp_file_flush)(MP, void *);
562 typedef void (*mp_file_writer)(MP, void *, const char *);
563 typedef void (*mp_binfile_writer)(MP, void *, void *, size_t);
564
565 @ @<Option variables@>=
566 mp_file_finder find_file;
567 mp_file_opener open_file;
568 mp_file_reader read_ascii_file;
569 mp_binfile_reader read_binary_file;
570 mp_file_closer close_file;
571 mp_file_eoftest eof_file;
572 mp_file_flush flush_file;
573 mp_file_writer write_ascii_file;
574 mp_binfile_writer write_binary_file;
575
576 @ The default function for finding files is |mp_find_file|. It is 
577 pretty stupid: it will only find files in the current directory.
578
579 This function may disappear altogether, it is currently only
580 used for the default font map file.
581
582 @c
583 static char *mp_find_file (MP mp, const char *fname, const char *fmode, int ftype)  {
584   (void) mp;
585   if (fmode[0] != 'r' || (! access (fname,R_OK)) || ftype) {  
586      return mp_strdup(fname);
587   }
588   return NULL;
589 }
590
591 @ Because |mp_find_file| is used so early, it has to be in the helpers
592 section.
593
594 @<Declarations@>=
595 static char *mp_find_file (MP mp, const char *fname, const char *fmode, int ftype) ;
596 static void *mp_open_file (MP mp , const char *fname, const char *fmode, int ftype) ;
597 static char *mp_read_ascii_file (MP mp, void *f, size_t *size) ;
598 static void mp_read_binary_file (MP mp, void *f, void **d, size_t *size) ;
599 static void mp_close_file (MP mp, void *f) ;
600 static int mp_eof_file (MP mp, void *f) ;
601 static void mp_flush_file (MP mp, void *f) ;
602 static void mp_write_ascii_file (MP mp, void *f, const char *s) ;
603 static void mp_write_binary_file (MP mp, void *f, void *s, size_t t) ;
604
605 @ The function to open files can now be very short.
606
607 @c
608 void *mp_open_file(MP mp, const char *fname, const char *fmode, int ftype)  {
609   char realmode[3];
610   (void) mp;
611   realmode[0] = *fmode;
612   realmode[1] = 'b';
613   realmode[2] = 0;
614   if (ftype==mp_filetype_terminal) {
615     return (fmode[0] == 'r' ? stdin : stdout);
616   } else if (ftype==mp_filetype_error) {
617     return stderr;
618   } else if (fname != NULL && (fmode[0] != 'r' || (! access (fname,R_OK)))) {
619     return (void *)fopen(fname, realmode);
620   }
621   return NULL;
622 }
623
624 @ This is a legacy interface: (almost) all file names pass through |name_of_file|.
625
626 @<Glob...@>=
627 char name_of_file[file_name_size+1]; /* the name of a system file */
628 int name_length;/* this many characters are actually
629   relevant in |name_of_file| (the rest are blank) */
630
631 @ @<Option variables@>=
632 int print_found_names; /* configuration parameter */
633
634 @ If this parameter is true, the terminal and log will report the found
635 file names for input files instead of the requested ones. 
636 It is off by default because it creates an extra filename lookup.
637
638 @<Allocate or initialize ...@>=
639 mp->print_found_names = (opt->print_found_names>0 ? true : false);
640
641 @ \MP's file-opening procedures return |false| if no file identified by
642 |name_of_file| could be opened.
643
644 The |OPEN_FILE| macro takes care of the |print_found_names| parameter.
645 It is not used for opening a mem file for read, because that file name 
646 is never printed.
647
648 @d OPEN_FILE(A) do {
649   if (mp->print_found_names) {
650     char *s = (mp->find_file)(mp,mp->name_of_file,A,ftype);
651     if (s!=NULL) {
652       *f = (mp->open_file)(mp,mp->name_of_file,A, ftype); 
653       strncpy(mp->name_of_file,s,file_name_size);
654       xfree(s);
655     } else {
656       *f = NULL;
657     }
658   } else {
659     *f = (mp->open_file)(mp,mp->name_of_file,A, ftype); 
660   }
661 } while (0);
662 return (*f ? true : false)
663
664 @c 
665 static boolean mp_a_open_in (MP mp, void **f, int ftype) {
666   /* open a text file for input */
667   OPEN_FILE("r");
668 }
669 @#
670 boolean mp_w_open_in (MP mp, void **f) {
671   /* open a word file for input */
672   *f = (mp->open_file)(mp,mp->name_of_file,"r",mp_filetype_memfile); 
673   return (*f ? true : false);
674 }
675 @#
676 static boolean mp_a_open_out (MP mp, void **f, int ftype) {
677   /* open a text file for output */
678   OPEN_FILE("w");
679 }
680 @#
681 static boolean mp_b_open_out (MP mp, void **f, int ftype) {
682   /* open a binary file for output */
683   OPEN_FILE("w");
684 }
685 @#
686 static boolean mp_w_open_out (MP mp, void **f) {
687   /* open a word file for output */
688   int ftype = mp_filetype_memfile;
689   OPEN_FILE("w");
690 }
691
692 @ @c
693 static char *mp_read_ascii_file (MP mp, void *ff, size_t *size) {
694   int c;
695   size_t len = 0, lim = 128;
696   char *s = NULL;
697   FILE *f = (FILE *)ff;
698   *size = 0;
699   (void) mp; /* for -Wunused */
700   if (f==NULL)
701     return NULL;
702   c = fgetc(f);
703   if (c==EOF)
704     return NULL;
705   s = malloc(lim); 
706   if (s==NULL) return NULL;
707   while (c!=EOF && c!='\n' && c!='\r') { 
708     if (len==lim) {
709       s =realloc(s, (lim+(lim>>2)));
710       if (s==NULL) return NULL;
711       lim+=(lim>>2);
712     }
713         s[len++] = c;
714     c =fgetc(f);
715   }
716   if (c=='\r') {
717     c = fgetc(f);
718     if (c!=EOF && c!='\n')
719        ungetc(c,f);
720   }
721   s[len] = 0;
722   *size = len;
723   return s;
724 }
725
726 @ @c
727 void mp_write_ascii_file (MP mp, void *f, const char *s) {
728   (void) mp;
729   if (f!=NULL) {
730     fputs(s,(FILE *)f);
731   }
732 }
733
734 @ @c
735 void mp_read_binary_file (MP mp, void *f, void **data, size_t *size) {
736   size_t len = 0;
737   (void) mp;
738   if (f!=NULL)
739     len = fread(*data,1,*size,(FILE *)f);
740   *size = len;
741 }
742
743 @ @c
744 void mp_write_binary_file (MP mp, void *f, void *s, size_t size) {
745   (void) mp;
746   if (f!=NULL)
747     (void)fwrite(s,size,1,(FILE *)f);
748 }
749
750
751 @ @c
752 void mp_close_file (MP mp, void *f) {
753   (void) mp;
754   if (f!=NULL)
755     fclose((FILE *)f);
756 }
757
758 @ @c
759 int mp_eof_file (MP mp, void *f) {
760   (void) mp;
761   if (f!=NULL)
762     return feof((FILE *)f);
763    else 
764     return 1;
765 }
766
767 @ @c
768 void mp_flush_file (MP mp, void *f) {
769   (void) mp;
770   if (f!=NULL)
771     fflush((FILE *)f);
772 }
773
774 @ Input from text files is read one line at a time, using a routine called
775 |input_ln|. This function is defined in terms of global variables called
776 |buffer|, |first|, and |last| that will be described in detail later; for
777 now, it suffices for us to know that |buffer| is an array of |ASCII_code|
778 values, and that |first| and |last| are indices into this array
779 representing the beginning and ending of a line of text.
780
781 @<Glob...@>=
782 size_t buf_size; /* maximum number of characters simultaneously present in
783                     current lines of open files */
784 ASCII_code *buffer; /* lines of characters being read */
785 size_t first; /* the first unused position in |buffer| */
786 size_t last; /* end of the line just input to |buffer| */
787 size_t max_buf_stack; /* largest index used in |buffer| */
788
789 @ @<Allocate or initialize ...@>=
790 mp->buf_size = 200;
791 mp->buffer = xmalloc((mp->buf_size+1),sizeof(ASCII_code));
792
793 @ @<Dealloc variables@>=
794 xfree(mp->buffer);
795
796 @ @c
797 static void mp_reallocate_buffer(MP mp, size_t l) {
798   ASCII_code *buffer;
799   if (l>max_halfword) {
800     mp_confusion(mp,"buffer size"); /* can't happen (I hope) */
801   }
802   buffer = xmalloc((l+1),sizeof(ASCII_code));
803   memcpy(buffer,mp->buffer,(mp->buf_size+1));
804   xfree(mp->buffer);
805   mp->buffer = buffer ;
806   mp->buf_size = l;
807 }
808
809 @ The |input_ln| function brings the next line of input from the specified
810 field into available positions of the buffer array and returns the value
811 |true|, unless the file has already been entirely read, in which case it
812 returns |false| and sets |last:=first|.  In general, the |ASCII_code|
813 numbers that represent the next line of the file are input into
814 |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
815 global variable |last| is set equal to |first| plus the length of the
816 line. Trailing blanks are removed from the line; thus, either |last=first|
817 (in which case the line was entirely blank) or |buffer[last-1]<>" "|.
818 @^inner loop@>
819
820 The variable |max_buf_stack|, which is used to keep track of how large
821 the |buf_size| parameter must be to accommodate the present job, is
822 also kept up to date by |input_ln|.
823
824 @c 
825 static boolean mp_input_ln (MP mp, void *f ) {
826   /* inputs the next line or returns |false| */
827   char *s;
828   size_t size = 0; 
829   mp->last=mp->first; /* cf.\ Matthew 19\thinspace:\thinspace30 */
830   s = (mp->read_ascii_file)(mp,f, &size);
831   if (s==NULL)
832         return false;
833   if (size>0) {
834     mp->last = mp->first+size;
835     if ( mp->last>=mp->max_buf_stack ) { 
836       mp->max_buf_stack=mp->last+1;
837       while ( mp->max_buf_stack>=mp->buf_size ) {
838         mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size>>2)));
839       }
840     }
841     memcpy((mp->buffer+mp->first),s,size);
842     /* while ( mp->buffer[mp->last]==' ' ) mp->last--; */
843   } 
844   free(s);
845   return true;
846 }
847
848 @ The user's terminal acts essentially like other files of text, except
849 that it is used both for input and for output. When the terminal is
850 considered an input file, the file variable is called |term_in|, and when it
851 is considered an output file the file variable is |term_out|.
852 @^system dependencies@>
853
854 @<Glob...@>=
855 void * term_in; /* the terminal as an input file */
856 void * term_out; /* the terminal as an output file */
857 void * err_out; /* the terminal as an output file */
858
859 @ Here is how to open the terminal files. In the default configuration,
860 nothing happens except that the command line (if there is one) is copied
861 to the input buffer.  The variable |command_line| will be filled by the 
862 |main| procedure. The copying can not be done earlier in the program 
863 logic because in the |INI| version, the |buffer| is also used for primitive 
864 initialization.
865
866 @d t_open_out  do {/* open the terminal for text output */
867     mp->term_out = (mp->open_file)(mp,"terminal", "w", mp_filetype_terminal);
868     mp->err_out = (mp->open_file)(mp,"error", "w", mp_filetype_error);
869 } while (0)
870 @d t_open_in  do { /* open the terminal for text input */
871     mp->term_in = (mp->open_file)(mp,"terminal", "r", mp_filetype_terminal);
872     if (mp->command_line!=NULL) {
873       mp->last = strlen(mp->command_line);
874       strncpy((char *)mp->buffer,mp->command_line,mp->last);
875       xfree(mp->command_line);
876     } else {
877           mp->last = 0;
878     }
879 } while (0)
880
881 @<Option variables@>=
882 char *command_line;
883
884 @ Sometimes it is necessary to synchronize the input/output mixture that
885 happens on the user's terminal, and three system-dependent
886 procedures are used for this
887 purpose. The first of these, |update_terminal|, is called when we want
888 to make sure that everything we have output to the terminal so far has
889 actually left the computer's internal buffers and been sent.
890 The second, |clear_terminal|, is called when we wish to cancel any
891 input that the user may have typed ahead (since we are about to
892 issue an unexpected error message). The third, |wake_up_terminal|,
893 is supposed to revive the terminal if the user has disabled it by
894 some instruction to the operating system.  The following macros show how
895 these operations can be specified:
896 @^system dependencies@>
897
898 @d update_terminal  (mp->flush_file)(mp,mp->term_out) /* empty the terminal output buffer */
899 @d clear_terminal   do_nothing /* clear the terminal input buffer */
900 @d wake_up_terminal (mp->flush_file)(mp,mp->term_out) 
901                     /* cancel the user's cancellation of output */
902
903 @ We need a special routine to read the first line of \MP\ input from
904 the user's terminal. This line is different because it is read before we
905 have opened the transcript file; there is sort of a ``chicken and
906 egg'' problem here. If the user types `\.{input cmr10}' on the first
907 line, or if some macro invoked by that line does such an \.{input},
908 the transcript file will be named `\.{cmr10.log}'; but if no \.{input}
909 commands are performed during the first line of terminal input, the transcript
910 file will acquire its default name `\.{mpout.log}'. (The transcript file
911 will not contain error messages generated by the first line before the
912 first \.{input} command.)
913
914 The first line is even more special. It's nice to let the user start
915 running a \MP\ job by typing a command line like `\.{MP cmr10}'; in
916 such a case, \MP\ will operate as if the first line of input were
917 `\.{cmr10}', i.e., the first line will consist of the remainder of the
918 command line, after the part that invoked \MP.
919
920 @ Different systems have different ways to get started. But regardless of
921 what conventions are adopted, the routine that initializes the terminal
922 should satisfy the following specifications:
923
924 \yskip\textindent{1)}It should open file |term_in| for input from the
925   terminal. (The file |term_out| will already be open for output to the
926   terminal.)
927
928 \textindent{2)}If the user has given a command line, this line should be
929   considered the first line of terminal input. Otherwise the
930   user should be prompted with `\.{**}', and the first line of input
931   should be whatever is typed in response.
932
933 \textindent{3)}The first line of input, which might or might not be a
934   command line, should appear in locations |first| to |last-1| of the
935   |buffer| array.
936
937 \textindent{4)}The global variable |loc| should be set so that the
938   character to be read next by \MP\ is in |buffer[loc]|. This
939   character should not be blank, and we should have |loc<last|.
940
941 \yskip\noindent(It may be necessary to prompt the user several times
942 before a non-blank line comes in. The prompt is `\.{**}' instead of the
943 later `\.*' because the meaning is slightly different: `\.{input}' need
944 not be typed immediately after~`\.{**}'.)
945
946 @d loc mp->cur_input.loc_field /* location of first unread character in |buffer| */
947
948 @c 
949 boolean mp_init_terminal (MP mp) { /* gets the terminal input started */
950   t_open_in; 
951   if (mp->last!=0) {
952     loc = 0; mp->first = 0;
953         return true;
954   }
955   while (1) { 
956     if (!mp->noninteractive) {
957           wake_up_terminal; do_fprintf(mp->term_out,"**"); update_terminal;
958 @.**@>
959     }
960     if ( ! mp_input_ln(mp, mp->term_in ) ) { /* this shouldn't happen */
961       do_fprintf(mp->term_out,"\n! End of file on the terminal... why?");
962 @.End of file on the terminal@>
963       return false;
964     }
965     loc=(halfword)mp->first;
966     while ( (loc<(int)mp->last)&&(mp->buffer[loc]==' ') ) 
967       incr(loc);
968     if ( loc<(int)mp->last ) { 
969       return true; /* return unless the line was all blank */
970     }
971     if (!mp->noninteractive) {
972           do_fprintf(mp->term_out,"Please type the name of your input file.\n");
973     }
974   }
975 }
976
977 @ @<Declarations@>=
978 static boolean mp_init_terminal (MP mp) ;
979
980
981 @* \[4] String handling.
982 Symbolic token names and diagnostic messages are variable-length strings
983 of eight-bit characters. Many strings \MP\ uses are simply literals
984 in the compiled source, like the error messages and the names of the
985 internal parameters. Other strings are used or defined from the \MP\ input 
986 language, and these have to be interned.
987
988 \MP\ uses strings more extensively than \MF\ does, but the necessary
989 operations can still be handled with a fairly simple data structure.
990 The array |str_pool| contains all of the (eight-bit) ASCII codes in all
991 of the strings, and the array |str_start| contains indices of the starting
992 points of each string. Strings are referred to by integer numbers, so that
993 string number |s| comprises the characters |str_pool[j]| for
994 |str_start[s]<=j<str_start[ss]| where |ss=next_str[s]|.  The string pool
995 is allocated sequentially and |str_pool[pool_ptr]| is the next unused
996 location.  The first string number not currently in use is |str_ptr|
997 and |next_str[str_ptr]| begins a list of free string numbers.  String
998 pool entries |str_start[str_ptr]| up to |pool_ptr| are reserved for a
999 string currently being constructed.
1000
1001 String numbers 0 to 255 are reserved for strings that correspond to single
1002 ASCII characters. This is in accordance with the conventions of \.{WEB},
1003 @.WEB@>
1004 which converts single-character strings into the ASCII code number of the
1005 single character involved, while it converts other strings into integers
1006 and builds a string pool file. Thus, when the string constant \.{"."} appears
1007 in the program below, \.{WEB} converts it into the integer 46, which is the
1008 ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"}
1009 into some integer greater than~255. String number 46 will presumably be the
1010 single character `\..'\thinspace; but some ASCII codes have no standard visible
1011 representation, and \MP\ may need to be able to print an arbitrary
1012 ASCII character, so the first 256 strings are used to specify exactly what
1013 should be printed for each of the 256 possibilities.
1014
1015 @<Types...@>=
1016 typedef int pool_pointer; /* for variables that point into |str_pool| */
1017 typedef int str_number; /* for variables that point into |str_start| */
1018
1019 @ @<Glob...@>=
1020 ASCII_code *str_pool; /* the characters */
1021 pool_pointer *str_start; /* the starting pointers */
1022 str_number *next_str; /* for linking strings in order */
1023 pool_pointer pool_ptr; /* first unused position in |str_pool| */
1024 str_number str_ptr; /* number of the current string being created */
1025 pool_pointer init_pool_ptr; /* the starting value of |pool_ptr| */
1026 str_number init_str_use; /* the initial number of strings in use */
1027 pool_pointer max_pool_ptr; /* the maximum so far of |pool_ptr| */
1028 str_number max_str_ptr; /* the maximum so far of |str_ptr| */
1029
1030 @ @<Allocate or initialize ...@>=
1031 mp->str_pool  = xmalloc ((mp->pool_size +1),sizeof(ASCII_code));
1032 mp->str_start = xmalloc ((mp->max_strings+1),sizeof(pool_pointer));
1033 mp->next_str  = xmalloc ((mp->max_strings+1),sizeof(str_number));
1034
1035 @ @<Dealloc variables@>=
1036 xfree(mp->str_pool);
1037 xfree(mp->str_start);
1038 xfree(mp->next_str);
1039
1040 @ Most printing is done from |char *|s, but sometimes not. Here are
1041 functions that convert an internal string into a |char *| for use
1042 by the printing routines, and vice versa.
1043
1044 @d str(A) mp_str(mp,A)
1045 @d rts(A) mp_rts(mp,A)
1046 @d null_str rts("")
1047
1048 @<Internal ...@>=
1049 int mp_xstrcmp (const char *a, const char *b);
1050 char * mp_str (MP mp, str_number s);
1051
1052 @ @<Declarations@>=
1053 static str_number mp_rts (MP mp, const char *s);
1054 static str_number mp_make_string (MP mp);
1055
1056 @ @c 
1057 int mp_xstrcmp (const char *a, const char *b) {
1058         if (a==NULL && b==NULL) 
1059           return 0;
1060     if (a==NULL)
1061       return -1;
1062     if (b==NULL)
1063       return 1;
1064     return strcmp(a,b);
1065 }
1066
1067 @ The attempt to catch interrupted strings that is in |mp_rts|, is not 
1068 very good: it does not handle nesting over more than one level.
1069
1070 @c
1071 char * mp_str (MP mp, str_number ss) {
1072   char *s;
1073   size_t len;
1074   if (ss==mp->str_ptr) {
1075     return NULL;
1076   } else {
1077     len = (size_t)length(ss);
1078     s = xmalloc(len+1,sizeof(char));
1079     strncpy(s,(char *)(mp->str_pool+(mp->str_start[ss])),len);
1080     s[len] = 0;
1081     return (char *)s;
1082   }
1083 }
1084 str_number mp_rts (MP mp, const char *s) {
1085   int r; /* the new string */ 
1086   int old; /* a possible string in progress */
1087   int i=0;
1088   if (strlen(s)==0) {
1089     return 256;
1090   } else if (strlen(s)==1) {
1091     return s[0];
1092   } else {
1093    old=0;
1094    str_room((integer)strlen(s));
1095    if (mp->str_start[mp->str_ptr]<mp->pool_ptr)
1096      old = mp_make_string(mp);
1097    while (*s) {
1098      append_char(*s);
1099      s++;
1100    }
1101    r = mp_make_string(mp);
1102    if (old!=0) {
1103       str_room(length(old));
1104       while (i<length(old)) {
1105         append_char((mp->str_start[old]+i));
1106       } 
1107       mp_flush_string(mp,old);
1108     }
1109     return r;
1110   }
1111 }
1112
1113 @ Except for |strs_used_up|, the following string statistics are only
1114 maintained when code between |stat| $\ldots$ |tats| delimiters is not
1115 commented out:
1116
1117 @<Glob...@>=
1118 integer strs_used_up; /* strings in use or unused but not reclaimed */
1119 integer pool_in_use; /* total number of cells of |str_pool| actually in use */
1120 integer strs_in_use; /* total number of strings actually in use */
1121 integer max_pl_used; /* maximum |pool_in_use| so far */
1122 integer max_strs_used; /* maximum |strs_in_use| so far */
1123
1124 @ Several of the elementary string operations are performed using \.{WEB}
1125 macros instead of functions, because many of the
1126 operations are done quite frequently and we want to avoid the
1127 overhead of procedure calls. For example, here is
1128 a simple macro that computes the length of a string.
1129 @.WEB@>
1130
1131 @d str_stop(A) mp->str_start[mp->next_str[(A)]] /* one cell past the end of string \# */
1132 @d length(A) (str_stop((A))-mp->str_start[(A)]) /* the number of characters in string \# */
1133
1134 @ The length of the current string is called |cur_length|.  If we decide that
1135 the current string is not needed, |flush_cur_string| resets |pool_ptr| so that
1136 |cur_length| becomes zero.
1137
1138 @d cur_length   (mp->pool_ptr - mp->str_start[mp->str_ptr])
1139 @d flush_cur_string   mp->pool_ptr=mp->str_start[mp->str_ptr]
1140
1141 @ Strings are created by appending character codes to |str_pool|.
1142 The |append_char| macro, defined here, does not check to see if the
1143 value of |pool_ptr| has gotten too high; this test is supposed to be
1144 made before |append_char| is used.
1145
1146 To test if there is room to append |l| more characters to |str_pool|,
1147 we shall write |str_room(l)|, which tries to make sure there is enough room
1148 by compacting the string pool if necessary.  If this does not work,
1149 |do_compaction| aborts \MP\ and gives an apologetic error message.
1150
1151 @d append_char(A)   /* put |ASCII_code| \# at the end of |str_pool| */
1152 { mp->str_pool[mp->pool_ptr]=(ASCII_code)(A); incr(mp->pool_ptr);
1153 }
1154 @d str_room(A)   /* make sure that the pool hasn't overflowed */
1155   { if ( mp->pool_ptr+(A) > mp->max_pool_ptr ) {
1156     if ( mp->pool_ptr+(A) > mp->pool_size ) mp_do_compaction(mp, (A));
1157     else mp->max_pool_ptr=mp->pool_ptr+(A); }
1158   }
1159
1160 @ The following routine is similar to |str_room(1)| but it uses the
1161 argument |mp->pool_size| to prevent |do_compaction| from aborting when
1162 string space is exhausted.
1163
1164 @<Declarations@>=
1165 static void mp_unit_str_room (MP mp);
1166
1167 @ @c
1168 void mp_unit_str_room (MP mp) { 
1169   if ( mp->pool_ptr>=mp->pool_size ) mp_do_compaction(mp, mp->pool_size);
1170   if ( mp->pool_ptr>=mp->max_pool_ptr ) mp->max_pool_ptr=mp->pool_ptr+1;
1171 }
1172
1173 @ \MP's string expressions are implemented in a brute-force way: Every
1174 new string or substring that is needed is simply copied into the string pool.
1175 Space is eventually reclaimed by a procedure called |do_compaction| with
1176 the aid of a simple system system of reference counts.
1177 @^reference counts@>
1178
1179 The number of references to string number |s| will be |str_ref[s]|. The
1180 special value |str_ref[s]=max_str_ref=127| is used to denote an unknown
1181 positive number of references; such strings will never be recycled. If
1182 a string is ever referred to more than 126 times, simultaneously, we
1183 put it in this category. Hence a single byte suffices to store each |str_ref|.
1184
1185 @d max_str_ref 127 /* ``infinite'' number of references */
1186 @d add_str_ref(A) { if ( mp->str_ref[(A)]<max_str_ref ) incr(mp->str_ref[(A)]); }
1187
1188 @<Glob...@>=
1189 int *str_ref;
1190
1191 @ @<Allocate or initialize ...@>=
1192 mp->str_ref = xmalloc ((mp->max_strings+1),sizeof(int));
1193
1194 @ @<Dealloc variables@>=
1195 xfree(mp->str_ref);
1196
1197 @ Here's what we do when a string reference disappears:
1198
1199 @d delete_str_ref(A)  { 
1200     if ( mp->str_ref[(A)]<max_str_ref ) {
1201        if ( mp->str_ref[(A)]>1 ) decr(mp->str_ref[(A)]); 
1202        else mp_flush_string(mp, (A));
1203     }
1204   }
1205
1206 @<Declarations@>=
1207 static void mp_flush_string (MP mp,str_number s) ;
1208
1209 @ We can't flush the first set of static strings at all, so there 
1210 is no point in trying
1211
1212 @c
1213 void mp_flush_string (MP mp,str_number s) { 
1214   if (length(s)>1) {
1215     mp->pool_in_use=mp->pool_in_use-length(s);
1216     decr(mp->strs_in_use);
1217     if ( mp->next_str[s]!=mp->str_ptr ) {
1218       mp->str_ref[s]=0;
1219     } else { 
1220       mp->str_ptr=s;
1221       decr(mp->strs_used_up);
1222     }
1223     mp->pool_ptr=mp->str_start[mp->str_ptr];
1224   }
1225 }
1226
1227 @ C literals cannot be simply added, they need to be set so they can't
1228 be flushed.
1229
1230 @d intern(A) mp_intern(mp,(A))
1231
1232 @c
1233 str_number mp_intern (MP mp, const char *s) {
1234   str_number r ;
1235   r = rts(s);
1236   mp->str_ref[r] = max_str_ref;
1237   return r;
1238 }
1239
1240 @ @<Declarations@>=
1241 static str_number mp_intern (MP mp, const char *s);
1242
1243
1244 @ Once a sequence of characters has been appended to |str_pool|, it
1245 officially becomes a string when the function |make_string| is called.
1246 This function returns the identification number of the new string as its
1247 value.
1248
1249 When getting the next unused string number from the linked list, we pretend
1250 that
1251 $$ \hbox{|max_str_ptr+1|, |max_str_ptr+2|, $\ldots$, |mp->max_strings|} $$
1252 are linked sequentially even though the |next_str| entries have not been
1253 initialized yet.  We never allow |str_ptr| to reach |mp->max_strings|;
1254 |do_compaction| is responsible for making sure of this.
1255
1256 @<Declarations@>=
1257 static str_number mp_make_string (MP mp);
1258
1259 @ @c 
1260 str_number mp_make_string (MP mp) { /* current string enters the pool */
1261   str_number s; /* the new string */
1262 RESTART: 
1263   s=mp->str_ptr;
1264   mp->str_ptr=mp->next_str[s];
1265   if ( mp->str_ptr>mp->max_str_ptr ) {
1266     if ( mp->str_ptr==mp->max_strings ) { 
1267       mp->str_ptr=s;
1268       mp_do_compaction(mp, 0);
1269       goto RESTART;
1270     } else {
1271       mp->max_str_ptr=mp->str_ptr;
1272       mp->next_str[mp->str_ptr]=mp->max_str_ptr+1;
1273     }
1274   }
1275   mp->str_ref[s]=1;
1276   mp->str_start[mp->str_ptr]=mp->pool_ptr;
1277   incr(mp->strs_used_up);
1278   incr(mp->strs_in_use);
1279   mp->pool_in_use=mp->pool_in_use+length(s);
1280   if ( mp->pool_in_use>mp->max_pl_used ) 
1281     mp->max_pl_used=mp->pool_in_use;
1282   if ( mp->strs_in_use>mp->max_strs_used ) 
1283     mp->max_strs_used=mp->strs_in_use;
1284   return s;
1285 }
1286
1287 @ The most interesting string operation is string pool compaction.  The idea
1288 is to recover unused space in the |str_pool| array by recopying the strings
1289 to close the gaps created when some strings become unused.  All string
1290 numbers~$k$ where |str_ref[k]=0| are to be linked into the list of free string
1291 numbers after |str_ptr|.  If this fails to free enough pool space we issue an
1292 |overflow| error unless |needed=mp->pool_size|.  Calling |do_compaction|
1293 with |needed=mp->pool_size| supresses all overflow tests.
1294
1295 The compaction process starts with |last_fixed_str| because all lower numbered
1296 strings are permanently allocated with |max_str_ref| in their |str_ref| entries.
1297
1298 @<Glob...@>=
1299 str_number last_fixed_str; /* last permanently allocated string */
1300 str_number fixed_str_use; /* number of permanently allocated strings */
1301
1302 @ @<Declarations@>=
1303 static void mp_do_compaction (MP mp, pool_pointer needed) ;
1304
1305 @ @c
1306 void mp_do_compaction (MP mp, pool_pointer needed) {
1307   str_number str_use; /* a count of strings in use */
1308   str_number r,s,t; /* strings being manipulated */
1309   pool_pointer p,q; /* destination and source for copying string characters */
1310   @<Advance |last_fixed_str| as far as possible and set |str_use|@>;
1311   r=mp->last_fixed_str;
1312   s=mp->next_str[r];
1313   p=mp->str_start[s];
1314   while ( s!=mp->str_ptr ) { 
1315     while ( mp->str_ref[s]==0 ) {
1316       @<Advance |s| and add the old |s| to the list of free string numbers;
1317         then |break| if |s=str_ptr|@>;
1318     }
1319     r=s; s=mp->next_str[s];
1320     incr(str_use);
1321     @<Move string |r| back so that |str_start[r]=p|; make |p| the location
1322      after the end of the string@>;
1323   }
1324 DONE:   
1325   @<Move the current string back so that it starts at |p|@>;
1326   if ( needed<mp->pool_size ) {
1327     @<Make sure that there is room for another string with |needed| characters@>;
1328   }
1329   @<Account for the compaction and make sure the statistics agree with the
1330      global versions@>;
1331   mp->strs_used_up=str_use;
1332 }
1333
1334 @ @<Advance |last_fixed_str| as far as possible and set |str_use|@>=
1335 t=mp->next_str[mp->last_fixed_str];
1336 while (t!=mp->str_ptr && mp->str_ref[t]==max_str_ref) {
1337   incr(mp->fixed_str_use);
1338   mp->last_fixed_str=t;
1339   t=mp->next_str[t];
1340 }
1341 str_use=mp->fixed_str_use
1342
1343 @ Because of the way |flush_string| has been written, it should never be
1344 necessary to |break| here.  The extra line of code seems worthwhile to
1345 preserve the generality of |do_compaction|.
1346
1347 @<Advance |s| and add the old |s| to the list of free string numbers;...@>=
1348 {
1349 t=s;
1350 s=mp->next_str[s];
1351 mp->next_str[r]=s;
1352 mp->next_str[t]=mp->next_str[mp->str_ptr];
1353 mp->next_str[mp->str_ptr]=t;
1354 if ( s==mp->str_ptr ) goto DONE;
1355 }
1356
1357 @ The string currently starts at |str_start[r]| and ends just before
1358 |str_start[s]|.  We don't change |str_start[s]| because it might be needed
1359 to locate the next string.
1360
1361 @<Move string |r| back so that |str_start[r]=p|; make |p| the location...@>=
1362 q=mp->str_start[r];
1363 mp->str_start[r]=p;
1364 while ( q<mp->str_start[s] ) { 
1365   mp->str_pool[p]=mp->str_pool[q];
1366   incr(p); incr(q);
1367 }
1368
1369 @ Pointers |str_start[str_ptr]| and |pool_ptr| have not been updated.  When
1370 we do this, anything between them should be moved.
1371
1372 @ @<Move the current string back so that it starts at |p|@>=
1373 q=mp->str_start[mp->str_ptr];
1374 mp->str_start[mp->str_ptr]=p;
1375 while ( q<mp->pool_ptr ) { 
1376   mp->str_pool[p]=mp->str_pool[q];
1377   incr(p); incr(q);
1378 }
1379 mp->pool_ptr=p
1380
1381 @ We must remember that |str_ptr| is not allowed to reach |mp->max_strings|.
1382
1383 @<Make sure that there is room for another string with |needed| char...@>=
1384 if ( str_use>=mp->max_strings-1 )
1385   mp_reallocate_strings (mp,str_use);
1386 if ( mp->pool_ptr+needed>mp->max_pool_ptr ) {
1387   mp_reallocate_pool(mp, mp->pool_ptr+needed);
1388   mp->max_pool_ptr=mp->pool_ptr+needed;
1389 }
1390
1391 @ @<Declarations@>=
1392 static void mp_reallocate_strings (MP mp, str_number str_use) ;
1393 static void mp_reallocate_pool(MP mp, pool_pointer needed) ;
1394
1395 @ @c 
1396 void mp_reallocate_strings (MP mp, str_number str_use) { 
1397   while ( str_use>=mp->max_strings-1 ) {
1398     int l = mp->max_strings + (mp->max_strings/4);
1399     XREALLOC (mp->str_ref,   l, int);
1400     XREALLOC (mp->str_start, l, pool_pointer);
1401     XREALLOC (mp->next_str,  l, str_number);
1402     mp->max_strings = l;
1403   }
1404 }
1405 void mp_reallocate_pool(MP mp, pool_pointer needed) {
1406   while ( needed>mp->pool_size ) {
1407     int l = mp->pool_size + (mp->pool_size/4);
1408         XREALLOC (mp->str_pool, l, ASCII_code);
1409     mp->pool_size = l;
1410   }
1411 }
1412
1413 @ @<Account for the compaction and make sure the statistics agree with...@>=
1414 if ( (mp->str_start[mp->str_ptr]!=mp->pool_in_use)||(str_use!=mp->strs_in_use) )
1415   mp_confusion(mp, "string");
1416 @:this can't happen string}{\quad string@>
1417 incr(mp->pact_count);
1418 mp->pact_chars=mp->pact_chars+mp->pool_ptr-str_stop(mp->last_fixed_str);
1419 mp->pact_strs=mp->pact_strs+str_use-mp->fixed_str_use;
1420
1421 @ A few more global variables are needed to keep track of statistics when
1422 |stat| $\ldots$ |tats| blocks are not commented out.
1423
1424 @<Glob...@>=
1425 integer pact_count; /* number of string pool compactions so far */
1426 integer pact_chars; /* total number of characters moved during compactions */
1427 integer pact_strs; /* total number of strings moved during compactions */
1428
1429 @ @<Initialize compaction statistics@>=
1430 mp->pact_count=0;
1431 mp->pact_chars=0;
1432 mp->pact_strs=0;
1433
1434 @ The following subroutine compares string |s| with another string of the
1435 same length that appears in |buffer| starting at position |k|;
1436 the result is |true| if and only if the strings are equal.
1437
1438 @c 
1439 static boolean mp_str_eq_buf (MP mp,str_number s, integer k) {
1440   /* test equality of strings */
1441   pool_pointer j; /* running index */
1442   j=mp->str_start[s];
1443   while ( j<str_stop(s) ) { 
1444     if ( mp->str_pool[j++]!=mp->buffer[k++] ) 
1445       return false;
1446   }
1447   return true;
1448 }
1449
1450 @ Here is a similar routine, but it compares two strings in the string pool,
1451 and it does not assume that they have the same length. If the first string
1452 is lexicographically greater than, less than, or equal to the second,
1453 the result is respectively positive, negative, or zero.
1454
1455 @c 
1456 static integer mp_str_vs_str (MP mp, str_number s, str_number t) {
1457   /* test equality of strings */
1458   pool_pointer j,k; /* running indices */
1459   integer ls,lt; /* lengths */
1460   integer l; /* length remaining to test */
1461   ls=length(s); lt=length(t);
1462   if ( ls<=lt ) l=ls; else l=lt;
1463   j=mp->str_start[s]; k=mp->str_start[t];
1464   while ( l-->0 ) { 
1465     if ( mp->str_pool[j]!=mp->str_pool[k] ) {
1466        return (mp->str_pool[j]-mp->str_pool[k]); 
1467     }
1468     incr(j); incr(k);
1469   }
1470   return (ls-lt);
1471 }
1472
1473 @ The initial values of |str_pool|, |str_start|, |pool_ptr|,
1474 and |str_ptr| are computed by the \.{INIMP} program, based in part
1475 on the information that \.{WEB} has output while processing \MP.
1476 @.INIMP@>
1477 @^string pool@>
1478
1479 @c 
1480 void mp_get_strings_started (MP mp) { 
1481   /* initializes the string pool,
1482     but returns |false| if something goes wrong */
1483   int k; /* small indices or counters */
1484   str_number g; /* a new string */
1485   mp->pool_ptr=0; mp->str_ptr=0; mp->max_pool_ptr=0; mp->max_str_ptr=0;
1486   mp->str_start[0]=0;
1487   mp->next_str[0]=1;
1488   mp->pool_in_use=0; mp->strs_in_use=0;
1489   mp->max_pl_used=0; mp->max_strs_used=0;
1490   @<Initialize compaction statistics@>;
1491   mp->strs_used_up=0;
1492   @<Make the first 256 strings@>;
1493   g=mp_make_string(mp); /* string 256 == "" */
1494   mp->str_ref[g]=max_str_ref;
1495   mp->last_fixed_str=mp->str_ptr-1;
1496   mp->fixed_str_use=mp->str_ptr;
1497   return;
1498 }
1499
1500 @ @<Declarations@>=
1501 static void mp_get_strings_started (MP mp);
1502
1503 @ The first 256 strings will consist of a single character only.
1504
1505 @<Make the first 256...@>=
1506 for (k=0;k<=255;k++) { 
1507   append_char(k);
1508   g=mp_make_string(mp); 
1509   mp->str_ref[g]=max_str_ref;
1510 }
1511
1512 @ The first 128 strings will contain 95 standard ASCII characters, and the
1513 other 33 characters will be printed in three-symbol form like `\.{\^\^A}'
1514 unless a system-dependent change is made here. Installations that have
1515 an extended character set, where for example |xchr[032]=@t\.{'^^Z'}@>|,
1516 would like string 032 to be printed as the single character 032 instead
1517 of the three characters 0136, 0136, 0132 (\.{\^\^Z}). On the other hand,
1518 even people with an extended character set will want to represent string
1519 015 by \.{\^\^M}, since 015 is ASCII's ``carriage return'' code; the idea is
1520 to produce visible strings instead of tabs or line-feeds or carriage-returns
1521 or bell-rings or characters that are treated anomalously in text files.
1522
1523 The boolean expression defined here should be |true| unless \MP\ internal
1524 code number~|k| corresponds to a non-troublesome visible symbol in the
1525 local character set.
1526 If character |k| cannot be printed, and |k<0200|, then character |k+0100| or
1527 |k-0100| must be printable; moreover, ASCII codes |[060..071, 0141..0146]|
1528 must be printable.
1529 @^character set dependencies@>
1530 @^system dependencies@>
1531
1532 @<Character |k| cannot be printed@>=
1533   (k<' ')||(k==127)
1534
1535 @* \[5] On-line and off-line printing.
1536 Messages that are sent to a user's terminal and to the transcript-log file
1537 are produced by several `|print|' procedures. These procedures will
1538 direct their output to a variety of places, based on the setting of
1539 the global variable |selector|, which has the following possible
1540 values:
1541
1542 \yskip
1543 \hang |term_and_log|, the normal setting, prints on the terminal and on the
1544   transcript file.
1545
1546 \hang |log_only|, prints only on the transcript file.
1547
1548 \hang |term_only|, prints only on the terminal.
1549
1550 \hang |no_print|, doesn't print at all. This is used only in rare cases
1551   before the transcript file is open.
1552
1553 \hang |pseudo|, puts output into a cyclic buffer that is used
1554   by the |show_context| routine; when we get to that routine we shall discuss
1555   the reasoning behind this curious mode.
1556
1557 \hang |new_string|, appends the output to the current string in the
1558   string pool.
1559
1560 \hang |>=write_file| prints on one of the files used for the \&{write}
1561 @:write_}{\&{write} primitive@>
1562   command.
1563
1564 \yskip
1565 \noindent The symbolic names `|term_and_log|', etc., have been assigned
1566 numeric codes that satisfy the convenient relations |no_print+1=term_only|,
1567 |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.  These
1568 relations are not used when |selector| could be |pseudo|, or |new_string|.
1569 We need not check for unprintable characters when |selector<pseudo|.
1570
1571 Three additional global variables, |tally|, |term_offset| and |file_offset|
1572 record the number of characters that have been printed
1573 since they were most recently cleared to zero. We use |tally| to record
1574 the length of (possibly very long) stretches of printing; |term_offset|,
1575 and |file_offset|, on the other hand, keep track of how many
1576 characters have appeared so far on the current line that has been output
1577 to the terminal, the transcript file, or the \ps\ output file, respectively.
1578
1579 @d new_string 0 /* printing is deflected to the string pool */
1580 @d pseudo 2 /* special |selector| setting for |show_context| */
1581 @d no_print 3 /* |selector| setting that makes data disappear */
1582 @d term_only 4 /* printing is destined for the terminal only */
1583 @d log_only 5 /* printing is destined for the transcript file only */
1584 @d term_and_log 6 /* normal |selector| setting */
1585 @d write_file 7 /* first write file selector */
1586
1587 @<Glob...@>=
1588 void * log_file; /* transcript of \MP\ session */
1589 void * ps_file; /* the generic font output goes here */
1590 unsigned int selector; /* where to print a message */
1591 unsigned char dig[23]; /* digits in a number, for rounding */
1592 integer tally; /* the number of characters recently printed */
1593 unsigned int term_offset;
1594   /* the number of characters on the current terminal line */
1595 unsigned int file_offset;
1596   /* the number of characters on the current file line */
1597 ASCII_code *trick_buf; /* circular buffer for pseudoprinting */
1598 integer trick_count; /* threshold for pseudoprinting, explained later */
1599 integer first_count; /* another variable for pseudoprinting */
1600
1601 @ @<Allocate or initialize ...@>=
1602 mp->trick_buf = xmalloc((mp->error_line+1),sizeof(ASCII_code));
1603
1604 @ @<Dealloc variables@>=
1605 xfree(mp->trick_buf);
1606
1607 @ @<Initialize the output routines@>=
1608 mp->selector=term_only; mp->tally=0; mp->term_offset=0; mp->file_offset=0; 
1609
1610 @ Macro abbreviations for output to the terminal and to the log file are
1611 defined here for convenience. Some systems need special conventions
1612 for terminal output, and it is possible to adhere to those conventions
1613 by changing |wterm|, |wterm_ln|, and |wterm_cr| here.
1614 @^system dependencies@>
1615
1616 @d do_fprintf(f,b) (mp->write_ascii_file)(mp,f,b)
1617 @d wterm(A)     do_fprintf(mp->term_out,(A))
1618 @d wterm_chr(A) { unsigned char ss[2]; ss[0]=(A); ss[1]='\0'; 
1619                   do_fprintf(mp->term_out,(char *)ss); }
1620 @d wterm_cr     do_fprintf(mp->term_out,"\n")
1621 @d wterm_ln(A)  { wterm_cr; do_fprintf(mp->term_out,(A)); }
1622 @d wlog(A)      do_fprintf(mp->log_file,(A))
1623 @d wlog_chr(A)  { unsigned char ss[2]; ss[0]=(A); ss[1]='\0'; 
1624                   do_fprintf(mp->log_file,(char *)ss); }
1625 @d wlog_cr      do_fprintf(mp->log_file, "\n")
1626 @d wlog_ln(A)   { wlog_cr; do_fprintf(mp->log_file,(A)); }
1627
1628
1629 @ To end a line of text output, we call |print_ln|.  Cases |0..max_write_files|
1630 use an array |wr_file| that will be declared later.
1631
1632 @d mp_print_text(A) mp_print_str(mp,text((A)))
1633
1634 @<Internal ...@>=
1635 void mp_print (MP mp, const char *s);
1636
1637 @ @<Declarations@>=
1638 static void mp_print_ln (MP mp);
1639 static void mp_print_visible_char (MP mp, ASCII_code s); 
1640 static void mp_print_char (MP mp, ASCII_code k);
1641 static void mp_print_str (MP mp, str_number s);
1642 static void mp_print_nl (MP mp, const char *s);
1643 static void mp_print_two (MP mp,scaled x, scaled y) ;
1644 static void mp_print_scaled (MP mp,scaled s);
1645
1646 @ @<Basic print...@>=
1647 static void mp_print_ln (MP mp) { /* prints an end-of-line */
1648  switch (mp->selector) {
1649   case term_and_log: 
1650     wterm_cr; wlog_cr;
1651     mp->term_offset=0;  mp->file_offset=0;
1652     break;
1653   case log_only: 
1654     wlog_cr; mp->file_offset=0;
1655     break;
1656   case term_only: 
1657     wterm_cr; mp->term_offset=0;
1658     break;
1659   case no_print:
1660   case pseudo: 
1661   case new_string: 
1662     break;
1663   default: 
1664     do_fprintf(mp->wr_file[(mp->selector-write_file)],"\n");
1665   }
1666 } /* note that |tally| is not affected */
1667
1668 @ The |print_visible_char| procedure sends one character to the desired
1669 destination, using the |xchr| array to map it into an external character
1670 compatible with |input_ln|.  (It assumes that it is always called with
1671 a visible ASCII character.)  All printing comes through |print_ln| or
1672 |print_char|, which ultimately calls |print_visible_char|, hence these
1673 routines are the ones that limit lines to at most |max_print_line| characters.
1674 But we must make an exception for the \ps\ output file since it is not safe
1675 to cut up lines arbitrarily in \ps.
1676
1677 Procedure |unit_str_room| needs to be declared |forward| here because it calls
1678 |do_compaction| and |do_compaction| can call the error routines.  Actually,
1679 |unit_str_room| avoids |overflow| errors but it can call |confusion|.
1680
1681 @<Basic printing...@>=
1682 static void mp_print_visible_char (MP mp, ASCII_code s) { /* prints a single character */
1683   switch (mp->selector) {
1684   case term_and_log: 
1685     wterm_chr(xchr(s)); wlog_chr(xchr(s));
1686     incr(mp->term_offset); incr(mp->file_offset);
1687     if ( mp->term_offset==(unsigned)mp->max_print_line ) { 
1688        wterm_cr; mp->term_offset=0;
1689     };
1690     if ( mp->file_offset==(unsigned)mp->max_print_line ) { 
1691        wlog_cr; mp->file_offset=0;
1692     };
1693     break;
1694   case log_only: 
1695     wlog_chr(xchr(s)); incr(mp->file_offset);
1696     if ( mp->file_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1697     break;
1698   case term_only: 
1699     wterm_chr(xchr(s)); incr(mp->term_offset);
1700     if ( mp->term_offset==(unsigned)mp->max_print_line ) mp_print_ln(mp);
1701     break;
1702   case no_print: 
1703     break;
1704   case pseudo: 
1705     if ( mp->tally<mp->trick_count ) 
1706       mp->trick_buf[mp->tally % mp->error_line]=s;
1707     break;
1708   case new_string: 
1709     if ( mp->pool_ptr>=mp->max_pool_ptr ) { 
1710       mp_unit_str_room(mp);
1711       if ( mp->pool_ptr>=mp->pool_size ) 
1712         goto DONE; /* drop characters if string space is full */
1713     };
1714     append_char(s);
1715     break;
1716   default:
1717     { text_char ss[2]; ss[0] = xchr(s); ss[1]=0;
1718       do_fprintf(mp->wr_file[(mp->selector-write_file)],(char *)ss);
1719     }
1720   }
1721 DONE:
1722   incr(mp->tally);
1723 }
1724
1725 @ The |print_char| procedure sends one character to the desired destination.
1726 File names and string expressions might contain |ASCII_code| values that
1727 can't be printed using |print_visible_char|.  These characters will be
1728 printed in three- or four-symbol form like `\.{\^\^A}' or `\.{\^\^e4}'.
1729 (This procedure assumes that it is safe to bypass all checks for unprintable
1730 characters when |selector| is in the range |0..max_write_files-1|.
1731 The user might want to write unprintable characters.
1732
1733 @<Basic printing...@>=
1734 static void mp_print_char (MP mp, ASCII_code k) { /* prints a single character */
1735   if ( mp->selector<pseudo || mp->selector>=write_file) {
1736     mp_print_visible_char(mp, k);
1737   } else if ( @<Character |k| cannot be printed@> ) { 
1738     mp_print(mp, "^^"); 
1739     if ( k<0100 ) { 
1740       mp_print_visible_char(mp, k+0100); 
1741     } else if ( k<0200 ) { 
1742       mp_print_visible_char(mp, k-0100); 
1743     } else {
1744       int l; /* small index or counter */
1745       l = (k / 16);
1746       mp_print_visible_char(mp, xord(l<10 ? l+'0' : l-10+'a'));
1747       l = (k % 16);
1748       mp_print_visible_char(mp, xord(l<10 ? l+'0' : l-10+'a'));
1749     }
1750   } else {
1751     mp_print_visible_char(mp, k);
1752   }
1753 }
1754
1755 @ An entire string is output by calling |print|. Note that if we are outputting
1756 the single standard ASCII character \.c, we could call |print("c")|, since
1757 |"c"=99| is the number of a single-character string, as explained above. But
1758 |print_char("c")| is quicker, so \MP\ goes directly to the |print_char|
1759 routine when it knows that this is safe. (The present implementation
1760 assumes that it is always safe to print a visible ASCII character.)
1761 @^system dependencies@>
1762
1763 @<Basic print...@>=
1764 static void mp_do_print (MP mp, const char *ss, size_t len) { /* prints string |s| */
1765   size_t j = 0;
1766   while ( j<len ){ 
1767     mp_print_char(mp, xord((int)ss[j])); incr(j);
1768   }
1769 }
1770
1771
1772 @<Basic print...@>=
1773 void mp_print (MP mp, const char *ss) {
1774   if (ss==NULL) return;
1775   mp_do_print(mp, ss,strlen(ss));
1776 }
1777 static void mp_print_str (MP mp, str_number s) {
1778   pool_pointer j; /* current character code position */
1779   if ( (s<0)||(s>mp->max_str_ptr) ) {
1780      mp_do_print(mp,"???",3); /* this can't happen */
1781 @.???@>
1782   }
1783   j=mp->str_start[s];
1784   mp_do_print(mp, (char *)(mp->str_pool+j), (size_t)(str_stop(s)-j));
1785 }
1786
1787
1788 @ Here is the very first thing that \MP\ prints: a headline that identifies
1789 the version number and base name. The |term_offset| variable is temporarily
1790 incorrect, but the discrepancy is not serious since we assume that the banner
1791 and mem identifier together will occupy at most |max_print_line|
1792 character positions.
1793
1794 @<Initialize the output...@>=
1795 wterm (mp->banner);
1796 if (mp->mem_ident!=NULL) 
1797   mp_print(mp,mp->mem_ident); 
1798 mp_print_ln(mp);
1799 update_terminal;
1800
1801 @ The procedure |print_nl| is like |print|, but it makes sure that the
1802 string appears at the beginning of a new line.
1803
1804 @<Basic print...@>=
1805 static void mp_print_nl (MP mp, const char *s) { /* prints string |s| at beginning of line */
1806   switch(mp->selector) {
1807   case term_and_log: 
1808     if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_ln(mp);
1809     break;
1810   case log_only: 
1811     if ( mp->file_offset>0 ) mp_print_ln(mp);
1812     break;
1813   case term_only: 
1814     if ( mp->term_offset>0 ) mp_print_ln(mp);
1815     break;
1816   case no_print:
1817   case pseudo:
1818   case new_string: 
1819         break;
1820   } /* there are no other cases */
1821   mp_print(mp, s);
1822 }
1823
1824 @ The following procedure, which prints out the decimal representation of a
1825 given integer |n|, assumes that all integers fit nicely into a |int|.
1826 @^system dependencies@>
1827
1828 @<Basic print...@>=
1829 static void mp_print_int (MP mp,integer n) { /* prints an integer in decimal form */
1830   char s[12];
1831   mp_snprintf(s,12,"%d", (int)n);
1832   mp_print(mp,s);
1833 }
1834
1835 @ @<Declarations@>=
1836 static void mp_print_int (MP mp,integer n);
1837
1838 @ \MP\ also makes use of a trivial procedure to print two digits. The
1839 following subroutine is usually called with a parameter in the range |0<=n<=99|.
1840
1841 @c 
1842 static void mp_print_dd (MP mp,integer n) { /* prints two least significant digits */
1843   n=abs(n) % 100; 
1844   mp_print_char(mp, xord('0'+(n / 10)));
1845   mp_print_char(mp, xord('0'+(n % 10)));
1846 }
1847
1848
1849 @ @<Declarations@>=
1850 static void mp_print_dd (MP mp,integer n);
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     if (!mp->noninteractive) {
1861       wake_up_terminal; mp_print(mp, (A)); 
1862     }
1863     mp_term_input(mp);
1864   } while (0) /* prints a string and gets a line of input */
1865
1866 @c 
1867 void mp_term_input (MP mp) { /* gets a line from the terminal */
1868   size_t k; /* index into |buffer| */
1869   if (mp->noninteractive) {
1870     if (!mp_input_ln(mp, mp->term_in ))
1871           longjmp(*(mp->jump_buf),1);  /* chunk finished */
1872     mp->buffer[mp->last]=xord('%'); 
1873   } else {
1874     update_terminal; /* Now the user sees the prompt for sure */
1875     if (!mp_input_ln(mp, mp->term_in )) {
1876           mp_fatal_error(mp, "End of file on the terminal!");
1877 @.End of file on the terminal@>
1878     }
1879     mp->term_offset=0; /* the user's line ended with \<\rm return> */
1880     decr(mp->selector); /* prepare to echo the input */
1881     if ( mp->last!=mp->first ) {
1882       for (k=mp->first;k<=mp->last-1;k++) {
1883         mp_print_char(mp, mp->buffer[k]);
1884       }
1885     }
1886     mp_print_ln(mp); 
1887     mp->buffer[mp->last]=xord('%'); 
1888     incr(mp->selector); /* restore previous status */
1889   }
1890 }
1891
1892 @* \[6] Reporting errors.
1893 When something anomalous is detected, \MP\ typically does something like this:
1894 $$\vbox{\halign{#\hfil\cr
1895 |print_err("Something anomalous has been detected");|\cr
1896 |help3("This is the first line of my offer to help.")|\cr
1897 |("This is the second line. I'm trying to")|\cr
1898 |("explain the best way for you to proceed.");|\cr
1899 |error;|\cr}}$$
1900 A two-line help message would be given using |help2|, etc.; these informal
1901 helps should use simple vocabulary that complements the words used in the
1902 official error message that was printed. (Outside the U.S.A., the help
1903 messages should preferably be translated into the local vernacular. Each
1904 line of help is at most 60 characters long, in the present implementation,
1905 so that |max_print_line| will not be exceeded.)
1906
1907 The |print_err| procedure supplies a `\.!' before the official message,
1908 and makes sure that the terminal is awake if a stop is going to occur.
1909 The |error| procedure supplies a `\..' after the official message, then it
1910 shows the location of the error; and if |interaction=error_stop_mode|,
1911 it also enters into a dialog with the user, during which time the help
1912 message may be printed.
1913 @^system dependencies@>
1914
1915 @ The global variable |interaction| has four settings, representing increasing
1916 amounts of user interaction:
1917
1918 @<Exported types@>=
1919 enum mp_interaction_mode { 
1920  mp_unspecified_mode=0, /* extra value for command-line switch */
1921  mp_batch_mode, /* omits all stops and omits terminal output */
1922  mp_nonstop_mode, /* omits all stops */
1923  mp_scroll_mode, /* omits error stops */
1924  mp_error_stop_mode /* stops at every opportunity to interact */
1925 };
1926
1927 @ @<Option variables@>=
1928 int interaction; /* current level of interaction */
1929 int noninteractive; /* do we have a terminal? */
1930
1931 @ Set it here so it can be overwritten by the commandline
1932
1933 @<Allocate or initialize ...@>=
1934 mp->interaction=opt->interaction;
1935 if (mp->interaction==mp_unspecified_mode || mp->interaction>mp_error_stop_mode) 
1936   mp->interaction=mp_error_stop_mode;
1937 if (mp->interaction<mp_unspecified_mode) 
1938   mp->interaction=mp_batch_mode;
1939
1940
1941
1942 @d print_err(A) mp_print_err(mp,(A))
1943
1944 @<Internal ...@>=
1945 void mp_print_err(MP mp, const char * A);
1946
1947 @ @c
1948 void mp_print_err(MP mp, const char * A) { 
1949   if ( mp->interaction==mp_error_stop_mode ) 
1950     wake_up_terminal;
1951   mp_print_nl(mp, "! "); 
1952   mp_print(mp, A);
1953 @.!\relax@>
1954 }
1955
1956
1957 @ \MP\ is careful not to call |error| when the print |selector| setting
1958 might be unusual. The only possible values of |selector| at the time of
1959 error messages are
1960
1961 \yskip\hang|no_print| (when |interaction=mp_batch_mode|
1962   and |log_file| not yet open);
1963
1964 \hang|term_only| (when |interaction>mp_batch_mode| and |log_file| not yet open);
1965
1966 \hang|log_only| (when |interaction=mp_batch_mode| and |log_file| is open);
1967
1968 \hang|term_and_log| (when |interaction>mp_batch_mode| and |log_file| is open).
1969
1970 @<Initialize the print |selector| based on |interaction|@>=
1971 if ( mp->interaction==mp_batch_mode ) mp->selector=no_print; else mp->selector=term_only
1972
1973 @ A global variable |deletions_allowed| is set |false| if the |get_next|
1974 routine is active when |error| is called; this ensures that |get_next|
1975 will never be called recursively.
1976 @^recursion@>
1977
1978 The global variable |history| records the worst level of error that
1979 has been detected. It has four possible values: |spotless|, |warning_issued|,
1980 |error_message_issued|, and |fatal_error_stop|.
1981
1982 Another global variable, |error_count|, is increased by one when an
1983 |error| occurs without an interactive dialog, and it is reset to zero at
1984 the end of every statement.  If |error_count| reaches 100, \MP\ decides
1985 that there is no point in continuing further.
1986
1987 @<Types...@>=
1988 enum mp_history_states {
1989   mp_spotless=0, /* |history| value when nothing has been amiss yet */
1990   mp_warning_issued, /* |history| value when |begin_diagnostic| has been called */
1991   mp_error_message_issued, /* |history| value when |error| has been called */
1992   mp_fatal_error_stop, /* |history| value when termination was premature */
1993   mp_system_error_stop /* |history| value when termination was due to disaster */
1994 };
1995
1996 @ @<Glob...@>=
1997 boolean deletions_allowed; /* is it safe for |error| to call |get_next|? */
1998 int history; /* has the source input been clean so far? */
1999 int error_count; /* the number of scrolled errors since the last statement ended */
2000
2001 @ The value of |history| is initially |fatal_error_stop|, but it will
2002 be changed to |spotless| if \MP\ survives the initialization process.
2003
2004 @<Allocate or ...@>=
2005 mp->deletions_allowed=true; /* |history| is initialized elsewhere */
2006
2007 @ Since errors can be detected almost anywhere in \MP, we want to declare the
2008 error procedures near the beginning of the program. But the error procedures
2009 in turn use some other procedures, which need to be declared |forward|
2010 before we get to |error| itself.
2011
2012 It is possible for |error| to be called recursively if some error arises
2013 when |get_next| is being used to delete a token, and/or if some fatal error
2014 occurs while \MP\ is trying to fix a non-fatal one. But such recursion
2015 @^recursion@>
2016 is never more than two levels deep.
2017
2018 @<Declarations@>=
2019 static void mp_get_next (MP mp);
2020 static void mp_term_input (MP mp);
2021 static void mp_show_context (MP mp);
2022 static void mp_begin_file_reading (MP mp);
2023 static void mp_open_log_file (MP mp);
2024 static void mp_clear_for_error_prompt (MP mp);
2025
2026 @ @<Internal ...@>=
2027 void mp_normalize_selector (MP mp);
2028
2029 @ Individual lines of help are recorded in the array |help_line|, which
2030 contains entries in positions |0..(help_ptr-1)|. They should be printed
2031 in reverse order, i.e., with |help_line[0]| appearing last.
2032
2033 @d hlp1(A) mp->help_line[0]=A; }
2034 @d hlp2(A,B) mp->help_line[1]=A; hlp1(B)
2035 @d hlp3(A,B,C) mp->help_line[2]=A; hlp2(B,C)
2036 @d hlp4(A,B,C,D) mp->help_line[3]=A; hlp3(B,C,D)
2037 @d hlp5(A,B,C,D,E) mp->help_line[4]=A; hlp4(B,C,D,E)
2038 @d hlp6(A,B,C,D,E,F) mp->help_line[5]=A; hlp5(B,C,D,E,F)
2039 @d help0 mp->help_ptr=0 /* sometimes there might be no help */
2040 @d help1  { mp->help_ptr=1; hlp1 /* use this with one help line */
2041 @d help2  { mp->help_ptr=2; hlp2 /* use this with two help lines */
2042 @d help3  { mp->help_ptr=3; hlp3 /* use this with three help lines */
2043 @d help4  { mp->help_ptr=4; hlp4 /* use this with four help lines */
2044 @d help5  { mp->help_ptr=5; hlp5 /* use this with five help lines */
2045 @d help6  { mp->help_ptr=6; hlp6 /* use this with six help lines */
2046
2047 @<Glob...@>=
2048 const char * help_line[6]; /* helps for the next |error| */
2049 unsigned int help_ptr; /* the number of help lines present */
2050 boolean use_err_help; /* should the |err_help| string be shown? */
2051 str_number err_help; /* a string set up by \&{errhelp} */
2052 str_number filename_template; /* a string set up by \&{filenametemplate} */
2053
2054 @ @<Allocate or ...@>=
2055 mp->use_err_help=false;
2056
2057 @ The |jump_out| procedure just cuts across all active procedure levels and
2058 goes to |end_of_MP|. This is the only nonlocal |goto| statement in the
2059 whole program. It is used when there is no recovery from a particular error.
2060
2061 The program uses a |jump_buf| to handle this, this is initialized at three
2062 spots: the start of |mp_new|, the start of |mp_initialize|, and the start 
2063 of |mp_run|. Those are the only library enty points.
2064
2065 @^system dependencies@>
2066
2067 @<Glob...@>=
2068 jmp_buf *jump_buf;
2069
2070 @ If the array of internals is still |NULL| when |jump_out| is called, a
2071 crash occured during initialization, and it is not safe to run the normal
2072 cleanup routine.
2073
2074 @<Error hand...@>=
2075 static void mp_jump_out (MP mp) { 
2076   if (mp->internal!=NULL && mp->history < mp_system_error_stop) 
2077     mp_close_files_and_terminate(mp);
2078   longjmp(*(mp->jump_buf),1);
2079 }
2080
2081 @ Here now is the general |error| routine.
2082
2083 @<Error hand...@>=
2084 void mp_error (MP mp) { /* completes the job of error reporting */
2085   ASCII_code c; /* what the user types */
2086   integer s1,s2,s3; /* used to save global variables when deleting tokens */
2087   pool_pointer j; /* character position being printed */
2088   if ( mp->history<mp_error_message_issued ) 
2089         mp->history=mp_error_message_issued;
2090   mp_print_char(mp, xord('.')); mp_show_context(mp);
2091   if ((!mp->noninteractive) && (mp->interaction==mp_error_stop_mode )) {
2092     @<Get user's advice and |return|@>;
2093   }
2094   incr(mp->error_count);
2095   if ( mp->error_count==100 ) { 
2096     mp_print_nl(mp,"(That makes 100 errors; please try again.)");
2097 @.That makes 100 errors...@>
2098     mp->history=mp_fatal_error_stop; mp_jump_out(mp);
2099   }
2100   @<Put help message on the transcript file@>;
2101 }
2102 void mp_warn (MP mp, const char *msg) {
2103   unsigned saved_selector = mp->selector;
2104   mp_normalize_selector(mp);
2105   mp_print_nl(mp,"Warning: ");
2106   mp_print(mp,msg);
2107   mp_print_ln(mp);
2108   mp->selector = saved_selector;
2109 }
2110
2111 @ @<Exported function ...@>=
2112 extern void mp_error (MP mp);
2113 extern void mp_warn (MP mp, const char *msg);
2114
2115
2116 @ @<Get user's advice...@>=
2117 while (true) { 
2118 CONTINUE:
2119   mp_clear_for_error_prompt(mp); prompt_input("? ");
2120 @.?\relax@>
2121   if ( mp->last==mp->first ) return;
2122   c=mp->buffer[mp->first];
2123   if ( c>='a' ) c=c+'A'-'a'; /* convert to uppercase */
2124   @<Interpret code |c| and |return| if done@>;
2125 }
2126
2127 @ It is desirable to provide an `\.E' option here that gives the user
2128 an easy way to return from \MP\ to the system editor, with the offending
2129 line ready to be edited. But such an extension requires some system
2130 wizardry, so the present implementation simply types out the name of the
2131 file that should be
2132 edited and the relevant line number.
2133 @^system dependencies@>
2134
2135 @<Exported types@>=
2136 typedef void (*mp_run_editor_command)(MP, char *, int);
2137
2138 @ @<Option variables@>=
2139 mp_run_editor_command run_editor;
2140
2141 @ @<Allocate or initialize ...@>=
2142 set_callback_option(run_editor);
2143
2144 @ @<Declarations@>=
2145 static void mp_run_editor (MP mp, char *fname, int fline);
2146
2147 @ @c 
2148 void mp_run_editor (MP mp, char *fname, int fline) {
2149     mp_print_nl(mp, "You want to edit file ");
2150 @.You want to edit file x@>
2151     mp_print(mp, fname);
2152     mp_print(mp, " at line "); 
2153     mp_print_int(mp, fline);
2154     mp->interaction=mp_scroll_mode; 
2155     mp_jump_out(mp);
2156 }
2157
2158
2159 There is a secret `\.D' option available when the debugging routines haven't
2160 been commented~out.
2161 @^debugging@>
2162
2163 @<Interpret code |c| and |return| if done@>=
2164 switch (c) {
2165 case '0': case '1': case '2': case '3': case '4':
2166 case '5': case '6': case '7': case '8': case '9': 
2167   if ( mp->deletions_allowed ) {
2168     @<Delete |c-"0"| tokens and |continue|@>;
2169   }
2170   break;
2171 case 'E': 
2172   if ( mp->file_ptr>0 ){ 
2173     (mp->run_editor)(mp, 
2174                      str(mp->input_stack[mp->file_ptr].name_field), 
2175                      mp_true_line(mp));
2176   }
2177   break;
2178 case 'H': 
2179   @<Print the help information and |continue|@>;
2180   /* |break;| */
2181 case 'I':
2182   @<Introduce new material from the terminal and |return|@>;
2183   /* |break;| */
2184 case 'Q': case 'R': case 'S':
2185   @<Change the interaction level and |return|@>;
2186   /* |break;| */
2187 case 'X':
2188   mp->interaction=mp_scroll_mode; mp_jump_out(mp);
2189   break;
2190 default:
2191   break;
2192 }
2193 @<Print the menu of available options@>
2194
2195 @ @<Print the menu...@>=
2196
2197   mp_print(mp, "Type <return> to proceed, S to scroll future error messages,");
2198 @.Type <return> to proceed...@>
2199   mp_print_nl(mp, "R to run without stopping, Q to run quietly,");
2200   mp_print_nl(mp, "I to insert something, ");
2201   if ( mp->file_ptr>0 ) 
2202     mp_print(mp, "E to edit your file,");
2203   if ( mp->deletions_allowed )
2204     mp_print_nl(mp, "1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
2205   mp_print_nl(mp, "H for help, X to quit.");
2206 }
2207
2208 @ Here the author of \MP\ apologizes for making use of the numerical
2209 relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
2210 |mp_batch_mode|, |mp_nonstop_mode|, |mp_scroll_mode|.
2211 @^Knuth, Donald Ervin@>
2212
2213 @<Change the interaction...@>=
2214
2215   mp->error_count=0; mp->interaction=mp_batch_mode+c-'Q';
2216   mp_print(mp, "OK, entering ");
2217   switch (c) {
2218   case 'Q': mp_print(mp, "batchmode"); decr(mp->selector); break;
2219   case 'R': mp_print(mp, "nonstopmode"); break;
2220   case 'S': mp_print(mp, "scrollmode"); break;
2221   } /* there are no other cases */
2222   mp_print(mp, "..."); mp_print_ln(mp); update_terminal; return;
2223 }
2224
2225 @ When the following code is executed, |buffer[(first+1)..(last-1)]| may
2226 contain the material inserted by the user; otherwise another prompt will
2227 be given. In order to understand this part of the program fully, you need
2228 to be familiar with \MP's input stacks.
2229
2230 @<Introduce new material...@>=
2231
2232   mp_begin_file_reading(mp); /* enter a new syntactic level for terminal input */
2233   if ( mp->last>mp->first+1 ) { 
2234     loc=(halfword)(mp->first+1); mp->buffer[mp->first]=xord(' ');
2235   } else { 
2236    prompt_input("insert>"); loc=(halfword)mp->first;
2237 @.insert>@>
2238   };
2239   mp->first=mp->last+1; mp->cur_input.limit_field=(halfword)mp->last; return;
2240 }
2241
2242 @ We allow deletion of up to 99 tokens at a time.
2243
2244 @<Delete |c-"0"| tokens...@>=
2245
2246   s1=mp->cur_cmd; s2=mp->cur_mod; s3=mp->cur_sym; mp->OK_to_interrupt=false;
2247   if ( (mp->last>mp->first+1) && (mp->buffer[mp->first+1]>='0')&&(mp->buffer[mp->first+1]<='9') )
2248     c=xord(c*10+mp->buffer[mp->first+1]-'0'*11);
2249   else 
2250     c=c-'0';
2251   while ( c>0 ) { 
2252     mp_get_next(mp); /* one-level recursive call of |error| is possible */
2253     @<Decrease the string reference count, if the current token is a string@>;
2254     decr(c);
2255   };
2256   mp->cur_cmd=s1; mp->cur_mod=s2; mp->cur_sym=s3; mp->OK_to_interrupt=true;
2257   help2("I have just deleted some text, as you asked.",
2258        "You can now delete more, or insert, or whatever.");
2259   mp_show_context(mp); 
2260   goto CONTINUE;
2261 }
2262
2263 @ @<Print the help info...@>=
2264
2265   if ( mp->use_err_help ) { 
2266     @<Print the string |err_help|, possibly on several lines@>;
2267     mp->use_err_help=false;
2268   } else { 
2269     if ( mp->help_ptr==0 ) {
2270       help2("Sorry, I don't know how to help in this situation.",
2271             "Maybe you should try asking a human?");
2272      }
2273     do { 
2274       decr(mp->help_ptr); mp_print(mp, mp->help_line[mp->help_ptr]); mp_print_ln(mp);
2275     } while (mp->help_ptr!=0);
2276   };
2277   help4("Sorry, I already gave what help I could...",
2278        "Maybe you should try asking a human?",
2279        "An error might have occurred before I noticed any problems.",
2280        "``If all else fails, read the instructions.''");
2281   goto CONTINUE;
2282 }
2283
2284 @ @<Print the string |err_help|, possibly on several lines@>=
2285 j=mp->str_start[mp->err_help];
2286 while ( j<str_stop(mp->err_help) ) { 
2287   if ( mp->str_pool[j]!='%' ) mp_print_str(mp, mp->str_pool[j]);
2288   else if ( j+1==str_stop(mp->err_help) ) mp_print_ln(mp);
2289   else if ( mp->str_pool[j+1]!='%' ) mp_print_ln(mp);
2290   else  { incr(j); mp_print_char(mp, xord('%')); };
2291   incr(j);
2292 }
2293
2294 @ @<Put help message on the transcript file@>=
2295 if ( mp->interaction>mp_batch_mode ) decr(mp->selector); /* avoid terminal output */
2296 if ( mp->use_err_help ) { 
2297   mp_print_nl(mp, "");
2298   @<Print the string |err_help|, possibly on several lines@>;
2299 } else { 
2300   while ( mp->help_ptr>0 ){ 
2301     decr(mp->help_ptr); mp_print_nl(mp, mp->help_line[mp->help_ptr]);
2302   };
2303 }
2304 mp_print_ln(mp);
2305 if ( mp->interaction>mp_batch_mode ) incr(mp->selector); /* re-enable terminal output */
2306 mp_print_ln(mp)
2307
2308 @ In anomalous cases, the print selector might be in an unknown state;
2309 the following subroutine is called to fix things just enough to keep
2310 running a bit longer.
2311
2312 @c 
2313 void mp_normalize_selector (MP mp) { 
2314   if ( mp->log_opened ) mp->selector=term_and_log;
2315   else mp->selector=term_only;
2316   if ( mp->job_name==NULL) mp_open_log_file(mp);
2317   if ( mp->interaction==mp_batch_mode ) decr(mp->selector);
2318 }
2319
2320 @ The following procedure prints \MP's last words before dying.
2321
2322 @d succumb { if ( mp->interaction==mp_error_stop_mode )
2323     mp->interaction=mp_scroll_mode; /* no more interaction */
2324   if ( mp->log_opened ) mp_error(mp);
2325   mp->history=mp_fatal_error_stop; mp_jump_out(mp); /* irrecoverable error */
2326   }
2327
2328 @<Error hand...@>=
2329 void mp_fatal_error (MP mp, const char *s) { /* prints |s|, and that's it */
2330   mp_normalize_selector(mp);
2331   print_err("Emergency stop"); help1(s); succumb;
2332 @.Emergency stop@>
2333 }
2334
2335 @ @<Exported function ...@>=
2336 extern void mp_fatal_error (MP mp, const char *s);
2337
2338
2339 @ Here is the most dreaded error message.
2340
2341 @<Error hand...@>=
2342 void mp_overflow (MP mp, const char *s, integer n) { /* stop due to finiteness */
2343   char msg[256];
2344   mp_normalize_selector(mp);
2345   mp_snprintf(msg, 256, "MetaPost capacity exceeded, sorry [%s=%d]",s,(int)n);
2346 @.MetaPost capacity exceeded ...@>
2347   print_err(msg);
2348   help2("If you really absolutely need more capacity,",
2349         "you can ask a wizard to enlarge me.");
2350   succumb;
2351 }
2352
2353 @ @<Internal library declarations@>=
2354 void mp_overflow (MP mp, const char *s, integer n);
2355
2356 @ The program might sometime run completely amok, at which point there is
2357 no choice but to stop. If no previous error has been detected, that's bad
2358 news; a message is printed that is really intended for the \MP\
2359 maintenance person instead of the user (unless the user has been
2360 particularly diabolical).  The index entries for `this can't happen' may
2361 help to pinpoint the problem.
2362 @^dry rot@>
2363
2364 @<Internal library ...@>=
2365 void mp_confusion (MP mp, const char *s);
2366
2367 @ Consistency check violated; |s| tells where.
2368 @<Error hand...@>=
2369 void mp_confusion (MP mp, const char *s) {
2370   char msg[256];
2371   mp_normalize_selector(mp);
2372   if ( mp->history<mp_error_message_issued ) { 
2373     mp_snprintf(msg, 256, "This can't happen (%s)",s);
2374 @.This can't happen@>
2375     print_err(msg);
2376     help1("I'm broken. Please show this to someone who can fix can fix");
2377   } else { 
2378     print_err("I can\'t go on meeting you like this");
2379 @.I can't go on...@>
2380     help2("One of your faux pas seems to have wounded me deeply...",
2381           "in fact, I'm barely conscious. Please fix it and try again.");
2382   }
2383   succumb;
2384 }
2385
2386 @ Users occasionally want to interrupt \MP\ while it's running.
2387 If the runtime system allows this, one can implement
2388 a routine that sets the global variable |interrupt| to some nonzero value
2389 when such an interrupt is signaled. Otherwise there is probably at least
2390 a way to make |interrupt| nonzero using the C debugger.
2391 @^system dependencies@>
2392 @^debugging@>
2393
2394 @d check_interrupt { if ( mp->interrupt!=0 )
2395    mp_pause_for_instructions(mp); }
2396
2397 @<Global...@>=
2398 integer interrupt; /* should \MP\ pause for instructions? */
2399 boolean OK_to_interrupt; /* should interrupts be observed? */
2400 integer run_state; /* are we processing input ?*/
2401 boolean finished; /* set true by |close_files_and_terminate| */
2402
2403 @ @<Allocate or ...@>=
2404 mp->OK_to_interrupt=true;
2405 mp->finished=false;
2406
2407 @ When an interrupt has been detected, the program goes into its
2408 highest interaction level and lets the user have the full flexibility of
2409 the |error| routine.  \MP\ checks for interrupts only at times when it is
2410 safe to do this.
2411
2412 @c 
2413 static void mp_pause_for_instructions (MP mp) { 
2414   if ( mp->OK_to_interrupt ) { 
2415     mp->interaction=mp_error_stop_mode;
2416     if ( (mp->selector==log_only)||(mp->selector==no_print) )
2417       incr(mp->selector);
2418     print_err("Interruption");
2419 @.Interruption@>
2420     help3("You rang?",
2421          "Try to insert some instructions for me (e.g.,`I show x'),",
2422          "unless you just want to quit by typing `X'.");
2423     mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
2424     mp->interrupt=0;
2425   }
2426 }
2427
2428 @ Many of \MP's error messages state that a missing token has been
2429 inserted behind the scenes. We can save string space and program space
2430 by putting this common code into a subroutine.
2431
2432 @c 
2433 static void mp_missing_err (MP mp, const char *s) { 
2434   char msg[256];
2435   mp_snprintf(msg, 256, "Missing `%s' has been inserted", s);
2436 @.Missing...inserted@>
2437   print_err(msg);
2438 }
2439
2440 @* \[7] Arithmetic with scaled numbers.
2441 The principal computations performed by \MP\ are done entirely in terms of
2442 integers less than $2^{31}$ in magnitude; thus, the arithmetic specified in this
2443 program can be carried out in exactly the same way on a wide variety of
2444 computers, including some small ones.
2445 @^small computers@>
2446
2447 But C does not rigidly define the |/| operation in the case of negative
2448 dividends; for example, the result of |(-2*n-1) / 2| is |-(n+1)| on some
2449 computers and |-n| on others (is this true ?).  There are two principal
2450 types of arithmetic: ``translation-preserving,'' in which the identity
2451 |(a+q*b)/b=(a/b)+q| is valid; and ``negation-preserving,'' in which
2452 |(-a)/b=-(a/b)|. This leads to two \MP s, which can produce
2453 different results, although the differences should be negligible when the
2454 language is being used properly.  The \TeX\ processor has been defined
2455 carefully so that both varieties of arithmetic will produce identical
2456 output, but it would be too inefficient to constrain \MP\ in a similar way.
2457
2458 @d el_gordo   0x7fffffff /* $2^{31}-1$, the largest value that \MP\ likes */
2459
2460
2461 @ One of \MP's most common operations is the calculation of
2462 $\lfloor{a+b\over2}\rfloor$,
2463 the midpoint of two given integers |a| and~|b|. The most decent way to do
2464 this is to write `|(a+b)/2|'; but on many machines it is more efficient 
2465 to calculate `|(a+b)>>1|'.
2466
2467 Therefore the midpoint operation will always be denoted by `|half(a+b)|'
2468 in this program. If \MP\ is being implemented with languages that permit
2469 binary shifting, the |half| macro should be changed to make this operation
2470 as efficient as possible.  Since some systems have shift operators that can
2471 only be trusted to work on positive numbers, there is also a macro |halfp|
2472 that is used only when the quantity being halved is known to be positive
2473 or zero.
2474
2475 @d half(A) ((A) / 2)
2476 @d halfp(A) (integer)((unsigned)(A) >> 1)
2477
2478 @ A single computation might use several subroutine calls, and it is
2479 desirable to avoid producing multiple error messages in case of arithmetic
2480 overflow. So the routines below set the global variable |arith_error| to |true|
2481 instead of reporting errors directly to the user.
2482 @^overflow in arithmetic@>
2483
2484 @<Glob...@>=
2485 boolean arith_error; /* has arithmetic overflow occurred recently? */
2486
2487 @ @<Allocate or ...@>=
2488 mp->arith_error=false;
2489
2490 @ At crucial points the program will say |check_arith|, to test if
2491 an arithmetic error has been detected.
2492
2493 @d check_arith { if ( mp->arith_error ) mp_clear_arith(mp); }
2494
2495 @c 
2496 static void mp_clear_arith (MP mp) { 
2497   print_err("Arithmetic overflow");
2498 @.Arithmetic overflow@>
2499   help4("Uh, oh. A little while ago one of the quantities that I was",
2500        "computing got too large, so I'm afraid your answers will be",
2501        "somewhat askew. You'll probably have to adopt different",
2502        "tactics next time. But I shall try to carry on anyway.");
2503   mp_error(mp); 
2504   mp->arith_error=false;
2505 }
2506
2507 @ Addition is not always checked to make sure that it doesn't overflow,
2508 but in places where overflow isn't too unlikely the |slow_add| routine
2509 is used.
2510
2511 @c static integer mp_slow_add (MP mp,integer x, integer y) { 
2512   if ( x>=0 )  {
2513     if ( y<=el_gordo-x ) { 
2514       return x+y;
2515     } else  { 
2516       mp->arith_error=true; 
2517           return el_gordo;
2518     }
2519   } else  if ( -y<=el_gordo+x ) {
2520     return x+y;
2521   } else { 
2522     mp->arith_error=true; 
2523         return -el_gordo;
2524   }
2525 }
2526
2527 @ Fixed-point arithmetic is done on {\sl scaled integers\/} that are multiples
2528 of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit
2529 positions from the right end of a binary computer word.
2530
2531 @d quarter_unit   040000 /* $2^{14}$, represents 0.250000 */
2532 @d half_unit   0100000 /* $2^{15}$, represents 0.50000 */
2533 @d three_quarter_unit   0140000 /* $3\cdot2^{14}$, represents 0.75000 */
2534 @d unity   0200000 /* $2^{16}$, represents 1.00000 */
2535 @d two   0400000 /* $2^{17}$, represents 2.00000 */
2536 @d three   0600000 /* $2^{17}+2^{16}$, represents 3.00000 */
2537
2538 @<Types...@>=
2539 typedef integer scaled; /* this type is used for scaled integers */
2540
2541 @ The following function is used to create a scaled integer from a given decimal
2542 fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
2543 given in |dig[i]|, and the calculation produces a correctly rounded result.
2544
2545 @c 
2546 static scaled mp_round_decimals (MP mp,quarterword k) {
2547   /* converts a decimal fraction */
2548  unsigned a = 0; /* the accumulator */
2549  while ( k-->0 ) { 
2550     a=(a+mp->dig[k]*two) / 10;
2551   }
2552   return (scaled)halfp(a+1);
2553 }
2554
2555 @ Conversely, here is a procedure analogous to |print_int|. If the output
2556 of this procedure is subsequently read by \MP\ and converted by the
2557 |round_decimals| routine above, it turns out that the original value will
2558 be reproduced exactly. A decimal point is printed only if the value is
2559 not an integer. If there is more than one way to print the result with
2560 the optimum number of digits following the decimal point, the closest
2561 possible value is given.
2562
2563 The invariant relation in the \&{repeat} loop is that a sequence of
2564 decimal digits yet to be printed will yield the original number if and only if
2565 they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
2566 We can stop if and only if $f=0$ satisfies this condition; the loop will
2567 terminate before $s$ can possibly become zero.
2568
2569 @<Basic printing...@>=
2570 void mp_print_scaled (MP mp,scaled s) { /* prints scaled real, rounded to five  digits */
2571   scaled delta; /* amount of allowable inaccuracy */
2572   if ( s<0 ) { 
2573         mp_print_char(mp, xord('-')); 
2574     negate(s); /* print the sign, if negative */
2575   }
2576   mp_print_int(mp, s / unity); /* print the integer part */
2577   s=10*(s % unity)+5;
2578   if ( s!=5 ) { 
2579     delta=10; 
2580     mp_print_char(mp, xord('.'));
2581     do {  
2582       if ( delta>unity )
2583         s=s+0100000-(delta / 2); /* round the final digit */
2584       mp_print_char(mp, xord('0'+(s / unity))); 
2585       s=10*(s % unity); 
2586       delta=delta*10;
2587     } while (s>delta);
2588   }
2589 }
2590
2591 @ We often want to print two scaled quantities in parentheses,
2592 separated by a comma.
2593
2594 @<Basic printing...@>=
2595 void mp_print_two (MP mp,scaled x, scaled y) { /* prints `|(x,y)|' */
2596   mp_print_char(mp, xord('(')); 
2597   mp_print_scaled(mp, x); 
2598   mp_print_char(mp, xord(',')); 
2599   mp_print_scaled(mp, y);
2600   mp_print_char(mp, xord(')'));
2601 }
2602
2603 @ The |scaled| quantities in \MP\ programs are generally supposed to be
2604 less than $2^{12}$ in absolute value, so \MP\ does much of its internal
2605 arithmetic with 28~significant bits of precision. A |fraction| denotes
2606 a scaled integer whose binary point is assumed to be 28 bit positions
2607 from the right.
2608
2609 @d fraction_half 01000000000 /* $2^{27}$, represents 0.50000000 */
2610 @d fraction_one 02000000000 /* $2^{28}$, represents 1.00000000 */
2611 @d fraction_two 04000000000 /* $2^{29}$, represents 2.00000000 */
2612 @d fraction_three 06000000000 /* $3\cdot2^{28}$, represents 3.00000000 */
2613 @d fraction_four 010000000000 /* $2^{30}$, represents 4.00000000 */
2614
2615 @<Types...@>=
2616 typedef integer fraction; /* this type is used for scaled fractions */
2617
2618 @ In fact, the two sorts of scaling discussed above aren't quite
2619 sufficient; \MP\ has yet another, used internally to keep track of angles
2620 in units of $2^{-20}$ degrees.
2621
2622 @d forty_five_deg 0264000000 /* $45\cdot2^{20}$, represents $45^\circ$ */
2623 @d ninety_deg 0550000000 /* $90\cdot2^{20}$, represents $90^\circ$ */
2624 @d one_eighty_deg 01320000000 /* $180\cdot2^{20}$, represents $180^\circ$ */
2625 @d three_sixty_deg 02640000000 /* $360\cdot2^{20}$, represents $360^\circ$ */
2626
2627 @<Types...@>=
2628 typedef integer angle; /* this type is used for scaled angles */
2629
2630 @ The |make_fraction| routine produces the |fraction| equivalent of
2631 |p/q|, given integers |p| and~|q|; it computes the integer
2632 $f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
2633 positive. If |p| and |q| are both of the same scaled type |t|,
2634 the ``type relation'' |make_fraction(t,t)=fraction| is valid;
2635 and it's also possible to use the subroutine ``backwards,'' using
2636 the relation |make_fraction(t,fraction)=t| between scaled types.
2637
2638 If the result would have magnitude $2^{31}$ or more, |make_fraction|
2639 sets |arith_error:=true|. Most of \MP's internal computations have
2640 been designed to avoid this sort of error.
2641
2642 If this subroutine were programmed in assembly language on a typical
2643 machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
2644 double-precision product can often be input to a fixed-point division
2645 instruction. But when we are restricted to int-eger arithmetic it
2646 is necessary either to resort to multiple-precision maneuvering
2647 or to use a simple but slow iteration. The multiple-precision technique
2648 would be about three times faster than the code adopted here, but it
2649 would be comparatively long and tricky, involving about sixteen
2650 additional multiplications and divisions.
2651
2652 This operation is part of \MP's ``inner loop''; indeed, it will
2653 consume nearly 10\pct! of the running time (exclusive of input and output)
2654 if the code below is left unchanged. A machine-dependent recoding
2655 will therefore make \MP\ run faster. The present implementation
2656 is highly portable, but slow; it avoids multiplication and division
2657 except in the initial stage. System wizards should be careful to
2658 replace it with a routine that is guaranteed to produce identical
2659 results in all cases.
2660 @^system dependencies@>
2661
2662 As noted below, a few more routines should also be replaced by machine-dependent
2663 code, for efficiency. But when a procedure is not part of the ``inner loop,''
2664 such changes aren't advisable; simplicity and robustness are
2665 preferable to trickery, unless the cost is too high.
2666 @^inner loop@>
2667
2668 @<Internal library declarations@>=
2669 integer mp_take_scaled (MP mp,integer q, scaled f) ;
2670
2671 @ @<Declarations@>=
2672 static fraction mp_make_fraction (MP mp,integer p, integer q);
2673
2674 @ If FIXPT is not defined, we need these preprocessor values
2675
2676 @d TWEXP31  2147483648.0
2677 @d TWEXP28  268435456.0
2678 @d TWEXP16 65536.0
2679 @d TWEXP_16 (1.0/65536.0)
2680 @d TWEXP_28 (1.0/268435456.0)
2681
2682
2683 @c 
2684 fraction mp_make_fraction (MP mp,integer p, integer q) {
2685   fraction i;
2686   if ( q==0 ) mp_confusion(mp, "/");
2687 @:this can't happen /}{\quad \./@>
2688 #ifdef FIXPT
2689 {
2690   integer f; /* the fraction bits, with a leading 1 bit */
2691   integer n; /* the integer part of $\vert p/q\vert$ */
2692   boolean negative = false; /* should the result be negated? */
2693   if ( p<0 ) {
2694     negate(p); negative=true;
2695   }
2696   if ( q<0 ) { 
2697     negate(q); negative = ! negative;
2698   }
2699   n=p / q; p=p % q;
2700   if ( n>=8 ){ 
2701     mp->arith_error=true;
2702     i= ( negative ? -el_gordo : el_gordo);
2703   } else { 
2704     n=(n-1)*fraction_one;
2705     @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>;
2706     i = (negative ? (-(f+n)) : (f+n));
2707   }
2708 }
2709 #else /* FIXPT */
2710   {
2711     register double d;
2712         d = TWEXP28 * (double)p /(double)q;
2713         if ((p^q) >= 0) {
2714                 d += 0.5;
2715                 if (d>=TWEXP31) {mp->arith_error=true; return el_gordo;}
2716                 i = (integer) d;
2717                 if (d==(double)i && ( ((q>0 ? -q : q)&077777)
2718                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2719         } else {
2720                 d -= 0.5;
2721                 if (d<= -TWEXP31) {mp->arith_error=true; return -el_gordo;}
2722                 i = (integer) d;
2723                 if (d==(double)i && ( ((q>0 ? q : -q)&077777)
2724                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2725         }
2726   }
2727 #endif /* FIXPT */
2728   return i;
2729 }
2730
2731 @ The |repeat| loop here preserves the following invariant relations
2732 between |f|, |p|, and~|q|:
2733 (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
2734 $p_0$ is the original value of~$p$.
2735
2736 Notice that the computation specifies
2737 |(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
2738 Let us hope that optimizing compilers do not miss this point; a
2739 special variable |be_careful| is used to emphasize the necessary
2740 order of computation. Optimizing compilers should keep |be_careful|
2741 in a register, not store it in memory.
2742 @^inner loop@>
2743
2744 @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>=
2745 {
2746   integer be_careful; /* disables certain compiler optimizations */
2747   f=1;
2748   do {  
2749     be_careful=p-q; p=be_careful+p;
2750     if ( p>=0 ) { 
2751       f=f+f+1;
2752     } else  { 
2753       f+=f; p=p+q;
2754     }
2755   } while (f<fraction_one);
2756   be_careful=p-q;
2757   if ( be_careful+p>=0 ) incr(f);
2758 }
2759
2760 @ The dual of |make_fraction| is |take_fraction|, which multiplies a
2761 given integer~|q| by a fraction~|f|. When the operands are positive, it
2762 computes $p=\lfloor qf/2^{28}+{1\over2}\rfloor$, a symmetric function
2763 of |q| and~|f|.
2764
2765 This routine is even more ``inner loopy'' than |make_fraction|;
2766 the present implementation consumes almost 20\pct! of \MP's computation
2767 time during typical jobs, so a machine-language substitute is advisable.
2768 @^inner loop@> @^system dependencies@>
2769
2770 @<Internal library declarations@>=
2771 integer mp_take_fraction (MP mp,integer q, fraction f) ;
2772
2773 @ @c 
2774 #ifdef FIXPT
2775 integer mp_take_fraction (MP mp,integer q, fraction f) {
2776   integer p; /* the fraction so far */
2777   boolean negative; /* should the result be negated? */
2778   integer n; /* additional multiple of $q$ */
2779   integer be_careful; /* disables certain compiler optimizations */
2780   @<Reduce to the case that |f>=0| and |q>=0|@>;
2781   if ( f<fraction_one ) { 
2782     n=0;
2783   } else { 
2784     n=f / fraction_one; f=f % fraction_one;
2785     if ( q<=el_gordo / n ) { 
2786       n=n*q ; 
2787     } else { 
2788       mp->arith_error=true; n=el_gordo;
2789     }
2790   }
2791   f=f+fraction_one;
2792   @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>;
2793   be_careful=n-el_gordo;
2794   if ( be_careful+p>0 ){ 
2795     mp->arith_error=true; n=el_gordo-p;
2796   }
2797   if ( negative ) 
2798         return (-(n+p));
2799   else 
2800     return (n+p);
2801 #else /* FIXPT */
2802 integer mp_take_fraction (MP mp,integer p, fraction q) {
2803     register double d;
2804         register integer i;
2805         d = (double)p * (double)q * TWEXP_28;
2806         if ((p^q) >= 0) {
2807                 d += 0.5;
2808                 if (d>=TWEXP31) {
2809                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2810                                 mp->arith_error = true;
2811                         return el_gordo;
2812                 }
2813                 i = (integer) d;
2814                 if (d==(double)i && (((p&077777)*(q&077777))&040000)!=0) --i;
2815         } else {
2816                 d -= 0.5;
2817                 if (d<= -TWEXP31) {
2818                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2819                                 mp->arith_error = true;
2820                         return -el_gordo;
2821                 }
2822                 i = (integer) d;
2823                 if (d==(double)i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2824         }
2825         return i;
2826 #endif /* FIXPT */
2827 }
2828
2829 @ @<Reduce to the case that |f>=0| and |q>=0|@>=
2830 if ( f>=0 ) {
2831   negative=false;
2832 } else { 
2833   negate( f); negative=true;
2834 }
2835 if ( q<0 ) { 
2836   negate(q); negative=! negative;
2837 }
2838
2839 @ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
2840 =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
2841 $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
2842 @^inner loop@>
2843
2844 @<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>=
2845 p=fraction_half; /* that's $2^{27}$; the invariants hold now with $k=28$ */
2846 if ( q<fraction_four ) {
2847   do {  
2848     if ( odd(f) ) p=halfp(p+q); else p=halfp(p);
2849     f=halfp(f);
2850   } while (f!=1);
2851 } else  {
2852   do {  
2853     if ( odd(f) ) p=p+halfp(q-p); else p=halfp(p);
2854     f=halfp(f);
2855   } while (f!=1);
2856 }
2857
2858
2859 @ When we want to multiply something by a |scaled| quantity, we use a scheme
2860 analogous to |take_fraction| but with a different scaling.
2861 Given positive operands, |take_scaled|
2862 computes the quantity $p=\lfloor qf/2^{16}+{1\over2}\rfloor$.
2863
2864 Once again it is a good idea to use a machine-language replacement if
2865 possible; otherwise |take_scaled| will use more than 2\pct! of the running time
2866 when the Computer Modern fonts are being generated.
2867 @^inner loop@>
2868
2869 @c 
2870 #ifdef FIXPT
2871 integer mp_take_scaled (MP mp,integer q, scaled f) {
2872   integer p; /* the fraction so far */
2873   boolean negative; /* should the result be negated? */
2874   integer n; /* additional multiple of $q$ */
2875   integer be_careful; /* disables certain compiler optimizations */
2876   @<Reduce to the case that |f>=0| and |q>=0|@>;
2877   if ( f<unity ) { 
2878     n=0;
2879   } else  { 
2880     n=f / unity; f=f % unity;
2881     if ( q<=el_gordo / n ) {
2882       n=n*q;
2883     } else  { 
2884       mp->arith_error=true; n=el_gordo;
2885     }
2886   }
2887   f=f+unity;
2888   @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>;
2889   be_careful=n-el_gordo;
2890   if ( be_careful+p>0 ) { 
2891     mp->arith_error=true; n=el_gordo-p;
2892   }
2893   return ( negative ?(-(n+p)) :(n+p));
2894 #else /* FIXPT */
2895 integer mp_take_scaled (MP mp,integer p, scaled q) {
2896     register double d;
2897         register integer i;
2898         d = (double)p * (double)q * TWEXP_16;
2899         if ((p^q) >= 0) {
2900                 d += 0.5;
2901                 if (d>=TWEXP31) {
2902                         if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
2903                                 mp->arith_error = true;
2904                         return el_gordo;
2905                 }
2906                 i = (integer) d;
2907                 if (d==(double)i && (((p&077777)*(q&077777))&040000)!=0) --i;
2908         } else {
2909                 d -= 0.5;
2910                 if (d<= -TWEXP31) {
2911                         if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
2912                                 mp->arith_error = true;
2913                         return -el_gordo;
2914                 }
2915                 i = (integer) d;
2916                 if (d==(double)i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
2917         }
2918         return i;
2919 #endif /* FIXPT */
2920 }
2921
2922 @ @<Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$@>=
2923 p=half_unit; /* that's $2^{15}$; the invariants hold now with $k=16$ */
2924 @^inner loop@>
2925 if ( q<fraction_four ) {
2926   do {  
2927     p = (odd(f) ? halfp(p+q) : halfp(p));
2928     f=halfp(f);
2929   } while (f!=1);
2930 } else {
2931   do {  
2932     p = (odd(f) ? p+halfp(q-p) : halfp(p));
2933     f=halfp(f);
2934   } while (f!=1);
2935 }
2936
2937 @ For completeness, there's also |make_scaled|, which computes a
2938 quotient as a |scaled| number instead of as a |fraction|.
2939 In other words, the result is $\lfloor2^{16}p/q+{1\over2}\rfloor$, if the
2940 operands are positive. \ (This procedure is not used especially often,
2941 so it is not part of \MP's inner loop.)
2942
2943 @<Internal library ...@>=
2944 scaled mp_make_scaled (MP mp,integer p, integer q) ;
2945
2946 @ @c 
2947 scaled mp_make_scaled (MP mp,integer p, integer q) {
2948   register integer i;
2949   if ( q==0 ) mp_confusion(mp, "/");
2950 @:this can't happen /}{\quad \./@>
2951   {
2952 #ifdef FIXPT 
2953     integer f; /* the fraction bits, with a leading 1 bit */
2954     integer n; /* the integer part of $\vert p/q\vert$ */
2955     boolean negative; /* should the result be negated? */
2956     integer be_careful; /* disables certain compiler optimizations */
2957     if ( p>=0 ) negative=false;
2958     else  { negate(p); negative=true; };
2959     if ( q<0 ) { 
2960       negate(q); negative=! negative;
2961     }
2962     n=p / q; p=p % q;
2963     if ( n>=0100000 ) { 
2964       mp->arith_error=true;
2965       return (negative ? (-el_gordo) : el_gordo);
2966     } else  { 
2967       n=(n-1)*unity;
2968       @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>;
2969       i = (negative ? (-(f+n)) :(f+n));
2970     }
2971 #else /* FIXPT */
2972     register double d;
2973         d = TWEXP16 * (double)p /(double)q;
2974         if ((p^q) >= 0) {
2975                 d += 0.5;
2976                 if (d>=TWEXP31) {mp->arith_error=true; return el_gordo;}
2977                 i = (integer) d;
2978                 if (d==(double)i && ( ((q>0 ? -q : q)&077777)
2979                                 * (((i&037777)<<1)-1) & 04000)!=0) --i;
2980         } else {
2981                 d -= 0.5;
2982                 if (d<= -TWEXP31) {mp->arith_error=true; return -el_gordo;}
2983                 i = (integer) d;
2984                 if (d==(double)i && ( ((q>0 ? q : -q)&077777)
2985                                 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
2986         }
2987 #endif /* FIXPT */
2988   }
2989   return i;
2990 }
2991
2992 @ @<Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$@>=
2993 f=1;
2994 do {  
2995   be_careful=p-q; p=be_careful+p;
2996   if ( p>=0 ) f=f+f+1;
2997   else  { f+=f; p=p+q; };
2998 } while (f<unity);
2999 be_careful=p-q;
3000 if ( be_careful+p>=0 ) incr(f)
3001
3002 @ Here is a typical example of how the routines above can be used.
3003 It computes the function
3004 $${1\over3\tau}f(\theta,\phi)=
3005 {\tau^{-1}\bigl(2+\sqrt2\,(\sin\theta-{1\over16}\sin\phi)
3006  (\sin\phi-{1\over16}\sin\theta)(\cos\theta-\cos\phi)\bigr)\over
3007 3\,\bigl(1+{1\over2}(\sqrt5-1)\cos\theta+{1\over2}(3-\sqrt5\,)\cos\phi\bigr)},$$
3008 where $\tau$ is a |scaled| ``tension'' parameter. This is \MP's magic
3009 fudge factor for placing the first control point of a curve that starts
3010 at an angle $\theta$ and ends at an angle $\phi$ from the straight path.
3011 (Actually, if the stated quantity exceeds 4, \MP\ reduces it to~4.)
3012
3013 The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$.
3014 (It's a sum of eight terms whose absolute values can be bounded using
3015 relations such as $\sin\theta\cos\theta\L{1\over2}$.) Thus the numerator
3016 is positive; and since the tension $\tau$ is constrained to be at least
3017 $3\over4$, the numerator is less than $16\over3$. The denominator is
3018 nonnegative and at most~6.  Hence the fixed-point calculations below
3019 are guaranteed to stay within the bounds of a 32-bit computer word.
3020
3021 The angles $\theta$ and $\phi$ are given implicitly in terms of |fraction|
3022 arguments |st|, |ct|, |sf|, and |cf|, representing $\sin\theta$, $\cos\theta$,
3023 $\sin\phi$, and $\cos\phi$, respectively.
3024
3025 @c 
3026 static fraction mp_velocity (MP mp,fraction st, fraction ct, fraction sf,
3027                       fraction cf, scaled t) {
3028   integer acc,num,denom; /* registers for intermediate calculations */
3029   acc=mp_take_fraction(mp, st-(sf / 16), sf-(st / 16));
3030   acc=mp_take_fraction(mp, acc,ct-cf);
3031   num=fraction_two+mp_take_fraction(mp, acc,379625062);
3032                    /* $2^{28}\sqrt2\approx379625062.497$ */
3033   denom=fraction_three+mp_take_fraction(mp, ct,497706707)+mp_take_fraction(mp, cf,307599661);
3034                       /* $3\cdot2^{27}\cdot(\sqrt5-1)\approx497706706.78$ and
3035                          $3\cdot2^{27}\cdot(3-\sqrt5\,)\approx307599661.22$ */
3036   if ( t!=unity ) num=mp_make_scaled(mp, num,t);
3037   /* |make_scaled(fraction,scaled)=fraction| */
3038   if ( num / 4>=denom ) 
3039     return fraction_four;
3040   else 
3041     return mp_make_fraction(mp, num, denom);
3042 }
3043
3044 @ The following somewhat different subroutine tests rigorously if $ab$ is
3045 greater than, equal to, or less than~$cd$,
3046 given integers $(a,b,c,d)$. In most cases a quick decision is reached.
3047 The result is $+1$, 0, or~$-1$ in the three respective cases.
3048
3049 @d mp_ab_vs_cd(M,A,B,C,D) mp_do_ab_vs_cd(A,B,C,D)
3050
3051 @c 
3052 static integer mp_do_ab_vs_cd (integer a,integer b, integer c, integer d) {
3053   integer q,r; /* temporary registers */
3054   @<Reduce to the case that |a,c>=0|, |b,d>0|@>;
3055   while (1) { 
3056     q = a / d; r = c / b;
3057     if ( q!=r )
3058       return ( q>r ? 1 : -1);
3059     q = a % d; r = c % b;
3060     if ( r==0 )
3061       return (q ? 1 : 0);
3062     if ( q==0 ) return -1;
3063     a=b; b=q; c=d; d=r;
3064   } /* now |a>d>0| and |c>b>0| */
3065 }
3066
3067 @ @<Reduce to the case that |a...@>=
3068 if ( a<0 ) { negate(a); negate(b);  };
3069 if ( c<0 ) { negate(c); negate(d);  };
3070 if ( d<=0 ) { 
3071   if ( b>=0 ) {
3072     if ( (a==0||b==0)&&(c==0||d==0) ) return 0;
3073     else return 1;
3074   }
3075   if ( d==0 )
3076     return ( a==0 ? 0 : -1);
3077   q=a; a=c; c=q; q=-b; b=-d; d=q;
3078 } else if ( b<=0 ) { 
3079   if ( b<0 ) if ( a>0 ) return -1;
3080   return (c==0 ? 0 : -1);
3081 }
3082
3083 @ We conclude this set of elementary routines with some simple rounding
3084 and truncation operations.
3085
3086 @<Internal library declarations@>=
3087 #define mp_floor_scaled(M,i) ((i)&(-65536))
3088 #define mp_round_unscaled(M,i) (((i/32768)+1)/2)
3089 #define mp_round_fraction(M,i) (((i/2048)+1)/2)
3090
3091
3092 @* \[8] Algebraic and transcendental functions.
3093 \MP\ computes all of the necessary special functions from scratch, without
3094 relying on |real| arithmetic or system subroutines for sines, cosines, etc.
3095
3096 @ To get the square root of a |scaled| number |x|, we want to calculate
3097 $s=\lfloor 2^8\!\sqrt x +{1\over2}\rfloor$. If $x>0$, this is the unique
3098 integer such that $2^{16}x-s\L s^2<2^{16}x+s$. The following subroutine
3099 determines $s$ by an iterative method that maintains the invariant
3100 relations $x=2^{46-2k}x_0\bmod 2^{30}$, $0<y=\lfloor 2^{16-2k}x_0\rfloor
3101 -s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$
3102 might, however, be zero at the start of the first iteration.
3103
3104 @<Declarations@>=
3105 static scaled mp_square_rt (MP mp,scaled x) ;
3106
3107 @ @c 
3108 scaled mp_square_rt (MP mp,scaled x) {
3109   quarterword k; /* iteration control counter */
3110   integer y; /* register for intermediate calculations */
3111   unsigned q; /* register for intermediate calculations */
3112   if ( x<=0 ) { 
3113     @<Handle square root of zero or negative argument@>;
3114   } else { 
3115     k=23; q=2;
3116     while ( x<fraction_two ) { /* i.e., |while x<@t$2^{29}$@>|\unskip */
3117       decr(k); x=x+x+x+x;
3118     }
3119     if ( x<fraction_four ) y=0;
3120     else  { x=x-fraction_four; y=1; };
3121     do {  
3122       @<Decrease |k| by 1, maintaining the invariant
3123       relations between |x|, |y|, and~|q|@>;
3124     } while (k!=0);
3125     return (scaled)(halfp(q));
3126   }
3127 }
3128
3129 @ @<Handle square root of zero...@>=
3130
3131   if ( x<0 ) { 
3132     print_err("Square root of ");
3133 @.Square root...replaced by 0@>
3134     mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3135     help2("Since I don't take square roots of negative numbers,",
3136           "I'm zeroing this one. Proceed, with fingers crossed.");
3137     mp_error(mp);
3138   };
3139   return 0;
3140 }
3141
3142 @ @<Decrease |k| by 1, maintaining...@>=
3143 x+=x; y+=y;
3144 if ( x>=fraction_four ) { /* note that |fraction_four=@t$2^{30}$@>| */
3145   x=x-fraction_four; incr(y);
3146 };
3147 x+=x; y=y+y-q; q+=q;
3148 if ( x>=fraction_four ) { x=x-fraction_four; incr(y); };
3149 if ( y>(int)q ){ y=y-q; q=q+2; }
3150 else if ( y<=0 )  { q=q-2; y=y+q;  };
3151 decr(k)
3152
3153 @ Pythagorean addition $\psqrt{a^2+b^2}$ is implemented by an elegant
3154 iterative scheme due to Cleve Moler and Donald Morrison [{\sl IBM Journal
3155 @^Moler, Cleve Barry@>
3156 @^Morrison, Donald Ross@>
3157 of Research and Development\/ \bf27} (1983), 577--581]. It modifies |a| and~|b|
3158 in such a way that their Pythagorean sum remains invariant, while the
3159 smaller argument decreases.
3160
3161 @<Internal library ...@>=
3162 integer mp_pyth_add (MP mp,integer a, integer b);
3163
3164
3165 @ @c 
3166 integer mp_pyth_add (MP mp,integer a, integer b) {
3167   fraction r; /* register used to transform |a| and |b| */
3168   boolean big; /* is the result dangerously near $2^{31}$? */
3169   a=abs(a); b=abs(b);
3170   if ( a<b ) { r=b; b=a; a=r; }; /* now |0<=b<=a| */
3171   if ( b>0 ) {
3172     if ( a<fraction_two ) {
3173       big=false;
3174     } else { 
3175       a=a / 4; b=b / 4; big=true;
3176     }; /* we reduced the precision to avoid arithmetic overflow */
3177     @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>;
3178     if ( big ) {
3179       if ( a<fraction_two ) {
3180         a=a+a+a+a;
3181       } else  { 
3182         mp->arith_error=true; a=el_gordo;
3183       };
3184     }
3185   }
3186   return a;
3187 }
3188
3189 @ The key idea here is to reflect the vector $(a,b)$ about the
3190 line through $(a,b/2)$.
3191
3192 @<Replace |a| by an approximation to $\psqrt{a^2+b^2}$@>=
3193 while (1) {  
3194   r=mp_make_fraction(mp, b,a);
3195   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3196   if ( r==0 ) break;
3197   r=mp_make_fraction(mp, r,fraction_four+r);
3198   a=a+mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3199 }
3200
3201
3202 @ Here is a similar algorithm for $\psqrt{a^2-b^2}$.
3203 It converges slowly when $b$ is near $a$, but otherwise it works fine.
3204
3205 @c 
3206 static integer mp_pyth_sub (MP mp,integer a, integer b) {
3207   fraction r; /* register used to transform |a| and |b| */
3208   boolean big; /* is the input dangerously near $2^{31}$? */
3209   a=abs(a); b=abs(b);
3210   if ( a<=b ) {
3211     @<Handle erroneous |pyth_sub| and set |a:=0|@>;
3212   } else { 
3213     if ( a<fraction_four ) {
3214       big=false;
3215     } else  { 
3216       a=(integer)halfp(a); b=(integer)halfp(b); big=true;
3217     }
3218     @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>;
3219     if ( big ) double(a);
3220   }
3221   return a;
3222 }
3223
3224 @ @<Replace |a| by an approximation to $\psqrt{a^2-b^2}$@>=
3225 while (1) { 
3226   r=mp_make_fraction(mp, b,a);
3227   r=mp_take_fraction(mp, r,r); /* now $r\approx b^2/a^2$ */
3228   if ( r==0 ) break;
3229   r=mp_make_fraction(mp, r,fraction_four-r);
3230   a=a-mp_take_fraction(mp, a+a,r); b=mp_take_fraction(mp, b,r);
3231 }
3232
3233 @ @<Handle erroneous |pyth_sub| and set |a:=0|@>=
3234
3235   if ( a<b ){ 
3236     print_err("Pythagorean subtraction "); mp_print_scaled(mp, a);
3237     mp_print(mp, "+-+"); mp_print_scaled(mp, b); 
3238     mp_print(mp, " has been replaced by 0");
3239 @.Pythagorean...@>
3240     help2("Since I don't take square roots of negative numbers,",
3241           "I'm zeroing this one. Proceed, with fingers crossed.");
3242     mp_error(mp);
3243   }
3244   a=0;
3245 }
3246
3247 @ The subroutines for logarithm and exponential involve two tables.
3248 The first is simple: |two_to_the[k]| equals $2^k$. The second involves
3249 a bit more calculation, which the author claims to have done correctly:
3250 |spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
3251 2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
3252 nearest integer.
3253
3254 @d two_to_the(A) (1<<(unsigned)(A))
3255
3256 @<Declarations@>=
3257 static const integer spec_log[29] = { 0, /* special logarithms */
3258 93032640, 38612034, 17922280, 8662214, 4261238, 2113709,
3259 1052693, 525315, 262400, 131136, 65552, 32772, 16385,
3260 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 1 };
3261
3262 @ @<Local variables for initialization@>=
3263 integer k; /* all-purpose loop index */
3264
3265
3266 @ Here is the routine that calculates $2^8$ times the natural logarithm
3267 of a |scaled| quantity; it is an integer approximation to $2^{24}\ln(x/2^{16})$,
3268 when |x| is a given positive integer.
3269
3270 The method is based on exercise 1.2.2--25 in {\sl The Art of Computer
3271 Programming\/}: During the main iteration we have $1\L 2^{-30}x<1/(1-2^{1-k})$,
3272 and the logarithm of $2^{30}x$ remains to be added to an accumulator
3273 register called~$y$. Three auxiliary bits of accuracy are retained in~$y$
3274 during the calculation, and sixteen auxiliary bits to extend |y| are
3275 kept in~|z| during the initial argument reduction. (We add
3276 $100\cdot2^{16}=6553600$ to~|z| and subtract 100 from~|y| so that |z| will
3277 not become negative; also, the actual amount subtracted from~|y| is~96,
3278 not~100, because we want to add~4 for rounding before the final division by~8.)
3279
3280 @c 
3281 static scaled mp_m_log (MP mp,scaled x) {
3282   integer y,z; /* auxiliary registers */
3283   integer k; /* iteration counter */
3284   if ( x<=0 ) {
3285      @<Handle non-positive logarithm@>;
3286   } else  { 
3287     y=1302456956+4-100; /* $14\times2^{27}\ln2\approx1302456956.421063$ */
3288     z=27595+6553600; /* and $2^{16}\times .421063\approx 27595$ */
3289     while ( x<fraction_four ) {
3290        double(x); y-=93032639; z-=48782;
3291     } /* $2^{27}\ln2\approx 93032639.74436163$ and $2^{16}\times.74436163\approx 48782$ */
3292     y=y+(z / unity); k=2;
3293     while ( x>fraction_four+4 ) {
3294       @<Increase |k| until |x| can be multiplied by a
3295         factor of $2^{-k}$, and adjust $y$ accordingly@>;
3296     }
3297     return (y / 8);
3298   }
3299 }
3300
3301 @ @<Increase |k| until |x| can...@>=
3302
3303   z=((x-1) / two_to_the(k))+1; /* $z=\lceil x/2^k\rceil$ */
3304   while ( x<fraction_four+z ) { z=halfp(z+1); incr(k); };
3305   y+=spec_log[k]; x-=z;
3306 }
3307
3308 @ @<Handle non-positive logarithm@>=
3309
3310   print_err("Logarithm of ");
3311 @.Logarithm...replaced by 0@>
3312   mp_print_scaled(mp, x); mp_print(mp, " has been replaced by 0");
3313   help2("Since I don't take logs of non-positive numbers,",
3314         "I'm zeroing this one. Proceed, with fingers crossed.");
3315   mp_error(mp); 
3316   return 0;
3317 }
3318
3319 @ Conversely, the exponential routine calculates $\exp(x/2^8)$,
3320 when |x| is |scaled|. The result is an integer approximation to
3321 $2^{16}\exp(x/2^{24})$, when |x| is regarded as an integer.
3322
3323 @c 
3324 static scaled mp_m_exp (MP mp,scaled x) {
3325   quarterword k; /* loop control index */
3326   integer y,z; /* auxiliary registers */
3327   if ( x>174436200 ) {
3328     /* $2^{24}\ln((2^{31}-1)/2^{16})\approx 174436199.51$ */
3329     mp->arith_error=true; 
3330     return el_gordo;
3331   } else if ( x<-197694359 ) {
3332         /* $2^{24}\ln(2^{-1}/2^{16})\approx-197694359.45$ */
3333     return 0;
3334   } else { 
3335     if ( x<=0 ) { 
3336        z=-8*x; y=04000000; /* $y=2^{20}$ */
3337     } else { 
3338       if ( x<=127919879 ) { 
3339         z=1023359037-8*x;
3340         /* $2^{27}\ln((2^{31}-1)/2^{20})\approx 1023359037.125$ */
3341       } else {
3342        z=8*(174436200-x); /* |z| is always nonnegative */
3343       }
3344       y=el_gordo;
3345     };
3346     @<Multiply |y| by $\exp(-z/2^{27})$@>;
3347     if ( x<=127919879 ) 
3348        return ((y+8) / 16);
3349      else 
3350        return y;
3351   }
3352 }
3353
3354 @ The idea here is that subtracting |spec_log[k]| from |z| corresponds
3355 to multiplying |y| by $1-2^{-k}$.
3356
3357 A subtle point (which had to be checked) was that if $x=127919879$, the
3358 value of~|y| will decrease so that |y+8| doesn't overflow. In fact,
3359 $z$ will be 5 in this case, and |y| will decrease by~64 when |k=25|
3360 and by~16 when |k=27|.
3361
3362 @<Multiply |y| by...@>=
3363 k=1;
3364 while ( z>0 ) { 
3365   while ( z>=spec_log[k] ) { 
3366     z-=spec_log[k];
3367     y=y-1-((y-two_to_the(k-1)) / two_to_the(k));
3368   }
3369   incr(k);
3370 }
3371
3372 @ The trigonometric subroutines use an auxiliary table such that
3373 |spec_atan[k]| contains an approximation to the |angle| whose tangent
3374 is~$1/2^k$. $\arctan2^{-k}$ times $2^{20}\cdot180/\pi$ 
3375
3376 @<Declarations@>=
3377 static const angle spec_atan[27] = { 0, 27855475, 14718068, 7471121, 3750058, 
3378 1876857, 938658, 469357, 234682, 117342, 58671, 29335, 14668, 7334, 3667, 
3379 1833, 917, 458, 229, 115, 57, 29, 14, 7, 4, 2, 1 };
3380
3381 @ Given integers |x| and |y|, not both zero, the |n_arg| function
3382 returns the |angle| whose tangent points in the direction $(x,y)$.
3383 This subroutine first determines the correct octant, then solves the
3384 problem for |0<=y<=x|, then converts the result appropriately to
3385 return an answer in the range |-one_eighty_deg<=@t$\theta$@><=one_eighty_deg|.
3386 (The answer is |+one_eighty_deg| if |y=0| and |x<0|, but an answer of
3387 |-one_eighty_deg| is possible if, for example, |y=-1| and $x=-2^{30}$.)
3388
3389 The octants are represented in a ``Gray code,'' since that turns out
3390 to be computationally simplest.
3391
3392 @d negate_x 1
3393 @d negate_y 2
3394 @d switch_x_and_y 4
3395 @d first_octant 1
3396 @d second_octant (first_octant+switch_x_and_y)
3397 @d third_octant (first_octant+switch_x_and_y+negate_x)
3398 @d fourth_octant (first_octant+negate_x)
3399 @d fifth_octant (first_octant+negate_x+negate_y)
3400 @d sixth_octant (first_octant+switch_x_and_y+negate_x+negate_y)
3401 @d seventh_octant (first_octant+switch_x_and_y+negate_y)
3402 @d eighth_octant (first_octant+negate_y)
3403
3404 @c 
3405 static angle mp_n_arg (MP mp,integer x, integer y) {
3406   angle z; /* auxiliary register */
3407   integer t; /* temporary storage */
3408   quarterword k; /* loop counter */
3409   int octant; /* octant code */
3410   if ( x>=0 ) {
3411     octant=first_octant;
3412   } else { 
3413     negate(x); octant=first_octant+negate_x;
3414   }
3415   if ( y<0 ) { 
3416     negate(y); octant=octant+negate_y;
3417   }
3418   if ( x<y ) { 
3419     t=y; y=x; x=t; octant=octant+switch_x_and_y;
3420   }
3421   if ( x==0 ) { 
3422     @<Handle undefined arg@>; 
3423   } else { 
3424     @<Set variable |z| to the arg of $(x,y)$@>;
3425     @<Return an appropriate answer based on |z| and |octant|@>;
3426   }
3427 }
3428
3429 @ @<Handle undefined arg@>=
3430
3431   print_err("angle(0,0) is taken as zero");
3432 @.angle(0,0)...zero@>
3433   help2("The `angle' between two identical points is undefined.",
3434         "I'm zeroing this one. Proceed, with fingers crossed.");
3435   mp_error(mp); 
3436   return 0;
3437 }
3438
3439 @ @<Return an appropriate answer...@>=
3440 switch (octant) {
3441 case first_octant: return z;
3442 case second_octant: return (ninety_deg-z);
3443 case third_octant: return (ninety_deg+z);
3444 case fourth_octant: return (one_eighty_deg-z);
3445 case fifth_octant: return (z-one_eighty_deg);
3446 case sixth_octant: return (-z-ninety_deg);
3447 case seventh_octant: return (z-ninety_deg);
3448 case eighth_octant: return (-z);
3449 }; /* there are no other cases */
3450 return 0
3451
3452 @ At this point we have |x>=y>=0|, and |x>0|. The numbers are scaled up
3453 or down until $2^{28}\L x<2^{29}$, so that accurate fixed-point calculations
3454 will be made.
3455
3456 @<Set variable |z| to the arg...@>=
3457 while ( x>=fraction_two ) { 
3458   x=halfp(x); y=halfp(y);
3459 }
3460 z=0;
3461 if ( y>0 ) { 
3462  while ( x<fraction_one ) { 
3463     x+=x; y+=y; 
3464  };
3465  @<Increase |z| to the arg of $(x,y)$@>;
3466 }
3467
3468 @ During the calculations of this section, variables |x| and~|y|
3469 represent actual coordinates $(x,2^{-k}y)$. We will maintain the
3470 condition |x>=y|, so that the tangent will be at most $2^{-k}$.
3471 If $x<2y$, the tangent is greater than $2^{-k-1}$. The transformation
3472 $(a,b)\mapsto(a+b\tan\phi,b-a\tan\phi)$ replaces $(a,b)$ by
3473 coordinates whose angle has decreased by~$\phi$; in the special case
3474 $a=x$, $b=2^{-k}y$, and $\tan\phi=2^{-k-1}$, this operation reduces
3475 to the particularly simple iteration shown here. [Cf.~John E. Meggitt,
3476 @^Meggitt, John E.@>
3477 {\sl IBM Journal of Research and Development\/ \bf6} (1962), 210--226.]
3478
3479 The initial value of |x| will be multiplied by at most
3480 $(1+{1\over2})(1+{1\over8})(1+{1\over32})\cdots\approx 1.7584$; hence
3481 there is no chance of integer overflow.
3482
3483 @<Increase |z|...@>=
3484 k=0;
3485 do {  
3486   y+=y; incr(k);
3487   if ( y>x ){ 
3488     z=z+spec_atan[k]; t=x; x=x+(y / two_to_the(k+k)); y=y-t;
3489   };
3490 } while (k!=15);
3491 do {  
3492   y+=y; incr(k);
3493   if ( y>x ) { z=z+spec_atan[k]; y=y-x; };
3494 } while (k!=26)
3495
3496 @ Conversely, the |n_sin_cos| routine takes an |angle| and produces the sine
3497 and cosine of that angle. The results of this routine are
3498 stored in global integer variables |n_sin| and |n_cos|.
3499
3500 @<Glob...@>=
3501 fraction n_sin;fraction n_cos; /* results computed by |n_sin_cos| */
3502
3503 @ Given an integer |z| that is $2^{20}$ times an angle $\theta$ in degrees,
3504 the purpose of |n_sin_cos(z)| is to set
3505 |x=@t$r\cos\theta$@>| and |y=@t$r\sin\theta$@>| (approximately),
3506 for some rather large number~|r|. The maximum of |x| and |y|
3507 will be between $2^{28}$ and $2^{30}$, so that there will be hardly
3508 any loss of accuracy. Then |x| and~|y| are divided by~|r|.
3509
3510 @c 
3511 static void mp_n_sin_cos (MP mp,angle z) { /* computes a multiple of the sine
3512                                        and cosine */ 
3513   quarterword k; /* loop control variable */
3514   int q; /* specifies the quadrant */
3515   fraction r; /* magnitude of |(x,y)| */
3516   integer x,y,t; /* temporary registers */
3517   while ( z<0 ) z=z+three_sixty_deg;
3518   z=z % three_sixty_deg; /* now |0<=z<three_sixty_deg| */
3519   q=z / forty_five_deg; z=z % forty_five_deg;
3520   x=fraction_one; y=x;
3521   if ( ! odd(q) ) z=forty_five_deg-z;
3522   @<Subtract angle |z| from |(x,y)|@>;
3523   @<Convert |(x,y)| to the octant determined by~|q|@>;
3524   r=mp_pyth_add(mp, x,y); 
3525   mp->n_cos=mp_make_fraction(mp, x,r); 
3526   mp->n_sin=mp_make_fraction(mp, y,r);
3527 }
3528
3529 @ In this case the octants are numbered sequentially.
3530
3531 @<Convert |(x,...@>=
3532 switch (q) {
3533 case 0: break;
3534 case 1: t=x; x=y; y=t; break;
3535 case 2: t=x; x=-y; y=t; break;
3536 case 3: negate(x); break;
3537 case 4: negate(x); negate(y); break;
3538 case 5: t=x; x=-y; y=-t; break;
3539 case 6: t=x; x=y; y=-t; break;
3540 case 7: negate(y); break;
3541 } /* there are no other cases */
3542
3543 @ The main iteration of |n_sin_cos| is similar to that of |n_arg| but
3544 applied in reverse. The values of |spec_atan[k]| decrease slowly enough
3545 that this loop is guaranteed to terminate before the (nonexistent) value
3546 |spec_atan[27]| would be required.
3547
3548 @<Subtract angle |z|...@>=
3549 k=1;
3550 while ( z>0 ){ 
3551   if ( z>=spec_atan[k] ) { 
3552     z=z-spec_atan[k]; t=x;
3553     x=t+y / two_to_the(k);
3554     y=y-t / two_to_the(k);
3555   }
3556   incr(k);
3557 }
3558 if ( y<0 ) y=0 /* this precaution may never be needed */
3559
3560 @ And now let's complete our collection of numeric utility routines
3561 by considering random number generation.
3562 \MP\ generates pseudo-random numbers with the additive scheme recommended
3563 in Section 3.6 of {\sl The Art of Computer Programming}; however, the
3564 results are random fractions between 0 and |fraction_one-1|, inclusive.
3565
3566 There's an auxiliary array |randoms| that contains 55 pseudo-random
3567 fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
3568 we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
3569 The global variable |j_random| tells which element has most recently
3570 been consumed.
3571 The global variable |random_seed| was introduced in version 0.9,
3572 for the sole reason of stressing the fact that the initial value of the
3573 random seed is system-dependant. The initialization code below will initialize
3574 this variable to |(internal[mp_time] div unity)+internal[mp_day]|, but this 
3575 is not good enough on modern fast machines that are capable of running
3576 multiple MetaPost processes within the same second.
3577 @^system dependencies@>
3578
3579 @<Glob...@>=
3580 fraction randoms[55]; /* the last 55 random values generated */
3581 int j_random; /* the number of unused |randoms| */
3582
3583 @ @<Option variables@>=
3584 int random_seed; /* the default random seed */
3585
3586 @ @<Allocate or initialize ...@>=
3587 mp->random_seed = (scaled)opt->random_seed;
3588
3589 @ To consume a random fraction, the program below will say `|next_random|'
3590 and then it will fetch |randoms[j_random]|.
3591
3592 @d next_random { if ( mp->j_random==0 ) mp_new_randoms(mp);
3593   else decr(mp->j_random); }
3594
3595 @c 
3596 static void mp_new_randoms (MP mp) {
3597   int k; /* index into |randoms| */
3598   fraction x; /* accumulator */
3599   for (k=0;k<=23;k++) { 
3600    x=mp->randoms[k]-mp->randoms[k+31];
3601     if ( x<0 ) x=x+fraction_one;
3602     mp->randoms[k]=x;
3603   }
3604   for (k=24;k<= 54;k++){ 
3605     x=mp->randoms[k]-mp->randoms[k-24];
3606     if ( x<0 ) x=x+fraction_one;
3607     mp->randoms[k]=x;
3608   }
3609   mp->j_random=54;
3610 }
3611
3612 @ @<Declarations@>=
3613 static void mp_init_randoms (MP mp,scaled seed);
3614
3615 @ To initialize the |randoms| table, we call the following routine.
3616
3617 @c 
3618 void mp_init_randoms (MP mp,scaled seed) {
3619   fraction j,jj,k; /* more or less random integers */
3620   int i; /* index into |randoms| */
3621   j=abs(seed);
3622   while ( j>=fraction_one ) j=halfp(j);
3623   k=1;
3624   for (i=0;i<=54;i++ ){ 
3625     jj=k; k=j-k; j=jj;
3626     if ( k<0 ) k=k+fraction_one;
3627     mp->randoms[(i*21)% 55]=j;
3628   }
3629   mp_new_randoms(mp); 
3630   mp_new_randoms(mp); 
3631   mp_new_randoms(mp); /* ``warm up'' the array */
3632 }
3633
3634 @ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
3635 or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
3636
3637 Note that the call of |take_fraction| will produce the values 0 and~|x|
3638 with about half the probability that it will produce any other particular
3639 values between 0 and~|x|, because it rounds its answers.
3640
3641 @c 
3642 static scaled mp_unif_rand (MP mp,scaled x) {
3643   scaled y; /* trial value */
3644   next_random; y=mp_take_fraction(mp, abs(x),mp->randoms[mp->j_random]);
3645   if ( y==abs(x) ) return 0;
3646   else if ( x>0 ) return y;
3647   else return (-y);
3648 }
3649
3650 @ Finally, a normal deviate with mean zero and unit standard deviation
3651 can readily be obtained with the ratio method (Algorithm 3.4.1R in
3652 {\sl The Art of Computer Programming\/}).
3653
3654 @c 
3655 static scaled mp_norm_rand (MP mp) {
3656   integer x,u,l; /* what the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$ */
3657   do { 
3658     do {  
3659       next_random;
3660       x=mp_take_fraction(mp, 112429,mp->randoms[mp->j_random]-fraction_half);
3661       /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */
3662       next_random; u=mp->randoms[mp->j_random];
3663     } while (abs(x)>=u);
3664     x=mp_make_fraction(mp, x,u);
3665     l=139548960-mp_m_log(mp, u); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */
3666   } while (mp_ab_vs_cd(mp, 1024,l,x,x)<0);
3667   return x;
3668 }
3669
3670 @* \[9] Packed data.
3671 In order to make efficient use of storage space, \MP\ bases its major data
3672 structures on a |memory_word|, which contains either a (signed) integer,
3673 possibly scaled, or a small number of fields that are one half or one
3674 quarter of the size used for storing integers.
3675
3676 If |x| is a variable of type |memory_word|, it contains up to four
3677 fields that can be referred to as follows:
3678 $$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr
3679 |x|&.|int|&(an |integer|)\cr
3680 |x|&.|sc|\qquad&(a |scaled| integer)\cr
3681 |x.hh.lh|, |x.hh|&.|rh|&(two halfword fields)\cr
3682 |x.hh.b0|, |x.hh.b1|, |x.hh|&.|rh|&(two quarterword fields, one halfword
3683   field)\cr
3684 |x.qqqq.b0|, |x.qqqq.b1|, |x.qqqq|&.|b2|, |x.qqqq.b3|\hskip-100pt
3685   &\qquad\qquad\qquad(four quarterword fields)\cr}}$$
3686 This is somewhat cumbersome to write, and not very readable either, but
3687 macros will be used to make the notation shorter and more transparent.
3688 The code below gives a formal definition of |memory_word| and
3689 its subsidiary types, using packed variant records. \MP\ makes no
3690 assumptions about the relative positions of the fields within a word.
3691
3692 @d max_quarterword 0x3FFF /* largest allowable value in a |quarterword| */
3693 @d max_halfword 0xFFFFFFF /* largest allowable value in a |halfword| */
3694
3695 @ Here are the inequalities that the quarterword and halfword values
3696 must satisfy (or rather, the inequalities that they mustn't satisfy):
3697
3698 @<Check the ``constant''...@>=
3699 if (mp->ini_version) {
3700   if ( mp->mem_max!=mp->mem_top ) mp->bad=8;
3701 } else {
3702   if ( mp->mem_max<mp->mem_top ) mp->bad=8;
3703 }
3704 if ( mp->mem_max>=max_halfword ) mp->bad=12;
3705 if ( mp->max_strings>max_halfword ) mp->bad=13;
3706
3707 @ The macros |qi| and |qo| are used for input to and output 
3708 from quarterwords. These are legacy macros.
3709 @^system dependencies@>
3710
3711 @d qo(A) (A) /* to read eight bits from a quarterword */
3712 @d qi(A) (quarterword)(A) /* to store eight bits in a quarterword */
3713
3714 @ The reader should study the following definitions closely:
3715 @^system dependencies@>
3716
3717 @d sc cint /* |scaled| data is equivalent to |integer| */
3718
3719 @<Types...@>=
3720 typedef short quarterword; /* 1/4 of a word */
3721 typedef int halfword; /* 1/2 of a word */
3722 typedef union {
3723   struct {
3724     halfword RH, LH;
3725   } v;
3726   struct { /* Make B0,B1 overlap the most significant bytes of LH.  */
3727     halfword junk;
3728     quarterword B0, B1;
3729   } u;
3730 } two_halves;
3731 typedef struct {
3732   struct {
3733     quarterword B2, B3, B0, B1;
3734   } u;
3735 } four_quarters;
3736 typedef union {
3737   two_halves hh;
3738   integer cint;
3739   four_quarters qqqq;
3740 } memory_word;
3741 #define b0 u.B0
3742 #define b1 u.B1
3743 #define b2 u.B2
3744 #define b3 u.B3
3745 #define rh v.RH
3746 #define lh v.LH
3747
3748 @ When debugging, we may want to print a |memory_word| without knowing
3749 what type it is; so we print it in all modes.
3750 @^debugging@>
3751
3752 @c 
3753 void mp_print_word (MP mp,memory_word w) {
3754   /* prints |w| in all ways */
3755   mp_print_int(mp, w.cint); mp_print_char(mp, xord(' '));
3756   mp_print_scaled(mp, w.sc); mp_print_char(mp, xord(' ')); 
3757   mp_print_scaled(mp, w.sc / 010000); mp_print_ln(mp);
3758   mp_print_int(mp, w.hh.lh); mp_print_char(mp, xord('=')); 
3759   mp_print_int(mp, w.hh.b0); mp_print_char(mp, xord(':'));
3760   mp_print_int(mp, w.hh.b1); mp_print_char(mp, xord(';')); 
3761   mp_print_int(mp, w.hh.rh); mp_print_char(mp, xord(' '));
3762   mp_print_int(mp, w.qqqq.b0); mp_print_char(mp, xord(':')); 
3763   mp_print_int(mp, w.qqqq.b1); mp_print_char(mp, xord(':'));
3764   mp_print_int(mp, w.qqqq.b2); mp_print_char(mp, xord(':')); 
3765   mp_print_int(mp, w.qqqq.b3);
3766 }
3767
3768
3769 @* \[10] Dynamic memory allocation.
3770
3771 The \MP\ system does nearly all of its own memory allocation, so that it
3772 can readily be transported into environments that do not have automatic
3773 facilities for strings, garbage collection, etc., and so that it can be in
3774 control of what error messages the user receives. The dynamic storage
3775 requirements of \MP\ are handled by providing a large array |mem| in
3776 which consecutive blocks of words are used as nodes by the \MP\ routines.
3777
3778 Pointer variables are indices into this array, or into another array
3779 called |eqtb| that will be explained later. A pointer variable might
3780 also be a special flag that lies outside the bounds of |mem|, so we
3781 allow pointers to assume any |halfword| value. The minimum memory
3782 index represents a null pointer.
3783
3784 @d null 0 /* the null pointer */
3785 @d mp_void (null+1) /* a null pointer different from |null| */
3786
3787
3788 @<Types...@>=
3789 typedef halfword pointer; /* a flag or a location in |mem| or |eqtb| */
3790
3791 @ The |mem| array is divided into two regions that are allocated separately,
3792 but the dividing line between these two regions is not fixed; they grow
3793 together until finding their ``natural'' size in a particular job.
3794 Locations less than or equal to |lo_mem_max| are used for storing
3795 variable-length records consisting of two or more words each. This region
3796 is maintained using an algorithm similar to the one described in exercise
3797 2.5--19 of {\sl The Art of Computer Programming}. However, no size field
3798 appears in the allocated nodes; the program is responsible for knowing the
3799 relevant size when a node is freed. Locations greater than or equal to
3800 |hi_mem_min| are used for storing one-word records; a conventional
3801 \.{AVAIL} stack is used for allocation in this region.
3802
3803 Locations of |mem| between |0| and |mem_top| may be dumped as part
3804 of preloaded mem files, by the \.{INIMP} preprocessor.
3805 @.INIMP@>
3806 Production versions of \MP\ may extend the memory at the top end in order to
3807 provide more space; these locations, between |mem_top| and |mem_max|,
3808 are always used for single-word nodes.
3809
3810 The key pointers that govern |mem| allocation have a prescribed order:
3811 $$\hbox{|null=0<lo_mem_max<hi_mem_min<mem_top<=mem_end<=mem_max|.}$$
3812
3813 @<Glob...@>=
3814 memory_word *mem; /* the big dynamic storage area */
3815 pointer lo_mem_max; /* the largest location of variable-size memory in use */
3816 pointer hi_mem_min; /* the smallest location of one-word memory in use */
3817
3818
3819
3820 @d xfree(A) do { mp_xfree(A); A=NULL; } while (0)
3821 @d xrealloc(P,A,B) mp_xrealloc(mp,P,(size_t)A,B)
3822 @d xmalloc(A,B)  mp_xmalloc(mp,(size_t)A,B)
3823 @d xstrdup(A)  mp_xstrdup(mp,A)
3824 @d XREALLOC(a,b,c) a = xrealloc(a,(b+1),sizeof(c));
3825
3826 @<Declare helpers@>=
3827 extern char *mp_strdup(const char *p) ;
3828 extern void mp_xfree ( @= /*@@only@@*/ /*@@out@@*/ /*@@null@@*/ @> void *x);
3829 extern @= /*@@only@@*/ @> void *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) ;
3830 extern @= /*@@only@@*/ @> void *mp_xmalloc (MP mp, size_t nmem, size_t size) ;
3831 extern @= /*@@only@@*/ @> char *mp_xstrdup(MP mp, const char *s);
3832 extern void mp_do_snprintf(char *str, int size, const char *fmt, ...);
3833
3834 @ The |max_size_test| guards against overflow, on the assumption that
3835 |size_t| is at least 31bits wide.
3836
3837 @d max_size_test 0x7FFFFFFF
3838
3839 @c
3840 char *mp_strdup(const char *p) {
3841   char *r;
3842   size_t l;
3843   if (p==NULL) return NULL;
3844   l = strlen(p);
3845   r = malloc (l*sizeof(char)+1);
3846   if (r==NULL)
3847     return NULL;
3848   return memcpy (r,p,(l+1));
3849 }
3850 void mp_xfree (void *x) {
3851   if (x!=NULL) free(x);
3852 }
3853 void  *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) {
3854   void *w ; 
3855   if ((max_size_test/size)<nmem) {
3856     do_fprintf(mp->err_out,"Memory size overflow!\n");
3857     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3858   }
3859   w = realloc (p,(nmem*size));
3860   if (w==NULL) {
3861     do_fprintf(mp->err_out,"Out of memory!\n");
3862     mp->history =mp_system_error_stop;    mp_jump_out(mp);
3863   }
3864   return w;
3865 }
3866 void  *mp_xmalloc (MP mp, size_t nmem, size_t size) {
3867   void *w;
3868   if ((max_size_test/size)<nmem) {
3869     do_fprintf(mp->err_out,"Memory size overflow!\n");
3870     mp->history =mp_fatal_error_stop;    mp_jump_out(mp);
3871   }
3872   w = malloc (nmem*size);
3873   if (w==NULL) {
3874     do_fprintf(mp->err_out,"Out of memory!\n");
3875     mp->history =mp_system_error_stop;    mp_jump_out(mp);
3876   }
3877   return w;
3878 }
3879 char *mp_xstrdup(MP mp, const char *s) {
3880   char *w; 
3881   if (s==NULL)
3882     return NULL;
3883   w = mp_strdup(s);
3884   if (w==NULL) {
3885     do_fprintf(mp->err_out,"Out of memory!\n");
3886     mp->history =mp_system_error_stop;    mp_jump_out(mp);
3887   }
3888   return w;
3889 }
3890
3891 @ @<Internal library declarations@>=
3892 #ifdef HAVE_SNPRINTF
3893 #define mp_snprintf (void)snprintf
3894 #else
3895 #define mp_snprintf mp_do_snprintf
3896 #endif
3897
3898 @ This internal version is rather stupid, but good enough for its purpose.
3899
3900 @c
3901 static char *mp_itoa (int i) {
3902   char res[32] ;
3903   unsigned idx = 30;
3904   unsigned v = (unsigned)abs(i);
3905   memset(res,0,32*sizeof(char));
3906   while (v>=10) {
3907     char d = (char)(v % 10);
3908     v = v / 10;
3909     res[idx--] = d;
3910   }
3911   res[idx--] = (char)v;
3912   if (i<0) {
3913       res[idx--] = '-';
3914   }
3915   return mp_strdup(res+idx);
3916 }
3917 static char *mp_utoa (unsigned v) {
3918   char res[32] ;
3919   unsigned idx = 30;
3920   memset(res,0,32*sizeof(char));
3921   while (v>=10) {
3922     char d = (char)(v % 10);
3923     v = v / 10;
3924     res[idx--] = d;
3925   }
3926   res[idx--] = (char)v;
3927   return mp_strdup(res+idx);
3928 }
3929 void mp_do_snprintf (char *str, int size, const char *format, ...) {
3930   const char *fmt;
3931   char *res;
3932   va_list ap;
3933   va_start(ap, format);
3934   res = str;
3935   for (fmt=format;*fmt!='\0';fmt++) {
3936      if (*fmt=='%') {
3937        fmt++;
3938        switch(*fmt) {
3939        case 's':
3940          {
3941            char *s = va_arg(ap, char *);
3942            while (*s) {
3943              *res = *s++;
3944              if (size-->0) res++;
3945            }
3946          }
3947          break;
3948        case 'i':
3949        case 'd':
3950          {
3951            char *s = mp_itoa(va_arg(ap, int));
3952            if (s != NULL) {
3953              while (*s) {
3954                *res = *s++;
3955                if (size-->0) res++;
3956              }
3957            }
3958          }
3959          break;
3960        case 'u':
3961          {
3962            char *s = mp_utoa(va_arg(ap, unsigned));
3963            if (s != NULL) {
3964              while (*s) {
3965                *res = *s++;
3966                if (size-->0) res++;
3967              }
3968            }
3969          }
3970          break;
3971        case '%':
3972          *res = '%';
3973          if (size-->0) res++;
3974          break;
3975        default:
3976          *res = '%';
3977          if (size-->0) res++;
3978          *res = *fmt;
3979          if (size-->0) res++;
3980          break;
3981        }
3982      } else {
3983        *res = *fmt;
3984        if (size-->0) res++;
3985      }
3986   }
3987   *res = '\0';
3988   va_end(ap);
3989 }
3990
3991
3992 @<Allocate or initialize ...@>=
3993 mp->mem = xmalloc ((mp->mem_max+1),sizeof (memory_word));
3994 memset(mp->mem,0,(mp->mem_max+1)*sizeof (memory_word));
3995
3996 @ @<Dealloc variables@>=
3997 xfree(mp->mem);
3998
3999 @ Users who wish to study the memory requirements of particular applications can
4000 can use optional special features that keep track of current and
4001 maximum memory usage. When code between the delimiters |stat| $\ldots$
4002 |tats| is not ``commented out,'' \MP\ will run a bit slower but it will
4003 report these statistics when |mp_tracing_stats| is positive.
4004
4005 @<Glob...@>=
4006 integer var_used; integer dyn_used; /* how much memory is in use */
4007
4008 @ Let's consider the one-word memory region first, since it's the
4009 simplest. The pointer variable |mem_end| holds the highest-numbered location
4010 of |mem| that has ever been used. The free locations of |mem| that
4011 occur between |hi_mem_min| and |mem_end|, inclusive, are of type
4012 |two_halves|, and we write |info(p)| and |mp_link(p)| for the |lh|
4013 and |rh| fields of |mem[p]| when it is of this type. The single-word
4014 free locations form a linked list
4015 $$|avail|,\;\hbox{|mp_link(avail)|},\;\hbox{|mp_link(mp_link(avail))|},\;\ldots$$
4016 terminated by |null|.
4017
4018 @d mp_link(A)   mp->mem[(A)].hh.rh /* the |link| field of a memory word */
4019 @d info(A)   mp->mem[(A)].hh.lh /* the |info| field of a memory word */
4020
4021 @<Glob...@>=
4022 pointer avail; /* head of the list of available one-word nodes */
4023 pointer mem_end; /* the last one-word node used in |mem| */
4024
4025 @ If one-word memory is exhausted, it might mean that the user has forgotten
4026 a token like `\&{enddef}' or `\&{endfor}'. We will define some procedures
4027 later that try to help pinpoint the trouble.
4028
4029 @ The function |get_avail| returns a pointer to a new one-word node whose
4030 |link| field is null. However, \MP\ will halt if there is no more room left.
4031 @^inner loop@>
4032
4033 @c 
4034 static pointer mp_get_avail (MP mp) { /* single-word node allocation */
4035   pointer p; /* the new node being got */
4036   p=mp->avail; /* get top location in the |avail| stack */
4037   if ( p!=null ) {
4038     mp->avail=mp_link(mp->avail); /* and pop it off */
4039   } else if ( mp->mem_end<mp->mem_max ) { /* or go into virgin territory */
4040     incr(mp->mem_end); p=mp->mem_end;
4041   } else { 
4042     decr(mp->hi_mem_min); p=mp->hi_mem_min;
4043     if ( mp->hi_mem_min<=mp->lo_mem_max ) { 
4044       mp_runaway(mp); /* if memory is exhausted, display possible runaway text */
4045       mp_overflow(mp, "main memory size",mp->mem_max);
4046       /* quit; all one-word nodes are busy */
4047 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4048     }
4049   }
4050   mp_link(p)=null; /* provide an oft-desired initialization of the new node */
4051   incr(mp->dyn_used);/* maintain statistics */
4052   return p;
4053 }
4054
4055 @ Conversely, a one-word node is recycled by calling |free_avail|.
4056
4057 @d free_avail(A)  /* single-word node liberation */
4058   { mp_link((A))=mp->avail; mp->avail=(A); decr(mp->dyn_used);  }
4059
4060 @ There's also a |fast_get_avail| routine, which saves the procedure-call
4061 overhead at the expense of extra programming. This macro is used in
4062 the places that would otherwise account for the most calls of |get_avail|.
4063 @^inner loop@>
4064
4065 @d fast_get_avail(A) { 
4066   (A)=mp->avail; /* avoid |get_avail| if possible, to save time */
4067   if ( (A)==null ) { (A)=mp_get_avail(mp); } 
4068   else { mp->avail=mp_link((A)); mp_link((A))=null;  incr(mp->dyn_used); }
4069   }
4070
4071 @ The available-space list that keeps track of the variable-size portion
4072 of |mem| is a nonempty, doubly-linked circular list of empty nodes,
4073 pointed to by the roving pointer |rover|.
4074
4075 Each empty node has size 2 or more; the first word contains the special
4076 value |max_halfword| in its |link| field and the size in its |info| field;
4077 the second word contains the two pointers for double linking.
4078
4079 Each nonempty node also has size 2 or more. Its first word is of type
4080 |two_halves|\kern-1pt, and its |link| field is never equal to |max_halfword|.
4081 Otherwise there is complete flexibility with respect to the contents
4082 of its other fields and its other words.
4083
4084 (We require |mem_max<max_halfword| because terrible things can happen
4085 when |max_halfword| appears in the |link| field of a nonempty node.)
4086
4087 @d empty_flag   max_halfword /* the |link| of an empty variable-size node */
4088 @d is_empty(A)   (mp_link((A))==empty_flag) /* tests for empty node */
4089 @d node_size   info /* the size field in empty variable-size nodes */
4090 @d lmp_link(A)   info((A)+1) /* left link in doubly-linked list of empty nodes */
4091 @d rmp_link(A)   mp_link((A)+1) /* right link in doubly-linked list of empty nodes */
4092
4093 @<Glob...@>=
4094 pointer rover; /* points to some node in the list of empties */
4095
4096 @ A call to |get_node| with argument |s| returns a pointer to a new node
4097 of size~|s|, which must be 2~or more. The |link| field of the first word
4098 of this new node is set to null. An overflow stop occurs if no suitable
4099 space exists.
4100
4101 If |get_node| is called with $s=2^{30}$, it simply merges adjacent free
4102 areas and returns the value |max_halfword|.
4103
4104 @<Internal library declarations@>=
4105 pointer mp_get_node (MP mp,integer s) ;
4106
4107 @ @c 
4108 pointer mp_get_node (MP mp,integer s) { /* variable-size node allocation */
4109   pointer p; /* the node currently under inspection */
4110   pointer q;  /* the node physically after node |p| */
4111   integer r; /* the newly allocated node, or a candidate for this honor */
4112   integer t,tt; /* temporary registers */
4113 @^inner loop@>
4114  RESTART: 
4115   p=mp->rover; /* start at some free node in the ring */
4116   do {  
4117     @<Try to allocate within node |p| and its physical successors,
4118      and |goto found| if allocation was possible@>;
4119     if (rmp_link(p)==null || (rmp_link(p)==p && p!=mp->rover)) {
4120       print_err("Free list garbled");
4121       help3("I found an entry in the list of free nodes that links",
4122        "badly. I will try to ignore the broken link, but something",
4123        "is seriously amiss. It is wise to warn the maintainers.")
4124           mp_error(mp);
4125       rmp_link(p)=mp->rover;
4126     }
4127         p=rmp_link(p); /* move to the next node in the ring */
4128   } while (p!=mp->rover); /* repeat until the whole list has been traversed */
4129   if ( s==010000000000 ) { 
4130     return max_halfword;
4131   };
4132   if ( mp->lo_mem_max+2<mp->hi_mem_min ) {
4133     if ( mp->lo_mem_max+2<=max_halfword ) {
4134       @<Grow more variable-size memory and |goto restart|@>;
4135     }
4136   }
4137   mp_overflow(mp, "main memory size",mp->mem_max);
4138   /* sorry, nothing satisfactory is left */
4139 @:MetaPost capacity exceeded main memory size}{\quad main memory size@>
4140 FOUND: 
4141   mp_link(r)=null; /* this node is now nonempty */
4142   mp->var_used+=s; /* maintain usage statistics */
4143   return r;
4144 }
4145
4146 @ The lower part of |mem| grows by 1000 words at a time, unless
4147 we are very close to going under. When it grows, we simply link
4148 a new node into the available-space list. This method of controlled
4149 growth helps to keep the |mem| usage consecutive when \MP\ is
4150 implemented on ``virtual memory'' systems.
4151 @^virtual memory@>
4152
4153 @<Grow more variable-size memory and |goto restart|@>=
4154
4155   if ( mp->hi_mem_min-mp->lo_mem_max>=1998 ) {
4156     t=mp->lo_mem_max+1000;
4157   } else {
4158     t=mp->lo_mem_max+1+(mp->hi_mem_min-mp->lo_mem_max) / 2; 
4159     /* |lo_mem_max+2<=t<hi_mem_min| */
4160   }
4161   if ( t>max_halfword ) t=max_halfword;
4162   p=lmp_link(mp->rover); q=mp->lo_mem_max; rmp_link(p)=q; lmp_link(mp->rover)=q;
4163   rmp_link(q)=mp->rover; lmp_link(q)=p; mp_link(q)=empty_flag; 
4164   node_size(q)=t-mp->lo_mem_max;
4165   mp->lo_mem_max=t; mp_link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4166   mp->rover=q; 
4167   goto RESTART;
4168 }
4169
4170 @ @<Try to allocate...@>=
4171 q=p+node_size(p); /* find the physical successor */
4172 while ( is_empty(q) ) { /* merge node |p| with node |q| */
4173   t=rmp_link(q); tt=lmp_link(q);
4174 @^inner loop@>
4175   if ( q==mp->rover ) mp->rover=t;
4176   lmp_link(t)=tt; rmp_link(tt)=t;
4177   q=q+node_size(q);
4178 }
4179 r=q-s;
4180 if ( r>p+1 ) {
4181   @<Allocate from the top of node |p| and |goto found|@>;
4182 }
4183 if ( r==p ) { 
4184   if ( rmp_link(p)!=p ) {
4185     @<Allocate entire node |p| and |goto found|@>;
4186   }
4187 }
4188 node_size(p)=q-p /* reset the size in case it grew */
4189
4190 @ @<Allocate from the top...@>=
4191
4192   node_size(p)=r-p; /* store the remaining size */
4193   mp->rover=p; /* start searching here next time */
4194   goto FOUND;
4195 }
4196
4197 @ Here we delete node |p| from the ring, and let |rover| rove around.
4198
4199 @<Allocate entire...@>=
4200
4201   mp->rover=rmp_link(p); t=lmp_link(p);
4202   lmp_link(mp->rover)=t; rmp_link(t)=mp->rover;
4203   goto FOUND;
4204 }
4205
4206 @ Conversely, when some variable-size node |p| of size |s| is no longer needed,
4207 the operation |free_node(p,s)| will make its words available, by inserting
4208 |p| as a new empty node just before where |rover| now points.
4209
4210 @<Internal library declarations@>=
4211 void mp_free_node (MP mp, pointer p, halfword s) ;
4212
4213 @ @c 
4214 void mp_free_node (MP mp, pointer p, halfword s) { /* variable-size node
4215   liberation */
4216   pointer q; /* |lmp_link(rover)| */
4217   node_size(p)=s; mp_link(p)=empty_flag;
4218 @^inner loop@>
4219   q=lmp_link(mp->rover); lmp_link(p)=q; rmp_link(p)=mp->rover; /* set both links */
4220   lmp_link(mp->rover)=p; rmp_link(q)=p; /* insert |p| into the ring */
4221   mp->var_used-=s; /* maintain statistics */
4222 }
4223
4224 @ Just before \.{INIMP} writes out the memory, it sorts the doubly linked
4225 available space list. The list is probably very short at such times, so a
4226 simple insertion sort is used. The smallest available location will be
4227 pointed to by |rover|, the next-smallest by |rmp_link(rover)|, etc.
4228
4229 @c 
4230 static void mp_sort_avail (MP mp) { /* sorts the available variable-size nodes
4231   by location */
4232   pointer p,q,r; /* indices into |mem| */
4233   pointer old_rover; /* initial |rover| setting */
4234   p=mp_get_node(mp, 010000000000); /* merge adjacent free areas */
4235   p=rmp_link(mp->rover); rmp_link(mp->rover)=max_halfword; old_rover=mp->rover;
4236   while ( p!=old_rover ) {
4237     @<Sort |p| into the list starting at |rover|
4238      and advance |p| to |rmp_link(p)|@>;
4239   }
4240   p=mp->rover;
4241   while ( rmp_link(p)!=max_halfword ) { 
4242     lmp_link(rmp_link(p))=p; p=rmp_link(p);
4243   };
4244   rmp_link(p)=mp->rover; lmp_link(mp->rover)=p;
4245 }
4246
4247 @ The following |while| loop is guaranteed to
4248 terminate, since the list that starts at
4249 |rover| ends with |max_halfword| during the sorting procedure.
4250
4251 @<Sort |p|...@>=
4252 if ( p<mp->rover ) { 
4253   q=p; p=rmp_link(q); rmp_link(q)=mp->rover; mp->rover=q;
4254 } else  { 
4255   q=mp->rover;
4256   while ( rmp_link(q)<p ) q=rmp_link(q);
4257   r=rmp_link(p); rmp_link(p)=rmp_link(q); rmp_link(q)=p; p=r;
4258 }
4259
4260 @* \[11] Memory layout.
4261 Some areas of |mem| are dedicated to fixed usage, since static allocation is
4262 more efficient than dynamic allocation when we can get away with it. For
4263 example, locations |0| to |1| are always used to store a
4264 two-word dummy token whose second word is zero.
4265 The following macro definitions accomplish the static allocation by giving
4266 symbolic names to the fixed positions. Static variable-size nodes appear
4267 in locations |0| through |lo_mem_stat_max|, and static single-word nodes
4268 appear in locations |hi_mem_stat_min| through |mem_top|, inclusive.
4269
4270 @d null_dash (2) /* the first two words are reserved for a null value */
4271 @d dep_head (null_dash+3) /* we will define |dash_node_size=3| */
4272 @d zero_val (dep_head+2) /* two words for a permanently zero value */
4273 @d temp_val (zero_val+2) /* two words for a temporary value node */
4274 @d end_attr temp_val /* we use |end_attr+2| only */
4275 @d inf_val (end_attr+2) /* and |inf_val+1| only */
4276 @d test_pen (inf_val+2)
4277   /* nine words for a pen used when testing the turning number */
4278 @d bad_vardef (test_pen+9) /* two words for \&{vardef} error recovery */
4279 @d lo_mem_stat_max (bad_vardef+1)  /* largest statically
4280   allocated word in the variable-size |mem| */
4281 @#
4282 @d sentinel mp->mem_top /* end of sorted lists */
4283 @d temp_head (mp->mem_top-1) /* head of a temporary list of some kind */
4284 @d hold_head (mp->mem_top-2) /* head of a temporary list of another kind */
4285 @d spec_head (mp->mem_top-3) /* head of a list of unprocessed \&{special} items */
4286 @d hi_mem_stat_min (mp->mem_top-3) /* smallest statically allocated word in
4287   the one-word |mem| */
4288
4289 @ The following code gets the dynamic part of |mem| off to a good start,
4290 when \MP\ is initializing itself the slow way.
4291
4292 @<Initialize table entries (done by \.{INIMP} only)@>=
4293 mp->rover=lo_mem_stat_max+1; /* initialize the dynamic memory */
4294 mp_link(mp->rover)=empty_flag;
4295 node_size(mp->rover)=1000; /* which is a 1000-word available node */
4296 lmp_link(mp->rover)=mp->rover; rmp_link(mp->rover)=mp->rover;
4297 mp->lo_mem_max=mp->rover+1000; 
4298 mp_link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null;
4299 for (k=hi_mem_stat_min;k<=(int)mp->mem_top;k++) {
4300   mp->mem[k]=mp->mem[mp->lo_mem_max]; /* clear list heads */
4301 }
4302 mp->avail=null; mp->mem_end=mp->mem_top;
4303 mp->hi_mem_min=hi_mem_stat_min; /* initialize the one-word memory */
4304 mp->var_used=lo_mem_stat_max+1; 
4305 mp->dyn_used=mp->mem_top+1-(hi_mem_stat_min);  /* initialize statistics */
4306 @<Initialize a pen at |test_pen| so that it fits in nine words@>;
4307
4308 @ The procedure |flush_list(p)| frees an entire linked list of one-word
4309 nodes that starts at a given position, until coming to |sentinel| or a
4310 pointer that is not in the one-word region. Another procedure,
4311 |flush_node_list|, frees an entire linked list of one-word and two-word
4312 nodes, until coming to a |null| pointer.
4313 @^inner loop@>
4314
4315 @c 
4316 static void mp_flush_list (MP mp,pointer p) { /* makes list of single-word nodes  available */
4317   pointer q,r; /* list traversers */
4318   if ( p>=mp->hi_mem_min ) if ( p!=sentinel ) { 
4319     r=p;
4320     do {  
4321       q=r; r=mp_link(r); 
4322       decr(mp->dyn_used);
4323       if ( r<mp->hi_mem_min ) break;
4324     } while (r!=sentinel);
4325   /* now |q| is the last node on the list */
4326     mp_link(q)=mp->avail; mp->avail=p;
4327   }
4328 }
4329 @#
4330 static void mp_flush_node_list (MP mp,pointer p) {
4331   pointer q; /* the node being recycled */
4332   while ( p!=null ){ 
4333     q=p; p=mp_link(p);
4334     if ( q<mp->hi_mem_min ) 
4335       mp_free_node(mp, q,2);
4336     else 
4337       free_avail(q);
4338   }
4339 }
4340
4341 @ If \MP\ is extended improperly, the |mem| array might get screwed up.
4342 For example, some pointers might be wrong, or some ``dead'' nodes might not
4343 have been freed when the last reference to them disappeared. Procedures
4344 |check_mem| and |search_mem| are available to help diagnose such
4345 problems. These procedures make use of two arrays called |free| and
4346 |was_free| that are present only if \MP's debugging routines have
4347 been included. (You may want to decrease the size of |mem| while you
4348 @^debugging@>
4349 are debugging.)
4350
4351 Because |boolean|s are typedef-d as ints, it is better to use
4352 unsigned chars here.
4353
4354 @<Glob...@>=
4355 unsigned char *free; /* free cells */
4356 unsigned char *was_free; /* previously free cells */
4357 pointer was_mem_end; pointer was_lo_max; pointer was_hi_min;
4358   /* previous |mem_end|, |lo_mem_max|,and |hi_mem_min| */
4359 boolean panicking; /* do we want to check memory constantly? */
4360
4361 @ @<Allocate or initialize ...@>=
4362 mp->free = xmalloc ((mp->mem_max+1),sizeof (unsigned char));
4363 mp->was_free = xmalloc ((mp->mem_max+1), sizeof (unsigned char));
4364
4365 @ @<Dealloc variables@>=
4366 xfree(mp->free);
4367 xfree(mp->was_free);
4368
4369 @ @<Allocate or ...@>=
4370 mp->was_hi_min=mp->mem_max;
4371 mp->panicking=false;
4372
4373 @ @<Declarations@>=
4374 static void mp_reallocate_memory(MP mp, int l) ;
4375
4376 @ @c
4377 static void mp_reallocate_memory(MP mp, int l) {
4378    XREALLOC(mp->free,     l, unsigned char);
4379    XREALLOC(mp->was_free, l, unsigned char);
4380    if (mp->mem) {
4381          int newarea = l-mp->mem_max;
4382      XREALLOC(mp->mem,      l, memory_word);
4383      memset (mp->mem+(mp->mem_max+1),0,sizeof(memory_word)*(newarea));
4384    } else {
4385      XREALLOC(mp->mem,      l, memory_word);
4386      memset(mp->mem,0,sizeof(memory_word)*(l+1));
4387    }
4388    mp->mem_max = l;
4389    if (mp->ini_version) 
4390      mp->mem_top = l;
4391 }
4392
4393
4394
4395 @ Procedure |check_mem| makes sure that the available space lists of
4396 |mem| are well formed, and it optionally prints out all locations
4397 that are reserved now but were free the last time this procedure was called.
4398
4399 @c 
4400 void mp_check_mem (MP mp,boolean print_locs ) {
4401   pointer p,q,r; /* current locations of interest in |mem| */
4402   boolean clobbered; /* is something amiss? */
4403   for (p=0;p<=mp->lo_mem_max;p++) {
4404     mp->free[p]=false; /* you can probably do this faster */
4405   }
4406   for (p=mp->hi_mem_min;p<= mp->mem_end;p++) {
4407     mp->free[p]=false; /* ditto */
4408   }
4409   @<Check single-word |avail| list@>;
4410   @<Check variable-size |avail| list@>;
4411   @<Check flags of unavailable nodes@>;
4412   @<Check the list of linear dependencies@>;
4413   if ( print_locs ) {
4414     @<Print newly busy locations@>;
4415   }
4416   memcpy(mp->was_free,mp->free, sizeof(char)*(mp->mem_end+1));
4417   mp->was_mem_end=mp->mem_end; 
4418   mp->was_lo_max=mp->lo_mem_max; 
4419   mp->was_hi_min=mp->hi_mem_min;
4420 }
4421
4422 @ @<Check single-word...@>=
4423 p=mp->avail; q=null; clobbered=false;
4424 while ( p!=null ) { 
4425   if ( (p>mp->mem_end)||(p<mp->hi_mem_min) ) clobbered=true;
4426   else if ( mp->free[p] ) clobbered=true;
4427   if ( clobbered ) { 
4428     mp_print_nl(mp, "AVAIL list clobbered at ");
4429 @.AVAIL list clobbered...@>
4430     mp_print_int(mp, q); break;
4431   }
4432   mp->free[p]=true; q=p; p=mp_link(q);
4433 }
4434
4435 @ @<Check variable-size...@>=
4436 p=mp->rover; q=null; clobbered=false;
4437 do {  
4438   if ( (p>=mp->lo_mem_max)||(p<0) ) clobbered=true;
4439   else if ( (rmp_link(p)>=mp->lo_mem_max)||(rmp_link(p)<0) ) clobbered=true;
4440   else if (  !(is_empty(p))||(node_size(p)<2)||
4441    (p+node_size(p)>mp->lo_mem_max)|| (lmp_link(rmp_link(p))!=p) ) clobbered=true;
4442   if ( clobbered ) { 
4443     mp_print_nl(mp, "Double-AVAIL list clobbered at ");
4444 @.Double-AVAIL list clobbered...@>
4445     mp_print_int(mp, q); break;
4446   }
4447   for (q=p;q<=p+node_size(p)-1;q++) { /* mark all locations free */
4448     if ( mp->free[q] ) { 
4449       mp_print_nl(mp, "Doubly free location at ");
4450 @.Doubly free location...@>
4451       mp_print_int(mp, q); break;
4452     }
4453     mp->free[q]=true;
4454   }
4455   q=p; p=rmp_link(p);
4456 } while (p!=mp->rover)
4457
4458
4459 @ @<Check flags...@>=
4460 p=0;
4461 while ( p<=mp->lo_mem_max ) { /* node |p| should not be empty */
4462   if ( is_empty(p) ) {
4463     mp_print_nl(mp, "Bad flag at "); mp_print_int(mp, p);
4464 @.Bad flag...@>
4465   }
4466   while ( (p<=mp->lo_mem_max) && ! mp->free[p] ) incr(p);
4467   while ( (p<=mp->lo_mem_max) && mp->free[p] ) incr(p);
4468 }
4469
4470 @ @<Print newly busy...@>=
4471
4472   @<Do intialization required before printing new busy locations@>;
4473   mp_print_nl(mp, "New busy locs:");
4474 @.New busy locs@>
4475   for (p=0;p<= mp->lo_mem_max;p++ ) {
4476     if ( ! mp->free[p] && ((p>mp->was_lo_max) || mp->was_free[p]) ) {
4477       @<Indicate that |p| is a new busy location@>;
4478     }
4479   }
4480   for (p=mp->hi_mem_min;p<=mp->mem_end;p++ ) {
4481     if ( ! mp->free[p] &&
4482         ((p<mp->was_hi_min) || (p>mp->was_mem_end) || mp->was_free[p]) ) {
4483       @<Indicate that |p| is a new busy location@>;
4484     }
4485   }
4486   @<Finish printing new busy locations@>;
4487 }
4488
4489 @ There might be many new busy locations so we are careful to print contiguous
4490 blocks compactly.  During this operation |q| is the last new busy location and
4491 |r| is the start of the block containing |q|.
4492
4493 @<Indicate that |p| is a new busy location@>=
4494
4495   if ( p>q+1 ) { 
4496     if ( q>r ) { 
4497       mp_print(mp, ".."); mp_print_int(mp, q);
4498     }
4499     mp_print_char(mp, xord(' ')); mp_print_int(mp, p);
4500     r=p;
4501   }
4502   q=p;
4503 }
4504
4505 @ @<Do intialization required before printing new busy locations@>=
4506 q=mp->mem_max; r=mp->mem_max
4507
4508 @ @<Finish printing new busy locations@>=
4509 if ( q>r ) { 
4510   mp_print(mp, ".."); mp_print_int(mp, q);
4511 }
4512
4513 @ The |search_mem| procedure attempts to answer the question ``Who points
4514 to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem|
4515 that might not be of type |two_halves|. Strictly speaking, this is
4516 undefined, and it can lead to ``false drops'' (words that seem to
4517 point to |p| purely by coincidence). But for debugging purposes, we want
4518 to rule out the places that do {\sl not\/} point to |p|, so a few false
4519 drops are tolerable.
4520
4521 @c
4522 void mp_search_mem (MP mp, pointer p) { /* look for pointers to |p| */
4523   integer q; /* current position being searched */
4524   for (q=0;q<=mp->lo_mem_max;q++) { 
4525     if ( mp_link(q)==p ){ 
4526       mp_print_nl(mp, "MP_LINK("); mp_print_int(mp, q); mp_print_char(mp, xord(')'));
4527     }
4528     if ( info(q)==p ) { 
4529       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, xord(')'));
4530     }
4531   }
4532   for (q=mp->hi_mem_min;q<=mp->mem_end;q++) {
4533     if ( mp_link(q)==p ) {
4534       mp_print_nl(mp, "MP_LINK("); mp_print_int(mp, q); mp_print_char(mp, xord(')'));
4535     }
4536     if ( info(q)==p ) {
4537       mp_print_nl(mp, "INFO("); mp_print_int(mp, q); mp_print_char(mp, xord(')'));
4538     }
4539   }
4540   @<Search |eqtb| for equivalents equal to |p|@>;
4541 }
4542
4543 @* \[12] The command codes.
4544 Before we can go much further, we need to define symbolic names for the internal
4545 code numbers that represent the various commands obeyed by \MP. These codes
4546 are somewhat arbitrary, but not completely so. For example,
4547 some codes have been made adjacent so that |case| statements in the
4548 program need not consider cases that are widely spaced, or so that |case|
4549 statements can be replaced by |if| statements. A command can begin an
4550 expression if and only if its code lies between |min_primary_command| and
4551 |max_primary_command|, inclusive. The first token of a statement that doesn't
4552 begin with an expression has a command code between |min_command| and
4553 |max_statement_command|, inclusive. Anything less than |min_command| is
4554 eliminated during macro expansions, and anything no more than |max_pre_command|
4555 is eliminated when expanding \TeX\ material.  Ranges such as
4556 |min_secondary_command..max_secondary_command| are used when parsing
4557 expressions, but the relative ordering within such a range is generally not
4558 critical.
4559
4560 The ordering of the highest-numbered commands
4561 (|comma<semicolon<end_group<stop|) is crucial for the parsing and
4562 error-recovery methods of this program as is the ordering |if_test<fi_or_else|
4563 for the smallest two commands.  The ordering is also important in the ranges
4564 |numeric_token..plus_or_minus| and |left_brace..ampersand|.
4565
4566 At any rate, here is the list, for future reference.
4567
4568 @d start_tex 1 /* begin \TeX\ material (\&{btex}, \&{verbatimtex}) */
4569 @d etex_marker 2 /* end \TeX\ material (\&{etex}) */
4570 @d mpx_break 3 /* stop reading an \.{MPX} file (\&{mpxbreak}) */
4571 @d max_pre_command mpx_break
4572 @d if_test 4 /* conditional text (\&{if}) */
4573 @d fi_or_else 5 /* delimiters for conditionals (\&{elseif}, \&{else}, \&{fi}) */
4574 @d input 6 /* input a source file (\&{input}, \&{endinput}) */
4575 @d iteration 7 /* iterate (\&{for}, \&{forsuffixes}, \&{forever}, \&{endfor}) */
4576 @d repeat_loop 8 /* special command substituted for \&{endfor} */
4577 @d exit_test 9 /* premature exit from a loop (\&{exitif}) */
4578 @d relax 10 /* do nothing (\.{\char`\\}) */
4579 @d scan_tokens 11 /* put a string into the input buffer */
4580 @d expand_after 12 /* look ahead one token */
4581 @d defined_macro 13 /* a macro defined by the user */
4582 @d min_command (defined_macro+1)
4583 @d save_command 14 /* save a list of tokens (\&{save}) */
4584 @d interim_command 15 /* save an internal quantity (\&{interim}) */
4585 @d let_command 16 /* redefine a symbolic token (\&{let}) */
4586 @d new_internal 17 /* define a new internal quantity (\&{newinternal}) */
4587 @d macro_def 18 /* define a macro (\&{def}, \&{vardef}, etc.) */
4588 @d ship_out_command 19 /* output a character (\&{shipout}) */
4589 @d add_to_command 20 /* add to edges (\&{addto}) */
4590 @d bounds_command 21  /* add bounding path to edges (\&{setbounds}, \&{clip}) */
4591 @d tfm_command 22 /* command for font metric info (\&{ligtable}, etc.) */
4592 @d protection_command 23 /* set protection flag (\&{outer}, \&{inner}) */
4593 @d show_command 24 /* diagnostic output (\&{show}, \&{showvariable}, etc.) */
4594 @d mode_command 25 /* set interaction level (\&{batchmode}, etc.) */
4595 @d mp_random_seed 26 /* initialize random number generator (\&{randomseed}) */
4596 @d message_command 27 /* communicate to user (\&{message}, \&{errmessage}) */
4597 @d every_job_command 28 /* designate a starting token (\&{everyjob}) */
4598 @d delimiters 29 /* define a pair of delimiters (\&{delimiters}) */
4599 @d special_command 30 /* output special info (\&{special})
4600                        or font map info (\&{fontmapfile}, \&{fontmapline}) */
4601 @d write_command 31 /* write text to a file (\&{write}) */
4602 @d type_name 32 /* declare a type (\&{numeric}, \&{pair}, etc.) */
4603 @d max_statement_command type_name
4604 @d min_primary_command type_name
4605 @d left_delimiter 33 /* the left delimiter of a matching pair */
4606 @d begin_group 34 /* beginning of a group (\&{begingroup}) */
4607 @d nullary 35 /* an operator without arguments (e.g., \&{normaldeviate}) */
4608 @d unary 36 /* an operator with one argument (e.g., \&{sqrt}) */
4609 @d str_op 37 /* convert a suffix to a string (\&{str}) */
4610 @d cycle 38 /* close a cyclic path (\&{cycle}) */
4611 @d primary_binary 39 /* binary operation taking `\&{of}' (e.g., \&{point}) */
4612 @d capsule_token 40 /* a value that has been put into a token list */
4613 @d string_token 41 /* a string constant (e.g., |"hello"|) */
4614 @d internal_quantity 42 /* internal numeric parameter (e.g., \&{pausing}) */
4615 @d min_suffix_token internal_quantity
4616 @d tag_token 43 /* a symbolic token without a primitive meaning */
4617 @d numeric_token 44 /* a numeric constant (e.g., \.{3.14159}) */
4618 @d max_suffix_token numeric_token
4619 @d plus_or_minus 45 /* either `\.+' or `\.-' */
4620 @d max_primary_command plus_or_minus /* should also be |numeric_token+1| */
4621 @d min_tertiary_command plus_or_minus
4622 @d tertiary_secondary_macro 46 /* a macro defined by \&{secondarydef} */
4623 @d tertiary_binary 47 /* an operator at the tertiary level (e.g., `\.{++}') */
4624 @d max_tertiary_command tertiary_binary
4625 @d left_brace 48 /* the operator `\.{\char`\{}' */
4626 @d min_expression_command left_brace
4627 @d path_join 49 /* the operator `\.{..}' */
4628 @d ampersand 50 /* the operator `\.\&' */
4629 @d expression_tertiary_macro 51 /* a macro defined by \&{tertiarydef} */
4630 @d expression_binary 52 /* an operator at the expression level (e.g., `\.<') */
4631 @d equals 53 /* the operator `\.=' */
4632 @d max_expression_command equals
4633 @d and_command 54 /* the operator `\&{and}' */
4634 @d min_secondary_command and_command
4635 @d secondary_primary_macro 55 /* a macro defined by \&{primarydef} */
4636 @d slash 56 /* the operator `\./' */
4637 @d secondary_binary 57 /* an operator at the binary level (e.g., \&{shifted}) */
4638 @d max_secondary_command secondary_binary
4639 @d param_type 58 /* type of parameter (\&{primary}, \&{expr}, \&{suffix}, etc.) */
4640 @d controls 59 /* specify control points explicitly (\&{controls}) */
4641 @d tension 60 /* specify tension between knots (\&{tension}) */
4642 @d at_least 61 /* bounded tension value (\&{atleast}) */
4643 @d curl_command 62 /* specify curl at an end knot (\&{curl}) */
4644 @d macro_special 63 /* special macro operators (\&{quote}, \.{\#\AT!}, etc.) */
4645 @d right_delimiter 64 /* the right delimiter of a matching pair */
4646 @d left_bracket 65 /* the operator `\.[' */
4647 @d right_bracket 66 /* the operator `\.]' */
4648 @d right_brace 67 /* the operator `\.{\char`\}}' */
4649 @d with_option 68 /* option for filling (\&{withpen}, \&{withweight}, etc.) */
4650 @d thing_to_add 69
4651   /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */
4652 @d of_token 70 /* the operator `\&{of}' */
4653 @d to_token 71 /* the operator `\&{to}' */
4654 @d step_token 72 /* the operator `\&{step}' */
4655 @d until_token 73 /* the operator `\&{until}' */
4656 @d within_token 74 /* the operator `\&{within}' */
4657 @d lig_kern_token 75
4658   /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}', etc. */
4659 @d assignment 76 /* the operator `\.{:=}' */
4660 @d skip_to 77 /* the operation `\&{skipto}' */
4661 @d bchar_label 78 /* the operator `\.{\char'174\char'174:}' */
4662 @d double_colon 79 /* the operator `\.{::}' */
4663 @d colon 80 /* the operator `\.:' */
4664 @#
4665 @d comma 81 /* the operator `\.,', must be |colon+1| */
4666 @d end_of_statement (mp->cur_cmd>comma)
4667 @d semicolon 82 /* the operator `\.;', must be |comma+1| */
4668 @d end_group 83 /* end a group (\&{endgroup}), must be |semicolon+1| */
4669 @d stop 84 /* end a job (\&{end}, \&{dump}), must be |end_group+1| */
4670 @d max_command_code stop
4671 @d outer_tag (max_command_code+1) /* protection code added to command code */
4672
4673 @<Types...@>=
4674 typedef int command_code;
4675
4676 @ Variables and capsules in \MP\ have a variety of ``types,''
4677 distinguished by the code numbers defined here. These numbers are also
4678 not completely arbitrary.  Things that get expanded must have types
4679 |>mp_independent|; a type remaining after expansion is numeric if and only if
4680 its code number is at least |numeric_type|; objects containing numeric
4681 parts must have types between |transform_type| and |pair_type|;
4682 all other types must be smaller than |transform_type|; and among the types
4683 that are not unknown or vacuous, the smallest two must be |boolean_type|
4684 and |string_type| in that order.
4685  
4686 @d undefined 0 /* no type has been declared */
4687 @d unknown_tag 1 /* this constant is added to certain type codes below */
4688 @d unknown_types mp_unknown_boolean: case mp_unknown_string:
4689   case mp_unknown_pen: case mp_unknown_picture: case mp_unknown_path
4690
4691 @<Types...@>=
4692 enum mp_variable_type {
4693 mp_vacuous=1, /* no expression was present */
4694 mp_boolean_type, /* \&{boolean} with a known value */
4695 mp_unknown_boolean,
4696 mp_string_type, /* \&{string} with a known value */
4697 mp_unknown_string,
4698 mp_pen_type, /* \&{pen} with a known value */
4699 mp_unknown_pen,
4700 mp_path_type, /* \&{path} with a known value */
4701 mp_unknown_path,
4702 mp_picture_type, /* \&{picture} with a known value */
4703 mp_unknown_picture,
4704 mp_transform_type, /* \&{transform} variable or capsule */
4705 mp_color_type, /* \&{color} variable or capsule */
4706 mp_cmykcolor_type, /* \&{cmykcolor} variable or capsule */
4707 mp_pair_type, /* \&{pair} variable or capsule */
4708 mp_numeric_type, /* variable that has been declared \&{numeric} but not used */
4709 mp_known, /* \&{numeric} with a known value */
4710 mp_dependent, /* a linear combination with |fraction| coefficients */
4711 mp_proto_dependent, /* a linear combination with |scaled| coefficients */
4712 mp_independent, /* \&{numeric} with unknown value */
4713 mp_token_list, /* variable name or suffix argument or text argument */
4714 mp_structured, /* variable with subscripts and attributes */
4715 mp_unsuffixed_macro, /* variable defined with \&{vardef} but no \.{\AT!\#} */
4716 mp_suffixed_macro /* variable defined with \&{vardef} and \.{\AT!\#} */
4717 } ;
4718
4719 @ @<Declarations@>=
4720 static void mp_print_type (MP mp,quarterword t) ;
4721
4722 @ @<Basic printing procedures@>=
4723 void mp_print_type (MP mp,quarterword t) { 
4724   switch (t) {
4725   case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
4726   case mp_boolean_type:mp_print(mp, "boolean"); break;
4727   case mp_unknown_boolean:mp_print(mp, "unknown boolean"); break;
4728   case mp_string_type:mp_print(mp, "string"); break;
4729   case mp_unknown_string:mp_print(mp, "unknown string"); break;
4730   case mp_pen_type:mp_print(mp, "pen"); break;
4731   case mp_unknown_pen:mp_print(mp, "unknown pen"); break;
4732   case mp_path_type:mp_print(mp, "path"); break;
4733   case mp_unknown_path:mp_print(mp, "unknown path"); break;
4734   case mp_picture_type:mp_print(mp, "picture"); break;
4735   case mp_unknown_picture:mp_print(mp, "unknown picture"); break;
4736   case mp_transform_type:mp_print(mp, "transform"); break;
4737   case mp_color_type:mp_print(mp, "color"); break;
4738   case mp_cmykcolor_type:mp_print(mp, "cmykcolor"); break;
4739   case mp_pair_type:mp_print(mp, "pair"); break;
4740   case mp_known:mp_print(mp, "known numeric"); break;
4741   case mp_dependent:mp_print(mp, "dependent"); break;
4742   case mp_proto_dependent:mp_print(mp, "proto-dependent"); break;
4743   case mp_numeric_type:mp_print(mp, "numeric"); break;
4744   case mp_independent:mp_print(mp, "independent"); break;
4745   case mp_token_list:mp_print(mp, "token list"); break;
4746   case mp_structured:mp_print(mp, "mp_structured"); break;
4747   case mp_unsuffixed_macro:mp_print(mp, "unsuffixed macro"); break;
4748   case mp_suffixed_macro:mp_print(mp, "suffixed macro"); break;
4749   default: mp_print(mp, "undefined"); break;
4750   }
4751 }
4752
4753 @ Values inside \MP\ are stored in two-word nodes that have a |name_type|
4754 as well as a |type|. The possibilities for |name_type| are defined
4755 here; they will be explained in more detail later.
4756
4757 @<Types...@>=
4758 enum mp_name_type {
4759  mp_root=0, /* |name_type| at the top level of a variable */
4760  mp_saved_root, /* same, when the variable has been saved */
4761  mp_structured_root, /* |name_type| where a |mp_structured| branch occurs */
4762  mp_subscr, /* |name_type| in a subscript node */
4763  mp_attr, /* |name_type| in an attribute node */
4764  mp_x_part_sector, /* |name_type| in the \&{xpart} of a node */
4765  mp_y_part_sector, /* |name_type| in the \&{ypart} of a node */
4766  mp_xx_part_sector, /* |name_type| in the \&{xxpart} of a node */
4767  mp_xy_part_sector, /* |name_type| in the \&{xypart} of a node */
4768  mp_yx_part_sector, /* |name_type| in the \&{yxpart} of a node */
4769  mp_yy_part_sector, /* |name_type| in the \&{yypart} of a node */
4770  mp_red_part_sector, /* |name_type| in the \&{redpart} of a node */
4771  mp_green_part_sector, /* |name_type| in the \&{greenpart} of a node */
4772  mp_blue_part_sector, /* |name_type| in the \&{bluepart} of a node */
4773  mp_cyan_part_sector, /* |name_type| in the \&{redpart} of a node */
4774  mp_magenta_part_sector, /* |name_type| in the \&{greenpart} of a node */
4775  mp_yellow_part_sector, /* |name_type| in the \&{bluepart} of a node */
4776  mp_black_part_sector, /* |name_type| in the \&{greenpart} of a node */
4777  mp_grey_part_sector, /* |name_type| in the \&{bluepart} of a node */
4778  mp_capsule, /* |name_type| in stashed-away subexpressions */
4779  mp_token  /* |name_type| in a numeric token or string token */
4780 };
4781
4782 @ Primitive operations that produce values have a secondary identification
4783 code in addition to their command code; it's something like genera and species.
4784 For example, `\.*' has the command code |primary_binary|, and its
4785 secondary identification is |times|. The secondary codes start at 30 so that
4786 they don't overlap with the type codes; some type codes (e.g., |mp_string_type|)
4787 are used as operators as well as type identifications.  The relative values
4788 are not critical, except for |true_code..false_code|, |or_op..and_op|,
4789 and |filled_op..bounded_op|.  The restrictions are that
4790 |and_op-false_code=or_op-true_code|, that the ordering of
4791 |x_part...blue_part| must match that of |x_part_sector..mp_blue_part_sector|,
4792 and the ordering of |filled_op..bounded_op| must match that of the code
4793 values they test for.
4794
4795 @d true_code 30 /* operation code for \.{true} */
4796 @d false_code 31 /* operation code for \.{false} */
4797 @d null_picture_code 32 /* operation code for \.{nullpicture} */
4798 @d null_pen_code 33 /* operation code for \.{nullpen} */
4799 @d job_name_op 34 /* operation code for \.{jobname} */
4800 @d read_string_op 35 /* operation code for \.{readstring} */
4801 @d pen_circle 36 /* operation code for \.{pencircle} */
4802 @d normal_deviate 37 /* operation code for \.{normaldeviate} */
4803 @d read_from_op 38 /* operation code for \.{readfrom} */
4804 @d close_from_op 39 /* operation code for \.{closefrom} */
4805 @d odd_op 40 /* operation code for \.{odd} */
4806 @d known_op 41 /* operation code for \.{known} */
4807 @d unknown_op 42 /* operation code for \.{unknown} */
4808 @d not_op 43 /* operation code for \.{not} */
4809 @d decimal 44 /* operation code for \.{decimal} */
4810 @d reverse 45 /* operation code for \.{reverse} */
4811 @d make_path_op 46 /* operation code for \.{makepath} */
4812 @d make_pen_op 47 /* operation code for \.{makepen} */
4813 @d oct_op 48 /* operation code for \.{oct} */
4814 @d hex_op 49 /* operation code for \.{hex} */
4815 @d ASCII_op 50 /* operation code for \.{ASCII} */
4816 @d char_op 51 /* operation code for \.{char} */
4817 @d length_op 52 /* operation code for \.{length} */
4818 @d turning_op 53 /* operation code for \.{turningnumber} */
4819 @d color_model_part 54 /* operation code for \.{colormodel} */
4820 @d x_part 55 /* operation code for \.{xpart} */
4821 @d y_part 56 /* operation code for \.{ypart} */
4822 @d xx_part 57 /* operation code for \.{xxpart} */
4823 @d xy_part 58 /* operation code for \.{xypart} */
4824 @d yx_part 59 /* operation code for \.{yxpart} */
4825 @d yy_part 60 /* operation code for \.{yypart} */
4826 @d red_part 61 /* operation code for \.{redpart} */
4827 @d green_part 62 /* operation code for \.{greenpart} */
4828 @d blue_part 63 /* operation code for \.{bluepart} */
4829 @d cyan_part 64 /* operation code for \.{cyanpart} */
4830 @d magenta_part 65 /* operation code for \.{magentapart} */
4831 @d yellow_part 66 /* operation code for \.{yellowpart} */
4832 @d black_part 67 /* operation code for \.{blackpart} */
4833 @d grey_part 68 /* operation code for \.{greypart} */
4834 @d font_part 69 /* operation code for \.{fontpart} */
4835 @d text_part 70 /* operation code for \.{textpart} */
4836 @d path_part 71 /* operation code for \.{pathpart} */
4837 @d pen_part 72 /* operation code for \.{penpart} */
4838 @d dash_part 73 /* operation code for \.{dashpart} */
4839 @d sqrt_op 74 /* operation code for \.{sqrt} */
4840 @d mp_m_exp_op 75 /* operation code for \.{mexp} */
4841 @d mp_m_log_op 76 /* operation code for \.{mlog} */
4842 @d sin_d_op 77 /* operation code for \.{sind} */
4843 @d cos_d_op 78 /* operation code for \.{cosd} */
4844 @d floor_op 79 /* operation code for \.{floor} */
4845 @d uniform_deviate 80 /* operation code for \.{uniformdeviate} */
4846 @d char_exists_op 81 /* operation code for \.{charexists} */
4847 @d font_size 82 /* operation code for \.{fontsize} */
4848 @d ll_corner_op 83 /* operation code for \.{llcorner} */
4849 @d lr_corner_op 84 /* operation code for \.{lrcorner} */
4850 @d ul_corner_op 85 /* operation code for \.{ulcorner} */
4851 @d ur_corner_op 86 /* operation code for \.{urcorner} */
4852 @d arc_length 87 /* operation code for \.{arclength} */
4853 @d angle_op 88 /* operation code for \.{angle} */
4854 @d cycle_op 89 /* operation code for \.{cycle} */
4855 @d filled_op 90 /* operation code for \.{filled} */
4856 @d stroked_op 91 /* operation code for \.{stroked} */
4857 @d textual_op 92 /* operation code for \.{textual} */
4858 @d clipped_op 93 /* operation code for \.{clipped} */
4859 @d bounded_op 94 /* operation code for \.{bounded} */
4860 @d plus 95 /* operation code for \.+ */
4861 @d minus 96 /* operation code for \.- */
4862 @d times 97 /* operation code for \.* */
4863 @d over 98 /* operation code for \./ */
4864 @d pythag_add 99 /* operation code for \.{++} */
4865 @d pythag_sub 100 /* operation code for \.{+-+} */
4866 @d or_op 101 /* operation code for \.{or} */
4867 @d and_op 102 /* operation code for \.{and} */
4868 @d less_than 103 /* operation code for \.< */
4869 @d less_or_equal 104 /* operation code for \.{<=} */
4870 @d greater_than 105 /* operation code for \.> */
4871 @d greater_or_equal 106 /* operation code for \.{>=} */
4872 @d equal_to 107 /* operation code for \.= */
4873 @d unequal_to 108 /* operation code for \.{<>} */
4874 @d concatenate 109 /* operation code for \.\& */
4875 @d rotated_by 110 /* operation code for \.{rotated} */
4876 @d slanted_by 111 /* operation code for \.{slanted} */
4877 @d scaled_by 112 /* operation code for \.{scaled} */
4878 @d shifted_by 113 /* operation code for \.{shifted} */
4879 @d transformed_by 114 /* operation code for \.{transformed} */
4880 @d x_scaled 115 /* operation code for \.{xscaled} */
4881 @d y_scaled 116 /* operation code for \.{yscaled} */
4882 @d z_scaled 117 /* operation code for \.{zscaled} */
4883 @d in_font 118 /* operation code for \.{infont} */
4884 @d intersect 119 /* operation code for \.{intersectiontimes} */
4885 @d double_dot 120 /* operation code for improper \.{..} */
4886 @d substring_of 121 /* operation code for \.{substring} */
4887 @d min_of substring_of
4888 @d subpath_of 122 /* operation code for \.{subpath} */
4889 @d direction_time_of 123 /* operation code for \.{directiontime} */
4890 @d point_of 124 /* operation code for \.{point} */
4891 @d precontrol_of 125 /* operation code for \.{precontrol} */
4892 @d postcontrol_of 126 /* operation code for \.{postcontrol} */
4893 @d pen_offset_of 127 /* operation code for \.{penoffset} */
4894 @d arc_time_of 128 /* operation code for \.{arctime} */
4895 @d mp_version 129 /* operation code for \.{mpversion} */
4896 @d envelope_of 130 /* operation code for \.{envelope} */
4897
4898 @c static void mp_print_op (MP mp,quarterword c) { 
4899   if (c<=mp_numeric_type ) {
4900     mp_print_type(mp, c);
4901   } else {
4902     switch (c) {
4903     case true_code:mp_print(mp, "true"); break;
4904     case false_code:mp_print(mp, "false"); break;
4905     case null_picture_code:mp_print(mp, "nullpicture"); break;
4906     case null_pen_code:mp_print(mp, "nullpen"); break;
4907     case job_name_op:mp_print(mp, "jobname"); break;
4908     case read_string_op:mp_print(mp, "readstring"); break;
4909     case pen_circle:mp_print(mp, "pencircle"); break;
4910     case normal_deviate:mp_print(mp, "normaldeviate"); break;
4911     case read_from_op:mp_print(mp, "readfrom"); break;
4912     case close_from_op:mp_print(mp, "closefrom"); break;
4913     case odd_op:mp_print(mp, "odd"); break;
4914     case known_op:mp_print(mp, "known"); break;
4915     case unknown_op:mp_print(mp, "unknown"); break;
4916     case not_op:mp_print(mp, "not"); break;
4917     case decimal:mp_print(mp, "decimal"); break;
4918     case reverse:mp_print(mp, "reverse"); break;
4919     case make_path_op:mp_print(mp, "makepath"); break;
4920     case make_pen_op:mp_print(mp, "makepen"); break;
4921     case oct_op:mp_print(mp, "oct"); break;
4922     case hex_op:mp_print(mp, "hex"); break;
4923     case ASCII_op:mp_print(mp, "ASCII"); break;
4924     case char_op:mp_print(mp, "char"); break;
4925     case length_op:mp_print(mp, "length"); break;
4926     case turning_op:mp_print(mp, "turningnumber"); break;
4927     case x_part:mp_print(mp, "xpart"); break;
4928     case y_part:mp_print(mp, "ypart"); break;
4929     case xx_part:mp_print(mp, "xxpart"); break;
4930     case xy_part:mp_print(mp, "xypart"); break;
4931     case yx_part:mp_print(mp, "yxpart"); break;
4932     case yy_part:mp_print(mp, "yypart"); break;
4933     case red_part:mp_print(mp, "redpart"); break;
4934     case green_part:mp_print(mp, "greenpart"); break;
4935     case blue_part:mp_print(mp, "bluepart"); break;
4936     case cyan_part:mp_print(mp, "cyanpart"); break;
4937     case magenta_part:mp_print(mp, "magentapart"); break;
4938     case yellow_part:mp_print(mp, "yellowpart"); break;
4939     case black_part:mp_print(mp, "blackpart"); break;
4940     case grey_part:mp_print(mp, "greypart"); break;
4941     case color_model_part:mp_print(mp, "colormodel"); break;
4942     case font_part:mp_print(mp, "fontpart"); break;
4943     case text_part:mp_print(mp, "textpart"); break;
4944     case path_part:mp_print(mp, "pathpart"); break;
4945     case pen_part:mp_print(mp, "penpart"); break;
4946     case dash_part:mp_print(mp, "dashpart"); break;
4947     case sqrt_op:mp_print(mp, "sqrt"); break;
4948     case mp_m_exp_op:mp_print(mp, "mexp"); break;
4949     case mp_m_log_op:mp_print(mp, "mlog"); break;
4950     case sin_d_op:mp_print(mp, "sind"); break;
4951     case cos_d_op:mp_print(mp, "cosd"); break;
4952     case floor_op:mp_print(mp, "floor"); break;
4953     case uniform_deviate:mp_print(mp, "uniformdeviate"); break;
4954     case char_exists_op:mp_print(mp, "charexists"); break;
4955     case font_size:mp_print(mp, "fontsize"); break;
4956     case ll_corner_op:mp_print(mp, "llcorner"); break;
4957     case lr_corner_op:mp_print(mp, "lrcorner"); break;
4958     case ul_corner_op:mp_print(mp, "ulcorner"); break;
4959     case ur_corner_op:mp_print(mp, "urcorner"); break;
4960     case arc_length:mp_print(mp, "arclength"); break;
4961     case angle_op:mp_print(mp, "angle"); break;
4962     case cycle_op:mp_print(mp, "cycle"); break;
4963     case filled_op:mp_print(mp, "filled"); break;
4964     case stroked_op:mp_print(mp, "stroked"); break;
4965     case textual_op:mp_print(mp, "textual"); break;
4966     case clipped_op:mp_print(mp, "clipped"); break;
4967     case bounded_op:mp_print(mp, "bounded"); break;
4968     case plus:mp_print_char(mp, xord('+')); break;
4969     case minus:mp_print_char(mp, xord('-')); break;
4970     case times:mp_print_char(mp, xord('*')); break;
4971     case over:mp_print_char(mp, xord('/')); break;
4972     case pythag_add:mp_print(mp, "++"); break;
4973     case pythag_sub:mp_print(mp, "+-+"); break;
4974     case or_op:mp_print(mp, "or"); break;
4975     case and_op:mp_print(mp, "and"); break;
4976     case less_than:mp_print_char(mp, xord('<')); break;
4977     case less_or_equal:mp_print(mp, "<="); break;
4978     case greater_than:mp_print_char(mp, xord('>')); break;
4979     case greater_or_equal:mp_print(mp, ">="); break;
4980     case equal_to:mp_print_char(mp, xord('=')); break;
4981     case unequal_to:mp_print(mp, "<>"); break;
4982     case concatenate:mp_print(mp, "&"); break;
4983     case rotated_by:mp_print(mp, "rotated"); break;
4984     case slanted_by:mp_print(mp, "slanted"); break;
4985     case scaled_by:mp_print(mp, "scaled"); break;
4986     case shifted_by:mp_print(mp, "shifted"); break;
4987     case transformed_by:mp_print(mp, "transformed"); break;
4988     case x_scaled:mp_print(mp, "xscaled"); break;
4989     case y_scaled:mp_print(mp, "yscaled"); break;
4990     case z_scaled:mp_print(mp, "zscaled"); break;
4991     case in_font:mp_print(mp, "infont"); break;
4992     case intersect:mp_print(mp, "intersectiontimes"); break;
4993     case substring_of:mp_print(mp, "substring"); break;
4994     case subpath_of:mp_print(mp, "subpath"); break;
4995     case direction_time_of:mp_print(mp, "directiontime"); break;
4996     case point_of:mp_print(mp, "point"); break;
4997     case precontrol_of:mp_print(mp, "precontrol"); break;
4998     case postcontrol_of:mp_print(mp, "postcontrol"); break;
4999     case pen_offset_of:mp_print(mp, "penoffset"); break;
5000     case arc_time_of:mp_print(mp, "arctime"); break;
5001     case mp_version:mp_print(mp, "mpversion"); break;
5002     case envelope_of:mp_print(mp, "envelope"); break;
5003     default: mp_print(mp, ".."); break;
5004     }
5005   }
5006 }
5007
5008 @ \MP\ also has a bunch of internal parameters that a user might want to
5009 fuss with. Every such parameter has an identifying code number, defined here.
5010
5011 @<Types...@>=
5012 enum mp_given_internal {
5013   mp_tracing_titles=1, /* show titles online when they appear */
5014   mp_tracing_equations, /* show each variable when it becomes known */
5015   mp_tracing_capsules, /* show capsules too */
5016   mp_tracing_choices, /* show the control points chosen for paths */
5017   mp_tracing_specs, /* show path subdivision prior to filling with polygonal a pen */
5018   mp_tracing_commands, /* show commands and operations before they are performed */
5019   mp_tracing_restores, /* show when a variable or internal is restored */
5020   mp_tracing_macros, /* show macros before they are expanded */
5021   mp_tracing_output, /* show digitized edges as they are output */
5022   mp_tracing_stats, /* show memory usage at end of job */
5023   mp_tracing_lost_chars, /* show characters that aren't \&{infont} */
5024   mp_tracing_online, /* show long diagnostics on terminal and in the log file */
5025   mp_year, /* the current year (e.g., 1984) */
5026   mp_month, /* the current month (e.g., 3 $\equiv$ March) */
5027   mp_day, /* the current day of the month */
5028   mp_time, /* the number of minutes past midnight when this job started */
5029   mp_char_code, /* the number of the next character to be output */
5030   mp_char_ext, /* the extension code of the next character to be output */
5031   mp_char_wd, /* the width of the next character to be output */
5032   mp_char_ht, /* the height of the next character to be output */
5033   mp_char_dp, /* the depth of the next character to be output */
5034   mp_char_ic, /* the italic correction of the next character to be output */
5035   mp_design_size, /* the unit of measure used for |mp_char_wd..mp_char_ic|, in points */
5036   mp_pausing, /* positive to display lines on the terminal before they are read */
5037   mp_showstopping, /* positive to stop after each \&{show} command */
5038   mp_fontmaking, /* positive if font metric output is to be produced */
5039   mp_linejoin, /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */
5040   mp_linecap, /* as in \ps: 0 for butt, 1 for round, 2 for square */
5041   mp_miterlimit, /* controls miter length as in \ps */
5042   mp_warning_check, /* controls error message when variable value is large */
5043   mp_boundary_char, /* the right boundary character for ligatures */
5044   mp_prologues, /* positive to output conforming PostScript using built-in fonts */
5045   mp_true_corners, /* positive to make \&{llcorner} etc. ignore \&{setbounds} */
5046   mp_default_color_model, /* the default color model for unspecified items */
5047   mp_restore_clip_color,
5048   mp_procset, /* wether or not create PostScript command shortcuts */
5049   mp_gtroffmode  /* whether the user specified |-troff| on the command line */
5050 };
5051
5052 @
5053
5054 @d max_given_internal mp_gtroffmode
5055
5056 @<Glob...@>=
5057 scaled *internal;  /* the values of internal quantities */
5058 char **int_name;  /* their names */
5059 int int_ptr;  /* the maximum internal quantity defined so far */
5060 int max_internal; /* current maximum number of internal quantities */
5061
5062 @ @<Option variables@>=
5063 int troff_mode; 
5064
5065 @ @<Allocate or initialize ...@>=
5066 mp->max_internal=2*max_given_internal;
5067 mp->internal = xmalloc ((mp->max_internal+1), sizeof(scaled));
5068 memset(mp->internal,0,(mp->max_internal+1)* sizeof(scaled));
5069 mp->int_name = xmalloc ((mp->max_internal+1), sizeof(char *));
5070 memset(mp->int_name,0,(mp->max_internal+1) * sizeof(char *));
5071 mp->troff_mode=(opt->troff_mode>0 ? true : false);
5072
5073 @ @<Exported function ...@>=
5074 int mp_troff_mode(MP mp);
5075
5076 @ @c
5077 int mp_troff_mode(MP mp) { return mp->troff_mode; }
5078
5079 @ @<Set initial ...@>=
5080 mp->int_ptr=max_given_internal;
5081
5082 @ The symbolic names for internal quantities are put into \MP's hash table
5083 by using a routine called |primitive|, which will be defined later. Let us
5084 enter them now, so that we don't have to list all those names again
5085 anywhere else.
5086
5087 @<Put each of \MP's primitives into the hash table@>=
5088 mp_primitive(mp, "tracingtitles",internal_quantity,mp_tracing_titles);
5089 @:tracingtitles_}{\&{tracingtitles} primitive@>
5090 mp_primitive(mp, "tracingequations",internal_quantity,mp_tracing_equations);
5091 @:mp_tracing_equations_}{\&{tracingequations} primitive@>
5092 mp_primitive(mp, "tracingcapsules",internal_quantity,mp_tracing_capsules);
5093 @:mp_tracing_capsules_}{\&{tracingcapsules} primitive@>
5094 mp_primitive(mp, "tracingchoices",internal_quantity,mp_tracing_choices);
5095 @:mp_tracing_choices_}{\&{tracingchoices} primitive@>
5096 mp_primitive(mp, "tracingspecs",internal_quantity,mp_tracing_specs);
5097 @:mp_tracing_specs_}{\&{tracingspecs} primitive@>
5098 mp_primitive(mp, "tracingcommands",internal_quantity,mp_tracing_commands);
5099 @:mp_tracing_commands_}{\&{tracingcommands} primitive@>
5100 mp_primitive(mp, "tracingrestores",internal_quantity,mp_tracing_restores);
5101 @:mp_tracing_restores_}{\&{tracingrestores} primitive@>
5102 mp_primitive(mp, "tracingmacros",internal_quantity,mp_tracing_macros);
5103 @:mp_tracing_macros_}{\&{tracingmacros} primitive@>
5104 mp_primitive(mp, "tracingoutput",internal_quantity,mp_tracing_output);
5105 @:mp_tracing_output_}{\&{tracingoutput} primitive@>
5106 mp_primitive(mp, "tracingstats",internal_quantity,mp_tracing_stats);
5107 @:mp_tracing_stats_}{\&{tracingstats} primitive@>
5108 mp_primitive(mp, "tracinglostchars",internal_quantity,mp_tracing_lost_chars);
5109 @:mp_tracing_lost_chars_}{\&{tracinglostchars} primitive@>
5110 mp_primitive(mp, "tracingonline",internal_quantity,mp_tracing_online);
5111 @:mp_tracing_online_}{\&{tracingonline} primitive@>
5112 mp_primitive(mp, "year",internal_quantity,mp_year);
5113 @:mp_year_}{\&{year} primitive@>
5114 mp_primitive(mp, "month",internal_quantity,mp_month);
5115 @:mp_month_}{\&{month} primitive@>
5116 mp_primitive(mp, "day",internal_quantity,mp_day);
5117 @:mp_day_}{\&{day} primitive@>
5118 mp_primitive(mp, "time",internal_quantity,mp_time);
5119 @:time_}{\&{time} primitive@>
5120 mp_primitive(mp, "charcode",internal_quantity,mp_char_code);
5121 @:mp_char_code_}{\&{charcode} primitive@>
5122 mp_primitive(mp, "charext",internal_quantity,mp_char_ext);
5123 @:mp_char_ext_}{\&{charext} primitive@>
5124 mp_primitive(mp, "charwd",internal_quantity,mp_char_wd);
5125 @:mp_char_wd_}{\&{charwd} primitive@>
5126 mp_primitive(mp, "charht",internal_quantity,mp_char_ht);
5127 @:mp_char_ht_}{\&{charht} primitive@>
5128 mp_primitive(mp, "chardp",internal_quantity,mp_char_dp);
5129 @:mp_char_dp_}{\&{chardp} primitive@>
5130 mp_primitive(mp, "charic",internal_quantity,mp_char_ic);
5131 @:mp_char_ic_}{\&{charic} primitive@>
5132 mp_primitive(mp, "designsize",internal_quantity,mp_design_size);
5133 @:mp_design_size_}{\&{designsize} primitive@>
5134 mp_primitive(mp, "pausing",internal_quantity,mp_pausing);
5135 @:mp_pausing_}{\&{pausing} primitive@>
5136 mp_primitive(mp, "showstopping",internal_quantity,mp_showstopping);
5137 @:mp_showstopping_}{\&{showstopping} primitive@>
5138 mp_primitive(mp, "fontmaking",internal_quantity,mp_fontmaking);
5139 @:mp_fontmaking_}{\&{fontmaking} primitive@>
5140 mp_primitive(mp, "linejoin",internal_quantity,mp_linejoin);
5141 @:mp_linejoin_}{\&{linejoin} primitive@>
5142 mp_primitive(mp, "linecap",internal_quantity,mp_linecap);
5143 @:mp_linecap_}{\&{linecap} primitive@>
5144 mp_primitive(mp, "miterlimit",internal_quantity,mp_miterlimit);
5145 @:mp_miterlimit_}{\&{miterlimit} primitive@>
5146 mp_primitive(mp, "warningcheck",internal_quantity,mp_warning_check);
5147 @:mp_warning_check_}{\&{warningcheck} primitive@>
5148 mp_primitive(mp, "boundarychar",internal_quantity,mp_boundary_char);
5149 @:mp_boundary_char_}{\&{boundarychar} primitive@>
5150 mp_primitive(mp, "prologues",internal_quantity,mp_prologues);
5151 @:mp_prologues_}{\&{prologues} primitive@>
5152 mp_primitive(mp, "truecorners",internal_quantity,mp_true_corners);
5153 @:mp_true_corners_}{\&{truecorners} primitive@>
5154 mp_primitive(mp, "mpprocset",internal_quantity,mp_procset);
5155 @:mp_procset_}{\&{mpprocset} primitive@>
5156 mp_primitive(mp, "troffmode",internal_quantity,mp_gtroffmode);
5157 @:troffmode_}{\&{troffmode} primitive@>
5158 mp_primitive(mp, "defaultcolormodel",internal_quantity,mp_default_color_model);
5159 @:mp_default_color_model_}{\&{defaultcolormodel} primitive@>
5160 mp_primitive(mp, "restoreclipcolor",internal_quantity,mp_restore_clip_color);
5161 @:mp_restore_clip_color_}{\&{restoreclipcolor} primitive@>
5162
5163 @ Colors can be specified in four color models. In the special
5164 case of |no_model|, MetaPost does not output any color operator to
5165 the postscript output.
5166
5167 Note: these values are passed directly on to |with_option|. This only
5168 works because the other possible values passed to |with_option| are
5169 8 and 10 respectively (from |with_pen| and |with_picture|).
5170
5171 There is a first state, that is only used for |gs_colormodel|. It flags
5172 the fact that there has not been any kind of color specification by
5173 the user so far in the game.
5174
5175 @(mplib.h@>=
5176 enum mp_color_model {
5177   mp_no_model=1,
5178   mp_grey_model=3,
5179   mp_rgb_model=5,
5180   mp_cmyk_model=7,
5181   mp_uninitialized_model=9
5182 };
5183
5184
5185 @ @<Initialize table entries (done by \.{INIMP} only)@>=
5186 mp->internal[mp_default_color_model]=(mp_rgb_model*unity);
5187 mp->internal[mp_restore_clip_color]=unity;
5188
5189 @ Well, we do have to list the names one more time, for use in symbolic
5190 printouts.
5191
5192 @<Initialize table...@>=
5193 mp->int_name[mp_tracing_titles]=xstrdup("tracingtitles");
5194 mp->int_name[mp_tracing_equations]=xstrdup("tracingequations");
5195 mp->int_name[mp_tracing_capsules]=xstrdup("tracingcapsules");
5196 mp->int_name[mp_tracing_choices]=xstrdup("tracingchoices");
5197 mp->int_name[mp_tracing_specs]=xstrdup("tracingspecs");
5198 mp->int_name[mp_tracing_commands]=xstrdup("tracingcommands");
5199 mp->int_name[mp_tracing_restores]=xstrdup("tracingrestores");
5200 mp->int_name[mp_tracing_macros]=xstrdup("tracingmacros");
5201 mp->int_name[mp_tracing_output]=xstrdup("tracingoutput");
5202 mp->int_name[mp_tracing_stats]=xstrdup("tracingstats");
5203 mp->int_name[mp_tracing_lost_chars]=xstrdup("tracinglostchars");
5204 mp->int_name[mp_tracing_online]=xstrdup("tracingonline");
5205 mp->int_name[mp_year]=xstrdup("year");
5206 mp->int_name[mp_month]=xstrdup("month");
5207 mp->int_name[mp_day]=xstrdup("day");
5208 mp->int_name[mp_time]=xstrdup("time");
5209 mp->int_name[mp_char_code]=xstrdup("charcode");
5210 mp->int_name[mp_char_ext]=xstrdup("charext");
5211 mp->int_name[mp_char_wd]=xstrdup("charwd");
5212 mp->int_name[mp_char_ht]=xstrdup("charht");
5213 mp->int_name[mp_char_dp]=xstrdup("chardp");
5214 mp->int_name[mp_char_ic]=xstrdup("charic");
5215 mp->int_name[mp_design_size]=xstrdup("designsize");
5216 mp->int_name[mp_pausing]=xstrdup("pausing");
5217 mp->int_name[mp_showstopping]=xstrdup("showstopping");
5218 mp->int_name[mp_fontmaking]=xstrdup("fontmaking");
5219 mp->int_name[mp_linejoin]=xstrdup("linejoin");
5220 mp->int_name[mp_linecap]=xstrdup("linecap");
5221 mp->int_name[mp_miterlimit]=xstrdup("miterlimit");
5222 mp->int_name[mp_warning_check]=xstrdup("warningcheck");
5223 mp->int_name[mp_boundary_char]=xstrdup("boundarychar");
5224 mp->int_name[mp_prologues]=xstrdup("prologues");
5225 mp->int_name[mp_true_corners]=xstrdup("truecorners");
5226 mp->int_name[mp_default_color_model]=xstrdup("defaultcolormodel");
5227 mp->int_name[mp_procset]=xstrdup("mpprocset");
5228 mp->int_name[mp_gtroffmode]=xstrdup("troffmode");
5229 mp->int_name[mp_restore_clip_color]=xstrdup("restoreclipcolor");
5230
5231 @ The following procedure, which is called just before \MP\ initializes its
5232 input and output, establishes the initial values of the date and time.
5233 @^system dependencies@>
5234
5235 Note that the values are |scaled| integers. Hence \MP\ can no longer
5236 be used after the year 32767.
5237
5238 @c 
5239 static void mp_fix_date_and_time (MP mp) { 
5240   time_t aclock = time ((time_t *) 0);
5241   struct tm *tmptr = localtime (&aclock);
5242   mp->internal[mp_time]=
5243       (tmptr->tm_hour*60+tmptr->tm_min)*unity; /* minutes since midnight */
5244   mp->internal[mp_day]=(tmptr->tm_mday)*unity; /* fourth day of the month */
5245   mp->internal[mp_month]=(tmptr->tm_mon+1)*unity; /* seventh month of the year */
5246   mp->internal[mp_year]=(tmptr->tm_year+1900)*unity; /* Anno Domini */
5247 }
5248
5249 @ @<Declarations@>=
5250 static void mp_fix_date_and_time (MP mp) ;
5251
5252 @ \MP\ is occasionally supposed to print diagnostic information that
5253 goes only into the transcript file, unless |mp_tracing_online| is positive.
5254 Now that we have defined |mp_tracing_online| we can define
5255 two routines that adjust the destination of print commands:
5256
5257 @<Declarations@>=
5258 static void mp_begin_diagnostic (MP mp) ;
5259 static void mp_end_diagnostic (MP mp,boolean blank_line);
5260 static void mp_print_diagnostic (MP mp, const char *s, const char *t, boolean nuline) ;
5261
5262 @ @<Basic printing...@>=
5263 void mp_begin_diagnostic (MP mp) { /* prepare to do some tracing */
5264   mp->old_setting=mp->selector;
5265   if ((mp->internal[mp_tracing_online]<=0)&&(mp->selector==term_and_log)){ 
5266     decr(mp->selector);
5267     if ( mp->history==mp_spotless ) mp->history=mp_warning_issued;
5268   }
5269 }
5270 @#
5271 void mp_end_diagnostic (MP mp,boolean blank_line) {
5272   /* restore proper conditions after tracing */
5273   mp_print_nl(mp, "");
5274   if ( blank_line ) mp_print_ln(mp);
5275   mp->selector=mp->old_setting;
5276 }
5277
5278
5279
5280 @<Glob...@>=
5281 unsigned int old_setting;
5282
5283 @ We will occasionally use |begin_diagnostic| in connection with line-number
5284 printing, as follows. (The parameter |s| is typically |"Path"| or
5285 |"Cycle spec"|, etc.)
5286
5287 @<Basic printing...@>=
5288 void mp_print_diagnostic (MP mp, const char *s, const char *t, boolean nuline) { 
5289   mp_begin_diagnostic(mp);
5290   if ( nuline ) mp_print_nl(mp, s); else mp_print(mp, s);
5291   mp_print(mp, " at line "); 
5292   mp_print_int(mp, mp_true_line(mp));
5293   mp_print(mp, t); mp_print_char(mp, xord(':'));
5294 }
5295
5296 @ The 256 |ASCII_code| characters are grouped into classes by means of
5297 the |char_class| table. Individual class numbers have no semantic
5298 or syntactic significance, except in a few instances defined here.
5299 There's also |max_class|, which can be used as a basis for additional
5300 class numbers in nonstandard extensions of \MP.
5301
5302 @d digit_class 0 /* the class number of \.{0123456789} */
5303 @d period_class 1 /* the class number of `\..' */
5304 @d space_class 2 /* the class number of spaces and nonstandard characters */
5305 @d percent_class 3 /* the class number of `\.\%' */
5306 @d string_class 4 /* the class number of `\."' */
5307 @d right_paren_class 8 /* the class number of `\.)' */
5308 @d isolated_classes 5: case 6: case 7: case 8 /* characters that make length-one tokens only */
5309 @d letter_class 9 /* letters and the underline character */
5310 @d left_bracket_class 17 /* `\.[' */
5311 @d right_bracket_class 18 /* `\.]' */
5312 @d invalid_class 20 /* bad character in the input */
5313 @d max_class 20 /* the largest class number */
5314
5315 @<Glob...@>=
5316 int char_class[256]; /* the class numbers */
5317
5318 @ If changes are made to accommodate non-ASCII character sets, they should
5319 follow the guidelines in Appendix~C of {\sl The {\logos METAFONT\/}book}.
5320 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
5321 @^system dependencies@>
5322
5323 @<Set initial ...@>=
5324 for (k='0';k<='9';k++) 
5325   mp->char_class[k]=digit_class;
5326 mp->char_class['.']=period_class;
5327 mp->char_class[' ']=space_class;
5328 mp->char_class['%']=percent_class;
5329 mp->char_class['"']=string_class;
5330 mp->char_class[',']=5;
5331 mp->char_class[';']=6;
5332 mp->char_class['(']=7;
5333 mp->char_class[')']=right_paren_class;
5334 for (k='A';k<= 'Z';k++ )
5335   mp->char_class[k]=letter_class;
5336 for (k='a';k<='z';k++) 
5337   mp->char_class[k]=letter_class;
5338 mp->char_class['_']=letter_class;
5339 mp->char_class['<']=10;
5340 mp->char_class['=']=10;
5341 mp->char_class['>']=10;
5342 mp->char_class[':']=10;
5343 mp->char_class['|']=10;
5344 mp->char_class['`']=11;
5345 mp->char_class['\'']=11;
5346 mp->char_class['+']=12;
5347 mp->char_class['-']=12;
5348 mp->char_class['/']=13;
5349 mp->char_class['*']=13;
5350 mp->char_class['\\']=13;
5351 mp->char_class['!']=14;
5352 mp->char_class['?']=14;
5353 mp->char_class['#']=15;
5354 mp->char_class['&']=15;
5355 mp->char_class['@@']=15;
5356 mp->char_class['$']=15;
5357 mp->char_class['^']=16;
5358 mp->char_class['~']=16;
5359 mp->char_class['[']=left_bracket_class;
5360 mp->char_class[']']=right_bracket_class;
5361 mp->char_class['{']=19;
5362 mp->char_class['}']=19;
5363 for (k=0;k<' ';k++)
5364   mp->char_class[k]=invalid_class;
5365 mp->char_class['\t']=space_class;
5366 mp->char_class['\f']=space_class;
5367 for (k=127;k<=255;k++)
5368   mp->char_class[k]=invalid_class;
5369
5370 @* \[13] The hash table.
5371 Symbolic tokens are stored and retrieved by means of a fairly standard hash
5372 table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
5373 in {\sl The Art of Computer Programming\/}). Once a symbolic token enters the
5374 table, it is never removed.
5375
5376 The actual sequence of characters forming a symbolic token is
5377 stored in the |str_pool| array together with all the other strings. An
5378 auxiliary array |hash| consists of items with two halfword fields per
5379 word. The first of these, called |next(p)|, points to the next identifier
5380 belonging to the same coalesced list as the identifier corresponding to~|p|;
5381 and the other, called |text(p)|, points to the |str_start| entry for
5382 |p|'s identifier. If position~|p| of the hash table is empty, we have
5383 |text(p)=0|; if position |p| is either empty or the end of a coalesced
5384 hash list, we have |next(p)=0|.
5385
5386 An auxiliary pointer variable called |hash_used| is maintained in such a
5387 way that all locations |p>=hash_used| are nonempty. The global variable
5388 |st_count| tells how many symbolic tokens have been defined, if statistics
5389 are being kept.
5390
5391 The first 256 locations of |hash| are reserved for symbols of length one.
5392
5393 There's a parallel array called |eqtb| that contains the current equivalent
5394 values of each symbolic token. The entries of this array consist of
5395 two halfwords called |eq_type| (a command code) and |equiv| (a secondary
5396 piece of information that qualifies the |eq_type|).
5397
5398 @d next(A)   mp->hash[(A)].lh /* link for coalesced lists */
5399 @d text(A)   mp->hash[(A)].rh /* string number for symbolic token name */
5400 @d eq_type(A)   mp->eqtb[(A)].lh /* the current ``meaning'' of a symbolic token */
5401 @d equiv(A)   mp->eqtb[(A)].rh /* parametric part of a token's meaning */
5402 @d hash_base 257 /* hashing actually starts here */
5403 @d hash_is_full   (mp->hash_used==hash_base) /* are all positions occupied? */
5404
5405 @<Glob...@>=
5406 pointer hash_used; /* allocation pointer for |hash| */
5407 integer st_count; /* total number of known identifiers */
5408
5409 @ Certain entries in the hash table are ``frozen'' and not redefinable,
5410 since they are used in error recovery.
5411
5412 @d hash_top (integer)(hash_base+mp->hash_size) /* the first location of the frozen area */
5413 @d frozen_inaccessible hash_top /* |hash| location to protect the frozen area */
5414 @d frozen_repeat_loop (hash_top+1) /* |hash| location of a loop-repeat token */
5415 @d frozen_right_delimiter (hash_top+2) /* |hash| location of a permanent `\.)' */
5416 @d frozen_left_bracket (hash_top+3) /* |hash| location of a permanent `\.[' */
5417 @d frozen_slash (hash_top+4) /* |hash| location of a permanent `\./' */
5418 @d frozen_colon (hash_top+5) /* |hash| location of a permanent `\.:' */
5419 @d frozen_semicolon (hash_top+6) /* |hash| location of a permanent `\.;' */
5420 @d frozen_end_for (hash_top+7) /* |hash| location of a permanent \&{endfor} */
5421 @d frozen_end_def (hash_top+8) /* |hash| location of a permanent \&{enddef} */
5422 @d frozen_fi (hash_top+9) /* |hash| location of a permanent \&{fi} */
5423 @d frozen_end_group (hash_top+10) /* |hash| location of a permanent `\.{endgroup}' */
5424 @d frozen_etex (hash_top+11) /* |hash| location of a permanent \&{etex} */
5425 @d frozen_mpx_break (hash_top+12) /* |hash| location of a permanent \&{mpxbreak} */
5426 @d frozen_bad_vardef (hash_top+13) /* |hash| location of `\.{a bad variable}' */
5427 @d frozen_undefined (hash_top+14) /* |hash| location that never gets defined */
5428 @d hash_end (integer)(hash_top+14) /* the actual size of the |hash| and |eqtb| arrays */
5429
5430 @<Glob...@>=
5431 two_halves *hash; /* the hash table */
5432 two_halves *eqtb; /* the equivalents */
5433
5434 @ @<Allocate or initialize ...@>=
5435 mp->hash = xmalloc((hash_end+1),sizeof(two_halves));
5436 mp->eqtb = xmalloc((hash_end+1),sizeof(two_halves));
5437
5438 @ @<Dealloc variables@>=
5439 xfree(mp->hash);
5440 xfree(mp->eqtb);
5441
5442 @ @<Set init...@>=
5443 next(1)=0; text(1)=0; eq_type(1)=tag_token; equiv(1)=null;
5444 for (k=2;k<=hash_end;k++)  { 
5445   mp->hash[k]=mp->hash[1]; mp->eqtb[k]=mp->eqtb[1];
5446 }
5447
5448 @ @<Initialize table entries...@>=
5449 mp->hash_used=frozen_inaccessible; /* nothing is used */
5450 mp->st_count=0;
5451 text(frozen_bad_vardef)=intern("a bad variable");
5452 text(frozen_etex)=intern("etex");
5453 text(frozen_mpx_break)=intern("mpxbreak");
5454 text(frozen_fi)=intern("fi");
5455 text(frozen_end_group)=intern("endgroup");
5456 text(frozen_end_def)=intern("enddef");
5457 text(frozen_end_for)=intern("endfor");
5458 text(frozen_semicolon)=intern(";");
5459 text(frozen_colon)=intern(":");
5460 text(frozen_slash)=intern("/");
5461 text(frozen_left_bracket)=intern("[");
5462 text(frozen_right_delimiter)=intern(")");
5463 text(frozen_inaccessible)=intern(" INACCESSIBLE");
5464 eq_type(frozen_right_delimiter)=right_delimiter;
5465
5466 @ @<Check the ``constant'' values...@>=
5467 if ( hash_end+mp->max_internal>max_halfword ) mp->bad=17;
5468
5469 @ Here is the subroutine that searches the hash table for an identifier
5470 that matches a given string of length~|l| appearing in |buffer[j..
5471 (j+l-1)]|. If the identifier is not found, it is inserted; hence it
5472 will always be found, and the corresponding hash table address
5473 will be returned.
5474
5475 @c 
5476 static pointer mp_id_lookup (MP mp,integer j, integer l) { /* search the hash table */
5477   integer h; /* hash code */
5478   pointer p; /* index in |hash| array */
5479   pointer k; /* index in |buffer| array */
5480   if (l==1) {
5481     @<Treat special case of length 1 and |break|@>;
5482   }
5483   @<Compute the hash code |h|@>;
5484   p=h+hash_base; /* we start searching here; note that |0<=h<hash_prime| */
5485   while (true)  { 
5486         if (text(p)>0 && length(text(p))==l && mp_str_eq_buf(mp, text(p),j)) 
5487       break;
5488     if ( next(p)==0 ) {
5489       @<Insert a new symbolic token after |p|, then
5490         make |p| point to it and |break|@>;
5491     }
5492     p=next(p);
5493   }
5494   return p;
5495 }
5496
5497 @ @<Treat special case of length 1...@>=
5498  p=mp->buffer[j]+1; text(p)=p-1; return p;
5499
5500
5501 @ @<Insert a new symbolic...@>=
5502 {
5503 if ( text(p)>0 ) { 
5504   do {  
5505     if ( hash_is_full )
5506       mp_overflow(mp, "hash size",(integer)mp->hash_size);
5507 @:MetaPost capacity exceeded hash size}{\quad hash size@>
5508     decr(mp->hash_used);
5509   } while (text(mp->hash_used)!=0); /* search for an empty location in |hash| */
5510   next(p)=mp->hash_used; 
5511   p=mp->hash_used;
5512 }
5513 str_room(l);
5514 for (k=j;k<=j+l-1;k++) {
5515   append_char(mp->buffer[k]);
5516 }
5517 text(p)=mp_make_string(mp); 
5518 mp->str_ref[text(p)]=max_str_ref;
5519 incr(mp->st_count);
5520 break;
5521 }
5522
5523
5524 @ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
5525 should be a prime number.  The theory of hashing tells us to expect fewer
5526 than two table probes, on the average, when the search is successful.
5527 [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
5528 @^Vitter, Jeffrey Scott@>
5529
5530 @<Compute the hash code |h|@>=
5531 h=mp->buffer[j];
5532 for (k=j+1;k<=j+l-1;k++){ 
5533   h=h+h+mp->buffer[k];
5534   while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
5535 }
5536
5537 @ @<Search |eqtb| for equivalents equal to |p|@>=
5538 for (q=1;q<=hash_end;q++) { 
5539   if ( equiv(q)==p ) { 
5540     mp_print_nl(mp, "EQUIV("); 
5541     mp_print_int(mp, q); 
5542     mp_print_char(mp, xord(')'));
5543   }
5544 }
5545
5546 @ We need to put \MP's ``primitive'' symbolic tokens into the hash
5547 table, together with their command code (which will be the |eq_type|)
5548 and an operand (which will be the |equiv|). The |primitive| procedure
5549 does this, in a way that no \MP\ user can. The global value |cur_sym|
5550 contains the new |eqtb| pointer after |primitive| has acted.
5551
5552 @c 
5553 static void mp_primitive (MP mp, const char *ss, halfword c, halfword o) {
5554   pool_pointer k; /* index into |str_pool| */
5555   quarterword j; /* index into |buffer| */
5556   quarterword l; /* length of the string */
5557   str_number s;
5558   s = intern(ss);
5559   k=mp->str_start[s]; l=str_stop(s)-k;
5560   /* we will move |s| into the (empty) |buffer| */
5561   for (j=0;j<=l-1;j++) {
5562     mp->buffer[j]=mp->str_pool[k+j];
5563   }
5564   mp->cur_sym=mp_id_lookup(mp, 0,l);
5565   if ( s>=256 ) { /* we don't want to have the string twice */
5566     mp_flush_string(mp, text(mp->cur_sym)); text(mp->cur_sym)=s;
5567   };
5568   eq_type(mp->cur_sym)=c; 
5569   equiv(mp->cur_sym)=o;
5570 }
5571
5572
5573 @ Many of \MP's primitives need no |equiv|, since they are identifiable
5574 by their |eq_type| alone. These primitives are loaded into the hash table
5575 as follows:
5576
5577 @<Put each of \MP's primitives into the hash table@>=
5578 mp_primitive(mp, "..",path_join,0);
5579 @:.._}{\.{..} primitive@>
5580 mp_primitive(mp, "[",left_bracket,0); mp->eqtb[frozen_left_bracket]=mp->eqtb[mp->cur_sym];
5581 @:[ }{\.{[} primitive@>
5582 mp_primitive(mp, "]",right_bracket,0);
5583 @:] }{\.{]} primitive@>
5584 mp_primitive(mp, "}",right_brace,0);
5585 @:]]}{\.{\char`\}} primitive@>
5586 mp_primitive(mp, "{",left_brace,0);
5587 @:][}{\.{\char`\{} primitive@>
5588 mp_primitive(mp, ":",colon,0); mp->eqtb[frozen_colon]=mp->eqtb[mp->cur_sym];
5589 @:: }{\.{:} primitive@>
5590 mp_primitive(mp, "::",double_colon,0);
5591 @::: }{\.{::} primitive@>
5592 mp_primitive(mp, "||:",bchar_label,0);
5593 @:::: }{\.{\char'174\char'174:} primitive@>
5594 mp_primitive(mp, ":=",assignment,0);
5595 @::=_}{\.{:=} primitive@>
5596 mp_primitive(mp, ",",comma,0);
5597 @:, }{\., primitive@>
5598 mp_primitive(mp, ";",semicolon,0); mp->eqtb[frozen_semicolon]=mp->eqtb[mp->cur_sym];
5599 @:; }{\.; primitive@>
5600 mp_primitive(mp, "\\",relax,0);
5601 @:]]\\}{\.{\char`\\} primitive@>
5602 @#
5603 mp_primitive(mp, "addto",add_to_command,0);
5604 @:add_to_}{\&{addto} primitive@>
5605 mp_primitive(mp, "atleast",at_least,0);
5606 @:at_least_}{\&{atleast} primitive@>
5607 mp_primitive(mp, "begingroup",begin_group,0); mp->bg_loc=mp->cur_sym;
5608 @:begin_group_}{\&{begingroup} primitive@>
5609 mp_primitive(mp, "controls",controls,0);
5610 @:controls_}{\&{controls} primitive@>
5611 mp_primitive(mp, "curl",curl_command,0);
5612 @:curl_}{\&{curl} primitive@>
5613 mp_primitive(mp, "delimiters",delimiters,0);
5614 @:delimiters_}{\&{delimiters} primitive@>
5615 mp_primitive(mp, "endgroup",end_group,0);
5616  mp->eqtb[frozen_end_group]=mp->eqtb[mp->cur_sym]; mp->eg_loc=mp->cur_sym;
5617 @:endgroup_}{\&{endgroup} primitive@>
5618 mp_primitive(mp, "everyjob",every_job_command,0);
5619 @:every_job_}{\&{everyjob} primitive@>
5620 mp_primitive(mp, "exitif",exit_test,0);
5621 @:exit_if_}{\&{exitif} primitive@>
5622 mp_primitive(mp, "expandafter",expand_after,0);
5623 @:expand_after_}{\&{expandafter} primitive@>
5624 mp_primitive(mp, "interim",interim_command,0);
5625 @:interim_}{\&{interim} primitive@>
5626 mp_primitive(mp, "let",let_command,0);
5627 @:let_}{\&{let} primitive@>
5628 mp_primitive(mp, "newinternal",new_internal,0);
5629 @:new_internal_}{\&{newinternal} primitive@>
5630 mp_primitive(mp, "of",of_token,0);
5631 @:of_}{\&{of} primitive@>
5632 mp_primitive(mp, "randomseed",mp_random_seed,0);
5633 @:mp_random_seed_}{\&{randomseed} primitive@>
5634 mp_primitive(mp, "save",save_command,0);
5635 @:save_}{\&{save} primitive@>
5636 mp_primitive(mp, "scantokens",scan_tokens,0);
5637 @:scan_tokens_}{\&{scantokens} primitive@>
5638 mp_primitive(mp, "shipout",ship_out_command,0);
5639 @:ship_out_}{\&{shipout} primitive@>
5640 mp_primitive(mp, "skipto",skip_to,0);
5641 @:skip_to_}{\&{skipto} primitive@>
5642 mp_primitive(mp, "special",special_command,0);
5643 @:special}{\&{special} primitive@>
5644 mp_primitive(mp, "fontmapfile",special_command,1);
5645 @:fontmapfile}{\&{fontmapfile} primitive@>
5646 mp_primitive(mp, "fontmapline",special_command,2);
5647 @:fontmapline}{\&{fontmapline} primitive@>
5648 mp_primitive(mp, "step",step_token,0);
5649 @:step_}{\&{step} primitive@>
5650 mp_primitive(mp, "str",str_op,0);
5651 @:str_}{\&{str} primitive@>
5652 mp_primitive(mp, "tension",tension,0);
5653 @:tension_}{\&{tension} primitive@>
5654 mp_primitive(mp, "to",to_token,0);
5655 @:to_}{\&{to} primitive@>
5656 mp_primitive(mp, "until",until_token,0);
5657 @:until_}{\&{until} primitive@>
5658 mp_primitive(mp, "within",within_token,0);
5659 @:within_}{\&{within} primitive@>
5660 mp_primitive(mp, "write",write_command,0);
5661 @:write_}{\&{write} primitive@>
5662
5663 @ Each primitive has a corresponding inverse, so that it is possible to
5664 display the cryptic numeric contents of |eqtb| in symbolic form.
5665 Every call of |primitive| in this program is therefore accompanied by some
5666 straightforward code that forms part of the |print_cmd_mod| routine
5667 explained below.
5668
5669 @<Cases of |print_cmd_mod| for symbolic printing of primitives@>=
5670 case add_to_command:mp_print(mp, "addto"); break;
5671 case assignment:mp_print(mp, ":="); break;
5672 case at_least:mp_print(mp, "atleast"); break;
5673 case bchar_label:mp_print(mp, "||:"); break;
5674 case begin_group:mp_print(mp, "begingroup"); break;
5675 case colon:mp_print(mp, ":"); break;
5676 case comma:mp_print(mp, ","); break;
5677 case controls:mp_print(mp, "controls"); break;
5678 case curl_command:mp_print(mp, "curl"); break;
5679 case delimiters:mp_print(mp, "delimiters"); break;
5680 case double_colon:mp_print(mp, "::"); break;
5681 case end_group:mp_print(mp, "endgroup"); break;
5682 case every_job_command:mp_print(mp, "everyjob"); break;
5683 case exit_test:mp_print(mp, "exitif"); break;
5684 case expand_after:mp_print(mp, "expandafter"); break;
5685 case interim_command:mp_print(mp, "interim"); break;
5686 case left_brace:mp_print(mp, "{"); break;
5687 case left_bracket:mp_print(mp, "["); break;
5688 case let_command:mp_print(mp, "let"); break;
5689 case new_internal:mp_print(mp, "newinternal"); break;
5690 case of_token:mp_print(mp, "of"); break;
5691 case path_join:mp_print(mp, ".."); break;
5692 case mp_random_seed:mp_print(mp, "randomseed"); break;
5693 case relax:mp_print_char(mp, xord('\\')); break;
5694 case right_brace:mp_print_char(mp, xord('}')); break;
5695 case right_bracket:mp_print_char(mp, xord(']')); break;
5696 case save_command:mp_print(mp, "save"); break;
5697 case scan_tokens:mp_print(mp, "scantokens"); break;
5698 case semicolon:mp_print_char(mp, xord(';')); break;
5699 case ship_out_command:mp_print(mp, "shipout"); break;
5700 case skip_to:mp_print(mp, "skipto"); break;
5701 case special_command: if ( m==2 ) mp_print(mp, "fontmapline"); else
5702                  if ( m==1 ) mp_print(mp, "fontmapfile"); else
5703                  mp_print(mp, "special"); break;
5704 case step_token:mp_print(mp, "step"); break;
5705 case str_op:mp_print(mp, "str"); break;
5706 case tension:mp_print(mp, "tension"); break;
5707 case to_token:mp_print(mp, "to"); break;
5708 case until_token:mp_print(mp, "until"); break;
5709 case within_token:mp_print(mp, "within"); break;
5710 case write_command:mp_print(mp, "write"); break;
5711
5712 @ We will deal with the other primitives later, at some point in the program
5713 where their |eq_type| and |equiv| values are more meaningful.  For example,
5714 the primitives for macro definitions will be loaded when we consider the
5715 routines that define macros.
5716 It is easy to find where each particular
5717 primitive was treated by looking in the index at the end; for example, the
5718 section where |"def"| entered |eqtb| is listed under `\&{def} primitive'.
5719
5720 @* \[14] Token lists.
5721 A \MP\ token is either symbolic or numeric or a string, or it denotes
5722 a macro parameter or capsule; so there are five corresponding ways to encode it
5723 @^token@>
5724 internally: (1)~A symbolic token whose hash code is~|p|
5725 is represented by the number |p|, in the |info| field of a single-word
5726 node in~|mem|. (2)~A numeric token whose |scaled| value is~|v| is
5727 represented in a two-word node of~|mem|; the |type| field is |known|,
5728 the |name_type| field is |token|, and the |value| field holds~|v|.
5729 The fact that this token appears in a two-word node rather than a
5730 one-word node is, of course, clear from the node address.
5731 (3)~A string token is also represented in a two-word node; the |type|
5732 field is |mp_string_type|, the |name_type| field is |token|, and the
5733 |value| field holds the corresponding |str_number|.  (4)~Capsules have
5734 |name_type=capsule|, and their |type| and |value| fields represent
5735 arbitrary values (in ways to be explained later).  (5)~Macro parameters
5736 are like symbolic tokens in that they appear in |info| fields of
5737 one-word nodes. The $k$th parameter is represented by |expr_base+k| if it
5738 is of type \&{expr}, or by |suffix_base+k| if it is of type \&{suffix}, or
5739 by |text_base+k| if it is of type \&{text}.  (Here |0<=k<param_size|.)
5740 Actual values of these parameters are kept in a separate stack, as we will
5741 see later.  The constants |expr_base|, |suffix_base|, and |text_base| are,
5742 of course, chosen so that there will be no confusion between symbolic
5743 tokens and parameters of various types.
5744
5745 Note that
5746 the `\\{type}' field of a node has nothing to do with ``type'' in a
5747 printer's sense. It's curious that the same word is used in such different ways.
5748
5749 @d type(A)   mp->mem[(A)].hh.b0 /* identifies what kind of value this is */
5750 @d name_type(A)   mp->mem[(A)].hh.b1 /* a clue to the name of this value */
5751 @d token_node_size 2 /* the number of words in a large token node */
5752 @d value_loc(A) ((A)+1) /* the word that contains the |value| field */
5753 @d value(A) mp->mem[value_loc((A))].cint /* the value stored in a large token node */
5754 @d expr_base (hash_end+1) /* code for the zeroth \&{expr} parameter */
5755 @d suffix_base (expr_base+mp->param_size) /* code for the zeroth \&{suffix} parameter */
5756 @d text_base (suffix_base+mp->param_size) /* code for the zeroth \&{text} parameter */
5757
5758 @<Check the ``constant''...@>=
5759 if ( text_base+mp->param_size>max_halfword ) mp->bad=18;
5760
5761 @ We have set aside a two word node beginning at |null| so that we can have
5762 |value(null)=0|.  We will make use of this coincidence later.
5763
5764 @<Initialize table entries...@>=
5765 mp_link(null)=null; value(null)=0;
5766
5767 @ A numeric token is created by the following trivial routine.
5768
5769 @c 
5770 static pointer mp_new_num_tok (MP mp,scaled v) {
5771   pointer p; /* the new node */
5772   p=mp_get_node(mp, token_node_size); value(p)=v;
5773   type(p)=mp_known; name_type(p)=mp_token; 
5774   return p;
5775 }
5776
5777 @ A token list is a singly linked list of nodes in |mem|, where
5778 each node contains a token and a link.  Here's a subroutine that gets rid
5779 of a token list when it is no longer needed.
5780
5781 @c static void mp_flush_token_list (MP mp,pointer p) {
5782   pointer q; /* the node being recycled */
5783   while ( p!=null ) { 
5784     q=p; p=mp_link(p);
5785     if ( q>=mp->hi_mem_min ) {
5786      free_avail(q);
5787     } else { 
5788       switch (type(q)) {
5789       case mp_vacuous: case mp_boolean_type: case mp_known:
5790         break;
5791       case mp_string_type:
5792         delete_str_ref(value(q));
5793         break;
5794       case unknown_types: case mp_pen_type: case mp_path_type: 
5795       case mp_picture_type: case mp_pair_type: case mp_color_type:
5796       case mp_cmykcolor_type: case mp_transform_type: case mp_dependent:
5797       case mp_proto_dependent: case mp_independent:
5798         mp_recycle_value(mp,q);
5799         break;
5800       default: mp_confusion(mp, "token");
5801 @:this can't happen token}{\quad token@>
5802       }
5803       mp_free_node(mp, q,token_node_size);
5804     }
5805   }
5806 }
5807
5808 @ The procedure |show_token_list|, which prints a symbolic form of
5809 the token list that starts at a given node |p|, illustrates these
5810 conventions. The token list being displayed should not begin with a reference
5811 count. However, the procedure is intended to be fairly robust, so that if the
5812 memory links are awry or if |p| is not really a pointer to a token list,
5813 almost nothing catastrophic can happen.
5814
5815 An additional parameter |q| is also given; this parameter is either null
5816 or it points to a node in the token list where a certain magic computation
5817 takes place that will be explained later. (Basically, |q| is non-null when
5818 we are printing the two-line context information at the time of an error
5819 message; |q| marks the place corresponding to where the second line
5820 should begin.)
5821
5822 The generation will stop, and `\.{\char`\ ETC.}' will be printed, if the length
5823 of printing exceeds a given limit~|l|; the length of printing upon entry is
5824 assumed to be a given amount called |null_tally|. (Note that
5825 |show_token_list| sometimes uses itself recursively to print
5826 variable names within a capsule.)
5827 @^recursion@>
5828
5829 Unusual entries are printed in the form of all-caps tokens
5830 preceded by a space, e.g., `\.{\char`\ BAD}'.
5831
5832 @<Declarations@>=
5833 static void mp_show_token_list (MP mp, integer p, integer q, integer l,
5834                          integer null_tally) ;
5835
5836 @ @c
5837 void mp_show_token_list (MP mp, integer p, integer q, integer l,
5838                          integer null_tally) {
5839   quarterword class,c; /* the |char_class| of previous and new tokens */
5840   integer r,v; /* temporary registers */
5841   class=percent_class;
5842   mp->tally=null_tally;
5843   while ( (p!=null) && (mp->tally<l) ) { 
5844     if ( p==q ) 
5845       @<Do magic computation@>;
5846     @<Display token |p| and set |c| to its class;
5847       but |return| if there are problems@>;
5848     class=c; p=mp_link(p);
5849   }
5850   if ( p!=null ) 
5851      mp_print(mp, " ETC.");
5852 @.ETC@>
5853   return;
5854 }
5855
5856 @ @<Display token |p| and set |c| to its class...@>=
5857 c=letter_class; /* the default */
5858 if ( (p<0)||(p>mp->mem_end) ) { 
5859   mp_print(mp, " CLOBBERED"); return;
5860 @.CLOBBERED@>
5861 }
5862 if ( p<mp->hi_mem_min ) { 
5863   @<Display two-word token@>;
5864 } else { 
5865   r=info(p);
5866   if ( r>=expr_base ) {
5867      @<Display a parameter token@>;
5868   } else {
5869     if ( r<1 ) {
5870       if ( r==0 ) { 
5871         @<Display a collective subscript@>
5872       } else {
5873         mp_print(mp, " IMPOSSIBLE");
5874 @.IMPOSSIBLE@>
5875       }
5876     } else { 
5877       r=text(r);
5878       if ( (r<0)||(r>mp->max_str_ptr) ) {
5879         mp_print(mp, " NONEXISTENT");
5880 @.NONEXISTENT@>
5881       } else {
5882        @<Print string |r| as a symbolic token
5883         and set |c| to its class@>;
5884       }
5885     }
5886   }
5887 }
5888
5889 @ @<Display two-word token@>=
5890 if ( name_type(p)==mp_token ) {
5891   if ( type(p)==mp_known ) {
5892     @<Display a numeric token@>;
5893   } else if ( type(p)!=mp_string_type ) {
5894     mp_print(mp, " BAD");
5895 @.BAD@>
5896   } else { 
5897     mp_print_char(mp, xord('"')); mp_print_str(mp, value(p)); mp_print_char(mp, xord('"'));
5898     c=string_class;
5899   }
5900 } else if ((name_type(p)!=mp_capsule)||(type(p)<mp_vacuous)||(type(p)>mp_independent) ) {
5901   mp_print(mp, " BAD");
5902 } else { 
5903   mp_print_capsule(mp,p); c=right_paren_class;
5904 }
5905
5906 @ @<Display a numeric token@>=
5907 if ( class==digit_class ) 
5908   mp_print_char(mp, xord(' '));
5909 v=value(p);
5910 if ( v<0 ){ 
5911   if ( class==left_bracket_class ) 
5912     mp_print_char(mp, xord(' '));
5913   mp_print_char(mp, xord('[')); mp_print_scaled(mp, v); mp_print_char(mp, xord(']'));
5914   c=right_bracket_class;
5915 } else { 
5916   mp_print_scaled(mp, v); c=digit_class;
5917 }
5918
5919
5920 @ Strictly speaking, a genuine token will never have |info(p)=0|.
5921 But we will see later (in the |print_variable_name| routine) that
5922 it is convenient to let |info(p)=0| stand for `\.{[]}'.
5923
5924 @<Display a collective subscript@>=
5925 {
5926 if ( class==left_bracket_class ) 
5927   mp_print_char(mp, xord(' '));
5928 mp_print(mp, "[]"); c=right_bracket_class;
5929 }
5930
5931 @ @<Display a parameter token@>=
5932 {
5933 if ( r<suffix_base ) { 
5934   mp_print(mp, "(EXPR"); r=r-(expr_base);
5935 @.EXPR@>
5936 } else if ( r<text_base ) { 
5937   mp_print(mp, "(SUFFIX"); r=r-(suffix_base);
5938 @.SUFFIX@>
5939 } else { 
5940   mp_print(mp, "(TEXT"); r=r-(text_base);
5941 @.TEXT@>
5942 }
5943 mp_print_int(mp, r); mp_print_char(mp, xord(')')); c=right_paren_class;
5944 }
5945
5946
5947 @ @<Print string |r| as a symbolic token...@>=
5948
5949 c=mp->char_class[mp->str_pool[mp->str_start[r]]];
5950 if ( c==class ) {
5951   switch (c) {
5952   case letter_class:mp_print_char(mp, xord('.')); break;
5953   case isolated_classes: break;
5954   default: mp_print_char(mp, xord(' ')); break;
5955   }
5956 }
5957 mp_print_str(mp, r);
5958 }
5959
5960 @ @<Declarations@>=
5961 static void mp_print_capsule (MP mp, pointer p);
5962
5963 @ @<Declare miscellaneous procedures that were declared |forward|@>=
5964 void mp_print_capsule (MP mp, pointer p) { 
5965   mp_print_char(mp, xord('(')); mp_print_exp(mp,p,0); mp_print_char(mp, xord(')'));
5966 }
5967
5968 @ Macro definitions are kept in \MP's memory in the form of token lists
5969 that have a few extra one-word nodes at the beginning.
5970
5971 The first node contains a reference count that is used to tell when the
5972 list is no longer needed. To emphasize the fact that a reference count is
5973 present, we shall refer to the |info| field of this special node as the
5974 |ref_count| field.
5975 @^reference counts@>
5976
5977 The next node or nodes after the reference count serve to describe the
5978 formal parameters. They consist of zero or more parameter tokens followed
5979 by a code for the type of macro.
5980
5981 @d ref_count info
5982   /* reference count preceding a macro definition or picture header */
5983 @d add_mac_ref(A) incr(ref_count((A))) /* make a new reference to a macro list */
5984 @d general_macro 0 /* preface to a macro defined with a parameter list */
5985 @d primary_macro 1 /* preface to a macro with a \&{primary} parameter */
5986 @d secondary_macro 2 /* preface to a macro with a \&{secondary} parameter */
5987 @d tertiary_macro 3 /* preface to a macro with a \&{tertiary} parameter */
5988 @d expr_macro 4 /* preface to a macro with an undelimited \&{expr} parameter */
5989 @d of_macro 5 /* preface to a macro with
5990   undelimited `\&{expr} |x| \&{of}~|y|' parameters */
5991 @d suffix_macro 6 /* preface to a macro with an undelimited \&{suffix} parameter */
5992 @d text_macro 7 /* preface to a macro with an undelimited \&{text} parameter */
5993
5994 @c 
5995 static void mp_delete_mac_ref (MP mp,pointer p) {
5996   /* |p| points to the reference count of a macro list that is
5997     losing one reference */
5998   if ( ref_count(p)==null ) mp_flush_token_list(mp, p);
5999   else decr(ref_count(p));
6000 }
6001
6002 @ The following subroutine displays a macro, given a pointer to its
6003 reference count.
6004
6005 @c 
6006 static void mp_show_macro (MP mp, pointer p, integer q, integer l) {
6007   pointer r; /* temporary storage */
6008   p=mp_link(p); /* bypass the reference count */
6009   while ( info(p)>text_macro ){ 
6010     r=mp_link(p); mp_link(p)=null;
6011     mp_show_token_list(mp, p,null,l,0); mp_link(p)=r; p=r;
6012     if ( l>0 ) l=l-mp->tally; else return;
6013   } /* control printing of `\.{ETC.}' */
6014 @.ETC@>
6015   mp->tally=0;
6016   switch(info(p)) {
6017   case general_macro:mp_print(mp, "->"); break;
6018 @.->@>
6019   case primary_macro: case secondary_macro: case tertiary_macro:
6020     mp_print_char(mp, xord('<'));
6021     mp_print_cmd_mod(mp, param_type,info(p)); 
6022     mp_print(mp, ">->");
6023     break;
6024   case expr_macro:mp_print(mp, "<expr>->"); break;
6025   case of_macro:mp_print(mp, "<expr>of<primary>->"); break;
6026   case suffix_macro:mp_print(mp, "<suffix>->"); break;
6027   case text_macro:mp_print(mp, "<text>->"); break;
6028   } /* there are no other cases */
6029   mp_show_token_list(mp, mp_link(p),q,l-mp->tally,0);
6030 }
6031
6032 @* \[15] Data structures for variables.
6033 The variables of \MP\ programs can be simple, like `\.x', or they can
6034 combine the structural properties of arrays and records, like `\.{x20a.b}'.
6035 A \MP\ user assigns a type to a variable like \.{x20a.b} by saying, for
6036 example, `\.{boolean} \.{x[]a.b}'. It's time for us to study how such
6037 things are represented inside of the computer.
6038
6039 Each variable value occupies two consecutive words, either in a two-word
6040 node called a value node, or as a two-word subfield of a larger node.  One
6041 of those two words is called the |value| field; it is an integer,
6042 containing either a |scaled| numeric value or the representation of some
6043 other type of quantity. (It might also be subdivided into halfwords, in
6044 which case it is referred to by other names instead of |value|.) The other
6045 word is broken into subfields called |type|, |name_type|, and |link|.  The
6046 |type| field is a quarterword that specifies the variable's type, and
6047 |name_type| is a quarterword from which \MP\ can reconstruct the
6048 variable's name (sometimes by using the |link| field as well).  Thus, only
6049 1.25 words are actually devoted to the value itself; the other
6050 three-quarters of a word are overhead, but they aren't wasted because they
6051 allow \MP\ to deal with sparse arrays and to provide meaningful diagnostics.
6052
6053 In this section we shall be concerned only with the structural aspects of
6054 variables, not their values. Later parts of the program will change the
6055 |type| and |value| fields, but we shall treat those fields as black boxes
6056 whose contents should not be touched.
6057
6058 However, if the |type| field is |mp_structured|, there is no |value| field,
6059 and the second word is broken into two pointer fields called |attr_head|
6060 and |subscr_head|. Those fields point to additional nodes that
6061 contain structural information, as we shall see.
6062
6063 @d subscr_head_loc(A)   (A)+1 /* where |value|, |subscr_head| and |attr_head| are */
6064 @d attr_head(A)   info(subscr_head_loc((A))) /* pointer to attribute info */
6065 @d subscr_head(A)   mp_link(subscr_head_loc((A))) /* pointer to subscript info */
6066 @d value_node_size 2 /* the number of words in a value node */
6067
6068 @ An attribute node is three words long. Two of these words contain |type|
6069 and |value| fields as described above, and the third word contains
6070 additional information:  There is an |attr_loc| field, which contains the
6071 hash address of the token that names this attribute; and there's also a
6072 |parent| field, which points to the value node of |mp_structured| type at the
6073 next higher level (i.e., at the level to which this attribute is
6074 subsidiary).  The |name_type| in an attribute node is `|attr|'.  The
6075 |link| field points to the next attribute with the same parent; these are
6076 arranged in increasing order, so that |attr_loc(mp_link(p))>attr_loc(p)|. The
6077 final attribute node links to the constant |end_attr|, whose |attr_loc|
6078 field is greater than any legal hash address. The |attr_head| in the
6079 parent points to a node whose |name_type| is |mp_structured_root|; this
6080 node represents the null attribute, i.e., the variable that is relevant
6081 when no attributes are attached to the parent. The |attr_head| node
6082 has the fields of either
6083 a value node, a subscript node, or an attribute node, depending on what
6084 the parent would be if it were not structured; but the subscript and
6085 attribute fields are ignored, so it effectively contains only the data of
6086 a value node. The |link| field in this special node points to an attribute
6087 node whose |attr_loc| field is zero; the latter node represents a collective
6088 subscript `\.{[]}' attached to the parent, and its |link| field points to
6089 the first non-special attribute node (or to |end_attr| if there are none).
6090
6091 A subscript node likewise occupies three words, with |type| and |value| fields
6092 plus extra information; its |name_type| is |subscr|. In this case the
6093 third word is called the |subscript| field, which is a |scaled| integer.
6094 The |link| field points to the subscript node with the next larger
6095 subscript, if any; otherwise the |link| points to the attribute node
6096 for collective subscripts at this level. We have seen that the latter node
6097 contains an upward pointer, so that the parent can be deduced.
6098
6099 The |name_type| in a parent-less value node is |root|, and the |link|
6100 is the hash address of the token that names this value.
6101
6102 In other words, variables have a hierarchical structure that includes
6103 enough threads running around so that the program is able to move easily
6104 between siblings, parents, and children. An example should be helpful:
6105 (The reader is advised to draw a picture while reading the following
6106 description, since that will help to firm up the ideas.)
6107 Suppose that `\.x' and `\.{x.a}' and `\.{x[]b}' and `\.{x5}'
6108 and `\.{x20b}' have been mentioned in a user's program, where
6109 \.{x[]b} has been declared to be of \&{boolean} type. Let |h(x)|, |h(a)|,
6110 and |h(b)| be the hash addresses of \.x, \.a, and~\.b. Then
6111 |eq_type(h(x))=name| and |equiv(h(x))=p|, where |p|~is a two-word value
6112 node with |name_type(p)=root| and |mp_link(p)=h(x)|. We have |type(p)=mp_structured|,
6113 |attr_head(p)=q|, and |subscr_head(p)=r|, where |q| points to a value
6114 node and |r| to a subscript node. (Are you still following this? Use
6115 a pencil to draw a diagram.) The lone variable `\.x' is represented by
6116 |type(q)| and |value(q)|; furthermore
6117 |name_type(q)=mp_structured_root| and |mp_link(q)=q1|, where |q1| points
6118 to an attribute node representing `\.{x[]}'. Thus |name_type(q1)=attr|,
6119 |attr_loc(q1)=collective_subscript=0|, |parent(q1)=p|,
6120 |type(q1)=mp_structured|, |attr_head(q1)=qq|, and |subscr_head(q1)=qq1|;
6121 |qq| is a  three-word ``attribute-as-value'' node with |type(qq)=numeric_type|
6122 (assuming that \.{x5} is numeric, because |qq| represents `\.{x[]}' 
6123 with no further attributes), |name_type(qq)=structured_root|, 
6124 |attr_loc(qq)=0|, |parent(qq)=p|, and
6125 |mp_link(qq)=qq1|. (Now pay attention to the next part.) Node |qq1| is
6126 an attribute node representing `\.{x[][]}', which has never yet
6127 occurred; its |type| field is |undefined|, and its |value| field is
6128 undefined. We have |name_type(qq1)=attr|, |attr_loc(qq1)=collective_subscript|,
6129 |parent(qq1)=q1|, and |mp_link(qq1)=qq2|. Since |qq2| represents
6130 `\.{x[]b}', |type(qq2)=mp_unknown_boolean|; also |attr_loc(qq2)=h(b)|,
6131 |parent(qq2)=q1|, |name_type(qq2)=attr|, |mp_link(qq2)=end_attr|.
6132 (Maybe colored lines will help untangle your picture.)
6133  Node |r| is a subscript node with |type| and |value|
6134 representing `\.{x5}'; |name_type(r)=subscr|, |subscript(r)=5.0|,
6135 and |mp_link(r)=r1| is another subscript node. To complete the picture,
6136 see if you can guess what |mp_link(r1)| is; give up? It's~|q1|.
6137 Furthermore |subscript(r1)=20.0|, |name_type(r1)=subscr|,
6138 |type(r1)=mp_structured|, |attr_head(r1)=qqq|, |subscr_head(r1)=qqq1|,
6139 and we finish things off with three more nodes
6140 |qqq|, |qqq1|, and |qqq2| hung onto~|r1|. (Perhaps you should start again
6141 with a larger sheet of paper.) The value of variable \.{x20b}
6142 appears in node~|qqq2|, as you can well imagine.
6143
6144 If the example in the previous paragraph doesn't make things crystal
6145 clear, a glance at some of the simpler subroutines below will reveal how
6146 things work out in practice.
6147
6148 The only really unusual thing about these conventions is the use of
6149 collective subscript attributes. The idea is to avoid repeating a lot of
6150 type information when many elements of an array are identical macros
6151 (for which distinct values need not be stored) or when they don't have
6152 all of the possible attributes. Branches of the structure below collective
6153 subscript attributes do not carry actual values except for macro identifiers;
6154 branches of the structure below subscript nodes do not carry significant
6155 information in their collective subscript attributes.
6156
6157 @d attr_loc_loc(A) ((A)+2) /* where the |attr_loc| and |parent| fields are */
6158 @d attr_loc(A) info(attr_loc_loc((A))) /* hash address of this attribute */
6159 @d parent(A) mp_link(attr_loc_loc((A))) /* pointer to |mp_structured| variable */
6160 @d subscript_loc(A) ((A)+2) /* where the |subscript| field lives */
6161 @d subscript(A) mp->mem[subscript_loc((A))].sc /* subscript of this variable */
6162 @d attr_node_size 3 /* the number of words in an attribute node */
6163 @d subscr_node_size 3 /* the number of words in a subscript node */
6164 @d collective_subscript 0 /* code for the attribute `\.{[]}' */
6165
6166 @<Initialize table...@>=
6167 attr_loc(end_attr)=hash_end+1; parent(end_attr)=null;
6168
6169 @ Variables of type \&{pair} will have values that point to four-word
6170 nodes containing two numeric values. The first of these values has
6171 |name_type=mp_x_part_sector| and the second has |name_type=mp_y_part_sector|;
6172 the |link| in the first points back to the node whose |value| points
6173 to this four-word node.
6174
6175 Variables of type \&{transform} are similar, but in this case their
6176 |value| points to a 12-word node containing six values, identified by
6177 |x_part_sector|, |y_part_sector|, |mp_xx_part_sector|, |mp_xy_part_sector|,
6178 |mp_yx_part_sector|, and |mp_yy_part_sector|.
6179 Finally, variables of type \&{color} have 3~values in 6~words
6180 identified by |mp_red_part_sector|, |mp_green_part_sector|, and |mp_blue_part_sector|.
6181
6182 When an entire structured variable is saved, the |root| indication
6183 is temporarily replaced by |saved_root|.
6184
6185 Some variables have no name; they just are used for temporary storage
6186 while expressions are being evaluated. We call them {\sl capsules}.
6187
6188 @d x_part_loc(A) (A) /* where the \&{xpart} is found in a pair or transform node */
6189 @d y_part_loc(A) ((A)+2) /* where the \&{ypart} is found in a pair or transform node */
6190 @d xx_part_loc(A) ((A)+4) /* where the \&{xxpart} is found in a transform node */
6191 @d xy_part_loc(A) ((A)+6) /* where the \&{xypart} is found in a transform node */
6192 @d yx_part_loc(A) ((A)+8) /* where the \&{yxpart} is found in a transform node */
6193 @d yy_part_loc(A) ((A)+10) /* where the \&{yypart} is found in a transform node */
6194 @d red_part_loc(A) (A) /* where the \&{redpart} is found in a color node */
6195 @d green_part_loc(A) ((A)+2) /* where the \&{greenpart} is found in a color node */
6196 @d blue_part_loc(A) ((A)+4) /* where the \&{bluepart} is found in a color node */
6197 @d cyan_part_loc(A) (A) /* where the \&{cyanpart} is found in a color node */
6198 @d magenta_part_loc(A) ((A)+2) /* where the \&{magentapart} is found in a color node */
6199 @d yellow_part_loc(A) ((A)+4) /* where the \&{yellowpart} is found in a color node */
6200 @d black_part_loc(A) ((A)+6) /* where the \&{blackpart} is found in a color node */
6201 @d grey_part_loc(A) (A) /* where the \&{greypart} is found in a color node */
6202 @#
6203 @d pair_node_size 4 /* the number of words in a pair node */
6204 @d transform_node_size 12 /* the number of words in a transform node */
6205 @d color_node_size 6 /* the number of words in a color node */
6206 @d cmykcolor_node_size 8 /* the number of words in a color node */
6207
6208 @<Glob...@>=
6209 quarterword big_node_size[mp_pair_type+1];
6210 quarterword sector0[mp_pair_type+1];
6211 quarterword sector_offset[mp_black_part_sector+1];
6212
6213 @ The |sector0| array gives for each big node type, |name_type| values
6214 for its first subfield; the |sector_offset| array gives for each
6215 |name_type| value, the offset from the first subfield in words;
6216 and the |big_node_size| array gives the size in words for each type of
6217 big node.
6218
6219 @<Set init...@>=
6220 mp->big_node_size[mp_transform_type]=transform_node_size;
6221 mp->big_node_size[mp_pair_type]=pair_node_size;
6222 mp->big_node_size[mp_color_type]=color_node_size;
6223 mp->big_node_size[mp_cmykcolor_type]=cmykcolor_node_size;
6224 mp->sector0[mp_transform_type]=mp_x_part_sector;
6225 mp->sector0[mp_pair_type]=mp_x_part_sector;
6226 mp->sector0[mp_color_type]=mp_red_part_sector;
6227 mp->sector0[mp_cmykcolor_type]=mp_cyan_part_sector;
6228 for (k=mp_x_part_sector;k<= mp_yy_part_sector;k++ ) {
6229   mp->sector_offset[k]=2*(k-mp_x_part_sector);
6230 }
6231 for (k=mp_red_part_sector;k<= mp_blue_part_sector ; k++) {
6232   mp->sector_offset[k]=2*(k-mp_red_part_sector);
6233 }
6234 for (k=mp_cyan_part_sector;k<= mp_black_part_sector;k++ ) {
6235   mp->sector_offset[k]=2*(k-mp_cyan_part_sector);
6236 }
6237
6238 @ If |type(p)=mp_pair_type| or |mp_transform_type| and if |value(p)=null|, the
6239 procedure call |init_big_node(p)| will allocate a pair or transform node
6240 for~|p|.  The individual parts of such nodes are initially of type
6241 |mp_independent|.
6242
6243 @c 
6244 static void mp_init_big_node (MP mp,pointer p) {
6245   pointer q; /* the new node */
6246   quarterword s; /* its size */
6247   s=mp->big_node_size[type(p)]; q=mp_get_node(mp, s);
6248   do {  
6249     s=s-2; 
6250     @<Make variable |q+s| newly independent@>;
6251     name_type(q+s)=halfp(s)+mp->sector0[type(p)]; 
6252     mp_link(q+s)=null;
6253   } while (s!=0);
6254   mp_link(q)=p; value(p)=q;
6255 }
6256
6257 @ The |id_transform| function creates a capsule for the
6258 identity transformation.
6259
6260 @c 
6261 static pointer mp_id_transform (MP mp) {
6262   pointer p,q,r; /* list manipulation registers */
6263   p=mp_get_node(mp, value_node_size); type(p)=mp_transform_type;
6264   name_type(p)=mp_capsule; value(p)=null; mp_init_big_node(mp, p); q=value(p);
6265   r=q+transform_node_size;
6266   do {  
6267     r=r-2;
6268     type(r)=mp_known; value(r)=0;
6269   } while (r!=q);
6270   value(xx_part_loc(q))=unity; 
6271   value(yy_part_loc(q))=unity;
6272   return p;
6273 }
6274
6275 @ Tokens are of type |tag_token| when they first appear, but they point
6276 to |null| until they are first used as the root of a variable.
6277 The following subroutine establishes the root node on such grand occasions.
6278
6279 @c 
6280 static void mp_new_root (MP mp,pointer x) {
6281   pointer p; /* the new node */
6282   p=mp_get_node(mp, value_node_size); type(p)=undefined; name_type(p)=mp_root;
6283   mp_link(p)=x; equiv(x)=p;
6284 }
6285
6286 @ These conventions for variable representation are illustrated by the
6287 |print_variable_name| routine, which displays the full name of a
6288 variable given only a pointer to its two-word value packet.
6289
6290 @<Declarations@>=
6291 static void mp_print_variable_name (MP mp, pointer p);
6292
6293 @ @c 
6294 void mp_print_variable_name (MP mp, pointer p) {
6295   pointer q; /* a token list that will name the variable's suffix */
6296   pointer r; /* temporary for token list creation */
6297   while ( name_type(p)>=mp_x_part_sector ) {
6298     @<Preface the output with a part specifier; |return| in the
6299       case of a capsule@>;
6300   }
6301   q=null;
6302   while ( name_type(p)>mp_saved_root ) {
6303     @<Ascend one level, pushing a token onto list |q|
6304      and replacing |p| by its parent@>;
6305   }
6306   r=mp_get_avail(mp); info(r)=mp_link(p); mp_link(r)=q;
6307   if ( name_type(p)==mp_saved_root ) mp_print(mp, "(SAVED)");
6308 @.SAVED@>
6309   mp_show_token_list(mp, r,null,el_gordo,mp->tally); 
6310   mp_flush_token_list(mp, r);
6311 }
6312
6313 @ @<Ascend one level, pushing a token onto list |q|...@>=
6314
6315   if ( name_type(p)==mp_subscr ) { 
6316     r=mp_new_num_tok(mp, subscript(p));
6317     do {  
6318       p=mp_link(p);
6319     } while (name_type(p)!=mp_attr);
6320   } else if ( name_type(p)==mp_structured_root ) {
6321     p=mp_link(p); goto FOUND;
6322   } else { 
6323     if ( name_type(p)!=mp_attr ) mp_confusion(mp, "var");
6324 @:this can't happen var}{\quad var@>
6325     r=mp_get_avail(mp); info(r)=attr_loc(p);
6326   }
6327   mp_link(r)=q; q=r;
6328 FOUND:  
6329   p=parent(p);
6330 }
6331
6332 @ @<Preface the output with a part specifier...@>=
6333 { switch (name_type(p)) {
6334   case mp_x_part_sector: mp_print_char(mp, xord('x')); break;
6335   case mp_y_part_sector: mp_print_char(mp, xord('y')); break;
6336   case mp_xx_part_sector: mp_print(mp, "xx"); break;
6337   case mp_xy_part_sector: mp_print(mp, "xy"); break;
6338   case mp_yx_part_sector: mp_print(mp, "yx"); break;
6339   case mp_yy_part_sector: mp_print(mp, "yy"); break;
6340   case mp_red_part_sector: mp_print(mp, "red"); break;
6341   case mp_green_part_sector: mp_print(mp, "green"); break;
6342   case mp_blue_part_sector: mp_print(mp, "blue"); break;
6343   case mp_cyan_part_sector: mp_print(mp, "cyan"); break;
6344   case mp_magenta_part_sector: mp_print(mp, "magenta"); break;
6345   case mp_yellow_part_sector: mp_print(mp, "yellow"); break;
6346   case mp_black_part_sector: mp_print(mp, "black"); break;
6347   case mp_grey_part_sector: mp_print(mp, "grey"); break;
6348   case mp_capsule: 
6349     mp_print(mp, "%CAPSULE"); mp_print_int(mp, p-null); return;
6350     break;
6351 @.CAPSULE@>
6352   } /* there are no other cases */
6353   mp_print(mp, "part "); 
6354   p=mp_link(p-mp->sector_offset[name_type(p)]);
6355 }
6356
6357 @ The |interesting| function returns |true| if a given variable is not
6358 in a capsule, or if the user wants to trace capsules.
6359
6360 @c 
6361 static boolean mp_interesting (MP mp,pointer p) {
6362   quarterword t; /* a |name_type| */
6363   if ( mp->internal[mp_tracing_capsules]>0 ) {
6364     return true;
6365   } else { 
6366     t=name_type(p);
6367     if ( t>=mp_x_part_sector ) if ( t!=mp_capsule )
6368       t=name_type(mp_link(p-mp->sector_offset[t]));
6369     return (t!=mp_capsule);
6370   }
6371 }
6372
6373 @ Now here is a subroutine that converts an unstructured type into an
6374 equivalent structured type, by inserting a |mp_structured| node that is
6375 capable of growing. This operation is done only when |name_type(p)=root|,
6376 |subscr|, or |attr|.
6377
6378 The procedure returns a pointer to the new node that has taken node~|p|'s
6379 place in the structure. Node~|p| itself does not move, nor are its
6380 |value| or |type| fields changed in any way.
6381
6382 @c 
6383 static pointer mp_new_structure (MP mp,pointer p) {
6384   pointer q,r=0; /* list manipulation registers */
6385   switch (name_type(p)) {
6386   case mp_root: 
6387     q=mp_link(p); r=mp_get_node(mp, value_node_size); equiv(q)=r;
6388     break;
6389   case mp_subscr: 
6390     @<Link a new subscript node |r| in place of node |p|@>;
6391     break;
6392   case mp_attr: 
6393     @<Link a new attribute node |r| in place of node |p|@>;
6394     break;
6395   default: 
6396     mp_confusion(mp, "struct");
6397 @:this can't happen struct}{\quad struct@>
6398     break;
6399   }
6400   mp_link(r)=mp_link(p); type(r)=mp_structured; name_type(r)=name_type(p);
6401   attr_head(r)=p; name_type(p)=mp_structured_root;
6402   q=mp_get_node(mp, attr_node_size); mp_link(p)=q; subscr_head(r)=q;
6403   parent(q)=r; type(q)=undefined; name_type(q)=mp_attr; mp_link(q)=end_attr;
6404   attr_loc(q)=collective_subscript; 
6405   return r;
6406 }
6407
6408 @ @<Link a new subscript node |r| in place of node |p|@>=
6409
6410   q=p;
6411   do {  
6412     q=mp_link(q);
6413   } while (name_type(q)!=mp_attr);
6414   q=parent(q); r=subscr_head_loc(q); /* |mp_link(r)=subscr_head(q)| */
6415   do {  
6416     q=r; r=mp_link(r);
6417   } while (r!=p);
6418   r=mp_get_node(mp, subscr_node_size);
6419   mp_link(q)=r; subscript(r)=subscript(p);
6420 }
6421
6422 @ If the attribute is |collective_subscript|, there are two pointers to
6423 node~|p|, so we must change both of them.
6424
6425 @<Link a new attribute node |r| in place of node |p|@>=
6426
6427   q=parent(p); r=attr_head(q);
6428   do {  
6429     q=r; r=mp_link(r);
6430   } while (r!=p);
6431   r=mp_get_node(mp, attr_node_size); mp_link(q)=r;
6432   mp->mem[attr_loc_loc(r)]=mp->mem[attr_loc_loc(p)]; /* copy |attr_loc| and |parent| */
6433   if ( attr_loc(p)==collective_subscript ) { 
6434     q=subscr_head_loc(parent(p));
6435     while ( mp_link(q)!=p ) q=mp_link(q);
6436     mp_link(q)=r;
6437   }
6438 }
6439
6440 @ The |find_variable| routine is given a pointer~|t| to a nonempty token
6441 list of suffixes; it returns a pointer to the corresponding two-word
6442 value. For example, if |t| points to token \.x followed by a numeric
6443 token containing the value~7, |find_variable| finds where the value of
6444 \.{x7} is stored in memory. This may seem a simple task, and it
6445 usually is, except when \.{x7} has never been referenced before.
6446 Indeed, \.x may never have even been subscripted before; complexities
6447 arise with respect to updating the collective subscript information.
6448
6449 If a macro type is detected anywhere along path~|t|, or if the first
6450 item on |t| isn't a |tag_token|, the value |null| is returned.
6451 Otherwise |p| will be a non-null pointer to a node such that
6452 |undefined<type(p)<mp_structured|.
6453
6454 @d abort_find { return null; }
6455
6456 @c 
6457 static pointer mp_find_variable (MP mp,pointer t) {
6458   pointer p,q,r,s; /* nodes in the ``value'' line */
6459   pointer pp,qq,rr,ss; /* nodes in the ``collective'' line */
6460   integer n; /* subscript or attribute */
6461   memory_word save_word; /* temporary storage for a word of |mem| */
6462 @^inner loop@>
6463   p=info(t); t=mp_link(t);
6464   if ( (eq_type(p) % outer_tag) != tag_token ) abort_find;
6465   if ( equiv(p)==null ) mp_new_root(mp, p);
6466   p=equiv(p); pp=p;
6467   while ( t!=null ) { 
6468     @<Make sure that both nodes |p| and |pp| are of |mp_structured| type@>;
6469     if ( t<mp->hi_mem_min ) {
6470       @<Descend one level for the subscript |value(t)|@>
6471     } else {
6472       @<Descend one level for the attribute |info(t)|@>;
6473     }
6474     t=mp_link(t);
6475   }
6476   if ( type(pp)>=mp_structured ) {
6477     if ( type(pp)==mp_structured ) pp=attr_head(pp); else abort_find;
6478   }
6479   if ( type(p)==mp_structured ) p=attr_head(p);
6480   if ( type(p)==undefined ) { 
6481     if ( type(pp)==undefined ) { type(pp)=mp_numeric_type; value(pp)=null; };
6482     type(p)=type(pp); value(p)=null;
6483   };
6484   return p;
6485 }
6486
6487 @ Although |pp| and |p| begin together, they diverge when a subscript occurs;
6488 |pp|~stays in the collective line while |p|~goes through actual subscript
6489 values.
6490
6491 @<Make sure that both nodes |p| and |pp|...@>=
6492 if ( type(pp)!=mp_structured ) { 
6493   if ( type(pp)>mp_structured ) abort_find;
6494   ss=mp_new_structure(mp, pp);
6495   if ( p==pp ) p=ss;
6496   pp=ss;
6497 }; /* now |type(pp)=mp_structured| */
6498 if ( type(p)!=mp_structured ) /* it cannot be |>mp_structured| */
6499   p=mp_new_structure(mp, p) /* now |type(p)=mp_structured| */
6500
6501 @ We want this part of the program to be reasonably fast, in case there are
6502 @^inner loop@>
6503 lots of subscripts at the same level of the data structure. Therefore
6504 we store an ``infinite'' value in the word that appears at the end of the
6505 subscript list, even though that word isn't part of a subscript node.
6506
6507 @<Descend one level for the subscript |value(t)|@>=
6508
6509   n=value(t);
6510   pp=mp_link(attr_head(pp)); /* now |attr_loc(pp)=collective_subscript| */
6511   q=mp_link(attr_head(p)); save_word=mp->mem[subscript_loc(q)];
6512   subscript(q)=el_gordo; s=subscr_head_loc(p); /* |mp_link(s)=subscr_head(p)| */
6513   do {  
6514     r=s; s=mp_link(s);
6515   } while (n>subscript(s));
6516   if ( n==subscript(s) ) {
6517     p=s;
6518   } else { 
6519     p=mp_get_node(mp, subscr_node_size); mp_link(r)=p; mp_link(p)=s;
6520     subscript(p)=n; name_type(p)=mp_subscr; type(p)=undefined;
6521   }
6522   mp->mem[subscript_loc(q)]=save_word;
6523 }
6524
6525 @ @<Descend one level for the attribute |info(t)|@>=
6526
6527   n=info(t);
6528   ss=attr_head(pp);
6529   do {  
6530     rr=ss; ss=mp_link(ss);
6531   } while (n>attr_loc(ss));
6532   if ( n<attr_loc(ss) ) { 
6533     qq=mp_get_node(mp, attr_node_size); mp_link(rr)=qq; mp_link(qq)=ss;
6534     attr_loc(qq)=n; name_type(qq)=mp_attr; type(qq)=undefined;
6535     parent(qq)=pp; ss=qq;
6536   }
6537   if ( p==pp ) { 
6538     p=ss; pp=ss;
6539   } else { 
6540     pp=ss; s=attr_head(p);
6541     do {  
6542       r=s; s=mp_link(s);
6543     } while (n>attr_loc(s));
6544     if ( n==attr_loc(s) ) {
6545       p=s;
6546     } else { 
6547       q=mp_get_node(mp, attr_node_size); mp_link(r)=q; mp_link(q)=s;
6548       attr_loc(q)=n; name_type(q)=mp_attr; type(q)=undefined;
6549       parent(q)=p; p=q;
6550     }
6551   }
6552 }
6553
6554 @ Variables lose their former values when they appear in a type declaration,
6555 or when they are defined to be macros or \&{let} equal to something else.
6556 A subroutine will be defined later that recycles the storage associated
6557 with any particular |type| or |value|; our goal now is to study a higher
6558 level process called |flush_variable|, which selectively frees parts of a
6559 variable structure.
6560
6561 This routine has some complexity because of examples such as
6562 `\hbox{\tt numeric x[]a[]b}'
6563 which recycles all variables of the form \.{x[i]a[j]b} (and no others), while
6564 `\hbox{\tt vardef x[]a[]=...}'
6565 discards all variables of the form \.{x[i]a[j]} followed by an arbitrary
6566 suffix, except for the collective node \.{x[]a[]} itself. The obvious way
6567 to handle such examples is to use recursion; so that's what we~do.
6568 @^recursion@>
6569
6570 Parameter |p| points to the root information of the variable;
6571 parameter |t| points to a list of one-word nodes that represent
6572 suffixes, with |info=collective_subscript| for subscripts.
6573
6574 @<Declarations@>=
6575 static void mp_flush_cur_exp (MP mp,scaled v) ;
6576
6577 @ @c 
6578 static void mp_flush_variable (MP mp,pointer p, pointer t, boolean discard_suffixes) {
6579   pointer q,r; /* list manipulation */
6580   halfword n; /* attribute to match */
6581   while ( t!=null ) { 
6582     if ( type(p)!=mp_structured ) return;
6583     n=info(t); t=mp_link(t);
6584     if ( n==collective_subscript ) { 
6585       r=subscr_head_loc(p); q=mp_link(r); /* |q=subscr_head(p)| */
6586       while ( name_type(q)==mp_subscr ){ 
6587         mp_flush_variable(mp, q,t,discard_suffixes);
6588         if ( t==null ) {
6589           if ( type(q)==mp_structured ) r=q;
6590           else  { mp_link(r)=mp_link(q); mp_free_node(mp, q,subscr_node_size);   }
6591         } else {
6592           r=q;
6593         }
6594         q=mp_link(r);
6595       }
6596     }
6597     p=attr_head(p);
6598     do {  
6599       r=p; p=mp_link(p);
6600     } while (attr_loc(p)<n);
6601     if ( attr_loc(p)!=n ) return;
6602   }
6603   if ( discard_suffixes ) {
6604     mp_flush_below_variable(mp, p);
6605   } else { 
6606     if ( type(p)==mp_structured ) p=attr_head(p);
6607     mp_recycle_value(mp, p);
6608   }
6609 }
6610
6611 @ The next procedure is simpler; it wipes out everything but |p| itself,
6612 which becomes undefined.
6613
6614 @<Declarations@>=
6615 static void mp_flush_below_variable (MP mp, pointer p);
6616
6617 @ @c
6618 void mp_flush_below_variable (MP mp,pointer p) {
6619    pointer q,r; /* list manipulation registers */
6620   if ( type(p)!=mp_structured ) {
6621     mp_recycle_value(mp, p); /* this sets |type(p)=undefined| */
6622   } else { 
6623     q=subscr_head(p);
6624     while ( name_type(q)==mp_subscr ) { 
6625       mp_flush_below_variable(mp, q); r=q; q=mp_link(q);
6626       mp_free_node(mp, r,subscr_node_size);
6627     }
6628     r=attr_head(p); q=mp_link(r); mp_recycle_value(mp, r);
6629     if ( name_type(p)<=mp_saved_root ) mp_free_node(mp, r,value_node_size);
6630     else mp_free_node(mp, r,subscr_node_size);
6631     /* we assume that |subscr_node_size=attr_node_size| */
6632     do {  
6633       mp_flush_below_variable(mp, q); r=q; q=mp_link(q); mp_free_node(mp, r,attr_node_size);
6634     } while (q!=end_attr);
6635     type(p)=undefined;
6636   }
6637 }
6638
6639 @ Just before assigning a new value to a variable, we will recycle the
6640 old value and make the old value undefined. The |und_type| routine
6641 determines what type of undefined value should be given, based on
6642 the current type before recycling.
6643
6644 @c 
6645 static quarterword mp_und_type (MP mp,pointer p) { 
6646   switch (type(p)) {
6647   case undefined: case mp_vacuous:
6648     return undefined;
6649   case mp_boolean_type: case mp_unknown_boolean:
6650     return mp_unknown_boolean;
6651   case mp_string_type: case mp_unknown_string:
6652     return mp_unknown_string;
6653   case mp_pen_type: case mp_unknown_pen:
6654     return mp_unknown_pen;
6655   case mp_path_type: case mp_unknown_path:
6656     return mp_unknown_path;
6657   case mp_picture_type: case mp_unknown_picture:
6658     return mp_unknown_picture;
6659   case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
6660   case mp_pair_type: case mp_numeric_type: 
6661     return type(p);
6662   case mp_known: case mp_dependent: case mp_proto_dependent: case mp_independent:
6663     return mp_numeric_type;
6664   } /* there are no other cases */
6665   return 0;
6666 }
6667
6668 @ The |clear_symbol| routine is used when we want to redefine the equivalent
6669 of a symbolic token. It must remove any variable structure or macro
6670 definition that is currently attached to that symbol. If the |saving|
6671 parameter is true, a subsidiary structure is saved instead of destroyed.
6672
6673 @c 
6674 static void mp_clear_symbol (MP mp,pointer p, boolean saving) {
6675   pointer q; /* |equiv(p)| */
6676   q=equiv(p);
6677   switch (eq_type(p) % outer_tag)  {
6678   case defined_macro:
6679   case secondary_primary_macro:
6680   case tertiary_secondary_macro:
6681   case expression_tertiary_macro: 
6682     if ( ! saving ) mp_delete_mac_ref(mp, q);
6683     break;
6684   case tag_token:
6685     if ( q!=null ) {
6686       if ( saving ) {
6687         name_type(q)=mp_saved_root;
6688       } else { 
6689         mp_flush_below_variable(mp, q); 
6690             mp_free_node(mp,q,value_node_size); 
6691       }
6692     }
6693     break;
6694   default:
6695     break;
6696   }
6697   mp->eqtb[p]=mp->eqtb[frozen_undefined];
6698 }
6699
6700 @* \[16] Saving and restoring equivalents.
6701 The nested structure given by \&{begingroup} and \&{endgroup}
6702 allows |eqtb| entries to be saved and restored, so that temporary changes
6703 can be made without difficulty.  When the user requests a current value to
6704 be saved, \MP\ puts that value into its ``save stack.'' An appearance of
6705 \&{endgroup} ultimately causes the old values to be removed from the save
6706 stack and put back in their former places.
6707
6708 The save stack is a linked list containing three kinds of entries,
6709 distinguished by their |info| fields. If |p| points to a saved item,
6710 then
6711
6712 \smallskip\hang
6713 |info(p)=0| stands for a group boundary; each \&{begingroup} contributes
6714 such an item to the save stack and each \&{endgroup} cuts back the stack
6715 until the most recent such entry has been removed.
6716
6717 \smallskip\hang
6718 |info(p)=q|, where |1<=q<=hash_end|, means that |mem[p+1]| holds the former
6719 contents of |eqtb[q]|. Such save stack entries are generated by \&{save}
6720 commands.
6721
6722 \smallskip\hang
6723 |info(p)=hash_end+q|, where |q>0|, means that |value(p)| is a |scaled|
6724 integer to be restored to internal parameter number~|q|. Such entries
6725 are generated by \&{interim} commands.
6726
6727 \smallskip\noindent
6728 The global variable |save_ptr| points to the top item on the save stack.
6729
6730 @d save_node_size 2 /* number of words per non-boundary save-stack node */
6731 @d saved_equiv(A) mp->mem[(A)+1].hh /* where an |eqtb| entry gets saved */
6732 @d save_boundary_item(A) { (A)=mp_get_avail(mp); info((A))=0;
6733   mp_link((A))=mp->save_ptr; mp->save_ptr=(A);
6734   }
6735
6736 @<Glob...@>=
6737 pointer save_ptr; /* the most recently saved item */
6738
6739 @ @<Set init...@>=mp->save_ptr=null;
6740
6741 @ The |save_variable| routine is given a hash address |q|; it salts this
6742 address in the save stack, together with its current equivalent,
6743 then makes token~|q| behave as though it were brand new.
6744
6745 Nothing is stacked when |save_ptr=null|, however; there's no way to remove
6746 things from the stack when the program is not inside a group, so there's
6747 no point in wasting the space.
6748
6749 @c 
6750 static void mp_save_variable (MP mp,pointer q) {
6751   pointer p; /* temporary register */
6752   if ( mp->save_ptr!=null ){ 
6753     p=mp_get_node(mp, save_node_size); info(p)=q; mp_link(p)=mp->save_ptr;
6754     saved_equiv(p)=mp->eqtb[q]; mp->save_ptr=p;
6755   }
6756   mp_clear_symbol(mp, q,(mp->save_ptr!=null));
6757 }
6758
6759 @ Similarly, |save_internal| is given the location |q| of an internal
6760 quantity like |mp_tracing_pens|. It creates a save stack entry of the
6761 third kind.
6762
6763 @c 
6764 static void mp_save_internal (MP mp,halfword q) {
6765   pointer p; /* new item for the save stack */
6766   if ( mp->save_ptr!=null ){ 
6767      p=mp_get_node(mp, save_node_size); info(p)=hash_end+q;
6768     mp_link(p)=mp->save_ptr; value(p)=mp->internal[q]; mp->save_ptr=p;
6769   }
6770 }
6771
6772 @ At the end of a group, the |unsave| routine restores all of the saved
6773 equivalents in reverse order. This routine will be called only when there
6774 is at least one boundary item on the save stack.
6775
6776 @c 
6777 static void mp_unsave (MP mp) {
6778   pointer q; /* index to saved item */
6779   pointer p; /* temporary register */
6780   while ( info(mp->save_ptr)!=0 ) {
6781     q=info(mp->save_ptr);
6782     if ( q>hash_end ) {
6783       if ( mp->internal[mp_tracing_restores]>0 ) {
6784         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6785         mp_print(mp, mp->int_name[q-(hash_end)]); mp_print_char(mp, xord('='));
6786         mp_print_scaled(mp, value(mp->save_ptr)); mp_print_char(mp, xord('}'));
6787         mp_end_diagnostic(mp, false);
6788       }
6789       mp->internal[q-(hash_end)]=value(mp->save_ptr);
6790     } else { 
6791       if ( mp->internal[mp_tracing_restores]>0 ) {
6792         mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
6793         mp_print_text(q); mp_print_char(mp, xord('}'));
6794         mp_end_diagnostic(mp, false);
6795       }
6796       mp_clear_symbol(mp, q,false);
6797       mp->eqtb[q]=saved_equiv(mp->save_ptr);
6798       if ( eq_type(q) % outer_tag==tag_token ) {
6799         p=equiv(q);
6800         if ( p!=null ) name_type(p)=mp_root;
6801       }
6802     }
6803     p=mp_link(mp->save_ptr); 
6804     mp_free_node(mp, mp->save_ptr,save_node_size); mp->save_ptr=p;
6805   }
6806   p=mp_link(mp->save_ptr); free_avail(mp->save_ptr); mp->save_ptr=p;
6807 }
6808
6809 @* \[17] Data structures for paths.
6810 When a \MP\ user specifies a path, \MP\ will create a list of knots
6811 and control points for the associated cubic spline curves. If the
6812 knots are $z_0$, $z_1$, \dots, $z_n$, there are control points
6813 $z_k^+$ and $z_{k+1}^-$ such that the cubic splines between knots
6814 $z_k$ and $z_{k+1}$ are defined by B\'ezier's formula
6815 @:Bezier}{B\'ezier, Pierre Etienne@>
6816 $$\eqalign{z(t)&=B(z_k,z_k^+,z_{k+1}^-,z_{k+1};t)\cr
6817 &=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_{k+1}^-+t^3z_{k+1}\cr}$$
6818 for |0<=t<=1|.
6819
6820 There is a 8-word node for each knot $z_k$, containing one word of
6821 control information and six words for the |x| and |y| coordinates of
6822 $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears in the
6823 |left_type| and |right_type| fields, which each occupy a quarter of
6824 the first word in the node; they specify properties of the curve as it
6825 enters and leaves the knot. There's also a halfword |link| field,
6826 which points to the following knot, and a final supplementary word (of
6827 which only a quarter is used).
6828
6829 If the path is a closed contour, knots 0 and |n| are identical;
6830 i.e., the |link| in knot |n-1| points to knot~0. But if the path
6831 is not closed, the |left_type| of knot~0 and the |right_type| of knot~|n|
6832 are equal to |endpoint|. In the latter case the |link| in knot~|n| points
6833 to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used.
6834
6835 @d left_type(A)   mp->mem[(A)].hh.b0 /* characterizes the path entering this knot */
6836 @d right_type(A)   mp->mem[(A)].hh.b1 /* characterizes the path leaving this knot */
6837 @d x_coord(A)   mp->mem[(A)+1].sc /* the |x| coordinate of this knot */
6838 @d y_coord(A)   mp->mem[(A)+2].sc /* the |y| coordinate of this knot */
6839 @d left_x(A)   mp->mem[(A)+3].sc /* the |x| coordinate of previous control point */
6840 @d left_y(A)   mp->mem[(A)+4].sc /* the |y| coordinate of previous control point */
6841 @d right_x(A)   mp->mem[(A)+5].sc /* the |x| coordinate of next control point */
6842 @d right_y(A)   mp->mem[(A)+6].sc /* the |y| coordinate of next control point */
6843 @d x_loc(A)   ((A)+1) /* where the |x| coordinate is stored in a knot */
6844 @d y_loc(A)   ((A)+2) /* where the |y| coordinate is stored in a knot */
6845 @d knot_coord(A)   mp->mem[(A)].sc /* |x| or |y| coordinate given |x_loc| or |y_loc| */
6846 @d left_coord(A)   mp->mem[(A)+2].sc
6847   /* coordinate of previous control point given |x_loc| or |y_loc| */
6848 @d right_coord(A)   mp->mem[(A)+4].sc
6849   /* coordinate of next control point given |x_loc| or |y_loc| */
6850 @d knot_node_size 8 /* number of words in a knot node */
6851
6852 @(mplib.h@>=
6853 enum mp_knot_type {
6854  mp_endpoint=0, /* |left_type| at path beginning and |right_type| at path end */
6855  mp_explicit, /* |left_type| or |right_type| when control points are known */
6856  mp_given, /* |left_type| or |right_type| when a direction is given */
6857  mp_curl, /* |left_type| or |right_type| when a curl is desired */
6858  mp_open, /* |left_type| or |right_type| when \MP\ should choose the direction */
6859  mp_end_cycle
6860 };
6861
6862 @ Before the B\'ezier control points have been calculated, the memory
6863 space they will ultimately occupy is taken up by information that can be
6864 used to compute them. There are four cases:
6865
6866 \yskip
6867 \textindent{$\bullet$} If |right_type=mp_open|, the curve should leave
6868 the knot in the same direction it entered; \MP\ will figure out a
6869 suitable direction.
6870
6871 \yskip
6872 \textindent{$\bullet$} If |right_type=mp_curl|, the curve should leave the
6873 knot in a direction depending on the angle at which it enters the next
6874 knot and on the curl parameter stored in |right_curl|.
6875
6876 \yskip
6877 \textindent{$\bullet$} If |right_type=mp_given|, the curve should leave the
6878 knot in a nonzero direction stored as an |angle| in |right_given|.
6879
6880 \yskip
6881 \textindent{$\bullet$} If |right_type=mp_explicit|, the B\'ezier control
6882 point for leaving this knot has already been computed; it is in the
6883 |right_x| and |right_y| fields.
6884
6885 \yskip\noindent
6886 The rules for |left_type| are similar, but they refer to the curve entering
6887 the knot, and to \\{left} fields instead of \\{right} fields.
6888
6889 Non-|explicit| control points will be chosen based on ``tension'' parameters
6890 in the |left_tension| and |right_tension| fields. The
6891 `\&{atleast}' option is represented by negative tension values.
6892 @:at_least_}{\&{atleast} primitive@>
6893
6894 For example, the \MP\ path specification
6895 $$\.{z0..z1..tension atleast 1..\{curl 2\}z2..z3\{-1,-2\}..tension
6896   3 and 4..p},$$
6897 where \.p is the path `\.{z4..controls z45 and z54..z5}', will be represented
6898 by the six knots
6899 \def\lodash{\hbox to 1.1em{\thinspace\hrulefill\thinspace}}
6900 $$\vbox{\halign{#\hfil&&\qquad#\hfil\cr
6901 |left_type|&\\{left} info&|x_coord,y_coord|&|right_type|&\\{right} info\cr
6902 \noalign{\yskip}
6903 |endpoint|&\lodash$,\,$\lodash&$x_0,y_0$&|curl|&$1.0,1.0$\cr
6904 |open|&\lodash$,1.0$&$x_1,y_1$&|open|&\lodash$,-1.0$\cr
6905 |curl|&$2.0,-1.0$&$x_2,y_2$&|curl|&$2.0,1.0$\cr
6906 |given|&$d,1.0$&$x_3,y_3$&|given|&$d,3.0$\cr
6907 |open|&\lodash$,4.0$&$x_4,y_4$&|explicit|&$x_{45},y_{45}$\cr
6908 |explicit|&$x_{54},y_{54}$&$x_5,y_5$&|endpoint|&\lodash$,\,$\lodash\cr}}$$
6909 Here |d| is the |angle| obtained by calling |n_arg(-unity,-two)|.
6910 Of course, this example is more complicated than anything a normal user
6911 would ever write.
6912
6913 These types must satisfy certain restrictions because of the form of \MP's
6914 path syntax:
6915 (i)~|open| type never appears in the same node together with |endpoint|,
6916 |given|, or |curl|.
6917 (ii)~The |right_type| of a node is |explicit| if and only if the
6918 |left_type| of the following node is |explicit|.
6919 (iii)~|endpoint| types occur only at the ends, as mentioned above.
6920
6921 @d left_curl left_x /* curl information when entering this knot */
6922 @d left_given left_x /* given direction when entering this knot */
6923 @d left_tension left_y /* tension information when entering this knot */
6924 @d right_curl right_x /* curl information when leaving this knot */
6925 @d right_given right_x /* given direction when leaving this knot */
6926 @d right_tension right_y /* tension information when leaving this knot */
6927
6928 @ Knots can be user-supplied, or they can be created by program code,
6929 like the |split_cubic| function, or |copy_path|. The distinction is
6930 needed for the cleanup routine that runs after |split_cubic|, because
6931 it should only delete knots it has previously inserted, and never
6932 anything that was user-supplied. In order to be able to differentiate
6933 one knot from another, we will set |originator(p):=mp_metapost_user| when
6934 it appeared in the actual metapost program, and
6935 |originator(p):=mp_program_code| in all other cases.
6936
6937 @d originator(A)   mp->mem[(A)+7].hh.b0 /* the creator of this knot */
6938
6939 @<Types...@>=
6940 enum {
6941   mp_program_code=0, /* not created by a user */
6942   mp_metapost_user /* created by a user */
6943 };
6944
6945 @ Here is a routine that prints a given knot list
6946 in symbolic form. It illustrates the conventions discussed above,
6947 and checks for anomalies that might arise while \MP\ is being debugged.
6948
6949 @<Declarations@>=
6950 static void mp_pr_path (MP mp,pointer h);
6951
6952 @ @c
6953 void mp_pr_path (MP mp,pointer h) {
6954   pointer p,q; /* for list traversal */
6955   p=h;
6956   do {  
6957     q=mp_link(p);
6958     if ( (p==null)||(q==null) ) { 
6959       mp_print_nl(mp, "???"); return; /* this won't happen */
6960 @.???@>
6961     }
6962     @<Print information for adjacent knots |p| and |q|@>;
6963   DONE1:
6964     p=q;
6965     if ( (p!=h)||(left_type(h)!=mp_endpoint) ) {
6966       @<Print two dots, followed by |given| or |curl| if present@>;
6967     }
6968   } while (p!=h);
6969   if ( left_type(h)!=mp_endpoint ) 
6970     mp_print(mp, "cycle");
6971 }
6972
6973 @ @<Print information for adjacent knots...@>=
6974 mp_print_two(mp, x_coord(p),y_coord(p));
6975 switch (right_type(p)) {
6976 case mp_endpoint: 
6977   if ( left_type(p)==mp_open ) mp_print(mp, "{open?}"); /* can't happen */
6978 @.open?@>
6979   if ( (left_type(q)!=mp_endpoint)||(q!=h) ) q=null; /* force an error */
6980   goto DONE1;
6981   break;
6982 case mp_explicit: 
6983   @<Print control points between |p| and |q|, then |goto done1|@>;
6984   break;
6985 case mp_open: 
6986   @<Print information for a curve that begins |open|@>;
6987   break;
6988 case mp_curl:
6989 case mp_given: 
6990   @<Print information for a curve that begins |curl| or |given|@>;
6991   break;
6992 default:
6993   mp_print(mp, "???"); /* can't happen */
6994 @.???@>
6995   break;
6996 }
6997 if ( left_type(q)<=mp_explicit ) {
6998   mp_print(mp, "..control?"); /* can't happen */
6999 @.control?@>
7000 } else if ( (right_tension(p)!=unity)||(left_tension(q)!=unity) ) {
7001   @<Print tension between |p| and |q|@>;
7002 }
7003
7004 @ Since |n_sin_cos| produces |fraction| results, which we will print as if they
7005 were |scaled|, the magnitude of a |given| direction vector will be~4096.
7006
7007 @<Print two dots...@>=
7008
7009   mp_print_nl(mp, " ..");
7010   if ( left_type(p)==mp_given ) { 
7011     mp_n_sin_cos(mp, left_given(p)); mp_print_char(mp, xord('{'));
7012     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, xord(','));
7013     mp_print_scaled(mp, mp->n_sin); mp_print_char(mp, xord('}'));
7014   } else if ( left_type(p)==mp_curl ){ 
7015     mp_print(mp, "{curl "); 
7016     mp_print_scaled(mp, left_curl(p)); mp_print_char(mp, xord('}'));
7017   }
7018 }
7019
7020 @ @<Print tension between |p| and |q|@>=
7021
7022   mp_print(mp, "..tension ");
7023   if ( right_tension(p)<0 ) mp_print(mp, "atleast");
7024   mp_print_scaled(mp, abs(right_tension(p)));
7025   if ( right_tension(p)!=left_tension(q) ){ 
7026     mp_print(mp, " and ");
7027     if ( left_tension(q)<0 ) mp_print(mp, "atleast");
7028     mp_print_scaled(mp, abs(left_tension(q)));
7029   }
7030 }
7031
7032 @ @<Print control points between |p| and |q|, then |goto done1|@>=
7033
7034   mp_print(mp, "..controls "); 
7035   mp_print_two(mp, right_x(p),right_y(p)); 
7036   mp_print(mp, " and ");
7037   if ( left_type(q)!=mp_explicit ) { 
7038     mp_print(mp, "??"); /* can't happen */
7039 @.??@>
7040   } else {
7041     mp_print_two(mp, left_x(q),left_y(q));
7042   }
7043   goto DONE1;
7044 }
7045
7046 @ @<Print information for a curve that begins |open|@>=
7047 if ( (left_type(p)!=mp_explicit)&&(left_type(p)!=mp_open) ) {
7048   mp_print(mp, "{open?}"); /* can't happen */
7049 @.open?@>
7050 }
7051
7052 @ A curl of 1 is shown explicitly, so that the user sees clearly that
7053 \MP's default curl is present.
7054
7055 @<Print information for a curve that begins |curl|...@>=
7056
7057   if ( left_type(p)==mp_open )  
7058     mp_print(mp, "??"); /* can't happen */
7059 @.??@>
7060   if ( right_type(p)==mp_curl ) { 
7061     mp_print(mp, "{curl "); mp_print_scaled(mp, right_curl(p));
7062   } else { 
7063     mp_n_sin_cos(mp, right_given(p)); mp_print_char(mp, xord('{'));
7064     mp_print_scaled(mp, mp->n_cos); mp_print_char(mp, xord(',')); 
7065     mp_print_scaled(mp, mp->n_sin);
7066   }
7067   mp_print_char(mp, xord('}'));
7068 }
7069
7070 @ It is convenient to have another version of |pr_path| that prints the path
7071 as a diagnostic message.
7072
7073 @<Declarations@>=
7074 static void mp_print_path (MP mp,pointer h, const char *s, boolean nuline) ;
7075
7076 @ @c
7077 void mp_print_path (MP mp,pointer h, const char *s, boolean nuline) { 
7078   mp_print_diagnostic(mp, "Path", s, nuline); mp_print_ln(mp);
7079 @.Path at line...@>
7080   mp_pr_path(mp, h);
7081   mp_end_diagnostic(mp, true);
7082 }
7083
7084 @ If we want to duplicate a knot node, we can say |copy_knot|:
7085
7086 @c 
7087 static pointer mp_copy_knot (MP mp,pointer p) {
7088   pointer q; /* the copy */
7089   int k; /* runs through the words of a knot node */
7090   q=mp_get_node(mp, knot_node_size);
7091   for (k=0;k<knot_node_size;k++) {
7092     mp->mem[q+k]=mp->mem[p+k];
7093   }
7094   originator(q)=originator(p);
7095   return q;
7096 }
7097
7098 @ The |copy_path| routine makes a clone of a given path.
7099
7100 @c 
7101 static pointer mp_copy_path (MP mp, pointer p) {
7102   pointer q,pp,qq; /* for list manipulation */
7103   q=mp_copy_knot(mp, p);
7104   qq=q; pp=mp_link(p);
7105   while ( pp!=p ) { 
7106     mp_link(qq)=mp_copy_knot(mp, pp);
7107     qq=mp_link(qq);
7108     pp=mp_link(pp);
7109   }
7110   mp_link(qq)=q;
7111   return q;
7112 }
7113
7114
7115 @ Just before |ship_out|, knot lists are exported for printing.
7116
7117 The |gr_XXXX| macros are defined in |mppsout.h|.
7118
7119 @c 
7120 static mp_knot *mp_export_knot (MP mp,pointer p) {
7121   mp_knot *q; /* the copy */
7122   if (p==null)
7123      return NULL;
7124   q = xmalloc(1, sizeof (mp_knot));
7125   memset(q,0,sizeof (mp_knot));
7126   gr_left_type(q)  = (unsigned short)left_type(p);
7127   gr_right_type(q) = (unsigned short)right_type(p);
7128   gr_x_coord(q)    = x_coord(p);
7129   gr_y_coord(q)    = y_coord(p);
7130   gr_left_x(q)     = left_x(p);
7131   gr_left_y(q)     = left_y(p);
7132   gr_right_x(q)    = right_x(p);
7133   gr_right_y(q)    = right_y(p);
7134   gr_originator(q) = (unsigned char)originator(p);
7135   return q;
7136 }
7137
7138 @ The |export_knot_list| routine therefore also makes a clone 
7139 of a given path.
7140
7141 @c 
7142 static mp_knot *mp_export_knot_list (MP mp, pointer p) {
7143   mp_knot *q, *qq; /* for list manipulation */
7144   pointer pp; /* for list manipulation */
7145   if (p==null)
7146      return NULL;
7147   q=mp_export_knot(mp, p);
7148   qq=q; pp=mp_link(p);
7149   while ( pp!=p ) { 
7150     gr_next_knot(qq)=mp_export_knot(mp, pp);
7151     qq=gr_next_knot(qq);
7152     pp=mp_link(pp);
7153   }
7154   gr_next_knot(qq)=q;
7155   return q;
7156 }
7157
7158
7159 @ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure
7160 returns a pointer to the first node of the copy, if the path is a cycle,
7161 but to the final node of a non-cyclic copy. The global
7162 variable |path_tail| will point to the final node of the original path;
7163 this trick makes it easier to implement `\&{doublepath}'.
7164
7165 All node types are assumed to be |endpoint| or |explicit| only.
7166
7167 @c 
7168 static pointer mp_htap_ypoc (MP mp,pointer p) {
7169   pointer q,pp,qq,rr; /* for list manipulation */
7170   q=mp_get_node(mp, knot_node_size); /* this will correspond to |p| */
7171   qq=q; pp=p;
7172   while (1) { 
7173     right_type(qq)=left_type(pp); left_type(qq)=right_type(pp);
7174     x_coord(qq)=x_coord(pp); y_coord(qq)=y_coord(pp);
7175     right_x(qq)=left_x(pp); right_y(qq)=left_y(pp);
7176     left_x(qq)=right_x(pp); left_y(qq)=right_y(pp);
7177     originator(qq)=originator(pp);
7178     if ( mp_link(pp)==p ) { 
7179       mp_link(q)=qq; mp->path_tail=pp; return q;
7180     }
7181     rr=mp_get_node(mp, knot_node_size); mp_link(rr)=qq; qq=rr; pp=mp_link(pp);
7182   }
7183 }
7184
7185 @ @<Glob...@>=
7186 pointer path_tail; /* the node that links to the beginning of a path */
7187
7188 @ When a cyclic list of knot nodes is no longer needed, it can be recycled by
7189 calling the following subroutine.
7190
7191 @<Declarations@>=
7192 static void mp_toss_knot_list (MP mp,pointer p) ;
7193
7194 @ @c
7195 void mp_toss_knot_list (MP mp,pointer p) {
7196   pointer q; /* the node being freed */
7197   pointer r; /* the next node */
7198   q=p;
7199   do {  
7200     r=mp_link(q); 
7201     mp_free_node(mp, q,knot_node_size); q=r;
7202   } while (q!=p);
7203 }
7204
7205 @* \[18] Choosing control points.
7206 Now we must actually delve into one of \MP's more difficult routines,
7207 the |make_choices| procedure that chooses angles and control points for
7208 the splines of a curve when the user has not specified them explicitly.
7209 The parameter to |make_choices| points to a list of knots and
7210 path information, as described above.
7211
7212 A path decomposes into independent segments at ``breakpoint'' knots,
7213 which are knots whose left and right angles are both prespecified in
7214 some way (i.e., their |left_type| and |right_type| aren't both open).
7215
7216 @c 
7217 static void mp_make_choices (MP mp,pointer knots) {
7218   pointer h; /* the first breakpoint */
7219   pointer p,q; /* consecutive breakpoints being processed */
7220   @<Other local variables for |make_choices|@>;
7221   check_arith; /* make sure that |arith_error=false| */
7222   if ( mp->internal[mp_tracing_choices]>0 )
7223     mp_print_path(mp, knots,", before choices",true);
7224   @<If consecutive knots are equal, join them explicitly@>;
7225   @<Find the first breakpoint, |h|, on the path;
7226     insert an artificial breakpoint if the path is an unbroken cycle@>;
7227   p=h;
7228   do {  
7229     @<Fill in the control points between |p| and the next breakpoint,
7230       then advance |p| to that breakpoint@>;
7231   } while (p!=h);
7232   if ( mp->internal[mp_tracing_choices]>0 )
7233     mp_print_path(mp, knots,", after choices",true);
7234   if ( mp->arith_error ) {
7235     @<Report an unexpected problem during the choice-making@>;
7236   }
7237 }
7238
7239 @ @<Report an unexpected problem during the choice...@>=
7240
7241   print_err("Some number got too big");
7242 @.Some number got too big@>
7243   help2("The path that I just computed is out of range.",
7244         "So it will probably look funny. Proceed, for a laugh.");
7245   mp_put_get_error(mp); mp->arith_error=false;
7246 }
7247
7248 @ Two knots in a row with the same coordinates will always be joined
7249 by an explicit ``curve'' whose control points are identical with the
7250 knots.
7251
7252 @<If consecutive knots are equal, join them explicitly@>=
7253 p=knots;
7254 do {  
7255   q=mp_link(p);
7256   if ( x_coord(p)==x_coord(q) && y_coord(p)==y_coord(q) && right_type(p)>mp_explicit ) { 
7257     right_type(p)=mp_explicit;
7258     if ( left_type(p)==mp_open ) { 
7259       left_type(p)=mp_curl; left_curl(p)=unity;
7260     }
7261     left_type(q)=mp_explicit;
7262     if ( right_type(q)==mp_open ) { 
7263       right_type(q)=mp_curl; right_curl(q)=unity;
7264     }
7265     right_x(p)=x_coord(p); left_x(q)=x_coord(p);
7266     right_y(p)=y_coord(p); left_y(q)=y_coord(p);
7267   }
7268   p=q;
7269 } while (p!=knots)
7270
7271 @ If there are no breakpoints, it is necessary to compute the direction
7272 angles around an entire cycle. In this case the |left_type| of the first
7273 node is temporarily changed to |end_cycle|.
7274
7275 @<Find the first breakpoint, |h|, on the path...@>=
7276 h=knots;
7277 while (1) { 
7278   if ( left_type(h)!=mp_open ) break;
7279   if ( right_type(h)!=mp_open ) break;
7280   h=mp_link(h);
7281   if ( h==knots ) { 
7282     left_type(h)=mp_end_cycle; break;
7283   }
7284 }
7285
7286 @ If |right_type(p)<given| and |q=mp_link(p)|, we must have
7287 |right_type(p)=left_type(q)=mp_explicit| or |endpoint|.
7288
7289 @<Fill in the control points between |p| and the next breakpoint...@>=
7290 q=mp_link(p);
7291 if ( right_type(p)>=mp_given ) { 
7292   while ( (left_type(q)==mp_open)&&(right_type(q)==mp_open) ) q=mp_link(q);
7293   @<Fill in the control information between
7294     consecutive breakpoints |p| and |q|@>;
7295 } else if ( right_type(p)==mp_endpoint ) {
7296   @<Give reasonable values for the unused control points between |p| and~|q|@>;
7297 }
7298 p=q
7299
7300 @ This step makes it possible to transform an explicitly computed path without
7301 checking the |left_type| and |right_type| fields.
7302
7303 @<Give reasonable values for the unused control points between |p| and~|q|@>=
7304
7305   right_x(p)=x_coord(p); right_y(p)=y_coord(p);
7306   left_x(q)=x_coord(q); left_y(q)=y_coord(q);
7307 }
7308
7309 @ Before we can go further into the way choices are made, we need to
7310 consider the underlying theory. The basic ideas implemented in |make_choices|
7311 are due to John Hobby, who introduced the notion of ``mock curvature''
7312 @^Hobby, John Douglas@>
7313 at a knot. Angles are chosen so that they preserve mock curvature when
7314 a knot is passed, and this has been found to produce excellent results.
7315
7316 It is convenient to introduce some notations that simplify the necessary
7317 formulas. Let $d_{k,k+1}=\vert z\k-z_k\vert$ be the (nonzero) distance
7318 between knots |k| and |k+1|; and let
7319 $${z\k-z_k\over z_k-z_{k-1}}={d_{k,k+1}\over d_{k-1,k}}e^{i\psi_k}$$
7320 so that a polygonal line from $z_{k-1}$ to $z_k$ to $z\k$ turns left
7321 through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$.
7322 The control points for the spline from $z_k$ to $z\k$ will be denoted by
7323 $$\eqalign{z_k^+&=z_k+
7324   \textstyle{1\over3}\rho_k e^{i\theta_k}(z\k-z_k),\cr
7325  z\k^-&=z\k-
7326   \textstyle{1\over3}\sigma\k e^{-i\phi\k}(z\k-z_k),\cr}$$
7327 where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the
7328 beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the
7329 corresponding ``offset angles.'' These angles satisfy the condition
7330 $$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$
7331 whenever the curve leaves an intermediate knot~|k| in the direction that
7332 it enters.
7333
7334 @ Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of
7335 the curve at its beginning and ending points. This means that
7336 $\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$,
7337 where $f(\theta,\phi)$ is \MP's standard velocity function defined in
7338 the |velocity| subroutine. The cubic spline $B(z_k^{\phantom+},z_k^+,
7339 z\k^-,z\k^{\phantom+};t)$
7340 has curvature
7341 @^curvature@>
7342 $${2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_{k,k+1}}
7343 \qquad{\rm and}\qquad
7344 {2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_{k,k+1}}$$
7345 at |t=0| and |t=1|, respectively. The mock curvature is the linear
7346 @^mock curvature@>
7347 approximation to this true curvature that arises in the limit for
7348 small $\theta_k$ and~$\phi\k$, if second-order terms are discarded.
7349 The standard velocity function satisfies
7350 $$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$
7351 hence the mock curvatures are respectively
7352 $${2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_{k,k+1}}
7353 \qquad{\rm and}\qquad
7354 {2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_{k,k+1}}.\eqno(**)$$
7355
7356 @ The turning angles $\psi_k$ are given, and equation $(*)$ above
7357 determines $\phi_k$ when $\theta_k$ is known, so the task of
7358 angle selection is essentially to choose appropriate values for each
7359 $\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables
7360 from $(**)$, we obtain a system of linear equations of the form
7361 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7362 where
7363 $$A_k={\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7364 \qquad B_k={3-\alpha_{k-1}\over\beta_k^2d_{k-1,k}},
7365 \qquad C_k={3-\beta\k\over\alpha_k^2d_{k,k+1}},
7366 \qquad D_k={\beta\k\over\alpha_k^2d_{k,k+1}}.$$
7367 The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$
7368 will be at most $4\over3$. It follows that $B_k\G{5\over4}A_k$ and
7369 $C_k\G{5\over4}D_k$; hence the equations are diagonally dominant;
7370 hence they have a unique solution. Moreover, in most cases the tensions
7371 are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the
7372 solution numerically stable, and there is an exponential damping
7373 effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by
7374 a factor of~$O(2^{-j})$.
7375
7376 @ However, we still must consider the angles at the starting and ending
7377 knots of a non-cyclic path. These angles might be given explicitly, or
7378 they might be specified implicitly in terms of an amount of ``curl.''
7379
7380 Let's assume that angles need to be determined for a non-cyclic path
7381 starting at $z_0$ and ending at~$z_n$. Then equations of the form
7382 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta_{k+1}=R_k$$
7383 have been given for $0<k<n$, and it will be convenient to introduce
7384 equations of the same form for $k=0$ and $k=n$, where
7385 $$A_0=B_0=C_n=D_n=0.$$
7386 If $\theta_0$ is supposed to have a given value $E_0$, we simply
7387 define $C_0=1$, $D_0=0$, and $R_0=E_0$. Otherwise a curl
7388 parameter, $\gamma_0$, has been specified at~$z_0$; this means
7389 that the mock curvature at $z_0$ should be $\gamma_0$ times the
7390 mock curvature at $z_1$; i.e.,
7391 $${2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_{01}}
7392 =\gamma_0{2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_{01}}.$$
7393 This equation simplifies to
7394 $$(\alpha_0\chi_0+3-\beta_1)\theta_0+
7395  \bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1=
7396  -\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$
7397 where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0=
7398 \chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$.
7399 It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$,
7400 hence the linear equations remain nonsingular.
7401
7402 Similar considerations apply at the right end, when the final angle $\phi_n$
7403 may or may not need to be determined. It is convenient to let $\psi_n=0$,
7404 hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$,
7405 or we have
7406 $$\bigl((3-\beta_n)\chi_n+\alpha_{n-1}\bigr)\theta_{n-1}+
7407 (\beta_n\chi_n+3-\alpha_{n-1})\theta_n=0,\qquad
7408   \chi_n={\beta_n^2\gamma_n\over\alpha_{n-1}^2}.$$
7409
7410 When |make_choices| chooses angles, it must compute the coefficients of
7411 these linear equations, then solve the equations. To compute the coefficients,
7412 it is necessary to compute arctangents of the given turning angles~$\psi_k$.
7413 When the equations are solved, the chosen directions $\theta_k$ are put
7414 back into the form of control points by essentially computing sines and
7415 cosines.
7416
7417 @ OK, we are ready to make the hard choices of |make_choices|.
7418 Most of the work is relegated to an auxiliary procedure
7419 called |solve_choices|, which has been introduced to keep
7420 |make_choices| from being extremely long.
7421
7422 @<Fill in the control information between...@>=
7423 @<Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$;
7424   set $n$ to the length of the path@>;
7425 @<Remove |open| types at the breakpoints@>;
7426 mp_solve_choices(mp, p,q,n)
7427
7428 @ It's convenient to precompute quantities that will be needed several
7429 times later. The values of |delta_x[k]| and |delta_y[k]| will be the
7430 coordinates of $z\k-z_k$, and the magnitude of this vector will be
7431 |delta[k]=@t$d_{k,k+1}$@>|. The path angle $\psi_k$ between $z_k-z_{k-1}$
7432 and $z\k-z_k$ will be stored in |psi[k]|.
7433
7434 @<Glob...@>=
7435 int path_size; /* maximum number of knots between breakpoints of a path */
7436 scaled *delta_x;
7437 scaled *delta_y;
7438 scaled *delta; /* knot differences */
7439 angle  *psi; /* turning angles */
7440
7441 @ @<Dealloc variables@>=
7442 xfree(mp->delta_x);
7443 xfree(mp->delta_y);
7444 xfree(mp->delta);
7445 xfree(mp->psi);
7446
7447 @ @<Other local variables for |make_choices|@>=
7448   int k,n; /* current and final knot numbers */
7449   pointer s,t; /* registers for list traversal */
7450   scaled delx,dely; /* directions where |open| meets |explicit| */
7451   fraction sine,cosine; /* trig functions of various angles */
7452
7453 @ @<Calculate the turning angles...@>=
7454 {
7455 RESTART:
7456   k=0; s=p; n=mp->path_size;
7457   do {  
7458     t=mp_link(s);
7459     mp->delta_x[k]=x_coord(t)-x_coord(s);
7460     mp->delta_y[k]=y_coord(t)-y_coord(s);
7461     mp->delta[k]=mp_pyth_add(mp, mp->delta_x[k],mp->delta_y[k]);
7462     if ( k>0 ) { 
7463       sine=mp_make_fraction(mp, mp->delta_y[k-1],mp->delta[k-1]);
7464       cosine=mp_make_fraction(mp, mp->delta_x[k-1],mp->delta[k-1]);
7465       mp->psi[k]=mp_n_arg(mp, mp_take_fraction(mp, mp->delta_x[k],cosine)+
7466         mp_take_fraction(mp, mp->delta_y[k],sine),
7467         mp_take_fraction(mp, mp->delta_y[k],cosine)-
7468           mp_take_fraction(mp, mp->delta_x[k],sine));
7469     }
7470     incr(k); s=t;
7471     if ( k==mp->path_size ) {
7472       mp_reallocate_paths(mp, mp->path_size+(mp->path_size/4));
7473       goto RESTART; /* retry, loop size has changed */
7474     }
7475     if ( s==q ) n=k;
7476   } while (!((k>=n)&&(left_type(s)!=mp_end_cycle)));
7477   if ( k==n ) mp->psi[n]=0; else mp->psi[k]=mp->psi[1];
7478 }
7479
7480 @ When we get to this point of the code, |right_type(p)| is either
7481 |given| or |curl| or |open|. If it is |open|, we must have
7482 |left_type(p)=mp_end_cycle| or |left_type(p)=mp_explicit|. In the latter
7483 case, the |open| type is converted to |given|; however, if the
7484 velocity coming into this knot is zero, the |open| type is
7485 converted to a |curl|, since we don't know the incoming direction.
7486
7487 Similarly, |left_type(q)| is either |given| or |curl| or |open| or
7488 |mp_end_cycle|. The |open| possibility is reduced either to |given| or to |curl|.
7489
7490 @<Remove |open| types at the breakpoints@>=
7491 if ( left_type(q)==mp_open ) { 
7492   delx=right_x(q)-x_coord(q); dely=right_y(q)-y_coord(q);
7493   if ( (delx==0)&&(dely==0) ) { 
7494     left_type(q)=mp_curl; left_curl(q)=unity;
7495   } else { 
7496     left_type(q)=mp_given; left_given(q)=mp_n_arg(mp, delx,dely);
7497   }
7498 }
7499 if ( (right_type(p)==mp_open)&&(left_type(p)==mp_explicit) ) { 
7500   delx=x_coord(p)-left_x(p); dely=y_coord(p)-left_y(p);
7501   if ( (delx==0)&&(dely==0) ) { 
7502     right_type(p)=mp_curl; right_curl(p)=unity;
7503   } else { 
7504     right_type(p)=mp_given; right_given(p)=mp_n_arg(mp, delx,dely);
7505   }
7506 }
7507
7508 @ Linear equations need to be solved whenever |n>1|; and also when |n=1|
7509 and exactly one of the breakpoints involves a curl. The simplest case occurs
7510 when |n=1| and there is a curl at both breakpoints; then we simply draw
7511 a straight line.
7512
7513 But before coding up the simple cases, we might as well face the general case,
7514 since we must deal with it sooner or later, and since the general case
7515 is likely to give some insight into the way simple cases can be handled best.
7516
7517 When there is no cycle, the linear equations to be solved form a tridiagonal
7518 system, and we can apply the standard technique of Gaussian elimination
7519 to convert that system to a sequence of equations of the form
7520 $$\theta_0+u_0\theta_1=v_0,\quad
7521 \theta_1+u_1\theta_2=v_1,\quad\ldots,\quad
7522 \theta_{n-1}+u_{n-1}\theta_n=v_{n-1},\quad
7523 \theta_n=v_n.$$
7524 It is possible to do this diagonalization while generating the equations.
7525 Once $\theta_n$ is known, it is easy to determine $\theta_{n-1}$, \dots,
7526 $\theta_1$, $\theta_0$; thus, the equations will be solved.
7527
7528 The procedure is slightly more complex when there is a cycle, but the
7529 basic idea will be nearly the same. In the cyclic case the right-hand
7530 sides will be $v_k+w_k\theta_0$ instead of simply $v_k$, and we will start
7531 the process off with $u_0=v_0=0$, $w_0=1$. The final equation will be not
7532 $\theta_n=v_n$ but $\theta_n+u_n\theta_1=v_n+w_n\theta_0$; an appropriate
7533 ending routine will take account of the fact that $\theta_n=\theta_0$ and
7534 eliminate the $w$'s from the system, after which the solution can be
7535 obtained as before.
7536
7537 When $u_k$, $v_k$, and $w_k$ are being computed, the three pointer
7538 variables |r|, |s|,~|t| will point respectively to knots |k-1|, |k|,
7539 and~|k+1|. The $u$'s and $w$'s are scaled by $2^{28}$, i.e., they are
7540 of type |fraction|; the $\theta$'s and $v$'s are of type |angle|.
7541
7542 @<Glob...@>=
7543 angle *theta; /* values of $\theta_k$ */
7544 fraction *uu; /* values of $u_k$ */
7545 angle *vv; /* values of $v_k$ */
7546 fraction *ww; /* values of $w_k$ */
7547
7548 @ @<Dealloc variables@>=
7549 xfree(mp->theta);
7550 xfree(mp->uu);
7551 xfree(mp->vv);
7552 xfree(mp->ww);
7553
7554 @ @<Declarations@>=
7555 static void mp_reallocate_paths (MP mp, int l);
7556
7557 @ @c
7558 void mp_reallocate_paths (MP mp, int l) {
7559   XREALLOC (mp->delta_x, l, scaled);
7560   XREALLOC (mp->delta_y, l, scaled);
7561   XREALLOC (mp->delta,   l, scaled);
7562   XREALLOC (mp->psi,     l, angle);
7563   XREALLOC (mp->theta,   l, angle);
7564   XREALLOC (mp->uu,      l, fraction);
7565   XREALLOC (mp->vv,      l, angle);
7566   XREALLOC (mp->ww,      l, fraction);
7567   mp->path_size = l;
7568 }
7569
7570 @ Our immediate problem is to get the ball rolling by setting up the
7571 first equation or by realizing that no equations are needed, and to fit
7572 this initialization into a framework suitable for the overall computation.
7573
7574 @<Declarations@>=
7575 static void mp_solve_choices (MP mp,pointer p, pointer q, halfword n) ;
7576
7577 @ @c
7578 void mp_solve_choices (MP mp,pointer p, pointer q, halfword n) {
7579   int k; /* current knot number */
7580   pointer r,s,t; /* registers for list traversal */
7581   @<Other local variables for |solve_choices|@>;
7582   k=0; s=p; r=0;
7583   while (1) { 
7584     t=mp_link(s);
7585     if ( k==0 ) {
7586       @<Get the linear equations started; or |return|
7587         with the control points in place, if linear equations
7588         needn't be solved@>
7589     } else  { 
7590       switch (left_type(s)) {
7591       case mp_end_cycle: case mp_open:
7592         @<Set up equation to match mock curvatures
7593           at $z_k$; then |goto found| with $\theta_n$
7594           adjusted to equal $\theta_0$, if a cycle has ended@>;
7595         break;
7596       case mp_curl:
7597         @<Set up equation for a curl at $\theta_n$
7598           and |goto found|@>;
7599         break;
7600       case mp_given:
7601         @<Calculate the given value of $\theta_n$
7602           and |goto found|@>;
7603         break;
7604       } /* there are no other cases */
7605     }
7606     r=s; s=t; incr(k);
7607   }
7608 FOUND:
7609   @<Finish choosing angles and assigning control points@>;
7610 }
7611
7612 @ On the first time through the loop, we have |k=0| and |r| is not yet
7613 defined. The first linear equation, if any, will have $A_0=B_0=0$.
7614
7615 @<Get the linear equations started...@>=
7616 switch (right_type(s)) {
7617 case mp_given: 
7618   if ( left_type(t)==mp_given ) {
7619     @<Reduce to simple case of two givens  and |return|@>
7620   } else {
7621     @<Set up the equation for a given value of $\theta_0$@>;
7622   }
7623   break;
7624 case mp_curl: 
7625   if ( left_type(t)==mp_curl ) {
7626     @<Reduce to simple case of straight line and |return|@>
7627   } else {
7628     @<Set up the equation for a curl at $\theta_0$@>;
7629   }
7630   break;
7631 case mp_open: 
7632   mp->uu[0]=0; mp->vv[0]=0; mp->ww[0]=fraction_one;
7633   /* this begins a cycle */
7634   break;
7635 } /* there are no other cases */
7636
7637 @ The general equation that specifies equality of mock curvature at $z_k$ is
7638 $$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$
7639 as derived above. We want to combine this with the already-derived equation
7640 $\theta_{k-1}+u_{k-1}\theta_k=v_{k-1}+w_{k-1}\theta_0$ in order to obtain
7641 a new equation
7642 $\theta_k+u_k\theta\k=v_k+w_k\theta_0$. This can be done by dividing the
7643 equation
7644 $$(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}
7645     -A_kw_{k-1}\theta_0$$
7646 by $B_k-u_{k-1}A_k+C_k$. The trick is to do this carefully with
7647 fixed-point arithmetic, avoiding the chance of overflow while retaining
7648 suitable precision.
7649
7650 The calculations will be performed in several registers that
7651 provide temporary storage for intermediate quantities.
7652
7653 @<Other local variables for |solve_choices|@>=
7654 fraction aa,bb,cc,ff,acc; /* temporary registers */
7655 scaled dd,ee; /* likewise, but |scaled| */
7656 scaled lt,rt; /* tension values */
7657
7658 @ @<Set up equation to match mock curvatures...@>=
7659 { @<Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$,
7660     $\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$,
7661     and $\\{cc}=(B_k-u_{k-1}A_k)/B_k$@>;
7662   @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>;
7663   mp->uu[k]=mp_take_fraction(mp, ff,bb);
7664   @<Calculate the values of $v_k$ and $w_k$@>;
7665   if ( left_type(s)==mp_end_cycle ) {
7666     @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>;
7667   }
7668 }
7669
7670 @ Since tension values are never less than 3/4, the values |aa| and
7671 |bb| computed here are never more than 4/5.
7672
7673 @<Calculate the values $\\{aa}=...@>=
7674 if ( abs(right_tension(r))==unity) { 
7675   aa=fraction_half; dd=2*mp->delta[k];
7676 } else { 
7677   aa=mp_make_fraction(mp, unity,3*abs(right_tension(r))-unity);
7678   dd=mp_take_fraction(mp, mp->delta[k],
7679     fraction_three-mp_make_fraction(mp, unity,abs(right_tension(r))));
7680 }
7681 if ( abs(left_tension(t))==unity ){ 
7682   bb=fraction_half; ee=2*mp->delta[k-1];
7683 } else { 
7684   bb=mp_make_fraction(mp, unity,3*abs(left_tension(t))-unity);
7685   ee=mp_take_fraction(mp, mp->delta[k-1],
7686     fraction_three-mp_make_fraction(mp, unity,abs(left_tension(t))));
7687 }
7688 cc=fraction_one-mp_take_fraction(mp, mp->uu[k-1],aa)
7689
7690 @ The ratio to be calculated in this step can be written in the form
7691 $$\beta_k^2\cdot\\{ee}\over\beta_k^2\cdot\\{ee}+\alpha_k^2\cdot
7692   \\{cc}\cdot\\{dd},$$
7693 because of the quantities just calculated. The values of |dd| and |ee|
7694 will not be needed after this step has been performed.
7695
7696 @<Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$@>=
7697 dd=mp_take_fraction(mp, dd,cc); lt=abs(left_tension(s)); rt=abs(right_tension(s));
7698 if ( lt!=rt ) { /* $\beta_k^{-1}\ne\alpha_k^{-1}$ */
7699   if ( lt<rt ) { 
7700     ff=mp_make_fraction(mp, lt,rt);
7701     ff=mp_take_fraction(mp, ff,ff); /* $\alpha_k^2/\beta_k^2$ */
7702     dd=mp_take_fraction(mp, dd,ff);
7703   } else { 
7704     ff=mp_make_fraction(mp, rt,lt);
7705     ff=mp_take_fraction(mp, ff,ff); /* $\beta_k^2/\alpha_k^2$ */
7706     ee=mp_take_fraction(mp, ee,ff);
7707   }
7708 }
7709 ff=mp_make_fraction(mp, ee,ee+dd)
7710
7711 @ The value of $u_{k-1}$ will be |<=1| except when $k=1$ and the previous
7712 equation was specified by a curl. In that case we must use a special
7713 method of computation to prevent overflow.
7714
7715 Fortunately, the calculations turn out to be even simpler in this ``hard''
7716 case. The curl equation makes $w_0=0$ and $v_0=-u_0\psi_1$, hence
7717 $-B_1\psi_1-A_1v_0=-(B_1-u_0A_1)\psi_1=-\\{cc}\cdot B_1\psi_1$.
7718
7719 @<Calculate the values of $v_k$ and $w_k$@>=
7720 acc=-mp_take_fraction(mp, mp->psi[k+1],mp->uu[k]);
7721 if ( right_type(r)==mp_curl ) { 
7722   mp->ww[k]=0;
7723   mp->vv[k]=acc-mp_take_fraction(mp, mp->psi[1],fraction_one-ff);
7724 } else { 
7725   ff=mp_make_fraction(mp, fraction_one-ff,cc); /* this is
7726     $B_k/(C_k+B_k-u_{k-1}A_k)<5$ */
7727   acc=acc-mp_take_fraction(mp, mp->psi[k],ff);
7728   ff=mp_take_fraction(mp, ff,aa); /* this is $A_k/(C_k+B_k-u_{k-1}A_k)$ */
7729   mp->vv[k]=acc-mp_take_fraction(mp, mp->vv[k-1],ff);
7730   if ( mp->ww[k-1]==0 ) mp->ww[k]=0;
7731   else mp->ww[k]=-mp_take_fraction(mp, mp->ww[k-1],ff);
7732 }
7733
7734 @ When a complete cycle has been traversed, we have $\theta_k+u_k\theta\k=
7735 v_k+w_k\theta_0$, for |1<=k<=n|. We would like to determine the value of
7736 $\theta_n$ and reduce the system to the form $\theta_k+u_k\theta\k=v_k$
7737 for |0<=k<n|, so that the cyclic case can be finished up just as if there
7738 were no cycle.
7739
7740 The idea in the following code is to observe that
7741 $$\eqalign{\theta_n&=v_n+w_n\theta_0-u_n\theta_1=\cdots\cr
7742 &=v_n+w_n\theta_0-u_n\bigl(v_1+w_1\theta_0-u_1(v_2+\cdots
7743   -u_{n-2}(v_{n-1}+w_{n-1}\theta_0-u_{n-1}\theta_0))\bigr),\cr}$$
7744 so we can solve for $\theta_n=\theta_0$.
7745
7746 @<Adjust $\theta_n$ to equal $\theta_0$ and |goto found|@>=
7747
7748 aa=0; bb=fraction_one; /* we have |k=n| */
7749 do {  decr(k);
7750 if ( k==0 ) k=n;
7751   aa=mp->vv[k]-mp_take_fraction(mp, aa,mp->uu[k]);
7752   bb=mp->ww[k]-mp_take_fraction(mp, bb,mp->uu[k]);
7753 } while (k!=n); /* now $\theta_n=\\{aa}+\\{bb}\cdot\theta_n$ */
7754 aa=mp_make_fraction(mp, aa,fraction_one-bb);
7755 mp->theta[n]=aa; mp->vv[0]=aa;
7756 for (k=1;k<=n-1;k++) {
7757   mp->vv[k]=mp->vv[k]+mp_take_fraction(mp, aa,mp->ww[k]);
7758 }
7759 goto FOUND;
7760 }
7761
7762 @ @d reduce_angle(A) if ( abs((A))>one_eighty_deg ) {
7763   if ( (A)>0 ) (A)=(A)-three_sixty_deg; else (A)=(A)+three_sixty_deg; }
7764
7765 @<Calculate the given value of $\theta_n$...@>=
7766
7767   mp->theta[n]=left_given(s)-mp_n_arg(mp, mp->delta_x[n-1],mp->delta_y[n-1]);
7768   reduce_angle(mp->theta[n]);
7769   goto FOUND;
7770 }
7771
7772 @ @<Set up the equation for a given value of $\theta_0$@>=
7773
7774   mp->vv[0]=right_given(s)-mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7775   reduce_angle(mp->vv[0]);
7776   mp->uu[0]=0; mp->ww[0]=0;
7777 }
7778
7779 @ @<Set up the equation for a curl at $\theta_0$@>=
7780 { cc=right_curl(s); lt=abs(left_tension(t)); rt=abs(right_tension(s));
7781   if ( (rt==unity)&&(lt==unity) )
7782     mp->uu[0]=mp_make_fraction(mp, cc+cc+unity,cc+two);
7783   else 
7784     mp->uu[0]=mp_curl_ratio(mp, cc,rt,lt);
7785   mp->vv[0]=-mp_take_fraction(mp, mp->psi[1],mp->uu[0]); mp->ww[0]=0;
7786 }
7787
7788 @ @<Set up equation for a curl at $\theta_n$...@>=
7789 { cc=left_curl(s); lt=abs(left_tension(s)); rt=abs(right_tension(r));
7790   if ( (rt==unity)&&(lt==unity) )
7791     ff=mp_make_fraction(mp, cc+cc+unity,cc+two);
7792   else 
7793     ff=mp_curl_ratio(mp, cc,lt,rt);
7794   mp->theta[n]=-mp_make_fraction(mp, mp_take_fraction(mp, mp->vv[n-1],ff),
7795     fraction_one-mp_take_fraction(mp, ff,mp->uu[n-1]));
7796   goto FOUND;
7797 }
7798
7799 @ The |curl_ratio| subroutine has three arguments, which our previous notation
7800 encourages us to call $\gamma$, $\alpha^{-1}$, and $\beta^{-1}$. It is
7801 a somewhat tedious program to calculate
7802 $${(3-\alpha)\alpha^2\gamma+\beta^3\over
7803   \alpha^3\gamma+(3-\beta)\beta^2},$$
7804 with the result reduced to 4 if it exceeds 4. (This reduction of curl
7805 is necessary only if the curl and tension are both large.)
7806 The values of $\alpha$ and $\beta$ will be at most~4/3.
7807
7808 @<Declarations@>=
7809 static fraction mp_curl_ratio (MP mp,scaled gamma, scaled a_tension, 
7810                         scaled b_tension) ;
7811
7812 @ @c
7813 fraction mp_curl_ratio (MP mp,scaled gamma, scaled a_tension, 
7814                         scaled b_tension) {
7815   fraction alpha,beta,num,denom,ff; /* registers */
7816   alpha=mp_make_fraction(mp, unity,a_tension);
7817   beta=mp_make_fraction(mp, unity,b_tension);
7818   if ( alpha<=beta ) {
7819     ff=mp_make_fraction(mp, alpha,beta); ff=mp_take_fraction(mp, ff,ff);
7820     gamma=mp_take_fraction(mp, gamma,ff);
7821     beta=beta / 010000; /* convert |fraction| to |scaled| */
7822     denom=mp_take_fraction(mp, gamma,alpha)+three-beta;
7823     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7824   } else { 
7825     ff=mp_make_fraction(mp, beta,alpha); ff=mp_take_fraction(mp, ff,ff);
7826     beta=mp_take_fraction(mp, beta,ff) / 010000; /* convert |fraction| to |scaled| */
7827     denom=mp_take_fraction(mp, gamma,alpha)+(ff / 1365)-beta;
7828       /* $1365\approx 2^{12}/3$ */
7829     num=mp_take_fraction(mp, gamma,fraction_three-alpha)+beta;
7830   }
7831   if ( num>=denom+denom+denom+denom ) return fraction_four;
7832   else return mp_make_fraction(mp, num,denom);
7833 }
7834
7835 @ We're in the home stretch now.
7836
7837 @<Finish choosing angles and assigning control points@>=
7838 for (k=n-1;k>=0;k--) {
7839   mp->theta[k]=mp->vv[k]-mp_take_fraction(mp,mp->theta[k+1],mp->uu[k]);
7840 }
7841 s=p; k=0;
7842 do {  
7843   t=mp_link(s);
7844   mp_n_sin_cos(mp, mp->theta[k]); mp->st=mp->n_sin; mp->ct=mp->n_cos;
7845   mp_n_sin_cos(mp, -mp->psi[k+1]-mp->theta[k+1]); mp->sf=mp->n_sin; mp->cf=mp->n_cos;
7846   mp_set_controls(mp, s,t,k);
7847   incr(k); s=t;
7848 } while (k!=n)
7849
7850 @ The |set_controls| routine actually puts the control points into
7851 a pair of consecutive nodes |p| and~|q|. Global variables are used to
7852 record the values of $\sin\theta$, $\cos\theta$, $\sin\phi$, and
7853 $\cos\phi$ needed in this calculation.
7854
7855 @<Glob...@>=
7856 fraction st;
7857 fraction ct;
7858 fraction sf;
7859 fraction cf; /* sines and cosines */
7860
7861 @ @<Declarations@>=
7862 static void mp_set_controls (MP mp,pointer p, pointer q, integer k);
7863
7864 @ @c
7865 void mp_set_controls (MP mp,pointer p, pointer q, integer k) {
7866   fraction rr,ss; /* velocities, divided by thrice the tension */
7867   scaled lt,rt; /* tensions */
7868   fraction sine; /* $\sin(\theta+\phi)$ */
7869   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7870   rr=mp_velocity(mp, mp->st,mp->ct,mp->sf,mp->cf,rt);
7871   ss=mp_velocity(mp, mp->sf,mp->cf,mp->st,mp->ct,lt);
7872   if ( (right_tension(p)<0)||(left_tension(q)<0) ) {
7873     @<Decrease the velocities,
7874       if necessary, to stay inside the bounding triangle@>;
7875   }
7876   right_x(p)=x_coord(p)+mp_take_fraction(mp, 
7877                           mp_take_fraction(mp, mp->delta_x[k],mp->ct)-
7878                           mp_take_fraction(mp, mp->delta_y[k],mp->st),rr);
7879   right_y(p)=y_coord(p)+mp_take_fraction(mp, 
7880                           mp_take_fraction(mp, mp->delta_y[k],mp->ct)+
7881                           mp_take_fraction(mp, mp->delta_x[k],mp->st),rr);
7882   left_x(q)=x_coord(q)-mp_take_fraction(mp, 
7883                          mp_take_fraction(mp, mp->delta_x[k],mp->cf)+
7884                          mp_take_fraction(mp, mp->delta_y[k],mp->sf),ss);
7885   left_y(q)=y_coord(q)-mp_take_fraction(mp, 
7886                          mp_take_fraction(mp, mp->delta_y[k],mp->cf)-
7887                          mp_take_fraction(mp, mp->delta_x[k],mp->sf),ss);
7888   right_type(p)=mp_explicit; left_type(q)=mp_explicit;
7889 }
7890
7891 @ The boundedness conditions $\\{rr}\L\sin\phi\,/\sin(\theta+\phi)$ and
7892 $\\{ss}\L\sin\theta\,/\sin(\theta+\phi)$ are to be enforced if $\sin\theta$,
7893 $\sin\phi$, and $\sin(\theta+\phi)$ all have the same sign. Otherwise
7894 there is no ``bounding triangle.''
7895
7896 @<Decrease the velocities, if necessary...@>=
7897 if (((mp->st>=0)&&(mp->sf>=0))||((mp->st<=0)&&(mp->sf<=0)) ) {
7898   sine=mp_take_fraction(mp, abs(mp->st),mp->cf)+
7899                             mp_take_fraction(mp, abs(mp->sf),mp->ct);
7900   if ( sine>0 ) {
7901     sine=mp_take_fraction(mp, sine,fraction_one+unity); /* safety factor */
7902     if ( right_tension(p)<0 )
7903      if ( mp_ab_vs_cd(mp, abs(mp->sf),fraction_one,rr,sine)<0 )
7904       rr=mp_make_fraction(mp, abs(mp->sf),sine);
7905     if ( left_tension(q)<0 )
7906      if ( mp_ab_vs_cd(mp, abs(mp->st),fraction_one,ss,sine)<0 )
7907       ss=mp_make_fraction(mp, abs(mp->st),sine);
7908   }
7909 }
7910
7911 @ Only the simple cases remain to be handled.
7912
7913 @<Reduce to simple case of two givens and |return|@>=
7914
7915   aa=mp_n_arg(mp, mp->delta_x[0],mp->delta_y[0]);
7916   mp_n_sin_cos(mp, right_given(p)-aa); mp->ct=mp->n_cos; mp->st=mp->n_sin;
7917   mp_n_sin_cos(mp, left_given(q)-aa); mp->cf=mp->n_cos; mp->sf=-mp->n_sin;
7918   mp_set_controls(mp, p,q,0); return;
7919 }
7920
7921 @ @<Reduce to simple case of straight line and |return|@>=
7922
7923   right_type(p)=mp_explicit; left_type(q)=mp_explicit;
7924   lt=abs(left_tension(q)); rt=abs(right_tension(p));
7925   if ( rt==unity ) {
7926     if ( mp->delta_x[0]>=0 ) right_x(p)=x_coord(p)+((mp->delta_x[0]+1) / 3);
7927     else right_x(p)=x_coord(p)+((mp->delta_x[0]-1) / 3);
7928     if ( mp->delta_y[0]>=0 ) right_y(p)=y_coord(p)+((mp->delta_y[0]+1) / 3);
7929     else right_y(p)=y_coord(p)+((mp->delta_y[0]-1) / 3);
7930   } else { 
7931     ff=mp_make_fraction(mp, unity,3*rt); /* $\alpha/3$ */
7932     right_x(p)=x_coord(p)+mp_take_fraction(mp, mp->delta_x[0],ff);
7933     right_y(p)=y_coord(p)+mp_take_fraction(mp, mp->delta_y[0],ff);
7934   }
7935   if ( lt==unity ) {
7936     if ( mp->delta_x[0]>=0 ) left_x(q)=x_coord(q)-((mp->delta_x[0]+1) / 3);
7937     else left_x(q)=x_coord(q)-((mp->delta_x[0]-1) / 3);
7938     if ( mp->delta_y[0]>=0 ) left_y(q)=y_coord(q)-((mp->delta_y[0]+1) / 3);
7939     else left_y(q)=y_coord(q)-((mp->delta_y[0]-1) / 3);
7940   } else  { 
7941     ff=mp_make_fraction(mp, unity,3*lt); /* $\beta/3$ */
7942     left_x(q)=x_coord(q)-mp_take_fraction(mp, mp->delta_x[0],ff);
7943     left_y(q)=y_coord(q)-mp_take_fraction(mp, mp->delta_y[0],ff);
7944   }
7945   return;
7946 }
7947
7948 @* \[19] Measuring paths.
7949 \MP's \&{llcorner}, \&{lrcorner}, \&{ulcorner}, and \&{urcorner} operators
7950 allow the user to measure the bounding box of anything that can go into a
7951 picture.  It's easy to get rough bounds on the $x$ and $y$ extent of a path
7952 by just finding the bounding box of the knots and the control points. We
7953 need a more accurate version of the bounding box, but we can still use the
7954 easy estimate to save time by focusing on the interesting parts of the path.
7955
7956 @ Computing an accurate bounding box involves a theme that will come up again
7957 and again. Given a Bernshte{\u\i}n polynomial
7958 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
7959 $$B(z_0,z_1,\ldots,z_n;t)=\sum_k{n\choose k}t^k(1-t)^{n-k}z_k,$$
7960 we can conveniently bisect its range as follows:
7961
7962 \smallskip
7963 \textindent{1)} Let $z_k^{(0)}=z_k$, for |0<=k<=n|.
7964
7965 \smallskip
7966 \textindent{2)} Let $z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$, for
7967 |0<=k<n-j|, for |0<=j<n|.
7968
7969 \smallskip\noindent
7970 Then
7971 $$B(z_0,z_1,\ldots,z_n;t)=B(z_0^{(0)},z_0^{(1)},\ldots,z_0^{(n)};2t)
7972  =B(z_0^{(n)},z_1^{(n-1)},\ldots,z_n^{(0)};2t-1).$$
7973 This formula gives us the coefficients of polynomials to use over the ranges
7974 $0\L t\L{1\over2}$ and ${1\over2}\L t\L1$.
7975
7976 @ Now here's a subroutine that's handy for all sorts of path computations:
7977 Given a quadratic polynomial $B(a,b,c;t)$, the |crossing_point| function
7978 returns the unique |fraction| value |t| between 0 and~1 at which
7979 $B(a,b,c;t)$ changes from positive to negative, or returns
7980 |t=fraction_one+1| if no such value exists. If |a<0| (so that $B(a,b,c;t)$
7981 is already negative at |t=0|), |crossing_point| returns the value zero.
7982
7983 @d no_crossing {  return (fraction_one+1); }
7984 @d one_crossing { return fraction_one; }
7985 @d zero_crossing { return 0; }
7986 @d mp_crossing_point(M,A,B,C) mp_do_crossing_point(A,B,C)
7987
7988 @c static fraction mp_do_crossing_point (integer a, integer b, integer c) {
7989   integer d; /* recursive counter */
7990   integer x,xx,x0,x1,x2; /* temporary registers for bisection */
7991   if ( a<0 ) zero_crossing;
7992   if ( c>=0 ) { 
7993     if ( b>=0 ) {
7994       if ( c>0 ) { no_crossing; }
7995       else if ( (a==0)&&(b==0) ) { no_crossing;} 
7996       else { one_crossing; } 
7997     }
7998     if ( a==0 ) zero_crossing;
7999   } else if ( a==0 ) {
8000     if ( b<=0 ) zero_crossing;
8001   }
8002   @<Use bisection to find the crossing point, if one exists@>;
8003 }
8004
8005 @ The general bisection method is quite simple when $n=2$, hence
8006 |crossing_point| does not take much time. At each stage in the
8007 recursion we have a subinterval defined by |l| and~|j| such that
8008 $B(a,b,c;2^{-l}(j+t))=B(x_0,x_1,x_2;t)$, and we want to ``zero in'' on
8009 the subinterval where $x_0\G0$ and $\min(x_1,x_2)<0$.
8010
8011 It is convenient for purposes of calculation to combine the values
8012 of |l| and~|j| in a single variable $d=2^l+j$, because the operation
8013 of bisection then corresponds simply to doubling $d$ and possibly
8014 adding~1. Furthermore it proves to be convenient to modify
8015 our previous conventions for bisection slightly, maintaining the
8016 variables $X_0=2^lx_0$, $X_1=2^l(x_0-x_1)$, and $X_2=2^l(x_1-x_2)$.
8017 With these variables the conditions $x_0\ge0$ and $\min(x_1,x_2)<0$ are
8018 equivalent to $\max(X_1,X_1+X_2)>X_0\ge0$.
8019
8020 The following code maintains the invariant relations
8021 $0\L|x0|<\max(|x1|,|x1|+|x2|)$,
8022 $\vert|x1|\vert<2^{30}$, $\vert|x2|\vert<2^{30}$;
8023 it has been constructed in such a way that no arithmetic overflow
8024 will occur if the inputs satisfy
8025 $a<2^{30}$, $\vert a-b\vert<2^{30}$, and $\vert b-c\vert<2^{30}$.
8026
8027 @<Use bisection to find the crossing point...@>=
8028 d=1; x0=a; x1=a-b; x2=b-c;
8029 do {  
8030   x=half(x1+x2);
8031   if ( x1-x0>x0 ) { 
8032     x2=x; x0+=x0; d+=d;  
8033   } else { 
8034     xx=x1+x-x0;
8035     if ( xx>x0 ) { 
8036       x2=x; x0+=x0; d+=d;
8037     }  else { 
8038       x0=x0-xx;
8039       if ( x<=x0 ) { if ( x+x2<=x0 ) no_crossing; }
8040       x1=x; d=d+d+1;
8041     }
8042   }
8043 } while (d<fraction_one);
8044 return (d-fraction_one)
8045
8046 @ Here is a routine that computes the $x$ or $y$ coordinate of the point on
8047 a cubic corresponding to the |fraction| value~|t|.
8048
8049 It is convenient to define a \.{WEB} macro |t_of_the_way| such that
8050 |t_of_the_way(a,b)| expands to |a-(a-b)*t|, i.e., to |t[a,b]|.
8051
8052 @d t_of_the_way(A,B) ((A)-mp_take_fraction(mp,((A)-(B)),t))
8053
8054 @c static scaled mp_eval_cubic (MP mp,pointer p, pointer q, fraction t) {
8055   scaled x1,x2,x3; /* intermediate values */
8056   x1=t_of_the_way(knot_coord(p),right_coord(p));
8057   x2=t_of_the_way(right_coord(p),left_coord(q));
8058   x3=t_of_the_way(left_coord(q),knot_coord(q));
8059   x1=t_of_the_way(x1,x2);
8060   x2=t_of_the_way(x2,x3);
8061   return t_of_the_way(x1,x2);
8062 }
8063
8064 @ The actual bounding box information is stored in global variables.
8065 Since it is convenient to address the $x$ and $y$ information
8066 separately, we define arrays indexed by |x_code..y_code| and use
8067 macros to give them more convenient names.
8068
8069 @<Types...@>=
8070 enum mp_bb_code  {
8071   mp_x_code=0, /* index for |minx| and |maxx| */
8072   mp_y_code /* index for |miny| and |maxy| */
8073 } ;
8074
8075
8076 @d minx mp->bbmin[mp_x_code]
8077 @d maxx mp->bbmax[mp_x_code]
8078 @d miny mp->bbmin[mp_y_code]
8079 @d maxy mp->bbmax[mp_y_code]
8080
8081 @<Glob...@>=
8082 scaled bbmin[mp_y_code+1];
8083 scaled bbmax[mp_y_code+1]; 
8084 /* the result of procedures that compute bounding box information */
8085
8086 @ Now we're ready for the key part of the bounding box computation.
8087 The |bound_cubic| procedure updates |bbmin[c]| and |bbmax[c]| based on
8088 $$B(\hbox{|knot_coord(p)|}, \hbox{|right_coord(p)|},
8089     \hbox{|left_coord(q)|}, \hbox{|knot_coord(q)|};t)
8090 $$
8091 for $0<t\le1$.  In other words, the procedure adjusts the bounds to
8092 accommodate |knot_coord(q)| and any extremes over the range $0<t<1$.
8093 The |c| parameter is |x_code| or |y_code|.
8094
8095 @c static void mp_bound_cubic (MP mp,pointer p, pointer q, quarterword c) {
8096   boolean wavy; /* whether we need to look for extremes */
8097   scaled del1,del2,del3,del,dmax; /* proportional to the control
8098      points of a quadratic derived from a cubic */
8099   fraction t,tt; /* where a quadratic crosses zero */
8100   scaled x; /* a value that |bbmin[c]| and |bbmax[c]| must accommodate */
8101   x=knot_coord(q);
8102   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8103   @<Check the control points against the bounding box and set |wavy:=true|
8104     if any of them lie outside@>;
8105   if ( wavy ) {
8106     del1=right_coord(p)-knot_coord(p);
8107     del2=left_coord(q)-right_coord(p);
8108     del3=knot_coord(q)-left_coord(q);
8109     @<Scale up |del1|, |del2|, and |del3| for greater accuracy;
8110       also set |del| to the first nonzero element of |(del1,del2,del3)|@>;
8111     if ( del<0 ) {
8112       negate(del1); negate(del2); negate(del3);
8113     };
8114     t=mp_crossing_point(mp, del1,del2,del3);
8115     if ( t<fraction_one ) {
8116       @<Test the extremes of the cubic against the bounding box@>;
8117     }
8118   }
8119 }
8120
8121 @ @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>=
8122 if ( x<mp->bbmin[c] ) mp->bbmin[c]=x;
8123 if ( x>mp->bbmax[c] ) mp->bbmax[c]=x
8124
8125 @ @<Check the control points against the bounding box and set...@>=
8126 wavy=true;
8127 if ( mp->bbmin[c]<=right_coord(p) )
8128   if ( right_coord(p)<=mp->bbmax[c] )
8129     if ( mp->bbmin[c]<=left_coord(q) )
8130       if ( left_coord(q)<=mp->bbmax[c] )
8131         wavy=false
8132
8133 @ If |del1=del2=del3=0|, it's impossible to obey the title of this
8134 section. We just set |del=0| in that case.
8135
8136 @<Scale up |del1|, |del2|, and |del3| for greater accuracy...@>=
8137 if ( del1!=0 ) del=del1;
8138 else if ( del2!=0 ) del=del2;
8139 else del=del3;
8140 if ( del!=0 ) {
8141   dmax=abs(del1);
8142   if ( abs(del2)>dmax ) dmax=abs(del2);
8143   if ( abs(del3)>dmax ) dmax=abs(del3);
8144   while ( dmax<fraction_half ) {
8145     dmax+=dmax; del1+=del1; del2+=del2; del3+=del3;
8146   }
8147 }
8148
8149 @ Since |crossing_point| has tried to choose |t| so that
8150 $B(|del1|,|del2|,|del3|;\tau)$ crosses zero at $\tau=|t|$ with negative
8151 slope, the value of |del2| computed below should not be positive.
8152 But rounding error could make it slightly positive in which case we
8153 must cut it to zero to avoid confusion.
8154
8155 @<Test the extremes of the cubic against the bounding box@>=
8156
8157   x=mp_eval_cubic(mp, p,q,t);
8158   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8159   del2=t_of_the_way(del2,del3);
8160     /* now |0,del2,del3| represent the derivative on the remaining interval */
8161   if ( del2>0 ) del2=0;
8162   tt=mp_crossing_point(mp, 0,-del2,-del3);
8163   if ( tt<fraction_one ) {
8164     @<Test the second extreme against the bounding box@>;
8165   }
8166 }
8167
8168 @ @<Test the second extreme against the bounding box@>=
8169 {
8170    x=mp_eval_cubic(mp, p,q,t_of_the_way(tt,fraction_one));
8171   @<Adjust |bbmin[c]| and |bbmax[c]| to accommodate |x|@>;
8172 }
8173
8174 @ Finding the bounding box of a path is basically a matter of applying
8175 |bound_cubic| twice for each pair of adjacent knots.
8176
8177 @c static void mp_path_bbox (MP mp,pointer h) {
8178   pointer p,q; /* a pair of adjacent knots */
8179    minx=x_coord(h); miny=y_coord(h);
8180   maxx=minx; maxy=miny;
8181   p=h;
8182   do {  
8183     if ( right_type(p)==mp_endpoint ) return;
8184     q=mp_link(p);
8185     mp_bound_cubic(mp, x_loc(p),x_loc(q),mp_x_code);
8186     mp_bound_cubic(mp, y_loc(p),y_loc(q),mp_y_code);
8187     p=q;
8188   } while (p!=h);
8189 }
8190
8191 @ Another important way to measure a path is to find its arc length.  This
8192 is best done by using the general bisection algorithm to subdivide the path
8193 until obtaining ``well behaved'' subpaths whose arc lengths can be approximated
8194 by simple means.
8195
8196 Since the arc length is the integral with respect to time of the magnitude of
8197 the velocity, it is natural to use Simpson's rule for the approximation.
8198 @^Simpson's rule@>
8199 If $\dot B(t)$ is the spline velocity, Simpson's rule gives
8200 $$ \vb\dot B(0)\vb + 4\vb\dot B({1\over2})\vb + \vb\dot B(1)\vb \over 6 $$
8201 for the arc length of a path of length~1.  For a cubic spline
8202 $B(z_0,z_1,z_2,z_3;t)$, the time derivative $\dot B(t)$ is
8203 $3B(dz_0,dz_1,dz_2;t)$, where $dz_i=z_{i+1}-z_i$.  Hence the arc length
8204 approximation is
8205 $$ {\vb dz_0\vb \over 2} + 2\vb dz_{02}\vb + {\vb dz_2\vb \over 2}, $$
8206 where
8207 $$ dz_{02}={1\over2}\left({dz_0+dz_1\over 2}+{dz_1+dz_2\over 2}\right)$$
8208 is the result of the bisection algorithm.
8209
8210 @ The remaining problem is how to decide when a subpath is ``well behaved.''
8211 This could be done via the theoretical error bound for Simpson's rule,
8212 @^Simpson's rule@>
8213 but this is impractical because it requires an estimate of the fourth
8214 derivative of the quantity being integrated.  It is much easier to just perform
8215 a bisection step and see how much the arc length estimate changes.  Since the
8216 error for Simpson's rule is proportional to the fourth power of the sample
8217 spacing, the remaining error is typically about $1\over16$ of the amount of
8218 the change.  We say ``typically'' because the error has a pseudo-random behavior
8219 that could cause the two estimates to agree when each contain large errors.
8220
8221 To protect against disasters such as undetected cusps, the bisection process
8222 should always continue until all the $dz_i$ vectors belong to a single
8223 $90^\circ$ sector.  This ensures that no point on the spline can have velocity
8224 less than 70\% of the minimum of $\vb dz_0\vb$, $\vb dz_1\vb$ and $\vb dz_2\vb$.
8225 If such a spline happens to produce an erroneous arc length estimate that
8226 is little changed by bisection, the amount of the error is likely to be fairly
8227 small.  We will try to arrange things so that freak accidents of this type do
8228 not destroy the inverse relationship between the \&{arclength} and
8229 \&{arctime} operations.
8230 @:arclength_}{\&{arclength} primitive@>
8231 @:arctime_}{\&{arctime} primitive@>
8232
8233 @ The \&{arclength} and \&{arctime} operations are both based on a recursive
8234 @^recursion@>
8235 function that finds the arc length of a cubic spline given $dz_0$, $dz_1$,
8236 $dz_2$. This |arc_test| routine also takes an arc length goal |a_goal| and
8237 returns the time when the arc length reaches |a_goal| if there is such a time.
8238 Thus the return value is either an arc length less than |a_goal| or, if the
8239 arc length would be at least |a_goal|, it returns a time value decreased by
8240 |two|.  This allows the caller to use the sign of the result to distinguish
8241 between arc lengths and time values.  On certain types of overflow, it is
8242 possible for |a_goal| and the result of |arc_test| both to be |el_gordo|.
8243 Otherwise, the result is always less than |a_goal|.
8244
8245 Rather than halving the control point coordinates on each recursive call to
8246 |arc_test|, it is better to keep them proportional to velocity on the original
8247 curve and halve the results instead.  This means that recursive calls can
8248 potentially use larger error tolerances in their arc length estimates.  How
8249 much larger depends on to what extent the errors behave as though they are
8250 independent of each other.  To save computing time, we use optimistic assumptions
8251 and increase the tolerance by a factor of about $\sqrt2$ for each recursive
8252 call.
8253
8254 In addition to the tolerance parameter, |arc_test| should also have parameters
8255 for ${1\over3}\vb\dot B(0)\vb$, ${2\over3}\vb\dot B({1\over2})\vb$, and
8256 ${1\over3}\vb\dot B(1)\vb$.  These quantities are relatively expensive to compute
8257 and they are needed in different instances of |arc_test|.
8258
8259 @c 
8260 static scaled mp_arc_test (MP mp, scaled dx0, scaled dy0, scaled dx1, scaled dy1, 
8261                     scaled dx2, scaled dy2, scaled  v0, scaled v02, 
8262                     scaled v2, scaled a_goal, scaled tol) {
8263   boolean simple; /* are the control points confined to a $90^\circ$ sector? */
8264   scaled dx01, dy01, dx12, dy12, dx02, dy02;  /* bisection results */
8265   scaled v002, v022;
8266     /* twice the velocity magnitudes at $t={1\over4}$ and $t={3\over4}$ */
8267   scaled arc; /* best arc length estimate before recursion */
8268   @<Other local variables in |arc_test|@>;
8269   @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,
8270     |dx2|, |dy2|@>;
8271   @<Initialize |v002|, |v022|, and the arc length estimate |arc|; if it overflows
8272     set |arc_test| and |return|@>;
8273   @<Test if the control points are confined to one quadrant or rotating them
8274     $45^\circ$ would put them in one quadrant.  Then set |simple| appropriately@>;
8275   if ( simple && (abs(arc-v02-halfp(v0+v2)) <= tol) ) {
8276     if ( arc < a_goal ) {
8277       return arc;
8278     } else {
8279        @<Estimate when the arc length reaches |a_goal| and set |arc_test| to
8280          that time minus |two|@>;
8281     }
8282   } else {
8283     @<Use one or two recursive calls to compute the |arc_test| function@>;
8284   }
8285 }
8286
8287 @ The |tol| value should by multiplied by $\sqrt 2$ before making recursive
8288 calls, but $1.5$ is an adequate approximation.  It is best to avoid using
8289 |make_fraction| in this inner loop.
8290 @^inner loop@>
8291
8292 @<Use one or two recursive calls to compute the |arc_test| function@>=
8293
8294   @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is as
8295     large as possible@>;
8296   tol = tol + halfp(tol);
8297   a = mp_arc_test(mp, dx0,dy0, dx01,dy01, dx02,dy02, v0, v002, 
8298                   halfp(v02), a_new, tol);
8299   if ( a<0 )  {
8300      return (-halfp(two-a));
8301   } else { 
8302     @<Update |a_new| to reduce |a_new+a_aux| by |a|@>;
8303     b = mp_arc_test(mp, dx02,dy02, dx12,dy12, dx2,dy2,
8304                     halfp(v02), v022, v2, a_new, tol);
8305     if ( b<0 )  
8306       return (-halfp(-b) - half_unit);
8307     else  
8308       return (a + half(b-a));
8309   }
8310 }
8311
8312 @ @<Other local variables in |arc_test|@>=
8313 scaled a,b; /* results of recursive calls */
8314 scaled a_new,a_aux; /* the sum of these gives the |a_goal| */
8315
8316 @ @<Set |a_new| and |a_aux| so their sum is |2*a_goal| and |a_new| is...@>=
8317 a_aux = el_gordo - a_goal;
8318 if ( a_goal > a_aux ) {
8319   a_aux = a_goal - a_aux;
8320   a_new = el_gordo;
8321 } else { 
8322   a_new = a_goal + a_goal;
8323   a_aux = 0;
8324 }
8325
8326 @ There is no need to maintain |a_aux| at this point so we use it as a temporary
8327 to force the additions and subtractions to be done in an order that avoids
8328 overflow.
8329
8330 @<Update |a_new| to reduce |a_new+a_aux| by |a|@>=
8331 if ( a > a_aux ) {
8332   a_aux = a_aux - a;
8333   a_new = a_new + a_aux;
8334 }
8335
8336 @ This code assumes all {\it dx} and {\it dy} variables have magnitude less than
8337 |fraction_four|.  To simplify the rest of the |arc_test| routine, we strengthen
8338 this assumption by requiring the norm of each $({\it dx},{\it dy})$ pair to obey
8339 this bound.  Note that recursive calls will maintain this invariant.
8340
8341 @<Bisect the B\'ezier quadratic given by |dx0|, |dy0|, |dx1|, |dy1|,...@>=
8342 dx01 = half(dx0 + dx1);
8343 dx12 = half(dx1 + dx2);
8344 dx02 = half(dx01 + dx12);
8345 dy01 = half(dy0 + dy1);
8346 dy12 = half(dy1 + dy2);
8347 dy02 = half(dy01 + dy12)
8348
8349 @ We should be careful to keep |arc<el_gordo| so that calling |arc_test| with
8350 |a_goal=el_gordo| is guaranteed to yield the arc length.
8351
8352 @<Initialize |v002|, |v022|, and the arc length estimate |arc|;...@>=
8353 v002 = mp_pyth_add(mp, dx01+half(dx0+dx02), dy01+half(dy0+dy02));
8354 v022 = mp_pyth_add(mp, dx12+half(dx02+dx2), dy12+half(dy02+dy2));
8355 tmp = halfp(v02+2);
8356 arc1 = v002 + half(halfp(v0+tmp) - v002);
8357 arc = v022 + half(halfp(v2+tmp) - v022);
8358 if ( (arc < el_gordo-arc1) )  {
8359   arc = arc+arc1;
8360 } else { 
8361   mp->arith_error = true;
8362   if ( a_goal==el_gordo )  return (el_gordo);
8363   else return (-two);
8364 }
8365
8366 @ @<Other local variables in |arc_test|@>=
8367 scaled tmp, tmp2; /* all purpose temporary registers */
8368 scaled arc1; /* arc length estimate for the first half */
8369
8370 @ @<Test if the control points are confined to one quadrant or rotating...@>=
8371 simple = ((dx0>=0) && (dx1>=0) && (dx2>=0)) ||
8372          ((dx0<=0) && (dx1<=0) && (dx2<=0));
8373 if ( simple )
8374   simple = ((dy0>=0) && (dy1>=0) && (dy2>=0)) ||
8375            ((dy0<=0) && (dy1<=0) && (dy2<=0));
8376 if ( ! simple ) {
8377   simple = ((dx0>=dy0) && (dx1>=dy1) && (dx2>=dy2)) ||
8378            ((dx0<=dy0) && (dx1<=dy1) && (dx2<=dy2));
8379   if ( simple ) 
8380     simple = ((-dx0>=dy0) && (-dx1>=dy1) && (-dx2>=dy2)) ||
8381              ((-dx0<=dy0) && (-dx1<=dy1) && (-dx2<=dy2));
8382 }
8383
8384 @ Since Simpson's rule is based on approximating the integrand by a parabola,
8385 @^Simpson's rule@>
8386 it is appropriate to use the same approximation to decide when the integral
8387 reaches the intermediate value |a_goal|.  At this point
8388 $$\eqalign{
8389     {\vb\dot B(0)\vb\over 3} &= \hbox{|v0|}, \qquad
8390     {\vb\dot B({1\over4})\vb\over 3} = {\hbox{|v002|}\over 2}, \qquad
8391     {\vb\dot B({1\over2})\vb\over 3} = {\hbox{|v02|}\over 2}, \cr
8392     {\vb\dot B({3\over4})\vb\over 3} &= {\hbox{|v022|}\over 2}, \qquad
8393     {\vb\dot B(1)\vb\over 3} = \hbox{|v2|} \cr
8394 }
8395 $$
8396 and
8397 $$ {\vb\dot B(t)\vb\over 3} \approx
8398   \cases{B\left(\hbox{|v0|},
8399       \hbox{|v002|}-{1\over 2}\hbox{|v0|}-{1\over 4}\hbox{|v02|},
8400       {1\over 2}\hbox{|v02|}; 2t \right)&
8401     if $t\le{1\over 2}$\cr
8402   B\left({1\over 2}\hbox{|v02|},
8403       \hbox{|v022|}-{1\over 4}\hbox{|v02|}-{1\over 2}\hbox{|v2|},
8404       \hbox{|v2|}; 2t-1 \right)&
8405     if $t\ge{1\over 2}$.\cr}
8406  \eqno (*)
8407 $$
8408 We can integrate $\vb\dot B(t)\vb$ by using
8409 $$\int 3B(a,b,c;\tau)\,dt =
8410   {B(0,a,a+b,a+b+c;\tau) + {\rm constant} \over {d\tau\over dt}}.
8411 $$
8412
8413 This construction allows us to find the time when the arc length reaches
8414 |a_goal| by solving a cubic equation of the form
8415 $$ B(0,a,a+b,a+b+c;\tau) = x, $$
8416 where $\tau$ is $2t$ or $2t+1$, $x$ is |a_goal| or |a_goal-arc1|, and $a$, $b$,
8417 and $c$ are the Bernshte{\u\i}n coefficients from $(*)$ divided by
8418 @^Bernshte{\u\i}n, Serge{\u\i} Natanovich@>
8419 $d\tau\over dt$.  We shall define a function |solve_rising_cubic| that finds
8420 $\tau$ given $a$, $b$, $c$, and $x$.
8421
8422 @<Estimate when the arc length reaches |a_goal| and set |arc_test| to...@>=
8423
8424   tmp = (v02 + 2) / 4;
8425   if ( a_goal<=arc1 ) {
8426     tmp2 = halfp(v0);
8427     return 
8428       (halfp(mp_solve_rising_cubic(mp, tmp2, arc1-tmp2-tmp, tmp, a_goal))- two);
8429   } else { 
8430     tmp2 = halfp(v2);
8431     return ((half_unit - two) +
8432       halfp(mp_solve_rising_cubic(mp, tmp, arc-arc1-tmp-tmp2, tmp2, a_goal-arc1)));
8433   }
8434 }
8435
8436 @ Here is the |solve_rising_cubic| routine that finds the time~$t$ when
8437 $$ B(0, a, a+b, a+b+c; t) = x. $$
8438 This routine is based on |crossing_point| but is simplified by the
8439 assumptions that $B(a,b,c;t)\ge0$ for $0\le t\le1$ and that |0<=x<=a+b+c|.
8440 If rounding error causes this condition to be violated slightly, we just ignore
8441 it and proceed with binary search.  This finds a time when the function value
8442 reaches |x| and the slope is positive.
8443
8444 @<Declarations@>=
8445 static scaled mp_solve_rising_cubic (MP mp,scaled a, scaled b,  scaled c, scaled x) ;
8446
8447 @ @c
8448 scaled mp_solve_rising_cubic (MP mp,scaled a, scaled b,  scaled c, scaled x) {
8449   scaled ab, bc, ac; /* bisection results */
8450   integer t; /* $2^k+q$ where unscaled answer is in $[q2^{-k},(q+1)2^{-k})$ */
8451   integer xx; /* temporary for updating |x| */
8452   if ( (a<0) || (c<0) ) mp_confusion(mp, "rising?");
8453 @:this can't happen rising?}{\quad rising?@>
8454   if ( x<=0 ) {
8455         return 0;
8456   } else if ( x >= a+b+c ) {
8457     return unity;
8458   } else { 
8459     t = 1;
8460     @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than
8461       |el_gordo div 3|@>;
8462     do {  
8463       t+=t;
8464       @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>;
8465       xx = x - a - ab - ac;
8466       if ( xx < -x ) { x+=x; b=ab; c=ac;  }
8467       else { x = x + xx;  a=ac; b=bc; t = t+1; };
8468     } while (t < unity);
8469     return (t - unity);
8470   }
8471 }
8472
8473 @ @<Subdivide the B\'ezier quadratic defined by |a|, |b|, |c|@>=
8474 ab = half(a+b);
8475 bc = half(b+c);
8476 ac = half(ab+bc)
8477
8478 @ @d one_third_el_gordo 05252525252 /* upper bound on |a|, |b|, and |c| */
8479
8480 @<Rescale if necessary to make sure |a|, |b|, and |c| are all less than...@>=
8481 while ((a>one_third_el_gordo)||(b>one_third_el_gordo)||(c>one_third_el_gordo)) { 
8482   a = halfp(a);
8483   b = half(b);
8484   c = halfp(c);
8485   x = halfp(x);
8486 }
8487
8488 @ It is convenient to have a simpler interface to |arc_test| that requires no
8489 unnecessary arguments and ensures that each $({\it dx},{\it dy})$ pair has
8490 length less than |fraction_four|.
8491
8492 @d arc_tol   16  /* quit when change in arc length estimate reaches this */
8493
8494 @c static scaled mp_do_arc_test (MP mp,scaled dx0, scaled dy0, scaled dx1, 
8495                           scaled dy1, scaled dx2, scaled dy2, scaled a_goal) {
8496   scaled v0,v1,v2; /* length of each $({\it dx},{\it dy})$ pair */
8497   scaled v02; /* twice the norm of the quadratic at $t={1\over2}$ */
8498   v0 = mp_pyth_add(mp, dx0,dy0);
8499   v1 = mp_pyth_add(mp, dx1,dy1);
8500   v2 = mp_pyth_add(mp, dx2,dy2);
8501   if ( (v0>=fraction_four) || (v1>=fraction_four) || (v2>=fraction_four) ) { 
8502     mp->arith_error = true;
8503     if ( a_goal==el_gordo )  return el_gordo;
8504     else return (-two);
8505   } else { 
8506     v02 = mp_pyth_add(mp, dx1+half(dx0+dx2), dy1+half(dy0+dy2));
8507     return (mp_arc_test(mp, dx0,dy0, dx1,dy1, dx2,dy2,
8508                                  v0, v02, v2, a_goal, arc_tol));
8509   }
8510 }
8511
8512 @ Now it is easy to find the arc length of an entire path.
8513
8514 @c static scaled mp_get_arc_length (MP mp,pointer h) {
8515   pointer p,q; /* for traversing the path */
8516   scaled a,a_tot; /* current and total arc lengths */
8517   a_tot = 0;
8518   p = h;
8519   while ( right_type(p)!=mp_endpoint ){ 
8520     q = mp_link(p);
8521     a = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8522       left_x(q)-right_x(p), left_y(q)-right_y(p),
8523       x_coord(q)-left_x(q), y_coord(q)-left_y(q), el_gordo);
8524     a_tot = mp_slow_add(mp, a, a_tot);
8525     if ( q==h ) break;  else p=q;
8526   }
8527   check_arith;
8528   return a_tot;
8529 }
8530
8531 @ The inverse operation of finding the time on a path~|h| when the arc length
8532 reaches some value |arc0| can also be accomplished via |do_arc_test|.  Some care
8533 is required to handle very large times or negative times on cyclic paths.  For
8534 non-cyclic paths, |arc0| values that are negative or too large cause
8535 |get_arc_time| to return 0 or the length of path~|h|.
8536
8537 If |arc0| is greater than the arc length of a cyclic path~|h|, the result is a
8538 time value greater than the length of the path.  Since it could be much greater,
8539 we must be prepared to compute the arc length of path~|h| and divide this into
8540 |arc0| to find how many multiples of the length of path~|h| to add.
8541
8542 @c static scaled mp_get_arc_time (MP mp,pointer h, scaled  arc0) {
8543   pointer p,q; /* for traversing the path */
8544   scaled t_tot; /* accumulator for the result */
8545   scaled t; /* the result of |do_arc_test| */
8546   scaled arc; /* portion of |arc0| not used up so far */
8547   integer n; /* number of extra times to go around the cycle */
8548   if ( arc0<0 ) {
8549     @<Deal with a negative |arc0| value and |return|@>;
8550   }
8551   if ( arc0==el_gordo ) decr(arc0);
8552   t_tot = 0;
8553   arc = arc0;
8554   p = h;
8555   while ( (right_type(p)!=mp_endpoint) && (arc>0) ) {
8556     q = mp_link(p);
8557     t = mp_do_arc_test(mp, right_x(p)-x_coord(p), right_y(p)-y_coord(p),
8558       left_x(q)-right_x(p), left_y(q)-right_y(p),
8559       x_coord(q)-left_x(q), y_coord(q)-left_y(q), arc);
8560     @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>;
8561     if ( q==h ) {
8562       @<Update |t_tot| and |arc| to avoid going around the cyclic
8563         path too many times but set |arith_error:=true| and |goto done| on
8564         overflow@>;
8565     }
8566     p = q;
8567   }
8568   check_arith;
8569   return t_tot;
8570 }
8571
8572 @ @<Update |arc| and |t_tot| after |do_arc_test| has just returned |t|@>=
8573 if ( t<0 ) { t_tot = t_tot + t + two;  arc = 0;  }
8574 else { t_tot = t_tot + unity;  arc = arc - t;  }
8575
8576 @ @<Deal with a negative |arc0| value and |return|@>=
8577
8578   if ( left_type(h)==mp_endpoint ) {
8579     t_tot=0;
8580   } else { 
8581     p = mp_htap_ypoc(mp, h);
8582     t_tot = -mp_get_arc_time(mp, p, -arc0);
8583     mp_toss_knot_list(mp, p);
8584   }
8585   check_arith;
8586   return t_tot;
8587 }
8588
8589 @ @<Update |t_tot| and |arc| to avoid going around the cyclic...@>=
8590 if ( arc>0 ) { 
8591   n = arc / (arc0 - arc);
8592   arc = arc - n*(arc0 - arc);
8593   if ( t_tot > (el_gordo / (n+1)) ) { 
8594         return el_gordo;
8595   }
8596   t_tot = (n + 1)*t_tot;
8597 }
8598
8599 @* \[20] Data structures for pens.
8600 A Pen in \MP\ can be either elliptical or polygonal.  Elliptical pens result
8601 in \ps\ \&{stroke} commands, while anything drawn with a polygonal pen is
8602 @:stroke}{\&{stroke} command@>
8603 converted into an area fill as described in the next part of this program.
8604 The mathematics behind this process is based on simple aspects of the theory
8605 of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge Stolfi
8606 [``A kinematic framework for computational geometry,'' Proc.\ IEEE Symp.\
8607 Foundations of Computer Science {\bf 24} (1983), 100--111].
8608
8609 Polygonal pens are created from paths via \MP's \&{makepen} primitive.
8610 @:makepen_}{\&{makepen} primitive@>
8611 This path representation is almost sufficient for our purposes except that
8612 a pen path should always be a convex polygon with the vertices in
8613 counter-clockwise order.
8614 Since we will need to scan pen polygons both forward and backward, a pen
8615 should be represented as a doubly linked ring of knot nodes.  There is
8616 room for the extra back pointer because we do not need the
8617 |left_type| or |right_type| fields.  In fact, we don't need the |left_x|,
8618 |left_y|, |right_x|, or |right_y| fields either but we leave these alone
8619 so that certain procedures can operate on both pens and paths.  In particular,
8620 pens can be copied using |copy_path| and recycled using |toss_knot_list|.
8621
8622 @d knil info
8623   /* this replaces the |left_type| and |right_type| fields in a pen knot */
8624
8625 @ The |make_pen| procedure turns a path into a pen by initializing
8626 the |knil| pointers and making sure the knots form a convex polygon.
8627 Thus each cubic in the given path becomes a straight line and the control
8628 points are ignored.  If the path is not cyclic, the ends are connected by a
8629 straight line.
8630
8631 @d copy_pen(A) mp_make_pen(mp, mp_copy_path(mp, (A)),false)
8632
8633 @c 
8634 static pointer mp_make_pen (MP mp,pointer h, boolean need_hull) {
8635   pointer p,q; /* two consecutive knots */
8636   q=h;
8637   do {  
8638     p=q; q=mp_link(q);
8639     knil(q)=p;
8640   } while (q!=h);
8641   if ( need_hull ){ 
8642     h=mp_convex_hull(mp, h);
8643     @<Make sure |h| isn't confused with an elliptical pen@>;
8644   }
8645   return h;
8646 }
8647
8648 @ The only information required about an elliptical pen is the overall
8649 transformation that has been applied to the original \&{pencircle}.
8650 @:pencircle_}{\&{pencircle} primitive@>
8651 Since it suffices to keep track of how the three points $(0,0)$, $(1,0)$,
8652 and $(0,1)$ are transformed, an elliptical pen can be stored in a single
8653 knot node and transformed as if it were a path.
8654
8655 @d pen_is_elliptical(A) ((A)==mp_link((A)))
8656
8657 @c 
8658 static pointer mp_get_pen_circle (MP mp,scaled diam) {
8659   pointer h; /* the knot node to return */
8660   h=mp_get_node(mp, knot_node_size);
8661   mp_link(h)=h; knil(h)=h;
8662   originator(h)=mp_program_code;
8663   x_coord(h)=0; y_coord(h)=0;
8664   left_x(h)=diam; left_y(h)=0;
8665   right_x(h)=0; right_y(h)=diam;
8666   return h;
8667 }
8668
8669 @ If the polygon being returned by |make_pen| has only one vertex, it will
8670 be interpreted as an elliptical pen.  This is no problem since a degenerate
8671 polygon can equally well be thought of as a degenerate ellipse.  We need only
8672 initialize the |left_x|, |left_y|, |right_x|, and |right_y| fields.
8673
8674 @<Make sure |h| isn't confused with an elliptical pen@>=
8675 if ( pen_is_elliptical( h) ){ 
8676   left_x(h)=x_coord(h); left_y(h)=y_coord(h);
8677   right_x(h)=x_coord(h); right_y(h)=y_coord(h);
8678 }
8679
8680 @ We have to cheat a little here but most operations on pens only use
8681 the first three words in each knot node.
8682 @^data structure assumptions@>
8683
8684 @<Initialize a pen at |test_pen| so that it fits in nine words@>=
8685 x_coord(test_pen)=-half_unit;
8686 y_coord(test_pen)=0;
8687 x_coord(test_pen+3)=half_unit;
8688 y_coord(test_pen+3)=0;
8689 x_coord(test_pen+6)=0;
8690 y_coord(test_pen+6)=unity;
8691 mp_link(test_pen)=test_pen+3;
8692 mp_link(test_pen+3)=test_pen+6;
8693 mp_link(test_pen+6)=test_pen;
8694 knil(test_pen)=test_pen+6;
8695 knil(test_pen+3)=test_pen;
8696 knil(test_pen+6)=test_pen+3
8697
8698 @ Printing a polygonal pen is very much like printing a path
8699
8700 @<Declarations@>=
8701 static void mp_pr_pen (MP mp,pointer h) ;
8702
8703 @ @c
8704 void mp_pr_pen (MP mp,pointer h) {
8705   pointer p,q; /* for list traversal */
8706   if ( pen_is_elliptical(h) ) {
8707     @<Print the elliptical pen |h|@>;
8708   } else { 
8709     p=h;
8710     do {  
8711       mp_print_two(mp, x_coord(p),y_coord(p));
8712       mp_print_nl(mp, " .. ");
8713       @<Advance |p| making sure the links are OK and |return| if there is
8714         a problem@>;
8715      } while (p!=h);
8716      mp_print(mp, "cycle");
8717   }
8718 }
8719
8720 @ @<Advance |p| making sure the links are OK and |return| if there is...@>=
8721 q=mp_link(p);
8722 if ( (q==null) || (knil(q)!=p) ) { 
8723   mp_print_nl(mp, "???"); return; /* this won't happen */
8724 @.???@>
8725 }
8726 p=q
8727
8728 @ @<Print the elliptical pen |h|@>=
8729
8730 mp_print(mp, "pencircle transformed (");
8731 mp_print_scaled(mp, x_coord(h));
8732 mp_print_char(mp, xord(','));
8733 mp_print_scaled(mp, y_coord(h));
8734 mp_print_char(mp, xord(','));
8735 mp_print_scaled(mp, left_x(h)-x_coord(h));
8736 mp_print_char(mp, xord(','));
8737 mp_print_scaled(mp, right_x(h)-x_coord(h));
8738 mp_print_char(mp, xord(','));
8739 mp_print_scaled(mp, left_y(h)-y_coord(h));
8740 mp_print_char(mp, xord(','));
8741 mp_print_scaled(mp, right_y(h)-y_coord(h));
8742 mp_print_char(mp, xord(')'));
8743 }
8744
8745 @ Here us another version of |pr_pen| that prints the pen as a diagnostic
8746 message.
8747
8748 @<Declarations@>=
8749 static void mp_print_pen (MP mp,pointer h, const char *s, boolean nuline) ;
8750
8751 @ @c
8752 void mp_print_pen (MP mp,pointer h, const char *s, boolean nuline) { 
8753   mp_print_diagnostic(mp, "Pen",s,nuline); mp_print_ln(mp);
8754 @.Pen at line...@>
8755   mp_pr_pen(mp, h);
8756   mp_end_diagnostic(mp, true);
8757 }
8758
8759 @ Making a polygonal pen into a path involves restoring the |left_type| and
8760 |right_type| fields and setting the control points so as to make a polygonal
8761 path.
8762
8763 @c 
8764 static void mp_make_path (MP mp,pointer h) {
8765   pointer p; /* for traversing the knot list */
8766   quarterword k; /* a loop counter */
8767   @<Other local variables in |make_path|@>;
8768   if ( pen_is_elliptical(h) ) {
8769     @<Make the elliptical pen |h| into a path@>;
8770   } else { 
8771     p=h;
8772     do {  
8773       left_type(p)=mp_explicit;
8774       right_type(p)=mp_explicit;
8775       @<copy the coordinates of knot |p| into its control points@>;
8776        p=mp_link(p);
8777     } while (p!=h);
8778   }
8779 }
8780
8781 @ @<copy the coordinates of knot |p| into its control points@>=
8782 left_x(p)=x_coord(p);
8783 left_y(p)=y_coord(p);
8784 right_x(p)=x_coord(p);
8785 right_y(p)=y_coord(p)
8786
8787 @ We need an eight knot path to get a good approximation to an ellipse.
8788
8789 @<Make the elliptical pen |h| into a path@>=
8790
8791   @<Extract the transformation parameters from the elliptical pen~|h|@>;
8792   p=h;
8793   for (k=0;k<=7;k++ ) { 
8794     @<Initialize |p| as the |k|th knot of a circle of unit diameter,
8795       transforming it appropriately@>;
8796     if ( k==7 ) mp_link(p)=h;  else mp_link(p)=mp_get_node(mp, knot_node_size);
8797     p=mp_link(p);
8798   }
8799 }
8800
8801 @ @<Extract the transformation parameters from the elliptical pen~|h|@>=
8802 center_x=x_coord(h);
8803 center_y=y_coord(h);
8804 width_x=left_x(h)-center_x;
8805 width_y=left_y(h)-center_y;
8806 height_x=right_x(h)-center_x;
8807 height_y=right_y(h)-center_y
8808
8809 @ @<Other local variables in |make_path|@>=
8810 scaled center_x,center_y; /* translation parameters for an elliptical pen */
8811 scaled width_x,width_y; /* the effect of a unit change in $x$ */
8812 scaled height_x,height_y; /* the effect of a unit change in $y$ */
8813 scaled dx,dy; /* the vector from knot |p| to its right control point */
8814 integer kk;
8815   /* |k| advanced $270^\circ$ around the ring (cf. $\sin\theta=\cos(\theta+270)$) */
8816
8817 @ The only tricky thing here are the tables |half_cos| and |d_cos| used to
8818 find the point $k/8$ of the way around the circle and the direction vector
8819 to use there.
8820
8821 @<Initialize |p| as the |k|th knot of a circle of unit diameter,...@>=
8822 kk=(k+6)% 8;
8823 x_coord(p)=center_x+mp_take_fraction(mp, mp->half_cos[k],width_x)
8824            +mp_take_fraction(mp, mp->half_cos[kk],height_x);
8825 y_coord(p)=center_y+mp_take_fraction(mp, mp->half_cos[k],width_y)
8826            +mp_take_fraction(mp, mp->half_cos[kk],height_y);
8827 dx=-mp_take_fraction(mp, mp->d_cos[kk],width_x)
8828    +mp_take_fraction(mp, mp->d_cos[k],height_x);
8829 dy=-mp_take_fraction(mp, mp->d_cos[kk],width_y)
8830    +mp_take_fraction(mp, mp->d_cos[k],height_y);
8831 right_x(p)=x_coord(p)+dx;
8832 right_y(p)=y_coord(p)+dy;
8833 left_x(p)=x_coord(p)-dx;
8834 left_y(p)=y_coord(p)-dy;
8835 left_type(p)=mp_explicit;
8836 right_type(p)=mp_explicit;
8837 originator(p)=mp_program_code
8838
8839 @ @<Glob...@>=
8840 fraction half_cos[8]; /* ${1\over2}\cos(45k)$ */
8841 fraction d_cos[8]; /* a magic constant times $\cos(45k)$ */
8842
8843 @ The magic constant for |d_cos| is the distance between $({1\over2},0)$ and
8844 $({1\over4}\sqrt2,{1\over4}\sqrt2)$ times the result of the |velocity|
8845 function for $\theta=\phi=22.5^\circ$.  This comes out to be
8846 $$ d = {\sqrt{2-\sqrt2}\over 3+3\cos22.5^\circ}
8847   \approx 0.132608244919772.
8848 $$
8849
8850 @<Set init...@>=
8851 mp->half_cos[0]=fraction_half;
8852 mp->half_cos[1]=94906266; /* $2^{26}\sqrt2\approx94906265.62$ */
8853 mp->half_cos[2]=0;
8854 mp->d_cos[0]=35596755; /* $2^{28}d\approx35596754.69$ */
8855 mp->d_cos[1]=25170707; /* $2^{27}\sqrt2\,d\approx25170706.63$ */
8856 mp->d_cos[2]=0;
8857 for (k=3;k<= 4;k++ ) { 
8858   mp->half_cos[k]=-mp->half_cos[4-k];
8859   mp->d_cos[k]=-mp->d_cos[4-k];
8860 }
8861 for (k=5;k<= 7;k++ ) { 
8862   mp->half_cos[k]=mp->half_cos[8-k];
8863   mp->d_cos[k]=mp->d_cos[8-k];
8864 }
8865
8866 @ The |convex_hull| function forces a pen polygon to be convex when it is
8867 returned by |make_pen| and after any subsequent transformation where rounding
8868 error might allow the convexity to be lost.
8869 The convex hull algorithm used here is described by F.~P. Preparata and
8870 M.~I. Shamos [{\sl Computational Geometry}, Springer-Verlag, 1985].
8871
8872 @<Declarations@>=
8873 static pointer mp_convex_hull (MP mp,pointer h);
8874
8875 @ @c
8876 pointer mp_convex_hull (MP mp,pointer h) { /* Make a polygonal pen convex */
8877   pointer l,r; /* the leftmost and rightmost knots */
8878   pointer p,q; /* knots being scanned */
8879   pointer s; /* the starting point for an upcoming scan */
8880   scaled dx,dy; /* a temporary pointer */
8881   if ( pen_is_elliptical(h) ) {
8882      return h;
8883   } else { 
8884     @<Set |l| to the leftmost knot in polygon~|h|@>;
8885     @<Set |r| to the rightmost knot in polygon~|h|@>;
8886     if ( l!=r ) { 
8887       s=mp_link(r);
8888       @<Find any knots on the path from |l| to |r| above the |l|-|r| line and
8889         move them past~|r|@>;
8890       @<Find any knots on the path from |s| to |l| below the |l|-|r| line and
8891         move them past~|l|@>;
8892       @<Sort the path from |l| to |r| by increasing $x$@>;
8893       @<Sort the path from |r| to |l| by decreasing $x$@>;
8894     }
8895     if ( l!=mp_link(l) ) {
8896       @<Do a Gramm scan and remove vertices where there is no left turn@>;
8897     }
8898     return l;
8899   }
8900 }
8901
8902 @ All comparisons are done primarily on $x$ and secondarily on $y$.
8903
8904 @<Set |l| to the leftmost knot in polygon~|h|@>=
8905 l=h;
8906 p=mp_link(h);
8907 while ( p!=h ) { 
8908   if ( x_coord(p)<=x_coord(l) )
8909     if ( (x_coord(p)<x_coord(l)) || (y_coord(p)<y_coord(l)) )
8910       l=p;
8911   p=mp_link(p);
8912 }
8913
8914 @ @<Set |r| to the rightmost knot in polygon~|h|@>=
8915 r=h;
8916 p=mp_link(h);
8917 while ( p!=h ) { 
8918   if ( x_coord(p)>=x_coord(r) )
8919     if ( (x_coord(p)>x_coord(r)) || (y_coord(p)>y_coord(r)) )
8920       r=p;
8921   p=mp_link(p);
8922 }
8923
8924 @ @<Find any knots on the path from |l| to |r| above the |l|-|r| line...@>=
8925 dx=x_coord(r)-x_coord(l);
8926 dy=y_coord(r)-y_coord(l);
8927 p=mp_link(l);
8928 while ( p!=r ) { 
8929   q=mp_link(p);
8930   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))>0 )
8931     mp_move_knot(mp, p, r);
8932   p=q;
8933 }
8934
8935 @ The |move_knot| procedure removes |p| from a doubly linked list and inserts
8936 it after |q|.
8937
8938 @ @<Declarations@>=
8939 static void mp_move_knot (MP mp,pointer p, pointer q) ;
8940
8941 @ @c
8942 void mp_move_knot (MP mp,pointer p, pointer q) { 
8943   mp_link(knil(p))=mp_link(p);
8944   knil(mp_link(p))=knil(p);
8945   knil(p)=q;
8946   mp_link(p)=mp_link(q);
8947   mp_link(q)=p;
8948   knil(mp_link(p))=p;
8949 }
8950
8951 @ @<Find any knots on the path from |s| to |l| below the |l|-|r| line...@>=
8952 p=s;
8953 while ( p!=l ) { 
8954   q=mp_link(p);
8955   if ( mp_ab_vs_cd(mp, dx,y_coord(p)-y_coord(l),dy,x_coord(p)-x_coord(l))<0 )
8956     mp_move_knot(mp, p,l);
8957   p=q;
8958 }
8959
8960 @ The list is likely to be in order already so we just do linear insertions.
8961 Secondary comparisons on $y$ ensure that the sort is consistent with the
8962 choice of |l| and |r|.
8963
8964 @<Sort the path from |l| to |r| by increasing $x$@>=
8965 p=mp_link(l);
8966 while ( p!=r ) { 
8967   q=knil(p);
8968   while ( x_coord(q)>x_coord(p) ) q=knil(q);
8969   while ( x_coord(q)==x_coord(p) ) {
8970     if ( y_coord(q)>y_coord(p) ) q=knil(q); else break;
8971   }
8972   if ( q==knil(p) ) p=mp_link(p);
8973   else { p=mp_link(p); mp_move_knot(mp, knil(p),q); };
8974 }
8975
8976 @ @<Sort the path from |r| to |l| by decreasing $x$@>=
8977 p=mp_link(r);
8978 while ( p!=l ){ 
8979   q=knil(p);
8980   while ( x_coord(q)<x_coord(p) ) q=knil(q);
8981   while ( x_coord(q)==x_coord(p) ) {
8982     if ( y_coord(q)<y_coord(p) ) q=knil(q); else break;
8983   }
8984   if ( q==knil(p) ) p=mp_link(p);
8985   else { p=mp_link(p); mp_move_knot(mp, knil(p),q); };
8986 }
8987
8988 @ The condition involving |ab_vs_cd| tests if there is not a left turn
8989 at knot |q|.  There usually will be a left turn so we streamline the case
8990 where the |then| clause is not executed.
8991
8992 @<Do a Gramm scan and remove vertices where there...@>=
8993
8994 p=l; q=mp_link(l);
8995 while (1) { 
8996   dx=x_coord(q)-x_coord(p);
8997   dy=y_coord(q)-y_coord(p);
8998   p=q; q=mp_link(q);
8999   if ( p==l ) break;
9000   if ( p!=r )
9001     if ( mp_ab_vs_cd(mp, dx,y_coord(q)-y_coord(p),dy,x_coord(q)-x_coord(p))<=0 ) {
9002       @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>;
9003     }
9004   }
9005 }
9006
9007 @ @<Remove knot |p| and back up |p| and |q| but don't go past |l|@>=
9008
9009 s=knil(p);
9010 mp_free_node(mp, p,knot_node_size);
9011 mp_link(s)=q; knil(q)=s;
9012 if ( s==l ) p=s;
9013 else { p=knil(s); q=s; };
9014 }
9015
9016 @ The |find_offset| procedure sets global variables |(cur_x,cur_y)| to the
9017 offset associated with the given direction |(x,y)|.  If two different offsets
9018 apply, it chooses one of them.
9019
9020 @c 
9021 static void mp_find_offset (MP mp,scaled x, scaled y, pointer h) {
9022   pointer p,q; /* consecutive knots */
9023   scaled wx,wy,hx,hy;
9024   /* the transformation matrix for an elliptical pen */
9025   fraction xx,yy; /* untransformed offset for an elliptical pen */
9026   fraction d; /* a temporary register */
9027   if ( pen_is_elliptical(h) ) {
9028     @<Find the offset for |(x,y)| on the elliptical pen~|h|@>
9029   } else { 
9030     q=h;
9031     do {  
9032       p=q; q=mp_link(q);
9033     } while (!(mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)>=0));
9034     do {  
9035       p=q; q=mp_link(q);
9036     } while (!(mp_ab_vs_cd(mp, x_coord(q)-x_coord(p),y, y_coord(q)-y_coord(p),x)<=0));
9037     mp->cur_x=x_coord(p);
9038     mp->cur_y=y_coord(p);
9039   }
9040 }
9041
9042 @ @<Glob...@>=
9043 scaled cur_x;
9044 scaled cur_y; /* all-purpose return value registers */
9045
9046 @ @<Find the offset for |(x,y)| on the elliptical pen~|h|@>=
9047 if ( (x==0) && (y==0) ) {
9048   mp->cur_x=x_coord(h); mp->cur_y=y_coord(h);  
9049 } else { 
9050   @<Find the non-constant part of the transformation for |h|@>;
9051   while ( (abs(x)<fraction_half) && (abs(y)<fraction_half) ){ 
9052     x+=x; y+=y;  
9053   };
9054   @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the
9055     untransformed version of |(x,y)|@>;
9056   mp->cur_x=x_coord(h)+mp_take_fraction(mp, xx,wx)+mp_take_fraction(mp, yy,hx);
9057   mp->cur_y=y_coord(h)+mp_take_fraction(mp, xx,wy)+mp_take_fraction(mp, yy,hy);
9058 }
9059
9060 @ @<Find the non-constant part of the transformation for |h|@>=
9061 wx=left_x(h)-x_coord(h);
9062 wy=left_y(h)-y_coord(h);
9063 hx=right_x(h)-x_coord(h);
9064 hy=right_y(h)-y_coord(h)
9065
9066 @ @<Make |(xx,yy)| the offset on the untransformed \&{pencircle} for the...@>=
9067 yy=-(mp_take_fraction(mp, x,hy)+mp_take_fraction(mp, y,-hx));
9068 xx=mp_take_fraction(mp, x,-wy)+mp_take_fraction(mp, y,wx);
9069 d=mp_pyth_add(mp, xx,yy);
9070 if ( d>0 ) { 
9071   xx=half(mp_make_fraction(mp, xx,d));
9072   yy=half(mp_make_fraction(mp, yy,d));
9073 }
9074
9075 @ Finding the bounding box of a pen is easy except if the pen is elliptical.
9076 But we can handle that case by just calling |find_offset| twice.  The answer
9077 is stored in the global variables |minx|, |maxx|, |miny|, and |maxy|.
9078
9079 @c 
9080 static void mp_pen_bbox (MP mp,pointer h) {
9081   pointer p; /* for scanning the knot list */
9082   if ( pen_is_elliptical(h) ) {
9083     @<Find the bounding box of an elliptical pen@>;
9084   } else { 
9085     minx=x_coord(h); maxx=minx;
9086     miny=y_coord(h); maxy=miny;
9087     p=mp_link(h);
9088     while ( p!=h ) {
9089       if ( x_coord(p)<minx ) minx=x_coord(p);
9090       if ( y_coord(p)<miny ) miny=y_coord(p);
9091       if ( x_coord(p)>maxx ) maxx=x_coord(p);
9092       if ( y_coord(p)>maxy ) maxy=y_coord(p);
9093       p=mp_link(p);
9094     }
9095   }
9096 }
9097
9098 @ @<Find the bounding box of an elliptical pen@>=
9099
9100 mp_find_offset(mp, 0,fraction_one,h);
9101 maxx=mp->cur_x;
9102 minx=2*x_coord(h)-mp->cur_x;
9103 mp_find_offset(mp, -fraction_one,0,h);
9104 maxy=mp->cur_y;
9105 miny=2*y_coord(h)-mp->cur_y;
9106 }
9107
9108 @* \[21] Edge structures.
9109 Now we come to \MP's internal scheme for representing pictures.
9110 The representation is very different from \MF's edge structures
9111 because \MP\ pictures contain \ps\ graphics objects instead of pixel
9112 images.  However, the basic idea is somewhat similar in that shapes
9113 are represented via their boundaries.
9114
9115 The main purpose of edge structures is to keep track of graphical objects
9116 until it is time to translate them into \ps.  Since \MP\ does not need to
9117 know anything about an edge structure other than how to translate it into
9118 \ps\ and how to find its bounding box, edge structures can be just linked
9119 lists of graphical objects.  \MP\ has no easy way to determine whether
9120 two such objects overlap, but it suffices to draw the first one first and
9121 let the second one overwrite it if necessary.
9122
9123 @(mplib.h@>=
9124 enum mp_graphical_object_code {
9125   @<Graphical object codes@>
9126   mp_final_graphic
9127 };
9128
9129 @ Let's consider the types of graphical objects one at a time.
9130 First of all, a filled contour is represented by a eight-word node.  The first
9131 word contains |type| and |link| fields, and the next six words contain a
9132 pointer to a cyclic path and the value to use for \ps' \&{currentrgbcolor}
9133 parameter.  If a pen is used for filling |pen_p|, |ljoin_val| and |miterlim_val|
9134 give the relevant information.
9135
9136 @d path_p(A) mp_link((A)+1)
9137   /* a pointer to the path that needs filling */
9138 @d pen_p(A) info((A)+1)
9139   /* a pointer to the pen to fill or stroke with */
9140 @d color_model(A) type((A)+2) /*  the color model  */
9141 @d obj_red_loc(A) ((A)+3)  /* the first of three locations for the color */
9142 @d obj_cyan_loc obj_red_loc  /* the first of four locations for the color */
9143 @d obj_grey_loc obj_red_loc  /* the location for the color */
9144 @d red_val(A) mp->mem[(A)+3].sc
9145   /* the red component of the color in the range $0\ldots1$ */
9146 @d cyan_val red_val
9147 @d grey_val red_val
9148 @d green_val(A) mp->mem[(A)+4].sc
9149   /* the green component of the color in the range $0\ldots1$ */
9150 @d magenta_val green_val
9151 @d blue_val(A) mp->mem[(A)+5].sc
9152   /* the blue component of the color in the range $0\ldots1$ */
9153 @d yellow_val blue_val
9154 @d black_val(A) mp->mem[(A)+6].sc
9155   /* the blue component of the color in the range $0\ldots1$ */
9156 @d ljoin_val(A) name_type((A))  /* the value of \&{linejoin} */
9157 @:mp_linejoin_}{\&{linejoin} primitive@>
9158 @d miterlim_val(A) mp->mem[(A)+7].sc  /* the value of \&{miterlimit} */
9159 @:mp_miterlimit_}{\&{miterlimit} primitive@>
9160 @d obj_color_part(A) mp->mem[(A)+3-red_part].sc
9161   /* interpret an object pointer that has been offset by |red_part..blue_part| */
9162 @d pre_script(A) mp->mem[(A)+8].hh.lh
9163 @d post_script(A) mp->mem[(A)+8].hh.rh
9164 @d fill_node_size 9
9165
9166 @ @<Graphical object codes@>=
9167 mp_fill_code=1,
9168
9169 @ @c 
9170 static pointer mp_new_fill_node (MP mp,pointer p) {
9171   /* make a fill node for cyclic path |p| and color black */
9172   pointer t; /* the new node */
9173   t=mp_get_node(mp, fill_node_size);
9174   type(t)=mp_fill_code;
9175   path_p(t)=p;
9176   pen_p(t)=null; /* |null| means don't use a pen */
9177   red_val(t)=0;
9178   green_val(t)=0;
9179   blue_val(t)=0;
9180   black_val(t)=0;
9181   color_model(t)=mp_uninitialized_model;
9182   pre_script(t)=null;
9183   post_script(t)=null;
9184   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9185   return t;
9186 }
9187
9188 @ @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>=
9189 if ( mp->internal[mp_linejoin]>unity ) ljoin_val(t)=2;
9190 else if ( mp->internal[mp_linejoin]>0 ) ljoin_val(t)=1;
9191 else ljoin_val(t)=0;
9192 if ( mp->internal[mp_miterlimit]<unity )
9193   miterlim_val(t)=unity;
9194 else
9195   miterlim_val(t)=mp->internal[mp_miterlimit]
9196
9197 @ A stroked path is represented by an eight-word node that is like a filled
9198 contour node except that it contains the current \&{linecap} value, a scale
9199 factor for the dash pattern, and a pointer that is non-null if the stroke
9200 is to be dashed.  The purpose of the scale factor is to allow a picture to
9201 be transformed without touching the picture that |dash_p| points to.
9202
9203 @d dash_p(A) mp_link((A)+9)
9204   /* a pointer to the edge structure that gives the dash pattern */
9205 @d lcap_val(A) type((A)+9)
9206   /* the value of \&{linecap} */
9207 @:mp_linecap_}{\&{linecap} primitive@>
9208 @d dash_scale(A) mp->mem[(A)+10].sc /* dash lengths are scaled by this factor */
9209 @d stroked_node_size 11
9210
9211 @ @<Graphical object codes@>=
9212 mp_stroked_code=2,
9213
9214 @ @c 
9215 static pointer mp_new_stroked_node (MP mp,pointer p) {
9216   /* make a stroked node for path |p| with |pen_p(p)| temporarily |null| */
9217   pointer t; /* the new node */
9218   t=mp_get_node(mp, stroked_node_size);
9219   type(t)=mp_stroked_code;
9220   path_p(t)=p; pen_p(t)=null;
9221   dash_p(t)=null;
9222   dash_scale(t)=unity;
9223   red_val(t)=0;
9224   green_val(t)=0;
9225   blue_val(t)=0;
9226   black_val(t)=0;
9227   color_model(t)=mp_uninitialized_model;
9228   pre_script(t)=null;
9229   post_script(t)=null;
9230   @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>;
9231   if ( mp->internal[mp_linecap]>unity ) lcap_val(t)=2;
9232   else if ( mp->internal[mp_linecap]>0 ) lcap_val(t)=1;
9233   else lcap_val(t)=0;
9234   return t;
9235 }
9236
9237 @ When a dashed line is computed in a transformed coordinate system, the dash
9238 lengths get scaled like the pen shape and we need to compensate for this.  Since
9239 there is no unique scale factor for an arbitrary transformation, we use the
9240 the square root of the determinant.  The properties of the determinant make it
9241 easier to maintain the |dash_scale|.  The computation is fairly straight-forward
9242 except for the initialization of the scale factor |s|.  The factor of 64 is
9243 needed because |square_rt| scales its result by $2^8$ while we need $2^{14}$
9244 to counteract the effect of |take_fraction|.
9245
9246 @ @c
9247 scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) {
9248   scaled maxabs; /* $max(|a|,|b|,|c|,|d|)$ */
9249   unsigned s; /* amount by which the result of |square_rt| needs to be scaled */
9250   @<Initialize |maxabs|@>;
9251   s=64;
9252   while ( (maxabs<fraction_one) && (s>1) ){ 
9253     a+=a; b+=b; c+=c; d+=d;
9254     maxabs+=maxabs; s=(unsigned)(halfp(s));
9255   }
9256   return (scaled)(s*mp_square_rt(mp, abs(mp_take_fraction(mp, a,d)-mp_take_fraction(mp, b,c))));
9257 }
9258 @#
9259 static scaled mp_get_pen_scale (MP mp,pointer p) { 
9260   return mp_sqrt_det(mp, 
9261     left_x(p)-x_coord(p), right_x(p)-x_coord(p),
9262     left_y(p)-y_coord(p), right_y(p)-y_coord(p));
9263 }
9264
9265 @ @<Declarations@>=
9266 static scaled mp_sqrt_det (MP mp,scaled a, scaled b, scaled c, scaled d) ;
9267
9268
9269 @ @<Initialize |maxabs|@>=
9270 maxabs=abs(a);
9271 if ( abs(b)>maxabs ) maxabs=abs(b);
9272 if ( abs(c)>maxabs ) maxabs=abs(c);
9273 if ( abs(d)>maxabs ) maxabs=abs(d)
9274
9275 @ When a picture contains text, this is represented by a fourteen-word node
9276 where the color information and |type| and |link| fields are augmented by
9277 additional fields that describe the text and  how it is transformed.
9278 The |path_p| and |pen_p| pointers are replaced by a number that identifies
9279 the font and a string number that gives the text to be displayed.
9280 The |width|, |height|, and |depth| fields
9281 give the dimensions of the text at its design size, and the remaining six
9282 words give a transformation to be applied to the text.  The |new_text_node|
9283 function initializes everything to default values so that the text comes out
9284 black with its reference point at the origin.
9285
9286 @d text_p(A) mp_link((A)+1)  /* a string pointer for the text to display */
9287 @d font_n(A) info((A)+1)  /* the font number */
9288 @d width_val(A) mp->mem[(A)+7].sc  /* unscaled width of the text */
9289 @d height_val(A) mp->mem[(A)+9].sc  /* unscaled height of the text */
9290 @d depth_val(A) mp->mem[(A)+10].sc  /* unscaled depth of the text */
9291 @d text_tx_loc(A) ((A)+11)
9292   /* the first of six locations for transformation parameters */
9293 @d tx_val(A) mp->mem[(A)+11].sc  /* $x$ shift amount */
9294 @d ty_val(A) mp->mem[(A)+12].sc  /* $y$ shift amount */
9295 @d txx_val(A) mp->mem[(A)+13].sc  /* |txx| transformation parameter */
9296 @d txy_val(A) mp->mem[(A)+14].sc  /* |txy| transformation parameter */
9297 @d tyx_val(A) mp->mem[(A)+15].sc  /* |tyx| transformation parameter */
9298 @d tyy_val(A) mp->mem[(A)+16].sc  /* |tyy| transformation parameter */
9299 @d text_trans_part(A) mp->mem[(A)+11-x_part].sc
9300     /* interpret a text node pointer that has been offset by |x_part..yy_part| */
9301 @d text_node_size 17
9302
9303 @ @<Graphical object codes@>=
9304 mp_text_code=3,
9305
9306 @ @c
9307 static pointer mp_new_text_node (MP mp,char *f,str_number s) {
9308   /* make a text node for font |f| and text string |s| */
9309   pointer t; /* the new node */
9310   t=mp_get_node(mp, text_node_size);
9311   type(t)=mp_text_code;
9312   text_p(t)=s;
9313   font_n(t)=(halfword)mp_find_font(mp, f); /* this identifies the font */
9314   red_val(t)=0;
9315   green_val(t)=0;
9316   blue_val(t)=0;
9317   black_val(t)=0;
9318   color_model(t)=mp_uninitialized_model;
9319   pre_script(t)=null;
9320   post_script(t)=null;
9321   tx_val(t)=0; ty_val(t)=0;
9322   txx_val(t)=unity; txy_val(t)=0;
9323   tyx_val(t)=0; tyy_val(t)=unity;
9324   mp_set_text_box(mp, t); /* this finds the bounding box */
9325   return t;
9326 }
9327
9328 @ The last two types of graphical objects that can occur in an edge structure
9329 are clipping paths and \&{setbounds} paths.  These are slightly more difficult
9330 @:set_bounds_}{\&{setbounds} primitive@>
9331 to implement because we must keep track of exactly what is being clipped or
9332 bounded when pictures get merged together.  For this reason, each clipping or
9333 \&{setbounds} operation is represented by a pair of nodes:  first comes a
9334 two-word node whose |path_p| gives the relevant path, then there is the list
9335 of objects to clip or bound followed by a two-word node whose second word is
9336 unused.
9337
9338 Using at least two words for each graphical object node allows them all to be
9339 allocated and deallocated similarly with a global array |gr_object_size| to
9340 give the size in words for each object type.
9341
9342 @d start_clip_size 2
9343 @d start_bounds_size 2
9344 @d stop_clip_size 2 /* the second word is not used here */
9345 @d stop_bounds_size 2 /* the second word is not used here */
9346 @#
9347 @d stop_type(A) ((A)+2)
9348   /* matching |type| for |start_clip_code| or |start_bounds_code| */
9349 @d has_color(A) (type((A))<mp_start_clip_code)
9350   /* does a graphical object have color fields? */
9351 @d has_pen(A) (type((A))<mp_text_code)
9352   /* does a graphical object have a |pen_p| field? */
9353 @d is_start_or_stop(A) (type((A))>=mp_start_clip_code)
9354 @d is_stop(A) (type((A))>=mp_stop_clip_code)
9355
9356 @ @<Graphical object codes@>=
9357 mp_start_clip_code=4, /* |type| of a node that starts clipping */
9358 mp_start_bounds_code=5, /* |type| of a node that gives a \&{setbounds} path */
9359 mp_stop_clip_code=6, /* |type| of a node that stops clipping */
9360 mp_stop_bounds_code=7, /* |type| of a node that stops \&{setbounds} */
9361
9362 @ @c 
9363 static pointer mp_new_bounds_node (MP mp,pointer p, quarterword  c) {
9364   /* make a node of type |c| where |p| is the clipping or \&{setbounds} path */
9365   pointer t; /* the new node */
9366   t=mp_get_node(mp, mp->gr_object_size[c]);
9367   type(t)=c;
9368   path_p(t)=p;
9369   return t;
9370 }
9371
9372 @ We need an array to keep track of the sizes of graphical objects.
9373
9374 @<Glob...@>=
9375 quarterword gr_object_size[mp_stop_bounds_code+1];
9376
9377 @ @<Set init...@>=
9378 mp->gr_object_size[mp_fill_code]=fill_node_size;
9379 mp->gr_object_size[mp_stroked_code]=stroked_node_size;
9380 mp->gr_object_size[mp_text_code]=text_node_size;
9381 mp->gr_object_size[mp_start_clip_code]=start_clip_size;
9382 mp->gr_object_size[mp_stop_clip_code]=stop_clip_size;
9383 mp->gr_object_size[mp_start_bounds_code]=start_bounds_size;
9384 mp->gr_object_size[mp_stop_bounds_code]=stop_bounds_size;
9385
9386 @ All the essential information in an edge structure is encoded as a linked list
9387 of graphical objects as we have just seen, but it is helpful to add some
9388 redundant information.  A single edge structure might be used as a dash pattern
9389 many times, and it would be nice to avoid scanning the same structure
9390 repeatedly.  Thus, an edge structure known to be a suitable dash pattern
9391 has a header that gives a list of dashes in a sorted order designed for rapid
9392 translation into \ps.
9393
9394 Each dash is represented by a three-word node containing the initial and final
9395 $x$~coordinates as well as the usual |link| field.  The |link| fields points to
9396 the dash node with the next higher $x$-coordinates and the final link points
9397 to a special location called |null_dash|.  (There should be no overlap between
9398 dashes).  Since the $y$~coordinate of the dash pattern is needed to determine
9399 the period of repetition, this needs to be stored in the edge header along
9400 with a pointer to the list of dash nodes.
9401
9402 @d start_x(A) mp->mem[(A)+1].sc  /* the starting $x$~coordinate in a dash node */
9403 @d stop_x(A) mp->mem[(A)+2].sc  /* the ending $x$~coordinate in a dash node */
9404 @d dash_node_size 3
9405 @d dash_list mp_link
9406   /* in an edge header this points to the first dash node */
9407 @d dash_y(A) mp->mem[(A)+1].sc  /* $y$ value for the dash list in an edge header */
9408
9409 @ It is also convenient for an edge header to contain the bounding
9410 box information needed by the \&{llcorner} and \&{urcorner} operators
9411 so that this does not have to be recomputed unnecessarily.  This is done by
9412 adding fields for the $x$~and $y$ extremes as well as a pointer that indicates
9413 how far the bounding box computation has gotten.  Thus if the user asks for
9414 the bounding box and then adds some more text to the picture before asking
9415 for more bounding box information, the second computation need only look at
9416 the additional text.
9417
9418 When the bounding box has not been computed, the |bblast| pointer points
9419 to a dummy link at the head of the graphical object list while the |minx_val|
9420 and |miny_val| fields contain |el_gordo| and the |maxx_val| and |maxy_val|
9421 fields contain |-el_gordo|.
9422
9423 Since the bounding box of pictures containing objects of type
9424 |mp_start_bounds_code| depends on the value of \&{truecorners}, the bounding box
9425 @:mp_true_corners_}{\&{truecorners} primitive@>
9426 data might not be valid for all values of this parameter.  Hence, the |bbtype|
9427 field is needed to keep track of this.
9428
9429 @d minx_val(A) mp->mem[(A)+2].sc
9430 @d miny_val(A) mp->mem[(A)+3].sc
9431 @d maxx_val(A) mp->mem[(A)+4].sc
9432 @d maxy_val(A) mp->mem[(A)+5].sc
9433 @d bblast(A) mp_link((A)+6)  /* last item considered in bounding box computation */
9434 @d bbtype(A) info((A)+6)  /* tells how bounding box data depends on \&{truecorners} */
9435 @d dummy_loc(A) ((A)+7)  /* where the object list begins in an edge header */
9436 @d no_bounds 0
9437   /* |bbtype| value when bounding box data is valid for all \&{truecorners} values */
9438 @d bounds_set 1
9439   /* |bbtype| value when bounding box data is for \&{truecorners}${}\le 0$ */
9440 @d bounds_unset 2
9441   /* |bbtype| value when bounding box data is for \&{truecorners}${}>0$ */
9442
9443 @c 
9444 static void mp_init_bbox (MP mp,pointer h) {
9445   /* Initialize the bounding box information in edge structure |h| */
9446   bblast(h)=dummy_loc(h);
9447   bbtype(h)=no_bounds;
9448   minx_val(h)=el_gordo;
9449   miny_val(h)=el_gordo;
9450   maxx_val(h)=-el_gordo;
9451   maxy_val(h)=-el_gordo;
9452 }
9453
9454 @ The only other entries in an edge header are a reference count in the first
9455 word and a pointer to the tail of the object list in the last word.
9456
9457 @d obj_tail(A) info((A)+7)  /* points to the last entry in the object list */
9458 @d edge_header_size 8
9459
9460 @c 
9461 static void mp_init_edges (MP mp,pointer h) {
9462   /* initialize an edge header to null values */
9463   dash_list(h)=null_dash;
9464   obj_tail(h)=dummy_loc(h);
9465   mp_link(dummy_loc(h))=null;
9466   ref_count(h)=null;
9467   mp_init_bbox(mp, h);
9468 }
9469
9470 @ Here is how edge structures are deleted.  The process can be recursive because
9471 of the need to dereference edge structures that are used as dash patterns.
9472 @^recursion@>
9473
9474 @d add_edge_ref(A) incr(ref_count(A))
9475 @d delete_edge_ref(A) { 
9476    if ( ref_count((A))==null ) 
9477      mp_toss_edges(mp, A);
9478    else 
9479      decr(ref_count(A)); 
9480    }
9481
9482 @<Declarations@>=
9483 static void mp_flush_dash_list (MP mp,pointer h);
9484 static pointer mp_toss_gr_object (MP mp,pointer p) ;
9485 static void mp_toss_edges (MP mp,pointer h) ;
9486
9487 @ @c void mp_toss_edges (MP mp,pointer h) {
9488   pointer p,q;  /* pointers that scan the list being recycled */
9489   pointer r; /* an edge structure that object |p| refers to */
9490   mp_flush_dash_list(mp, h);
9491   q=mp_link(dummy_loc(h));
9492   while ( (q!=null) ) { 
9493     p=q; q=mp_link(q);
9494     r=mp_toss_gr_object(mp, p);
9495     if ( r!=null ) delete_edge_ref(r);
9496   }
9497   mp_free_node(mp, h,edge_header_size);
9498 }
9499 void mp_flush_dash_list (MP mp,pointer h) {
9500   pointer p,q;  /* pointers that scan the list being recycled */
9501   q=dash_list(h);
9502   while ( q!=null_dash ) { 
9503     p=q; q=mp_link(q);
9504     mp_free_node(mp, p,dash_node_size);
9505   }
9506   dash_list(h)=null_dash;
9507 }
9508 pointer mp_toss_gr_object (MP mp,pointer p) {
9509   /* returns an edge structure that needs to be dereferenced */
9510   pointer e; /* the edge structure to return */
9511   e=null;
9512   @<Prepare to recycle graphical object |p|@>;
9513   mp_free_node(mp, p,mp->gr_object_size[type(p)]);
9514   return e;
9515 }
9516
9517 @ @<Prepare to recycle graphical object |p|@>=
9518 switch (type(p)) {
9519 case mp_fill_code: 
9520   mp_toss_knot_list(mp, path_p(p));
9521   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9522   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9523   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9524   break;
9525 case mp_stroked_code: 
9526   mp_toss_knot_list(mp, path_p(p));
9527   if ( pen_p(p)!=null ) mp_toss_knot_list(mp, pen_p(p));
9528   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9529   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9530   e=dash_p(p);
9531   break;
9532 case mp_text_code: 
9533   delete_str_ref(text_p(p));
9534   if ( pre_script(p)!=null ) delete_str_ref(pre_script(p));
9535   if ( post_script(p)!=null ) delete_str_ref(post_script(p));
9536   break;
9537 case mp_start_clip_code:
9538 case mp_start_bounds_code: 
9539   mp_toss_knot_list(mp, path_p(p));
9540   break;
9541 case mp_stop_clip_code:
9542 case mp_stop_bounds_code: 
9543   break;
9544 } /* there are no other cases */
9545
9546 @ If we use |add_edge_ref| to ``copy'' edge structures, the real copying needs
9547 to be done before making a significant change to an edge structure.  Much of
9548 the work is done in a separate routine |copy_objects| that copies a list of
9549 graphical objects into a new edge header.
9550
9551 @c
9552 static pointer mp_private_edges (MP mp,pointer h) {
9553   /* make a private copy of the edge structure headed by |h| */
9554   pointer hh;  /* the edge header for the new copy */
9555   pointer p,pp;  /* pointers for copying the dash list */
9556   if ( ref_count(h)==null ) {
9557     return h;
9558   } else { 
9559     decr(ref_count(h));
9560     hh=mp_copy_objects(mp, mp_link(dummy_loc(h)),null);
9561     @<Copy the dash list from |h| to |hh|@>;
9562     @<Copy the bounding box information from |h| to |hh| and make |bblast(hh)|
9563       point into the new object list@>;
9564     return hh;
9565   }
9566 }
9567
9568 @ Here we use the fact that |dash_list(hh)=mp_link(hh)|.
9569 @^data structure assumptions@>
9570
9571 @<Copy the dash list from |h| to |hh|@>=
9572 pp=hh; p=dash_list(h);
9573 while ( (p!=null_dash) ) { 
9574   mp_link(pp)=mp_get_node(mp, dash_node_size);
9575   pp=mp_link(pp);
9576   start_x(pp)=start_x(p);
9577   stop_x(pp)=stop_x(p);
9578   p=mp_link(p);
9579 }
9580 mp_link(pp)=null_dash;
9581 dash_y(hh)=dash_y(h)
9582
9583
9584 @ |h| is an edge structure
9585
9586 @c
9587 static mp_dash_object *mp_export_dashes (MP mp, pointer q, scaled *w) {
9588   mp_dash_object *d;
9589   pointer p, h;
9590   scaled scf; /* scale factor */
9591   int *dashes = NULL;
9592   int num_dashes = 1;
9593   h = dash_p(q);
9594   if (h==null ||  dash_list(h)==null_dash) 
9595         return NULL;
9596   p = dash_list(h);
9597   scf=mp_get_pen_scale(mp, pen_p(q));
9598   if (scf==0) {
9599     if (*w==0) scf = dash_scale(q); else return NULL;
9600   } else {
9601     scf=mp_make_scaled(mp, *w,scf);
9602     scf=mp_take_scaled(mp, scf,dash_scale(q));
9603   }
9604   *w = scf;
9605   d = xmalloc(1,sizeof(mp_dash_object));
9606   start_x(null_dash)=start_x(p)+dash_y(h);
9607   while (p != null_dash) { 
9608         dashes = xrealloc(dashes, (num_dashes+2), sizeof(scaled));
9609         dashes[(num_dashes-1)] = 
9610       mp_take_scaled(mp,(stop_x(p)-start_x(p)),scf);
9611         dashes[(num_dashes)]   = 
9612       mp_take_scaled(mp,(start_x(mp_link(p))-stop_x(p)),scf);
9613         dashes[(num_dashes+1)] = -1; /* terminus */
9614         num_dashes+=2;
9615     p=mp_link(p);
9616   }
9617   d->array_field  = dashes;
9618   d->offset_field = 
9619     mp_take_scaled(mp,mp_dash_offset(mp, h),scf);
9620   return d;
9621 }
9622
9623
9624
9625 @ @<Copy the bounding box information from |h| to |hh|...@>=
9626 minx_val(hh)=minx_val(h);
9627 miny_val(hh)=miny_val(h);
9628 maxx_val(hh)=maxx_val(h);
9629 maxy_val(hh)=maxy_val(h);
9630 bbtype(hh)=bbtype(h);
9631 p=dummy_loc(h); pp=dummy_loc(hh);
9632 while ((p!=bblast(h)) ) { 
9633   if ( p==null ) mp_confusion(mp, "bblast");
9634 @:this can't happen bblast}{\quad bblast@>
9635   p=mp_link(p); pp=mp_link(pp);
9636 }
9637 bblast(hh)=pp
9638
9639 @ Here is the promised routine for copying graphical objects into a new edge
9640 structure.  It starts copying at object~|p| and stops just before object~|q|.
9641 If |q| is null, it copies the entire sublist headed at |p|.  The resulting edge
9642 structure requires further initialization by |init_bbox|.
9643
9644 @<Declarations@>=
9645 static pointer mp_copy_objects (MP mp, pointer p, pointer q);
9646
9647 @ @c
9648 pointer mp_copy_objects (MP mp, pointer p, pointer q) {
9649   pointer hh;  /* the new edge header */
9650   pointer pp;  /* the last newly copied object */
9651   quarterword k;  /* temporary register */
9652   hh=mp_get_node(mp, edge_header_size);
9653   dash_list(hh)=null_dash;
9654   ref_count(hh)=null;
9655   pp=dummy_loc(hh);
9656   while ( (p!=q) ) {
9657     @<Make |mp_link(pp)| point to a copy of object |p|, and update |p| and |pp|@>;
9658   }
9659   obj_tail(hh)=pp;
9660   mp_link(pp)=null;
9661   return hh;
9662 }
9663
9664 @ @<Make |mp_link(pp)| point to a copy of object |p|, and update |p| and |pp|@>=
9665 { k=mp->gr_object_size[type(p)];
9666   mp_link(pp)=mp_get_node(mp, k);
9667   pp=mp_link(pp);
9668   while ( (k>0) ) { decr(k); mp->mem[pp+k]=mp->mem[p+k];  };
9669   @<Fix anything in graphical object |pp| that should differ from the
9670     corresponding field in |p|@>;
9671   p=mp_link(p);
9672 }
9673
9674 @ @<Fix anything in graphical object |pp| that should differ from the...@>=
9675 switch (type(p)) {
9676 case mp_start_clip_code:
9677 case mp_start_bounds_code: 
9678   path_p(pp)=mp_copy_path(mp, path_p(p));
9679   break;
9680 case mp_fill_code: 
9681   path_p(pp)=mp_copy_path(mp, path_p(p));
9682   if ( pre_script(p)!=null )  add_str_ref(pre_script(p));
9683   if ( post_script(p)!=null ) add_str_ref(post_script(p));
9684   if ( pen_p(p)!=null ) pen_p(pp)=copy_pen(pen_p(p));
9685   break;
9686 case mp_stroked_code: 
9687   if ( pre_script(p)!=null )  add_str_ref(pre_script(p));
9688   if ( post_script(p)!=null ) add_str_ref(post_script(p));
9689   path_p(pp)=mp_copy_path(mp, path_p(p));
9690   pen_p(pp)=copy_pen(pen_p(p));
9691   if ( dash_p(p)!=null ) add_edge_ref(dash_p(pp));
9692   break;
9693 case mp_text_code: 
9694   if ( pre_script(p)!=null )  add_str_ref(pre_script(p));
9695   if ( post_script(p)!=null ) add_str_ref(post_script(p));
9696   add_str_ref(text_p(pp));
9697   break;
9698 case mp_stop_clip_code:
9699 case mp_stop_bounds_code: 
9700   break;
9701 }  /* there are no other cases */
9702
9703 @ Here is one way to find an acceptable value for the second argument to
9704 |copy_objects|.  Given a non-null graphical object list, |skip_1component|
9705 skips past one picture component, where a ``picture component'' is a single
9706 graphical object, or a start bounds or start clip object and everything up
9707 through the matching stop bounds or stop clip object.  The macro version avoids
9708 procedure call overhead and error handling: |skip_component(p)(e)| advances |p|
9709 unless |p| points to a stop bounds or stop clip node, in which case it executes
9710 |e| instead.
9711
9712 @d skip_component(A)
9713     if ( ! is_start_or_stop((A)) ) (A)=mp_link((A));
9714     else if ( ! is_stop((A)) ) (A)=mp_skip_1component(mp, (A));
9715     else 
9716
9717 @c 
9718 static pointer mp_skip_1component (MP mp,pointer p) {
9719   integer lev; /* current nesting level */
9720   lev=0;
9721   do {  
9722    if ( is_start_or_stop(p) ) {
9723      if ( is_stop(p) ) decr(lev);  else incr(lev);
9724    }
9725    p=mp_link(p);
9726   } while (lev!=0);
9727   return p;
9728 }
9729
9730 @ Here is a diagnostic routine for printing an edge structure in symbolic form.
9731
9732 @<Declarations@>=
9733 static void mp_print_edges (MP mp,pointer h, const char *s, boolean nuline) ;
9734
9735 @ @c
9736 void mp_print_edges (MP mp,pointer h, const char *s, boolean nuline) {
9737   pointer p;  /* a graphical object to be printed */
9738   pointer hh,pp;  /* temporary pointers */
9739   scaled scf;  /* a scale factor for the dash pattern */
9740   boolean ok_to_dash;  /* |false| for polygonal pen strokes */
9741   mp_print_diagnostic(mp, "Edge structure",s,nuline);
9742   p=dummy_loc(h);
9743   while ( mp_link(p)!=null ) { 
9744     p=mp_link(p);
9745     mp_print_ln(mp);
9746     switch (type(p)) {
9747       @<Cases for printing graphical object node |p|@>;
9748     default: 
9749           mp_print(mp, "[unknown object type!]");
9750           break;
9751     }
9752   }
9753   mp_print_nl(mp, "End edges");
9754   if ( p!=obj_tail(h) ) mp_print(mp, "?");
9755 @.End edges?@>
9756   mp_end_diagnostic(mp, true);
9757 }
9758
9759 @ @<Cases for printing graphical object node |p|@>=
9760 case mp_fill_code: 
9761   mp_print(mp, "Filled contour ");
9762   mp_print_obj_color(mp, p);
9763   mp_print_char(mp, xord(':')); mp_print_ln(mp);
9764   mp_pr_path(mp, path_p(p)); mp_print_ln(mp);
9765   if ( (pen_p(p)!=null) ) {
9766     @<Print join type for graphical object |p|@>;
9767     mp_print(mp, " with pen"); mp_print_ln(mp);
9768     mp_pr_pen(mp, pen_p(p));
9769   }
9770   break;
9771
9772 @ @<Print join type for graphical object |p|@>=
9773 switch (ljoin_val(p)) {
9774 case 0:
9775   mp_print(mp, "mitered joins limited ");
9776   mp_print_scaled(mp, miterlim_val(p));
9777   break;
9778 case 1:
9779   mp_print(mp, "round joins");
9780   break;
9781 case 2:
9782   mp_print(mp, "beveled joins");
9783   break;
9784 default: 
9785   mp_print(mp, "?? joins");
9786 @.??@>
9787   break;
9788 }
9789
9790 @ For stroked nodes, we need to print |lcap_val(p)| as well.
9791
9792 @<Print join and cap types for stroked node |p|@>=
9793 switch (lcap_val(p)) {
9794 case 0:mp_print(mp, "butt"); break;
9795 case 1:mp_print(mp, "round"); break;
9796 case 2:mp_print(mp, "square"); break;
9797 default: mp_print(mp, "??"); break;
9798 @.??@>
9799 }
9800 mp_print(mp, " ends, ");
9801 @<Print join type for graphical object |p|@>
9802
9803 @ Here is a routine that prints the color of a graphical object if it isn't
9804 black (the default color).
9805
9806 @<Declarations@>=
9807 static void mp_print_obj_color (MP mp,pointer p) ;
9808
9809 @ @c
9810 void mp_print_obj_color (MP mp,pointer p) { 
9811   if ( color_model(p)==mp_grey_model ) {
9812     if ( grey_val(p)>0 ) { 
9813       mp_print(mp, "greyed ");
9814       mp_print_compact_node(mp, obj_grey_loc(p),1);
9815     };
9816   } else if ( color_model(p)==mp_cmyk_model ) {
9817     if ( (cyan_val(p)>0) || (magenta_val(p)>0) || 
9818          (yellow_val(p)>0) || (black_val(p)>0) ) { 
9819       mp_print(mp, "processcolored ");
9820       mp_print_compact_node(mp, obj_cyan_loc(p),4);
9821     };
9822   } else if ( color_model(p)==mp_rgb_model ) {
9823     if ( (red_val(p)>0) || (green_val(p)>0) || (blue_val(p)>0) ) { 
9824       mp_print(mp, "colored "); 
9825       mp_print_compact_node(mp, obj_red_loc(p),3);
9826     };
9827   }
9828 }
9829
9830 @ We also need a procedure for printing consecutive scaled values as if they
9831 were a known big node.
9832
9833 @<Declarations@>=
9834 static void mp_print_compact_node (MP mp,pointer p, quarterword k) ;
9835
9836 @ @c
9837 void mp_print_compact_node (MP mp,pointer p, quarterword k) {
9838   pointer q;  /* last location to print */
9839   q=p+k-1;
9840   mp_print_char(mp, xord('('));
9841   while ( p<=q ){ 
9842     mp_print_scaled(mp, mp->mem[p].sc);
9843     if ( p<q ) mp_print_char(mp, xord(','));
9844     incr(p);
9845   }
9846   mp_print_char(mp, xord(')'));
9847 }
9848
9849 @ @<Cases for printing graphical object node |p|@>=
9850 case mp_stroked_code: 
9851   mp_print(mp, "Filled pen stroke ");
9852   mp_print_obj_color(mp, p);
9853   mp_print_char(mp, xord(':')); mp_print_ln(mp);
9854   mp_pr_path(mp, path_p(p));
9855   if ( dash_p(p)!=null ) { 
9856     mp_print_nl(mp, "dashed (");
9857     @<Finish printing the dash pattern that |p| refers to@>;
9858   }
9859   mp_print_ln(mp);
9860   @<Print join and cap types for stroked node |p|@>;
9861   mp_print(mp, " with pen"); mp_print_ln(mp);
9862   if ( pen_p(p)==null ) mp_print(mp, "???"); /* shouldn't happen */
9863 @.???@>
9864   else mp_pr_pen(mp, pen_p(p));
9865   break;
9866
9867 @ Normally, the  |dash_list| field in an edge header is set to |null_dash|
9868 when it is not known to define a suitable dash pattern.  This is disallowed
9869 here because the |dash_p| field should never point to such an edge header.
9870 Note that memory is allocated for |start_x(null_dash)| and we are free to
9871 give it any convenient value.
9872
9873 @<Finish printing the dash pattern that |p| refers to@>=
9874 ok_to_dash=pen_is_elliptical(pen_p(p));
9875 if ( ! ok_to_dash ) scf=unity; else scf=dash_scale(p);
9876 hh=dash_p(p);
9877 pp=dash_list(hh);
9878 if ( (pp==null_dash) || (dash_y(hh)<0) ) {
9879   mp_print(mp, " ??");
9880 } else { start_x(null_dash)=start_x(pp)+dash_y(hh);
9881   while ( pp!=null_dash ) { 
9882     mp_print(mp, "on ");
9883     mp_print_scaled(mp, mp_take_scaled(mp, stop_x(pp)-start_x(pp),scf));
9884     mp_print(mp, " off ");
9885     mp_print_scaled(mp, mp_take_scaled(mp, start_x(mp_link(pp))-stop_x(pp),scf));
9886     pp = mp_link(pp);
9887     if ( pp!=null_dash ) mp_print_char(mp, xord(' '));
9888   }
9889   mp_print(mp, ") shifted ");
9890   mp_print_scaled(mp, -mp_take_scaled(mp, mp_dash_offset(mp, hh),scf));
9891   if ( ! ok_to_dash || (dash_y(hh)==0) ) mp_print(mp, " (this will be ignored)");
9892 }
9893
9894 @ @<Declarations@>=
9895 static scaled mp_dash_offset (MP mp,pointer h) ;
9896
9897 @ @c
9898 scaled mp_dash_offset (MP mp,pointer h) {
9899   scaled x;  /* the answer */
9900   if (dash_list(h)==null_dash || dash_y(h)<0) mp_confusion(mp, "dash0");
9901 @:this can't happen dash0}{\quad dash0@>
9902   if ( dash_y(h)==0 ) {
9903     x=0; 
9904   } else { 
9905     x=-(start_x(dash_list(h)) % dash_y(h));
9906     if ( x<0 ) x=x+dash_y(h);
9907   }
9908   return x;
9909 }
9910
9911 @ @<Cases for printing graphical object node |p|@>=
9912 case mp_text_code: 
9913   mp_print_char(mp, xord('"')); mp_print_str(mp,text_p(p));
9914   mp_print(mp, "\" infont \""); mp_print(mp, mp->font_name[font_n(p)]);
9915   mp_print_char(mp, xord('"')); mp_print_ln(mp);
9916   mp_print_obj_color(mp, p);
9917   mp_print(mp, "transformed ");
9918   mp_print_compact_node(mp, text_tx_loc(p),6);
9919   break;
9920
9921 @ @<Cases for printing graphical object node |p|@>=
9922 case mp_start_clip_code: 
9923   mp_print(mp, "clipping path:");
9924   mp_print_ln(mp);
9925   mp_pr_path(mp, path_p(p));
9926   break;
9927 case mp_stop_clip_code: 
9928   mp_print(mp, "stop clipping");
9929   break;
9930
9931 @ @<Cases for printing graphical object node |p|@>=
9932 case mp_start_bounds_code: 
9933   mp_print(mp, "setbounds path:");
9934   mp_print_ln(mp);
9935   mp_pr_path(mp, path_p(p));
9936   break;
9937 case mp_stop_bounds_code: 
9938   mp_print(mp, "end of setbounds");
9939   break;
9940
9941 @ To initialize the |dash_list| field in an edge header~|h|, we need a
9942 subroutine that scans an edge structure and tries to interpret it as a dash
9943 pattern.  This can only be done when there are no filled regions or clipping
9944 paths and all the pen strokes have the same color.  The first step is to let
9945 $y_0$ be the initial $y$~coordinate of the first pen stroke.  Then we implicitly
9946 project all the pen stroke paths onto the line $y=y_0$ and require that there
9947 be no retracing.  If the resulting paths cover a range of $x$~coordinates of
9948 length $\Delta x$, we set |dash_y(h)| to the length of the dash pattern by
9949 finding the maximum of $\Delta x$ and the absolute value of~$y_0$.
9950
9951 @c 
9952 static pointer mp_make_dashes (MP mp,pointer h) { /* returns |h| or |null| */
9953   pointer p;  /* this scans the stroked nodes in the object list */
9954   pointer p0;  /* if not |null| this points to the first stroked node */
9955   pointer pp,qq,rr;  /* pointers into |path_p(p)| */
9956   pointer d,dd;  /* pointers used to create the dash list */
9957   scaled y0;
9958   @<Other local variables in |make_dashes|@>;
9959   y0=0;  /* the initial $y$ coordinate */
9960   if ( dash_list(h)!=null_dash ) 
9961         return h;
9962   p0=null;
9963   p=mp_link(dummy_loc(h));
9964   while ( p!=null ) { 
9965     if ( type(p)!=mp_stroked_code ) {
9966       @<Compain that the edge structure contains a node of the wrong type
9967         and |goto not_found|@>;
9968     }
9969     pp=path_p(p);
9970     if ( p0==null ){ p0=p; y0=y_coord(pp);  };
9971     @<Make |d| point to a new dash node created from stroke |p| and path |pp|
9972       or |goto not_found| if there is an error@>;
9973     @<Insert |d| into the dash list and |goto not_found| if there is an error@>;
9974     p=mp_link(p);
9975   }
9976   if ( dash_list(h)==null_dash ) 
9977     goto NOT_FOUND; /* No error message */
9978   @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>;
9979   @<Set |dash_y(h)| and merge the first and last dashes if necessary@>;
9980   return h;
9981 NOT_FOUND: 
9982   @<Flush the dash list, recycle |h| and return |null|@>;
9983 }
9984
9985 @ @<Compain that the edge structure contains a node of the wrong type...@>=
9986
9987 print_err("Picture is too complicated to use as a dash pattern");
9988 help3("When you say `dashed p', picture p should not contain any",
9989   "text, filled regions, or clipping paths.  This time it did",
9990   "so I'll just make it a solid line instead.");
9991 mp_put_get_error(mp);
9992 goto NOT_FOUND;
9993 }
9994
9995 @ A similar error occurs when monotonicity fails.
9996
9997 @<Declarations@>=
9998 static void mp_x_retrace_error (MP mp) ;
9999
10000 @ @c
10001 void mp_x_retrace_error (MP mp) { 
10002 print_err("Picture is too complicated to use as a dash pattern");
10003 help3("When you say `dashed p', every path in p should be monotone",
10004   "in x and there must be no overlapping.  This failed",
10005   "so I'll just make it a solid line instead.");
10006 mp_put_get_error(mp);
10007 }
10008
10009 @ We stash |p| in |info(d)| if |dash_p(p)<>0| so that subsequent processing can
10010 handle the case where the pen stroke |p| is itself dashed.
10011
10012 @<Make |d| point to a new dash node created from stroke |p| and path...@>=
10013 @<Make sure |p| and |p0| are the same color and |goto not_found| if there is
10014   an error@>;
10015 rr=pp;
10016 if ( mp_link(pp)!=pp ) {
10017   do {  
10018     qq=rr; rr=mp_link(rr);
10019     @<Check for retracing between knots |qq| and |rr| and |goto not_found|
10020       if there is a problem@>;
10021   } while (right_type(rr)!=mp_endpoint);
10022 }
10023 d=mp_get_node(mp, dash_node_size);
10024 if ( dash_p(p)==0 ) info(d)=0;  else info(d)=p;
10025 if ( x_coord(pp)<x_coord(rr) ) { 
10026   start_x(d)=x_coord(pp);
10027   stop_x(d)=x_coord(rr);
10028 } else { 
10029   start_x(d)=x_coord(rr);
10030   stop_x(d)=x_coord(pp);
10031 }
10032
10033 @ We also need to check for the case where the segment from |qq| to |rr| is
10034 monotone in $x$ but is reversed relative to the path from |pp| to |qq|.
10035
10036 @<Check for retracing between knots |qq| and |rr| and |goto not_found|...@>=
10037 x0=x_coord(qq);
10038 x1=right_x(qq);
10039 x2=left_x(rr);
10040 x3=x_coord(rr);
10041 if ( (x0>x1) || (x1>x2) || (x2>x3) ) {
10042   if ( (x0<x1) || (x1<x2) || (x2<x3) ) {
10043     if ( mp_ab_vs_cd(mp, x2-x1,x2-x1,x1-x0,x3-x2)>0 ) {
10044       mp_x_retrace_error(mp); goto NOT_FOUND;
10045     }
10046   }
10047 }
10048 if ( (x_coord(pp)>x0) || (x0>x3) ) {
10049   if ( (x_coord(pp)<x0) || (x0<x3) ) {
10050     mp_x_retrace_error(mp); goto NOT_FOUND;
10051   }
10052 }
10053
10054 @ @<Other local variables in |make_dashes|@>=
10055   scaled x0,x1,x2,x3;  /* $x$ coordinates of the segment from |qq| to |rr| */
10056
10057 @ @<Make sure |p| and |p0| are the same color and |goto not_found|...@>=
10058 if ( (red_val(p)!=red_val(p0)) || (black_val(p)!=black_val(p0)) ||
10059   (green_val(p)!=green_val(p0)) || (blue_val(p)!=blue_val(p0)) ) {
10060   print_err("Picture is too complicated to use as a dash pattern");
10061   help3("When you say `dashed p', everything in picture p should",
10062     "be the same color.  I can\'t handle your color changes",
10063     "so I'll just make it a solid line instead.");
10064   mp_put_get_error(mp);
10065   goto NOT_FOUND;
10066 }
10067
10068 @ @<Insert |d| into the dash list and |goto not_found| if there is an error@>=
10069 start_x(null_dash)=stop_x(d);
10070 dd=h; /* this makes |mp_link(dd)=dash_list(h)| */
10071 while ( start_x(mp_link(dd))<stop_x(d) )
10072   dd=mp_link(dd);
10073 if ( dd!=h ) {
10074   if ( (stop_x(dd)>start_x(d)) )
10075     { mp_x_retrace_error(mp); goto NOT_FOUND;  };
10076 }
10077 mp_link(d)=mp_link(dd);
10078 mp_link(dd)=d
10079
10080 @ @<Set |dash_y(h)| and merge the first and last dashes if necessary@>=
10081 d=dash_list(h);
10082 while ( (mp_link(d)!=null_dash) )
10083   d=mp_link(d);
10084 dd=dash_list(h);
10085 dash_y(h)=stop_x(d)-start_x(dd);
10086 if ( abs(y0)>dash_y(h) ) {
10087   dash_y(h)=abs(y0);
10088 } else if ( d!=dd ) { 
10089   dash_list(h)=mp_link(dd);
10090   stop_x(d)=stop_x(dd)+dash_y(h);
10091   mp_free_node(mp, dd,dash_node_size);
10092 }
10093
10094 @ We get here when the argument is a null picture or when there is an error.
10095 Recovering from an error involves making |dash_list(h)| empty to indicate
10096 that |h| is not known to be a valid dash pattern.  We also dereference |h|
10097 since it is not being used for the return value.
10098
10099 @<Flush the dash list, recycle |h| and return |null|@>=
10100 mp_flush_dash_list(mp, h);
10101 delete_edge_ref(h);
10102 return null
10103
10104 @ Having carefully saved the dashed stroked nodes in the
10105 corresponding dash nodes, we must be prepared to break up these dashes into
10106 smaller dashes.
10107
10108 @<Scan |dash_list(h)| and deal with any dashes that are themselves dashed@>=
10109 d=h;  /* now |mp_link(d)=dash_list(h)| */
10110 while ( mp_link(d)!=null_dash ) {
10111   ds=info(mp_link(d));
10112   if ( ds==null ) { 
10113     d=mp_link(d);
10114   } else {
10115     hh=dash_p(ds);
10116     hsf=dash_scale(ds);
10117     if ( (hh==null) ) mp_confusion(mp, "dash1");
10118 @:this can't happen dash0}{\quad dash1@>
10119     if ( dash_y(hh)==0 ) {
10120       d=mp_link(d);
10121     } else { 
10122       if ( dash_list(hh)==null ) mp_confusion(mp, "dash1");
10123 @:this can't happen dash0}{\quad dash1@>
10124       @<Replace |mp_link(d)| by a dashed version as determined by edge header
10125           |hh| and scale factor |ds|@>;
10126     }
10127   }
10128 }
10129
10130 @ @<Other local variables in |make_dashes|@>=
10131 pointer dln;  /* |mp_link(d)| */
10132 pointer hh;  /* an edge header that tells how to break up |dln| */
10133 scaled hsf;  /* the dash pattern from |hh| gets scaled by this */
10134 pointer ds;  /* the stroked node from which |hh| and |hsf| are derived */
10135 scaled xoff;  /* added to $x$ values in |dash_list(hh)| to match |dln| */
10136
10137 @ @<Replace |mp_link(d)| by a dashed version as determined by edge header...@>=
10138 dln=mp_link(d);
10139 dd=dash_list(hh);
10140 xoff=start_x(dln)-mp_take_scaled(mp, hsf,start_x(dd))-
10141         mp_take_scaled(mp, hsf,mp_dash_offset(mp, hh));
10142 start_x(null_dash)=mp_take_scaled(mp, hsf,start_x(dd))
10143                    +mp_take_scaled(mp, hsf,dash_y(hh));
10144 stop_x(null_dash)=start_x(null_dash);
10145 @<Advance |dd| until finding the first dash that overlaps |dln| when
10146   offset by |xoff|@>;
10147 while ( start_x(dln)<=stop_x(dln) ) {
10148   @<If |dd| has `fallen off the end', back up to the beginning and fix |xoff|@>;
10149   @<Insert a dash between |d| and |dln| for the overlap with the offset version
10150     of |dd|@>;
10151   dd=mp_link(dd);
10152   start_x(dln)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
10153 }
10154 mp_link(d)=mp_link(dln);
10155 mp_free_node(mp, dln,dash_node_size)
10156
10157 @ The name of this module is a bit of a lie because we just find the
10158 first |dd| where |take_scaled (hsf, stop_x(dd))| is large enough to make an
10159 overlap possible.  It could be that the unoffset version of dash |dln| falls
10160 in the gap between |dd| and its predecessor.
10161
10162 @<Advance |dd| until finding the first dash that overlaps |dln| when...@>=
10163 while ( xoff+mp_take_scaled(mp, hsf,stop_x(dd))<start_x(dln) ) {
10164   dd=mp_link(dd);
10165 }
10166
10167 @ @<If |dd| has `fallen off the end', back up to the beginning and fix...@>=
10168 if ( dd==null_dash ) { 
10169   dd=dash_list(hh);
10170   xoff=xoff+mp_take_scaled(mp, hsf,dash_y(hh));
10171 }
10172
10173 @ At this point we already know that
10174 |start_x(dln)<=xoff+take_scaled(hsf,stop_x(dd))|.
10175
10176 @<Insert a dash between |d| and |dln| for the overlap with the offset...@>=
10177 if ( (xoff+mp_take_scaled(mp, hsf,start_x(dd)))<=stop_x(dln) ) {
10178   mp_link(d)=mp_get_node(mp, dash_node_size);
10179   d=mp_link(d);
10180   mp_link(d)=dln;
10181   if ( start_x(dln)>(xoff+mp_take_scaled(mp, hsf,start_x(dd))))
10182     start_x(d)=start_x(dln);
10183   else 
10184     start_x(d)=xoff+mp_take_scaled(mp, hsf,start_x(dd));
10185   if ( stop_x(dln)<(xoff+mp_take_scaled(mp, hsf,stop_x(dd)))) 
10186     stop_x(d)=stop_x(dln);
10187   else 
10188     stop_x(d)=xoff+mp_take_scaled(mp, hsf,stop_x(dd));
10189 }
10190
10191 @ The next major task is to update the bounding box information in an edge
10192 header~|h|. This is done via a procedure |adjust_bbox| that enlarges an edge
10193 header's bounding box to accommodate the box computed by |path_bbox| or
10194 |pen_bbox|. (This is stored in global variables |minx|, |miny|, |maxx|, and
10195 |maxy|.)
10196
10197 @c static void mp_adjust_bbox (MP mp,pointer h) { 
10198   if ( minx<minx_val(h) ) minx_val(h)=minx;
10199   if ( miny<miny_val(h) ) miny_val(h)=miny;
10200   if ( maxx>maxx_val(h) ) maxx_val(h)=maxx;
10201   if ( maxy>maxy_val(h) ) maxy_val(h)=maxy;
10202 }
10203
10204 @ Here is a special routine for updating the bounding box information in
10205 edge header~|h| to account for the squared-off ends of a non-cyclic path~|p|
10206 that is to be stroked with the pen~|pp|.
10207
10208 @c static void mp_box_ends (MP mp, pointer p, pointer pp, pointer h) {
10209   pointer q;  /* a knot node adjacent to knot |p| */
10210   fraction dx,dy;  /* a unit vector in the direction out of the path at~|p| */
10211   scaled d;  /* a factor for adjusting the length of |(dx,dy)| */
10212   scaled z;  /* a coordinate being tested against the bounding box */
10213   scaled xx,yy;  /* the extreme pen vertex in the |(dx,dy)| direction */
10214   integer i; /* a loop counter */
10215   if ( right_type(p)!=mp_endpoint ) { 
10216     q=mp_link(p);
10217     while (1) { 
10218       @<Make |(dx,dy)| the final direction for the path segment from
10219         |q| to~|p|; set~|d|@>;
10220       d=mp_pyth_add(mp, dx,dy);
10221       if ( d>0 ) { 
10222          @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>;
10223          for (i=1;i<= 2;i++) { 
10224            @<Use |(dx,dy)| to generate a vertex of the square end cap and
10225              update the bounding box to accommodate it@>;
10226            dx=-dx; dy=-dy; 
10227         }
10228       }
10229       if ( right_type(p)==mp_endpoint ) {
10230          return;
10231       } else {
10232         @<Advance |p| to the end of the path and make |q| the previous knot@>;
10233       } 
10234     }
10235   }
10236 }
10237
10238 @ @<Make |(dx,dy)| the final direction for the path segment from...@>=
10239 if ( q==mp_link(p) ) { 
10240   dx=x_coord(p)-right_x(p);
10241   dy=y_coord(p)-right_y(p);
10242   if ( (dx==0)&&(dy==0) ) {
10243     dx=x_coord(p)-left_x(q);
10244     dy=y_coord(p)-left_y(q);
10245   }
10246 } else { 
10247   dx=x_coord(p)-left_x(p);
10248   dy=y_coord(p)-left_y(p);
10249   if ( (dx==0)&&(dy==0) ) {
10250     dx=x_coord(p)-right_x(q);
10251     dy=y_coord(p)-right_y(q);
10252   }
10253 }
10254 dx=x_coord(p)-x_coord(q);
10255 dy=y_coord(p)-y_coord(q)
10256
10257 @ @<Normalize the direction |(dx,dy)| and find the pen offset |(xx,yy)|@>=
10258 dx=mp_make_fraction(mp, dx,d);
10259 dy=mp_make_fraction(mp, dy,d);
10260 mp_find_offset(mp, -dy,dx,pp);
10261 xx=mp->cur_x; yy=mp->cur_y
10262
10263 @ @<Use |(dx,dy)| to generate a vertex of the square end cap and...@>=
10264 mp_find_offset(mp, dx,dy,pp);
10265 d=mp_take_fraction(mp, xx-mp->cur_x,dx)+mp_take_fraction(mp, yy-mp->cur_y,dy);
10266 if ( ((d<0)&&(i==1)) || ((d>0)&&(i==2))) 
10267   mp_confusion(mp, "box_ends");
10268 @:this can't happen box ends}{\quad\\{box\_ends}@>
10269 z=x_coord(p)+mp->cur_x+mp_take_fraction(mp, d,dx);
10270 if ( z<minx_val(h) ) minx_val(h)=z;
10271 if ( z>maxx_val(h) ) maxx_val(h)=z;
10272 z=y_coord(p)+mp->cur_y+mp_take_fraction(mp, d,dy);
10273 if ( z<miny_val(h) ) miny_val(h)=z;
10274 if ( z>maxy_val(h) ) maxy_val(h)=z
10275
10276 @ @<Advance |p| to the end of the path and make |q| the previous knot@>=
10277 do {  
10278   q=p;
10279   p=mp_link(p);
10280 } while (right_type(p)!=mp_endpoint)
10281
10282 @ The major difficulty in finding the bounding box of an edge structure is the
10283 effect of clipping paths.  We treat them conservatively by only clipping to the
10284 clipping path's bounding box, but this still
10285 requires recursive calls to |set_bbox| in order to find the bounding box of
10286 @^recursion@>
10287 the objects to be clipped.  Such calls are distinguished by the fact that the
10288 boolean parameter |top_level| is false.
10289
10290 @c 
10291 void mp_set_bbox (MP mp,pointer h, boolean top_level) {
10292   pointer p;  /* a graphical object being considered */
10293   scaled sminx,sminy,smaxx,smaxy;
10294   /* for saving the bounding box during recursive calls */
10295   scaled x0,x1,y0,y1;  /* temporary registers */
10296   integer lev;  /* nesting level for |mp_start_bounds_code| nodes */
10297   @<Wipe out any existing bounding box information if |bbtype(h)| is
10298   incompatible with |internal[mp_true_corners]|@>;
10299   while ( mp_link(bblast(h))!=null ) { 
10300     p=mp_link(bblast(h));
10301     bblast(h)=p;
10302     switch (type(p)) {
10303     case mp_stop_clip_code: 
10304       if ( top_level ) mp_confusion(mp, "bbox");  else return;
10305 @:this can't happen bbox}{\quad bbox@>
10306       break;
10307     @<Other cases for updating the bounding box based on the type of object |p|@>;
10308     } /* all cases are enumerated above */
10309   }
10310   if ( ! top_level ) mp_confusion(mp, "bbox");
10311 }
10312
10313 @ @<Declarations@>=
10314 static void mp_set_bbox (MP mp,pointer h, boolean top_level);
10315
10316 @ @<Wipe out any existing bounding box information if |bbtype(h)| is...@>=
10317 switch (bbtype(h)) {
10318 case no_bounds: 
10319   break;
10320 case bounds_set: 
10321   if ( mp->internal[mp_true_corners]>0 ) mp_init_bbox(mp, h);
10322   break;
10323 case bounds_unset: 
10324   if ( mp->internal[mp_true_corners]<=0 ) mp_init_bbox(mp, h);
10325   break;
10326 } /* there are no other cases */
10327
10328 @ @<Other cases for updating the bounding box...@>=
10329 case mp_fill_code: 
10330   mp_path_bbox(mp, path_p(p));
10331   if ( pen_p(p)!=null ) { 
10332     x0=minx; y0=miny;
10333     x1=maxx; y1=maxy;
10334     mp_pen_bbox(mp, pen_p(p));
10335     minx=minx+x0;
10336     miny=miny+y0;
10337     maxx=maxx+x1;
10338     maxy=maxy+y1;
10339   }
10340   mp_adjust_bbox(mp, h);
10341   break;
10342
10343 @ @<Other cases for updating the bounding box...@>=
10344 case mp_start_bounds_code: 
10345   if ( mp->internal[mp_true_corners]>0 ) {
10346     bbtype(h)=bounds_unset;
10347   } else { 
10348     bbtype(h)=bounds_set;
10349     mp_path_bbox(mp, path_p(p));
10350     mp_adjust_bbox(mp, h);
10351     @<Scan to the matching |mp_stop_bounds_code| node and update |p| and
10352       |bblast(h)|@>;
10353   }
10354   break;
10355 case mp_stop_bounds_code: 
10356   if ( mp->internal[mp_true_corners]<=0 ) mp_confusion(mp, "bbox2");
10357 @:this can't happen bbox2}{\quad bbox2@>
10358   break;
10359
10360 @ @<Scan to the matching |mp_stop_bounds_code| node and update |p| and...@>=
10361 lev=1;
10362 while ( lev!=0 ) { 
10363   if ( mp_link(p)==null ) mp_confusion(mp, "bbox2");
10364 @:this can't happen bbox2}{\quad bbox2@>
10365   p=mp_link(p);
10366   if ( type(p)==mp_start_bounds_code ) incr(lev);
10367   else if ( type(p)==mp_stop_bounds_code ) decr(lev);
10368 }
10369 bblast(h)=p
10370
10371 @ It saves a lot of grief here to be slightly conservative and not account for
10372 omitted parts of dashed lines.  We also don't worry about the material omitted
10373 when using butt end caps.  The basic computation is for round end caps and
10374 |box_ends| augments it for square end caps.
10375
10376 @<Other cases for updating the bounding box...@>=
10377 case mp_stroked_code: 
10378   mp_path_bbox(mp, path_p(p));
10379   x0=minx; y0=miny;
10380   x1=maxx; y1=maxy;
10381   mp_pen_bbox(mp, pen_p(p));
10382   minx=minx+x0;
10383   miny=miny+y0;
10384   maxx=maxx+x1;
10385   maxy=maxy+y1;
10386   mp_adjust_bbox(mp, h);
10387   if ( (left_type(path_p(p))==mp_endpoint)&&(lcap_val(p)==2) )
10388     mp_box_ends(mp, path_p(p), pen_p(p), h);
10389   break;
10390
10391 @ The height width and depth information stored in a text node determines a
10392 rectangle that needs to be transformed according to the transformation
10393 parameters stored in the text node.
10394
10395 @<Other cases for updating the bounding box...@>=
10396 case mp_text_code: 
10397   x1=mp_take_scaled(mp, txx_val(p),width_val(p));
10398   y0=mp_take_scaled(mp, txy_val(p),-depth_val(p));
10399   y1=mp_take_scaled(mp, txy_val(p),height_val(p));
10400   minx=tx_val(p);
10401   maxx=minx;
10402   if ( y0<y1 ) { minx=minx+y0; maxx=maxx+y1;  }
10403   else         { minx=minx+y1; maxx=maxx+y0;  }
10404   if ( x1<0 ) minx=minx+x1;  else maxx=maxx+x1;
10405   x1=mp_take_scaled(mp, tyx_val(p),width_val(p));
10406   y0=mp_take_scaled(mp, tyy_val(p),-depth_val(p));
10407   y1=mp_take_scaled(mp, tyy_val(p),height_val(p));
10408   miny=ty_val(p);
10409   maxy=miny;
10410   if ( y0<y1 ) { miny=miny+y0; maxy=maxy+y1;  }
10411   else         { miny=miny+y1; maxy=maxy+y0;  }
10412   if ( x1<0 ) miny=miny+x1;  else maxy=maxy+x1;
10413   mp_adjust_bbox(mp, h);
10414   break;
10415
10416 @ This case involves a recursive call that advances |bblast(h)| to the node of
10417 type |mp_stop_clip_code| that matches |p|.
10418
10419 @<Other cases for updating the bounding box...@>=
10420 case mp_start_clip_code: 
10421   mp_path_bbox(mp, path_p(p));
10422   x0=minx; y0=miny;
10423   x1=maxx; y1=maxy;
10424   sminx=minx_val(h); sminy=miny_val(h);
10425   smaxx=maxx_val(h); smaxy=maxy_val(h);
10426   @<Reinitialize the bounding box in header |h| and call |set_bbox| recursively
10427     starting at |mp_link(p)|@>;
10428   @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,
10429     |y0|, |y1|@>;
10430   minx=sminx; miny=sminy;
10431   maxx=smaxx; maxy=smaxy;
10432   mp_adjust_bbox(mp, h);
10433   break;
10434
10435 @ @<Reinitialize the bounding box in header |h| and call |set_bbox|...@>=
10436 minx_val(h)=el_gordo;
10437 miny_val(h)=el_gordo;
10438 maxx_val(h)=-el_gordo;
10439 maxy_val(h)=-el_gordo;
10440 mp_set_bbox(mp, h,false)
10441
10442 @ @<Clip the bounding box in |h| to the rectangle given by |x0|, |x1|,...@>=
10443 if ( minx_val(h)<x0 ) minx_val(h)=x0;
10444 if ( miny_val(h)<y0 ) miny_val(h)=y0;
10445 if ( maxx_val(h)>x1 ) maxx_val(h)=x1;
10446 if ( maxy_val(h)>y1 ) maxy_val(h)=y1
10447
10448 @* \[22] Finding an envelope.
10449 When \MP\ has a path and a polygonal pen, it needs to express the desired
10450 shape in terms of things \ps\ can understand.  The present task is to compute
10451 a new path that describes the region to be filled.  It is convenient to
10452 define this as a two step process where the first step is determining what
10453 offset to use for each segment of the path.
10454
10455 @ Given a pointer |c| to a cyclic path,
10456 and a pointer~|h| to the first knot of a pen polygon,
10457 the |offset_prep| routine changes the path into cubics that are
10458 associated with particular pen offsets. Thus if the cubic between |p|
10459 and~|q| is associated with the |k|th offset and the cubic between |q| and~|r|
10460 has offset |l| then |info(q)=zero_off+l-k|. (The constant |zero_off| is added
10461 to because |l-k| could be negative.)
10462
10463 After overwriting the type information with offset differences, we no longer
10464 have a true path so we refer to the knot list returned by |offset_prep| as an
10465 ``envelope spec.''
10466 @^envelope spec@>
10467 Since an envelope spec only determines relative changes in pen offsets,
10468 |offset_prep| sets a global variable |spec_offset| to the relative change from
10469 |h| to the first offset.
10470
10471 @d zero_off 16384 /* added to offset changes to make them positive */
10472
10473 @<Glob...@>=
10474 integer spec_offset; /* number of pen edges between |h| and the initial offset */
10475
10476 @ @c
10477 static pointer mp_offset_prep (MP mp,pointer c, pointer h) {
10478   halfword n; /* the number of vertices in the pen polygon */
10479   pointer c0,p,q,q0,r,w, ww; /* for list manipulation */
10480   integer k_needed; /* amount to be added to |info(p)| when it is computed */
10481   pointer w0; /* a pointer to pen offset to use just before |p| */
10482   scaled dxin,dyin; /* the direction into knot |p| */
10483   integer turn_amt; /* change in pen offsets for the current cubic */
10484   @<Other local variables for |offset_prep|@>;
10485   dx0=0; dy0=0;
10486   @<Initialize the pen size~|n|@>;
10487   @<Initialize the incoming direction and pen offset at |c|@>;
10488   p=c; c0=c; k_needed=0;
10489   do {  
10490     q=mp_link(p);
10491     @<Split the cubic between |p| and |q|, if necessary, into cubics
10492       associated with single offsets, after which |q| should
10493       point to the end of the final such cubic@>;
10494   NOT_FOUND:
10495     @<Advance |p| to node |q|, removing any ``dead'' cubics that
10496       might have been introduced by the splitting process@>;
10497   } while (q!=c);
10498   @<Fix the offset change in |info(c)| and set |c| to the return value of
10499     |offset_prep|@>;
10500   return c;
10501 }
10502
10503 @ We shall want to keep track of where certain knots on the cyclic path
10504 wind up in the envelope spec.  It doesn't suffice just to keep pointers to
10505 knot nodes because some nodes are deleted while removing dead cubics.  Thus
10506 |offset_prep| updates the following pointers
10507
10508 @<Glob...@>=
10509 pointer spec_p1;
10510 pointer spec_p2; /* pointers to distinguished knots */
10511
10512 @ @<Set init...@>=
10513 mp->spec_p1=null; mp->spec_p2=null;
10514
10515 @ @<Initialize the pen size~|n|@>=
10516 n=0; p=h;
10517 do {  
10518   incr(n);
10519   p=mp_link(p);
10520 } while (p!=h)
10521
10522 @ Since the true incoming direction isn't known yet, we just pick a direction
10523 consistent with the pen offset~|h|.  If this is wrong, it can be corrected
10524 later.
10525
10526 @<Initialize the incoming direction and pen offset at |c|@>=
10527 dxin=x_coord(mp_link(h))-x_coord(knil(h));
10528 dyin=y_coord(mp_link(h))-y_coord(knil(h));
10529 if ( (dxin==0)&&(dyin==0) ) {
10530   dxin=y_coord(knil(h))-y_coord(h);
10531   dyin=x_coord(h)-x_coord(knil(h));
10532 }
10533 w0=h
10534
10535 @ We must be careful not to remove the only cubic in a cycle.
10536
10537 But we must also be careful for another reason. If the user-supplied
10538 path starts with a set of degenerate cubics, the target node |q| can
10539 be collapsed to the initial node |p| which might be the same as the
10540 initial node |c| of the curve. This would cause the |offset_prep| routine
10541 to bail out too early, causing distress later on. (See for example
10542 the testcase reported by Bogus\l{}aw Jackowski in tracker id 267, case 52c
10543 on Sarovar.)
10544
10545 @<Advance |p| to node |q|, removing any ``dead'' cubics...@>=
10546 q0=q;
10547 do { 
10548   r=mp_link(p);
10549   if ( x_coord(p)==right_x(p) && y_coord(p)==right_y(p) &&
10550        x_coord(p)==left_x(r)  && y_coord(p)==left_y(r) &&
10551        x_coord(p)==x_coord(r) && y_coord(p)==y_coord(r) &&
10552        r!=p ) {
10553       @<Remove the cubic following |p| and update the data structures
10554         to merge |r| into |p|@>;
10555   }
10556   p=r;
10557 } while (p!=q);
10558 /* Check if we removed too much */
10559 if ((q!=q0)&&(q!=c||c==c0))
10560   q = mp_link(q)
10561
10562 @ @<Remove the cubic following |p| and update the data structures...@>=
10563 { k_needed=info(p)-zero_off;
10564   if ( r==q ) { 
10565     q=p;
10566   } else { 
10567     info(p)=k_needed+info(r);
10568     k_needed=0;
10569   };
10570   if ( r==c ) { info(p)=info(c); c=p; };
10571   if ( r==mp->spec_p1 ) mp->spec_p1=p;
10572   if ( r==mp->spec_p2 ) mp->spec_p2=p;
10573   r=p; mp_remove_cubic(mp, p);
10574 }
10575
10576 @ Not setting the |info| field of the newly created knot allows the splitting
10577 routine to work for paths.
10578
10579 @<Declarations@>=
10580 static void mp_split_cubic (MP mp,pointer p, fraction t) ;
10581
10582 @ @c
10583 void mp_split_cubic (MP mp,pointer p, fraction t) { /* splits the cubic after |p| */
10584   scaled v; /* an intermediate value */
10585   pointer q,r; /* for list manipulation */
10586   q=mp_link(p); r=mp_get_node(mp, knot_node_size); mp_link(p)=r; mp_link(r)=q;
10587   originator(r)=mp_program_code;
10588   left_type(r)=mp_explicit; right_type(r)=mp_explicit;
10589   v=t_of_the_way(right_x(p),left_x(q));
10590   right_x(p)=t_of_the_way(x_coord(p),right_x(p));
10591   left_x(q)=t_of_the_way(left_x(q),x_coord(q));
10592   left_x(r)=t_of_the_way(right_x(p),v);
10593   right_x(r)=t_of_the_way(v,left_x(q));
10594   x_coord(r)=t_of_the_way(left_x(r),right_x(r));
10595   v=t_of_the_way(right_y(p),left_y(q));
10596   right_y(p)=t_of_the_way(y_coord(p),right_y(p));
10597   left_y(q)=t_of_the_way(left_y(q),y_coord(q));
10598   left_y(r)=t_of_the_way(right_y(p),v);
10599   right_y(r)=t_of_the_way(v,left_y(q));
10600   y_coord(r)=t_of_the_way(left_y(r),right_y(r));
10601 }
10602
10603 @ This does not set |info(p)| or |right_type(p)|.
10604
10605 @<Declarations@>=
10606 static void mp_remove_cubic (MP mp,pointer p) ; 
10607
10608 @ @c
10609 void mp_remove_cubic (MP mp,pointer p) { /* removes the dead cubic following~|p| */
10610   pointer q; /* the node that disappears */
10611   q=mp_link(p); mp_link(p)=mp_link(q);
10612   right_x(p)=right_x(q); right_y(p)=right_y(q);
10613   mp_free_node(mp, q,knot_node_size);
10614 }
10615
10616 @ Let $d\prec d'$ mean that the counter-clockwise angle from $d$ to~$d'$ is
10617 strictly between zero and $180^\circ$.  Then we can define $d\preceq d'$ to
10618 mean that the angle could be zero or $180^\circ$. If $w_k=(u_k,v_k)$ is the
10619 $k$th pen offset, the $k$th pen edge direction is defined by the formula
10620 $$d_k=(u\k-u_k,\,v\k-v_k).$$
10621 When listed by increasing $k$, these directions occur in counter-clockwise
10622 order so that $d_k\preceq d\k$ for all~$k$.
10623 The goal of |offset_prep| is to find an offset index~|k| to associate with
10624 each cubic, such that the direction $d(t)$ of the cubic satisfies
10625 $$d_{k-1}\preceq d(t)\preceq d_k\qquad\hbox{for $0\le t\le 1$.}\eqno(*)$$
10626 We may have to split a cubic into many pieces before each
10627 piece corresponds to a unique offset.
10628
10629 @<Split the cubic between |p| and |q|, if necessary, into cubics...@>=
10630 info(p)=zero_off+k_needed;
10631 k_needed=0;
10632 @<Prepare for derivative computations;
10633   |goto not_found| if the current cubic is dead@>;
10634 @<Find the initial direction |(dx,dy)|@>;
10635 @<Update |info(p)| and find the offset $w_k$ such that
10636   $d_{k-1}\preceq(\\{dx},\\{dy})\prec d_k$; also advance |w0| for
10637   the direction change at |p|@>;
10638 @<Find the final direction |(dxin,dyin)|@>;
10639 @<Decide on the net change in pen offsets and set |turn_amt|@>;
10640 @<Complete the offset splitting process@>;
10641 w0=mp_pen_walk(mp, w0,turn_amt)
10642
10643 @ @<Declarations@>=
10644 static pointer mp_pen_walk (MP mp,pointer w, integer k) ;
10645
10646 @ @c
10647 pointer mp_pen_walk (MP mp,pointer w, integer k) {
10648   /* walk |k| steps around a pen from |w| */
10649   while ( k>0 ) { w=mp_link(w); decr(k);  };
10650   while ( k<0 ) { w=knil(w); incr(k);  };
10651   return w;
10652 }
10653
10654 @ The direction of a cubic $B(z_0,z_1,z_2,z_3;t)=\bigl(x(t),y(t)\bigr)$ can be
10655 calculated from the quadratic polynomials
10656 ${1\over3}x'(t)=B(x_1-x_0,x_2-x_1,x_3-x_2;t)$ and
10657 ${1\over3}y'(t)=B(y_1-y_0,y_2-y_1,y_3-y_2;t)$.
10658 Since we may be calculating directions from several cubics
10659 split from the current one, it is desirable to do these calculations
10660 without losing too much precision. ``Scaled up'' values of the
10661 derivatives, which will be less tainted by accumulated errors than
10662 derivatives found from the cubics themselves, are maintained in
10663 local variables |x0|, |x1|, and |x2|, representing $X_0=2^l(x_1-x_0)$,
10664 $X_1=2^l(x_2-x_1)$, and $X_2=2^l(x_3-x_2)$; similarly |y0|, |y1|, and~|y2|
10665 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)$.
10666
10667 @<Other local variables for |offset_prep|@>=
10668 integer x0,x1,x2,y0,y1,y2; /* representatives of derivatives */
10669 integer t0,t1,t2; /* coefficients of polynomial for slope testing */
10670 integer du,dv,dx,dy; /* for directions of the pen and the curve */
10671 integer dx0,dy0; /* initial direction for the first cubic in the curve */
10672 integer max_coef; /* used while scaling */
10673 integer x0a,x1a,x2a,y0a,y1a,y2a; /* intermediate values */
10674 fraction t; /* where the derivative passes through zero */
10675 fraction s; /* a temporary value */
10676
10677 @ @<Prepare for derivative computations...@>=
10678 x0=right_x(p)-x_coord(p);
10679 x2=x_coord(q)-left_x(q);
10680 x1=left_x(q)-right_x(p);
10681 y0=right_y(p)-y_coord(p); y2=y_coord(q)-left_y(q);
10682 y1=left_y(q)-right_y(p);
10683 max_coef=abs(x0);
10684 if ( abs(x1)>max_coef ) max_coef=abs(x1);
10685 if ( abs(x2)>max_coef ) max_coef=abs(x2);
10686 if ( abs(y0)>max_coef ) max_coef=abs(y0);
10687 if ( abs(y1)>max_coef ) max_coef=abs(y1);
10688 if ( abs(y2)>max_coef ) max_coef=abs(y2);
10689 if ( max_coef==0 ) goto NOT_FOUND;
10690 while ( max_coef<fraction_half ) {
10691   double(max_coef);
10692   double(x0); double(x1); double(x2);
10693   double(y0); double(y1); double(y2);
10694 }
10695
10696 @ Let us first solve a special case of the problem: Suppose we
10697 know an index~$k$ such that either (i)~$d(t)\succeq d_{k-1}$ for all~$t$
10698 and $d(0)\prec d_k$, or (ii)~$d(t)\preceq d_k$ for all~$t$ and
10699 $d(0)\succ d_{k-1}$.
10700 Then, in a sense, we're halfway done, since one of the two relations
10701 in $(*)$ is satisfied, and the other couldn't be satisfied for
10702 any other value of~|k|.
10703
10704 Actually, the conditions can be relaxed somewhat since a relation such as
10705 $d(t)\succeq d_{k-1}$ restricts $d(t)$ to a half plane when all that really
10706 matters is whether $d(t)$ crosses the ray in the $d_{k-1}$ direction from
10707 the origin.  The condition for case~(i) becomes $d_{k-1}\preceq d(0)\prec d_k$
10708 and $d(t)$ never crosses the $d_{k-1}$ ray in the clockwise direction.
10709 Case~(ii) is similar except $d(t)$ cannot cross the $d_k$ ray in the
10710 counterclockwise direction.
10711
10712 The |fin_offset_prep| subroutine solves the stated subproblem.
10713 It has a parameter called |rise| that is |1| in
10714 case~(i), |-1| in case~(ii). Parameters |x0| through |y2| represent
10715 the derivative of the cubic following |p|.
10716 The |w| parameter should point to offset~$w_k$ and |info(p)| should already
10717 be set properly.  The |turn_amt| parameter gives the absolute value of the
10718 overall net change in pen offsets.
10719
10720 @<Declarations@>=
10721 static void mp_fin_offset_prep (MP mp,pointer p, pointer w, integer 
10722   x0,integer x1, integer x2, integer y0, integer y1, integer y2, 
10723   integer rise, integer turn_amt) ;
10724
10725 @ @c
10726 void mp_fin_offset_prep (MP mp,pointer p, pointer w, integer 
10727   x0,integer x1, integer x2, integer y0, integer y1, integer y2, 
10728   integer rise, integer turn_amt)  {
10729   pointer ww; /* for list manipulation */
10730   scaled du,dv; /* for slope calculation */
10731   integer t0,t1,t2; /* test coefficients */
10732   fraction t; /* place where the derivative passes a critical slope */
10733   fraction s; /* slope or reciprocal slope */
10734   integer v; /* intermediate value for updating |x0..y2| */
10735   pointer q; /* original |mp_link(p)| */
10736   q=mp_link(p);
10737   while (1)  { 
10738     if ( rise>0 ) ww=mp_link(w); /* a pointer to $w\k$ */
10739     else  ww=knil(w); /* a pointer to $w_{k-1}$ */
10740     @<Compute test coefficients |(t0,t1,t2)|
10741       for $d(t)$ versus $d_k$ or $d_{k-1}$@>;
10742     t=mp_crossing_point(mp, t0,t1,t2);
10743     if ( t>=fraction_one ) {
10744       if ( turn_amt>0 ) t=fraction_one;  else return;
10745     }
10746     @<Split the cubic at $t$,
10747       and split off another cubic if the derivative crosses back@>;
10748     w=ww;
10749   }
10750 }
10751
10752 @ We want $B(\\{t0},\\{t1},\\{t2};t)$ to be the dot product of $d(t)$ with a
10753 $-90^\circ$ rotation of the vector from |w| to |ww|.  This makes the resulting
10754 function cross from positive to negative when $d_{k-1}\preceq d(t)\preceq d_k$
10755 begins to fail.
10756
10757 @<Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...@>=
10758 du=x_coord(ww)-x_coord(w); dv=y_coord(ww)-y_coord(w);
10759 if ( abs(du)>=abs(dv) ) {
10760   s=mp_make_fraction(mp, dv,du);
10761   t0=mp_take_fraction(mp, x0,s)-y0;
10762   t1=mp_take_fraction(mp, x1,s)-y1;
10763   t2=mp_take_fraction(mp, x2,s)-y2;
10764   if ( du<0 ) { negate(t0); negate(t1); negate(t2);  }
10765 } else { 
10766   s=mp_make_fraction(mp, du,dv);
10767   t0=x0-mp_take_fraction(mp, y0,s);
10768   t1=x1-mp_take_fraction(mp, y1,s);
10769   t2=x2-mp_take_fraction(mp, y2,s);
10770   if ( dv<0 ) { negate(t0); negate(t1); negate(t2);  }
10771 }
10772 if ( t0<0 ) t0=0 /* should be positive without rounding error */
10773
10774 @ The curve has crossed $d_k$ or $d_{k-1}$; its initial segment satisfies
10775 $(*)$, and it might cross again and return towards $s_{k-1}$ or $s_k$,
10776 respectively, yielding another solution of $(*)$.
10777
10778 @<Split the cubic at $t$, and split off another...@>=
10779
10780 mp_split_cubic(mp, p,t); p=mp_link(p); info(p)=zero_off+rise;
10781 decr(turn_amt);
10782 v=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10783 x0=t_of_the_way(v,x1);
10784 v=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10785 y0=t_of_the_way(v,y1);
10786 if ( turn_amt<0 ) {
10787   t1=t_of_the_way(t1,t2);
10788   if ( t1>0 ) t1=0; /* without rounding error, |t1| would be |<=0| */
10789   t=mp_crossing_point(mp, 0,-t1,-t2);
10790   if ( t>fraction_one ) t=fraction_one;
10791   incr(turn_amt);
10792   if ( (t==fraction_one)&&(mp_link(p)!=q) ) {
10793     info(mp_link(p))=info(mp_link(p))-rise;
10794   } else { 
10795     mp_split_cubic(mp, p,t); info(mp_link(p))=zero_off-rise;
10796     v=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10797     x2=t_of_the_way(x1,v);
10798     v=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10799     y2=t_of_the_way(y1,v);
10800   }
10801 }
10802 }
10803
10804 @ Now we must consider the general problem of |offset_prep|, when
10805 nothing is known about a given cubic. We start by finding its
10806 direction in the vicinity of |t=0|.
10807
10808 If $z'(t)=0$, the given cubic is numerically unstable but |offset_prep|
10809 has not yet introduced any more numerical errors.  Thus we can compute
10810 the true initial direction for the given cubic, even if it is almost
10811 degenerate.
10812
10813 @<Find the initial direction |(dx,dy)|@>=
10814 dx=x0; dy=y0;
10815 if ( dx==0 && dy==0 ) { 
10816   dx=x1; dy=y1;
10817   if ( dx==0 && dy==0 ) { 
10818     dx=x2; dy=y2;
10819   }
10820 }
10821 if ( p==c ) { dx0=dx; dy0=dy;  }
10822
10823 @ @<Find the final direction |(dxin,dyin)|@>=
10824 dxin=x2; dyin=y2;
10825 if ( dxin==0 && dyin==0 ) {
10826   dxin=x1; dyin=y1;
10827   if ( dxin==0 && dyin==0 ) {
10828     dxin=x0; dyin=y0;
10829   }
10830 }
10831
10832 @ The next step is to bracket the initial direction between consecutive
10833 edges of the pen polygon.  We must be careful to turn clockwise only if
10834 this makes the turn less than $180^\circ$. (A $180^\circ$ turn must be
10835 counter-clockwise in order to make \&{doublepath} envelopes come out
10836 @:double_path_}{\&{doublepath} primitive@>
10837 right.) This code depends on |w0| being the offset for |(dxin,dyin)|.
10838
10839 @<Update |info(p)| and find the offset $w_k$ such that...@>=
10840 turn_amt=mp_get_turn_amt(mp,w0,dx,dy,(mp_ab_vs_cd(mp, dy,dxin,dx,dyin)>=0));
10841 w=mp_pen_walk(mp, w0, turn_amt);
10842 w0=w;
10843 info(p)=info(p)+turn_amt
10844
10845 @ Decide how many pen offsets to go away from |w| in order to find the offset
10846 for |(dx,dy)|, going counterclockwise if |ccw| is |true|.  This assumes that
10847 |w| is the offset for some direction $(x',y')$ from which the angle to |(dx,dy)|
10848 in the sense determined by |ccw| is less than or equal to $180^\circ$.
10849
10850 If the pen polygon has only two edges, they could both be parallel
10851 to |(dx,dy)|.  In this case, we must be careful to stop after crossing the first
10852 such edge in order to avoid an infinite loop.
10853
10854 @<Declarations@>=
10855 static integer mp_get_turn_amt (MP mp,pointer w, scaled  dx,
10856                          scaled dy, boolean  ccw);
10857
10858 @ @c
10859 integer mp_get_turn_amt (MP mp,pointer w, scaled  dx,
10860                          scaled dy, boolean  ccw) {
10861   pointer ww; /* a neighbor of knot~|w| */
10862   integer s; /* turn amount so far */
10863   integer t; /* |ab_vs_cd| result */
10864   s=0;
10865   if ( ccw ) { 
10866     ww=mp_link(w);
10867     do {  
10868       t=mp_ab_vs_cd(mp, dy,(x_coord(ww)-x_coord(w)),
10869                         dx,(y_coord(ww)-y_coord(w)));
10870       if ( t<0 ) break;
10871       incr(s);
10872       w=ww; ww=mp_link(ww);
10873     } while (t>0);
10874   } else { 
10875     ww=knil(w);
10876     while ( mp_ab_vs_cd(mp, dy,(x_coord(w)-x_coord(ww)),
10877                             dx,(y_coord(w)-y_coord(ww))) < 0) { 
10878       decr(s);
10879       w=ww; ww=knil(ww);
10880     }
10881   }
10882   return s;
10883 }
10884
10885 @ When we're all done, the final offset is |w0| and the final curve direction
10886 is |(dxin,dyin)|.  With this knowledge of the incoming direction at |c|, we
10887 can correct |info(c)| which was erroneously based on an incoming offset
10888 of~|h|.
10889
10890 @d fix_by(A) info(c)=info(c)+(A)
10891
10892 @<Fix the offset change in |info(c)| and set |c| to the return value of...@>=
10893 mp->spec_offset=info(c)-zero_off;
10894 if ( mp_link(c)==c ) {
10895   info(c)=zero_off+n;
10896 } else { 
10897   fix_by(k_needed);
10898   while ( w0!=h ) { fix_by(1); w0=mp_link(w0);  };
10899   while ( info(c)<=zero_off-n ) fix_by(n);
10900   while ( info(c)>zero_off ) fix_by(-n);
10901   if ( (info(c)!=zero_off)&&(mp_ab_vs_cd(mp, dy0,dxin,dx0,dyin)>=0) ) fix_by(n);
10902 }
10903
10904 @ Finally we want to reduce the general problem to situations that
10905 |fin_offset_prep| can handle. We split the cubic into at most three parts
10906 with respect to $d_{k-1}$, and apply |fin_offset_prep| to each part.
10907
10908 @<Complete the offset splitting process@>=
10909 ww=knil(w);
10910 @<Compute test coeff...@>;
10911 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set
10912   |t:=fraction_one+1|@>;
10913 if ( t>fraction_one ) {
10914   mp_fin_offset_prep(mp, p,w,x0,x1,x2,y0,y1,y2,1,turn_amt);
10915 } else {
10916   mp_split_cubic(mp, p,t); r=mp_link(p);
10917   x1a=t_of_the_way(x0,x1); x1=t_of_the_way(x1,x2);
10918   x2a=t_of_the_way(x1a,x1);
10919   y1a=t_of_the_way(y0,y1); y1=t_of_the_way(y1,y2);
10920   y2a=t_of_the_way(y1a,y1);
10921   mp_fin_offset_prep(mp, p,w,x0,x1a,x2a,y0,y1a,y2a,1,0); x0=x2a; y0=y2a;
10922   info(r)=zero_off-1;
10923   if ( turn_amt>=0 ) {
10924     t1=t_of_the_way(t1,t2);
10925     if ( t1>0 ) t1=0;
10926     t=mp_crossing_point(mp, 0,-t1,-t2);
10927     if ( t>fraction_one ) t=fraction_one;
10928     @<Split off another rising cubic for |fin_offset_prep|@>;
10929     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,0);
10930   } else {
10931     mp_fin_offset_prep(mp, r,ww,x0,x1,x2,y0,y1,y2,-1,(-1-turn_amt));
10932   }
10933 }
10934
10935 @ @<Split off another rising cubic for |fin_offset_prep|@>=
10936 mp_split_cubic(mp, r,t); info(mp_link(r))=zero_off+1;
10937 x1a=t_of_the_way(x1,x2); x1=t_of_the_way(x0,x1);
10938 x0a=t_of_the_way(x1,x1a);
10939 y1a=t_of_the_way(y1,y2); y1=t_of_the_way(y0,y1);
10940 y0a=t_of_the_way(y1,y1a);
10941 mp_fin_offset_prep(mp, mp_link(r),w,x0a,x1a,x2,y0a,y1a,y2,1,turn_amt);
10942 x2=x0a; y2=y0a
10943
10944 @ At this point, the direction of the incoming pen edge is |(-du,-dv)|.
10945 When the component of $d(t)$ perpendicular to |(-du,-dv)| crosses zero, we
10946 need to decide whether the directions are parallel or antiparallel.  We
10947 can test this by finding the dot product of $d(t)$ and |(-du,-dv)|, but this
10948 should be avoided when the value of |turn_amt| already determines the
10949 answer.  If |t2<0|, there is one crossing and it is antiparallel only if
10950 |turn_amt>=0|.  If |turn_amt<0|, there should always be at least one
10951 crossing and the first crossing cannot be antiparallel.
10952
10953 @<Find the first |t| where $d(t)$ crosses $d_{k-1}$ or set...@>=
10954 t=mp_crossing_point(mp, t0,t1,t2);
10955 if ( turn_amt>=0 ) {
10956   if ( t2<0 ) {
10957     t=fraction_one+1;
10958   } else { 
10959     u0=t_of_the_way(x0,x1);
10960     u1=t_of_the_way(x1,x2);
10961     ss=mp_take_fraction(mp, -du,t_of_the_way(u0,u1));
10962     v0=t_of_the_way(y0,y1);
10963     v1=t_of_the_way(y1,y2);
10964     ss=ss+mp_take_fraction(mp, -dv,t_of_the_way(v0,v1));
10965     if ( ss<0 ) t=fraction_one+1;
10966   }
10967 } else if ( t>fraction_one ) {
10968   t=fraction_one;
10969 }
10970
10971 @ @<Other local variables for |offset_prep|@>=
10972 integer u0,u1,v0,v1; /* intermediate values for $d(t)$ calculation */
10973 integer ss = 0; /* the part of the dot product computed so far */
10974 int d_sign; /* sign of overall change in direction for this cubic */
10975
10976 @ If the cubic almost has a cusp, it is a numerically ill-conditioned
10977 problem to decide which way it loops around but that's OK as long we're
10978 consistent.  To make \&{doublepath} envelopes work properly, reversing
10979 the path should always change the sign of |turn_amt|.
10980
10981 @<Decide on the net change in pen offsets and set |turn_amt|@>=
10982 d_sign=mp_ab_vs_cd(mp, dx,dyin, dxin,dy);
10983 if ( d_sign==0 ) {
10984   @<Check rotation direction based on node position@>
10985 }
10986 if ( d_sign==0 ) {
10987   if ( dx==0 ) {
10988     if ( dy>0 ) d_sign=1;  else d_sign=-1;
10989   } else {
10990     if ( dx>0 ) d_sign=1;  else d_sign=-1; 
10991   }
10992 }
10993 @<Make |ss| negative if and only if the total change in direction is
10994   more than $180^\circ$@>;
10995 turn_amt=mp_get_turn_amt(mp, w, dxin, dyin, (d_sign>0));
10996 if ( ss<0 ) turn_amt=turn_amt-d_sign*n
10997
10998 @ We check rotation direction by looking at the vector connecting the current
10999 node with the next. If its angle with incoming and outgoing tangents has the
11000 same sign, we pick this as |d_sign|, since it means we have a flex, not a cusp.
11001 Otherwise we proceed to the cusp code.
11002
11003 @<Check rotation direction based on node position@>=
11004 u0=x_coord(q)-x_coord(p);
11005 u1=y_coord(q)-y_coord(p);
11006 d_sign = half(mp_ab_vs_cd(mp, dx, u1, u0, dy)+
11007   mp_ab_vs_cd(mp, u0, dyin, dxin, u1));
11008
11009 @ In order to be invariant under path reversal, the result of this computation
11010 should not change when |x0|, |y0|, $\ldots$ are all negated and |(x0,y0)| is
11011 then swapped with |(x2,y2)|.  We make use of the identities
11012 |take_fraction(-a,-b)=take_fraction(a,b)| and
11013 |t_of_the_way(-a,-b)=-(t_of_the_way(a,b))|.
11014
11015 @<Make |ss| negative if and only if the total change in direction is...@>=
11016 t0=half(mp_take_fraction(mp, x0,y2))-half(mp_take_fraction(mp, x2,y0));
11017 t1=half(mp_take_fraction(mp, x1,(y0+y2)))-half(mp_take_fraction(mp, y1,(x0+x2)));
11018 if ( t0==0 ) t0=d_sign; /* path reversal always negates |d_sign| */
11019 if ( t0>0 ) {
11020   t=mp_crossing_point(mp, t0,t1,-t0);
11021   u0=t_of_the_way(x0,x1);
11022   u1=t_of_the_way(x1,x2);
11023   v0=t_of_the_way(y0,y1);
11024   v1=t_of_the_way(y1,y2);
11025 } else { 
11026   t=mp_crossing_point(mp, -t0,t1,t0);
11027   u0=t_of_the_way(x2,x1);
11028   u1=t_of_the_way(x1,x0);
11029   v0=t_of_the_way(y2,y1);
11030   v1=t_of_the_way(y1,y0);
11031 }
11032 ss=mp_take_fraction(mp, (x0+x2),t_of_the_way(u0,u1))+
11033    mp_take_fraction(mp, (y0+y2),t_of_the_way(v0,v1))
11034
11035 @ Here's a routine that prints an envelope spec in symbolic form.  It assumes
11036 that the |cur_pen| has not been walked around to the first offset.
11037
11038 @c 
11039 static void mp_print_spec (MP mp,pointer cur_spec, pointer cur_pen, const char *s) {
11040   pointer p,q; /* list traversal */
11041   pointer w; /* the current pen offset */
11042   mp_print_diagnostic(mp, "Envelope spec",s,true);
11043   p=cur_spec; w=mp_pen_walk(mp, cur_pen,mp->spec_offset);
11044   mp_print_ln(mp);
11045   mp_print_two(mp, x_coord(cur_spec),y_coord(cur_spec));
11046   mp_print(mp, " % beginning with offset ");
11047   mp_print_two(mp, x_coord(w),y_coord(w));
11048   do { 
11049     while (1) {  
11050       q=mp_link(p);
11051       @<Print the cubic between |p| and |q|@>;
11052       p=q;
11053           if ((p==cur_spec) || (info(p)!=zero_off)) 
11054         break;
11055     }
11056     if ( info(p)!=zero_off ) {
11057       @<Update |w| as indicated by |info(p)| and print an explanation@>;
11058     }
11059   } while (p!=cur_spec);
11060   mp_print_nl(mp, " & cycle");
11061   mp_end_diagnostic(mp, true);
11062 }
11063
11064 @ @<Update |w| as indicated by |info(p)| and print an explanation@>=
11065
11066   w=mp_pen_walk(mp, w, (info(p)-zero_off));
11067   mp_print(mp, " % ");
11068   if ( info(p)>zero_off ) mp_print(mp, "counter");
11069   mp_print(mp, "clockwise to offset ");
11070   mp_print_two(mp, x_coord(w),y_coord(w));
11071 }
11072
11073 @ @<Print the cubic between |p| and |q|@>=
11074
11075   mp_print_nl(mp, "   ..controls ");
11076   mp_print_two(mp, right_x(p),right_y(p));
11077   mp_print(mp, " and ");
11078   mp_print_two(mp, left_x(q),left_y(q));
11079   mp_print_nl(mp, " ..");
11080   mp_print_two(mp, x_coord(q),y_coord(q));
11081 }
11082
11083 @ Once we have an envelope spec, the remaining task to construct the actual
11084 envelope by offsetting each cubic as determined by the |info| fields in
11085 the knots.  First we use |offset_prep| to convert the |c| into an envelope
11086 spec. Then we add the offsets so that |c| becomes a cyclic path that represents
11087 the envelope.
11088
11089 The |ljoin| and |miterlim| parameters control the treatment of points where the
11090 pen offset changes, and |lcap| controls the endpoints of a \&{doublepath}.
11091 The endpoints are easily located because |c| is given in undoubled form
11092 and then doubled in this procedure.  We use |spec_p1| and |spec_p2| to keep
11093 track of the endpoints and treat them like very sharp corners.
11094 Butt end caps are treated like beveled joins; round end caps are treated like
11095 round joins; and square end caps are achieved by setting |join_type:=3|.
11096
11097 None of these parameters apply to inside joins where the convolution tracing
11098 has retrograde lines.  In such cases we use a simple connect-the-endpoints
11099 approach that is achieved by setting |join_type:=2|.
11100
11101 @c
11102 static pointer mp_make_envelope (MP mp,pointer c, pointer h, quarterword ljoin,
11103   quarterword lcap, scaled miterlim) {
11104   pointer p,q,r,q0; /* for manipulating the path */
11105   int join_type=0; /* codes |0..3| for mitered, round, beveled, or square */
11106   pointer w,w0; /* the pen knot for the current offset */
11107   scaled qx,qy; /* unshifted coordinates of |q| */
11108   halfword k,k0; /* controls pen edge insertion */
11109   @<Other local variables for |make_envelope|@>;
11110   dxin=0; dyin=0; dxout=0; dyout=0;
11111   mp->spec_p1=null; mp->spec_p2=null;
11112   @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>;
11113   @<Use |offset_prep| to compute the envelope spec then walk |h| around to
11114     the initial offset@>;
11115   w=h;
11116   p=c;
11117   do {  
11118     q=mp_link(p); q0=q;
11119     qx=x_coord(q); qy=y_coord(q);
11120     k=info(q);
11121     k0=k; w0=w;
11122     if ( k!=zero_off ) {
11123       @<Set |join_type| to indicate how to handle offset changes at~|q|@>;
11124     }
11125     @<Add offset |w| to the cubic from |p| to |q|@>;
11126     while ( k!=zero_off ) { 
11127       @<Step |w| and move |k| one step closer to |zero_off|@>;
11128       if ( (join_type==1)||(k==zero_off) )
11129          q=mp_insert_knot(mp, q,qx+x_coord(w),qy+y_coord(w));
11130     };
11131     if ( q!=mp_link(p) ) {
11132       @<Set |p=mp_link(p)| and add knots between |p| and |q| as
11133         required by |join_type|@>;
11134     }
11135     p=q;
11136   } while (q0!=c);
11137   return c;
11138 }
11139
11140 @ @<Use |offset_prep| to compute the envelope spec then walk |h| around to...@>=
11141 c=mp_offset_prep(mp, c,h);
11142 if ( mp->internal[mp_tracing_specs]>0 ) 
11143   mp_print_spec(mp, c,h,"");
11144 h=mp_pen_walk(mp, h,mp->spec_offset)
11145
11146 @ Mitered and squared-off joins depend on path directions that are difficult to
11147 compute for degenerate cubics.  The envelope spec computed by |offset_prep| can
11148 have degenerate cubics only if the entire cycle collapses to a single
11149 degenerate cubic.  Setting |join_type:=2| in this case makes the computed
11150 envelope degenerate as well.
11151
11152 @<Set |join_type| to indicate how to handle offset changes at~|q|@>=
11153 if ( k<zero_off ) {
11154   join_type=2;
11155 } else {
11156   if ( (q!=mp->spec_p1)&&(q!=mp->spec_p2) ) join_type=ljoin;
11157   else if ( lcap==2 ) join_type=3;
11158   else join_type=2-lcap;
11159   if ( (join_type==0)||(join_type==3) ) {
11160     @<Set the incoming and outgoing directions at |q|; in case of
11161       degeneracy set |join_type:=2|@>;
11162     if ( join_type==0 ) {
11163       @<If |miterlim| is less than the secant of half the angle at |q|
11164         then set |join_type:=2|@>;
11165     }
11166   }
11167 }
11168
11169 @ @<If |miterlim| is less than the secant of half the angle at |q|...@>=
11170
11171   tmp=mp_take_fraction(mp, miterlim,fraction_half+
11172       half(mp_take_fraction(mp, dxin,dxout)+mp_take_fraction(mp, dyin,dyout)));
11173   if ( tmp<unity )
11174     if ( mp_take_scaled(mp, miterlim,tmp)<unity ) join_type=2;
11175 }
11176
11177 @ @<Other local variables for |make_envelope|@>=
11178 fraction dxin,dyin,dxout,dyout; /* directions at |q| when square or mitered */
11179 scaled tmp; /* a temporary value */
11180
11181 @ The coordinates of |p| have already been shifted unless |p| is the first
11182 knot in which case they get shifted at the very end.
11183
11184 @<Add offset |w| to the cubic from |p| to |q|@>=
11185 right_x(p)=right_x(p)+x_coord(w);
11186 right_y(p)=right_y(p)+y_coord(w);
11187 left_x(q)=left_x(q)+x_coord(w);
11188 left_y(q)=left_y(q)+y_coord(w);
11189 x_coord(q)=x_coord(q)+x_coord(w);
11190 y_coord(q)=y_coord(q)+y_coord(w);
11191 left_type(q)=mp_explicit;
11192 right_type(q)=mp_explicit
11193
11194 @ @<Step |w| and move |k| one step closer to |zero_off|@>=
11195 if ( k>zero_off ){ w=mp_link(w); decr(k);  }
11196 else { w=knil(w); incr(k);  }
11197
11198 @ The cubic from |q| to the new knot at |(x,y)| becomes a line segment and
11199 the |right_x| and |right_y| fields of |r| are set from |q|.  This is done in
11200 case the cubic containing these control points is ``yet to be examined.''
11201
11202 @<Declarations@>=
11203 static pointer mp_insert_knot (MP mp,pointer q, scaled x, scaled y);
11204
11205 @ @c
11206 pointer mp_insert_knot (MP mp,pointer q, scaled x, scaled y) {
11207   /* returns the inserted knot */
11208   pointer r; /* the new knot */
11209   r=mp_get_node(mp, knot_node_size);
11210   mp_link(r)=mp_link(q); mp_link(q)=r;
11211   right_x(r)=right_x(q);
11212   right_y(r)=right_y(q);
11213   x_coord(r)=x;
11214   y_coord(r)=y;
11215   right_x(q)=x_coord(q);
11216   right_y(q)=y_coord(q);
11217   left_x(r)=x_coord(r);
11218   left_y(r)=y_coord(r);
11219   left_type(r)=mp_explicit;
11220   right_type(r)=mp_explicit;
11221   originator(r)=mp_program_code;
11222   return r;
11223 }
11224
11225 @ After setting |p:=mp_link(p)|, either |join_type=1| or |q=mp_link(p)|.
11226
11227 @<Set |p=mp_link(p)| and add knots between |p| and |q| as...@>=
11228
11229   p=mp_link(p);
11230   if ( (join_type==0)||(join_type==3) ) {
11231     if ( join_type==0 ) {
11232       @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>
11233     } else {
11234       @<Make |r| the last of two knots inserted between |p| and |q| to form a
11235         squared join@>;
11236     }
11237     if ( r!=null ) { 
11238       right_x(r)=x_coord(r);
11239       right_y(r)=y_coord(r);
11240     }
11241   }
11242 }
11243
11244 @ For very small angles, adding a knot is unnecessary and would cause numerical
11245 problems, so we just set |r:=null| in that case.
11246
11247 @<Insert a new knot |r| between |p| and |q| as required for a mitered join@>=
11248
11249   det=mp_take_fraction(mp, dyout,dxin)-mp_take_fraction(mp, dxout,dyin);
11250   if ( abs(det)<26844 ) { 
11251      r=null; /* sine $<10^{-4}$ */
11252   } else { 
11253     tmp=mp_take_fraction(mp, x_coord(q)-x_coord(p),dyout)-
11254         mp_take_fraction(mp, y_coord(q)-y_coord(p),dxout);
11255     tmp=mp_make_fraction(mp, tmp,det);
11256     r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
11257       y_coord(p)+mp_take_fraction(mp, tmp,dyin));
11258   }
11259 }
11260
11261 @ @<Other local variables for |make_envelope|@>=
11262 fraction det; /* a determinant used for mitered join calculations */
11263
11264 @ @<Make |r| the last of two knots inserted between |p| and |q| to form a...@>=
11265
11266   ht_x=y_coord(w)-y_coord(w0);
11267   ht_y=x_coord(w0)-x_coord(w);
11268   while ( (abs(ht_x)<fraction_half)&&(abs(ht_y)<fraction_half) ) { 
11269     ht_x+=ht_x; ht_y+=ht_y;
11270   }
11271   @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range dot
11272     product with |(ht_x,ht_y)|@>;
11273   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxin,ht_x)+
11274                                   mp_take_fraction(mp, dyin,ht_y));
11275   r=mp_insert_knot(mp, p,x_coord(p)+mp_take_fraction(mp, tmp,dxin),
11276                          y_coord(p)+mp_take_fraction(mp, tmp,dyin));
11277   tmp=mp_make_fraction(mp, max_ht,mp_take_fraction(mp, dxout,ht_x)+
11278                                   mp_take_fraction(mp, dyout,ht_y));
11279   r=mp_insert_knot(mp, r,x_coord(q)+mp_take_fraction(mp, tmp,dxout),
11280                          y_coord(q)+mp_take_fraction(mp, tmp,dyout));
11281 }
11282
11283 @ @<Other local variables for |make_envelope|@>=
11284 fraction ht_x,ht_y; /* perpendicular to the segment from |p| to |q| */
11285 scaled max_ht; /* maximum height of the pen polygon above the |w0|-|w| line */
11286 halfword kk; /* keeps track of the pen vertices being scanned */
11287 pointer ww; /* the pen vertex being tested */
11288
11289 @ The dot product of the vector from |w0| to |ww| with |(ht_x,ht_y)| ranges
11290 from zero to |max_ht|.
11291
11292 @<Scan the pen polygon between |w0| and |w| and make |max_ht| the range...@>=
11293 max_ht=0;
11294 kk=zero_off;
11295 ww=w;
11296 while (1)  { 
11297   @<Step |ww| and move |kk| one step closer to |k0|@>;
11298   if ( kk==k0 ) break;
11299   tmp=mp_take_fraction(mp, (x_coord(ww)-x_coord(w0)),ht_x)+
11300       mp_take_fraction(mp, (y_coord(ww)-y_coord(w0)),ht_y);
11301   if ( tmp>max_ht ) max_ht=tmp;
11302 }
11303
11304
11305 @ @<Step |ww| and move |kk| one step closer to |k0|@>=
11306 if ( kk>k0 ) { ww=mp_link(ww); decr(kk);  }
11307 else { ww=knil(ww); incr(kk);  }
11308
11309 @ @<If endpoint, double the path |c|, and set |spec_p1| and |spec_p2|@>=
11310 if ( left_type(c)==mp_endpoint ) { 
11311   mp->spec_p1=mp_htap_ypoc(mp, c);
11312   mp->spec_p2=mp->path_tail;
11313   originator(mp->spec_p1)=mp_program_code;
11314   mp_link(mp->spec_p2)=mp_link(mp->spec_p1);
11315   mp_link(mp->spec_p1)=c;
11316   mp_remove_cubic(mp, mp->spec_p1);
11317   c=mp->spec_p1;
11318   if ( c!=mp_link(c) ) {
11319     originator(mp->spec_p2)=mp_program_code;
11320     mp_remove_cubic(mp, mp->spec_p2);
11321   } else {
11322     @<Make |c| look like a cycle of length one@>;
11323   }
11324 }
11325
11326 @ @<Make |c| look like a cycle of length one@>=
11327
11328   left_type(c)=mp_explicit; right_type(c)=mp_explicit;
11329   left_x(c)=x_coord(c); left_y(c)=y_coord(c);
11330   right_x(c)=x_coord(c); right_y(c)=y_coord(c);
11331 }
11332
11333 @ In degenerate situations we might have to look at the knot preceding~|q|.
11334 That knot is |p| but if |p<>c|, its coordinates have already been offset by |w|.
11335
11336 @<Set the incoming and outgoing directions at |q|; in case of...@>=
11337 dxin=x_coord(q)-left_x(q);
11338 dyin=y_coord(q)-left_y(q);
11339 if ( (dxin==0)&&(dyin==0) ) {
11340   dxin=x_coord(q)-right_x(p);
11341   dyin=y_coord(q)-right_y(p);
11342   if ( (dxin==0)&&(dyin==0) ) {
11343     dxin=x_coord(q)-x_coord(p);
11344     dyin=y_coord(q)-y_coord(p);
11345     if ( p!=c ) { /* the coordinates of |p| have been offset by |w| */
11346       dxin=dxin+x_coord(w);
11347       dyin=dyin+y_coord(w);
11348     }
11349   }
11350 }
11351 tmp=mp_pyth_add(mp, dxin,dyin);
11352 if ( tmp==0 ) {
11353   join_type=2;
11354 } else { 
11355   dxin=mp_make_fraction(mp, dxin,tmp);
11356   dyin=mp_make_fraction(mp, dyin,tmp);
11357   @<Set the outgoing direction at |q|@>;
11358 }
11359
11360 @ If |q=c| then the coordinates of |r| and the control points between |q|
11361 and~|r| have already been offset by |h|.
11362
11363 @<Set the outgoing direction at |q|@>=
11364 dxout=right_x(q)-x_coord(q);
11365 dyout=right_y(q)-y_coord(q);
11366 if ( (dxout==0)&&(dyout==0) ) {
11367   r=mp_link(q);
11368   dxout=left_x(r)-x_coord(q);
11369   dyout=left_y(r)-y_coord(q);
11370   if ( (dxout==0)&&(dyout==0) ) {
11371     dxout=x_coord(r)-x_coord(q);
11372     dyout=y_coord(r)-y_coord(q);
11373   }
11374 }
11375 if ( q==c ) {
11376   dxout=dxout-x_coord(h);
11377   dyout=dyout-y_coord(h);
11378 }
11379 tmp=mp_pyth_add(mp, dxout,dyout);
11380 if ( tmp==0 ) mp_confusion(mp, "degenerate spec");
11381 @:this can't happen degerate spec}{\quad degenerate spec@>
11382 dxout=mp_make_fraction(mp, dxout,tmp);
11383 dyout=mp_make_fraction(mp, dyout,tmp)
11384
11385 @* \[23] Direction and intersection times.
11386 A path of length $n$ is defined parametrically by functions $x(t)$ and
11387 $y(t)$, for |0<=t<=n|; we can regard $t$ as the ``time'' at which the path
11388 reaches the point $\bigl(x(t),y(t)\bigr)$.  In this section of the program
11389 we shall consider operations that determine special times associated with
11390 given paths: the first time that a path travels in a given direction, and
11391 a pair of times at which two paths cross each other.
11392
11393 @ Let's start with the easier task. The function |find_direction_time| is
11394 given a direction |(x,y)| and a path starting at~|h|. If the path never
11395 travels in direction |(x,y)|, the direction time will be~|-1|; otherwise
11396 it will be nonnegative.
11397
11398 Certain anomalous cases can arise: If |(x,y)=(0,0)|, so that the given
11399 direction is undefined, the direction time will be~0. If $\bigl(x'(t),
11400 y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be
11401 assumed to match any given direction at time~|t|.
11402
11403 The routine solves this problem in nondegenerate cases by rotating the path
11404 and the given direction so that |(x,y)=(1,0)|; i.e., the main task will be
11405 to find when a given path first travels ``due east.''
11406
11407 @c 
11408 static scaled mp_find_direction_time (MP mp,scaled x, scaled y, pointer h) {
11409   scaled max; /* $\max\bigl(\vert x\vert,\vert y\vert\bigr)$ */
11410   pointer p,q; /* for list traversal */
11411   scaled n; /* the direction time at knot |p| */
11412   scaled tt; /* the direction time within a cubic */
11413   @<Other local variables for |find_direction_time|@>;
11414   @<Normalize the given direction for better accuracy;
11415     but |return| with zero result if it's zero@>;
11416   n=0; p=h; phi=0;
11417   while (1) { 
11418     if ( right_type(p)==mp_endpoint ) break;
11419     q=mp_link(p);
11420     @<Rotate the cubic between |p| and |q|; then
11421       |goto found| if the rotated cubic travels due east at some time |tt|;
11422       but |break| if an entire cyclic path has been traversed@>;
11423     p=q; n=n+unity;
11424   }
11425   return (-unity);
11426 FOUND: 
11427   return (n+tt);
11428 }
11429
11430 @ @<Normalize the given direction for better accuracy...@>=
11431 if ( abs(x)<abs(y) ) { 
11432   x=mp_make_fraction(mp, x,abs(y));
11433   if ( y>0 ) y=fraction_one; else y=-fraction_one;
11434 } else if ( x==0 ) { 
11435   return 0;
11436 } else  { 
11437   y=mp_make_fraction(mp, y,abs(x));
11438   if ( x>0 ) x=fraction_one; else x=-fraction_one;
11439 }
11440
11441 @ Since we're interested in the tangent directions, we work with the
11442 derivative $${1\over3}B'(x_0,x_1,x_2,x_3;t)=
11443 B(x_1-x_0,x_2-x_1,x_3-x_2;t)$$ instead of
11444 $B(x_0,x_1,x_2,x_3;t)$ itself. The derived coefficients are also scaled up
11445 in order to achieve better accuracy.
11446
11447 The given path may turn abruptly at a knot, and it might pass the critical
11448 tangent direction at such a time. Therefore we remember the direction |phi|
11449 in which the previous rotated cubic was traveling. (The value of |phi| will be
11450 undefined on the first cubic, i.e., when |n=0|.)
11451
11452 @<Rotate the cubic between |p| and |q|; then...@>=
11453 tt=0;
11454 @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples of the control
11455   points of the rotated derivatives@>;
11456 if ( y1==0 ) if ( x1>=0 ) goto FOUND;
11457 if ( n>0 ) { 
11458   @<Exit to |found| if an eastward direction occurs at knot |p|@>;
11459   if ( p==h ) break;
11460   };
11461 if ( (x3!=0)||(y3!=0) ) phi=mp_n_arg(mp, x3,y3);
11462 @<Exit to |found| if the curve whose derivatives are specified by
11463   |x1,x2,x3,y1,y2,y3| travels eastward at some time~|tt|@>
11464
11465 @ @<Other local variables for |find_direction_time|@>=
11466 scaled x1,x2,x3,y1,y2,y3;  /* multiples of rotated derivatives */
11467 angle theta,phi; /* angles of exit and entry at a knot */
11468 fraction t; /* temp storage */
11469
11470 @ @<Set local variables |x1,x2,x3| and |y1,y2,y3| to multiples...@>=
11471 x1=right_x(p)-x_coord(p); x2=left_x(q)-right_x(p);
11472 x3=x_coord(q)-left_x(q);
11473 y1=right_y(p)-y_coord(p); y2=left_y(q)-right_y(p);
11474 y3=y_coord(q)-left_y(q);
11475 max=abs(x1);
11476 if ( abs(x2)>max ) max=abs(x2);
11477 if ( abs(x3)>max ) max=abs(x3);
11478 if ( abs(y1)>max ) max=abs(y1);
11479 if ( abs(y2)>max ) max=abs(y2);
11480 if ( abs(y3)>max ) max=abs(y3);
11481 if ( max==0 ) goto FOUND;
11482 while ( max<fraction_half ){ 
11483   max+=max; x1+=x1; x2+=x2; x3+=x3;
11484   y1+=y1; y2+=y2; y3+=y3;
11485 }
11486 t=x1; x1=mp_take_fraction(mp, x1,x)+mp_take_fraction(mp, y1,y);
11487 y1=mp_take_fraction(mp, y1,x)-mp_take_fraction(mp, t,y);
11488 t=x2; x2=mp_take_fraction(mp, x2,x)+mp_take_fraction(mp, y2,y);
11489 y2=mp_take_fraction(mp, y2,x)-mp_take_fraction(mp, t,y);
11490 t=x3; x3=mp_take_fraction(mp, x3,x)+mp_take_fraction(mp, y3,y);
11491 y3=mp_take_fraction(mp, y3,x)-mp_take_fraction(mp, t,y)
11492
11493 @ @<Exit to |found| if an eastward direction occurs at knot |p|@>=
11494 theta=mp_n_arg(mp, x1,y1);
11495 if ( theta>=0 ) if ( phi<=0 ) if ( phi>=theta-one_eighty_deg ) goto FOUND;
11496 if ( theta<=0 ) if ( phi>=0 ) if ( phi<=theta+one_eighty_deg ) goto FOUND
11497
11498 @ In this step we want to use the |crossing_point| routine to find the
11499 roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$.
11500 Several complications arise: If the quadratic equation has a double root,
11501 the curve never crosses zero, and |crossing_point| will find nothing;
11502 this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic
11503 equation has simple roots, or only one root, we may have to negate it
11504 so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root.
11505 And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is
11506 identically zero.
11507
11508 @ @<Exit to |found| if the curve whose derivatives are specified by...@>=
11509 if ( x1<0 ) if ( x2<0 ) if ( x3<0 ) goto DONE;
11510 if ( mp_ab_vs_cd(mp, y1,y3,y2,y2)==0 ) {
11511   @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11512     either |goto found| or |goto done|@>;
11513 }
11514 if ( y1<=0 ) {
11515   if ( y1<0 ) { y1=-y1; y2=-y2; y3=-y3; }
11516   else if ( y2>0 ){ y2=-y2; y3=-y3; };
11517 }
11518 @<Check the places where $B(y_1,y_2,y_3;t)=0$ to see if
11519   $B(x_1,x_2,x_3;t)\ge0$@>;
11520 DONE:
11521
11522 @ The quadratic polynomial $B(y_1,y_2,y_3;t)$ begins |>=0| and has at most
11523 two roots, because we know that it isn't identically zero.
11524
11525 It must be admitted that the |crossing_point| routine is not perfectly accurate;
11526 rounding errors might cause it to find a root when $y_1y_3>y_2^2$, or to
11527 miss the roots when $y_1y_3<y_2^2$. The rotation process is itself
11528 subject to rounding errors. Yet this code optimistically tries to
11529 do the right thing.
11530
11531 @d we_found_it { tt=(t+04000) / 010000; goto FOUND; }
11532
11533 @<Check the places where $B(y_1,y_2,y_3;t)=0$...@>=
11534 t=mp_crossing_point(mp, y1,y2,y3);
11535 if ( t>fraction_one ) goto DONE;
11536 y2=t_of_the_way(y2,y3);
11537 x1=t_of_the_way(x1,x2);
11538 x2=t_of_the_way(x2,x3);
11539 x1=t_of_the_way(x1,x2);
11540 if ( x1>=0 ) we_found_it;
11541 if ( y2>0 ) y2=0;
11542 tt=t; t=mp_crossing_point(mp, 0,-y2,-y3);
11543 if ( t>fraction_one ) goto DONE;
11544 x1=t_of_the_way(x1,x2);
11545 x2=t_of_the_way(x2,x3);
11546 if ( t_of_the_way(x1,x2)>=0 ) { 
11547   t=t_of_the_way(tt,fraction_one); we_found_it;
11548 }
11549
11550 @ @<Handle the test for eastward directions when $y_1y_3=y_2^2$;
11551     either |goto found| or |goto done|@>=
11552
11553   if ( mp_ab_vs_cd(mp, y1,y2,0,0)<0 ) {
11554     t=mp_make_fraction(mp, y1,y1-y2);
11555     x1=t_of_the_way(x1,x2);
11556     x2=t_of_the_way(x2,x3);
11557     if ( t_of_the_way(x1,x2)>=0 ) we_found_it;
11558   } else if ( y3==0 ) {
11559     if ( y1==0 ) {
11560       @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|@>;
11561     } else if ( x3>=0 ) {
11562       tt=unity; goto FOUND;
11563     }
11564   }
11565   goto DONE;
11566 }
11567
11568 @ At this point we know that the derivative of |y(t)| is identically zero,
11569 and that |x1<0|; but either |x2>=0| or |x3>=0|, so there's some hope of
11570 traveling east.
11571
11572 @<Exit to |found| if the derivative $B(x_1,x_2,x_3;t)$ becomes |>=0|...@>=
11573
11574   t=mp_crossing_point(mp, -x1,-x2,-x3);
11575   if ( t<=fraction_one ) we_found_it;
11576   if ( mp_ab_vs_cd(mp, x1,x3,x2,x2)<=0 ) { 
11577     t=mp_make_fraction(mp, x1,x1-x2); we_found_it;
11578   }
11579 }
11580
11581 @ The intersection of two cubics can be found by an interesting variant
11582 of the general bisection scheme described in the introduction to
11583 |crossing_point|.\
11584 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)$,
11585 we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$,
11586 if an intersection exists. First we find the smallest rectangle that
11587 encloses the points $\{w_0,w_1,w_2,w_3\}$ and check that it overlaps
11588 the smallest rectangle that encloses
11589 $\{z_0,z_1,z_2,z_3\}$; if not, the cubics certainly don't intersect.
11590 But if the rectangles do overlap, we bisect the intervals, getting
11591 new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first
11592 tries for an intersection between $w'$ and~$z'$, then (if unsuccessful)
11593 between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$,
11594 finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful
11595 levels of bisection we will have determined the intersection times $t_1$
11596 and~$t_2$ to $l$~bits of accuracy.
11597
11598 \def\submin{_{\rm min}} \def\submax{_{\rm max}}
11599 As before, it is better to work with the numbers $W_k=2^l(w_k-w_{k-1})$
11600 and $Z_k=2^l(z_k-z_{k-1})$ rather than the coefficients $w_k$ and $z_k$
11601 themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$,
11602 to determine when the enclosing rectangles overlap. Here's why:
11603 The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$,
11604 and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$,
11605 if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin=
11606 \min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates
11607 overlap if and only if $u\submin\L x\submax$ and
11608 $x\submin\L u\submax$. Letting
11609 $$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\;
11610   U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$
11611 we have $2^lu\submin=2^lu_0+U\submin$, etc.; the condition for overlap
11612 reduces to
11613 $$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$
11614 Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly,
11615 the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The
11616 coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases,
11617 because of the overlap condition; i.e., we know that $X\submin$,
11618 $X\submax$, and their relatives are bounded, hence $X\submax-
11619 U\submin$ and $X\submin-U\submax$ are bounded.
11620
11621 @ Incidentally, if the given cubics intersect more than once, the process
11622 just sketched will not necessarily find the lexicographically smallest pair
11623 $(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled
11624 order''; i.e., if $t_1=(.a_1a_2\ldots a_{16})_2$ and
11625 $t_2=(.b_1b_2\ldots b_{16})_2$, then we will minimize
11626 $a_1b_1a_2b_2\ldots a_{16}b_{16}$, not
11627 $a_1a_2\ldots a_{16}b_1b_2\ldots b_{16}$.
11628 Shuffled order agrees with lexicographic order if all pairs of solutions
11629 $(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff
11630 $t_2<t_2'$; but in general, lexicographic order can be quite different,
11631 and the bisection algorithm would be substantially less efficient if it were
11632 constrained by lexicographic order.
11633
11634 For example, suppose that an overlap has been found for $l=3$ and
11635 $(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by
11636 either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4.
11637 Then there is probably an intersection in one of the subintervals
11638 $(.1011,.011x)$; but lexicographic order would require us to explore
11639 $(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't
11640 want to store all of the subdivision data for the second path, so the
11641 subdivisions would have to be regenerated many times. Such inefficiencies
11642 would be associated with every `1' in the binary representation of~$t_1$.
11643
11644 @ The subdivision process introduces rounding errors, hence we need to
11645 make a more liberal test for overlap. It is not hard to show that the
11646 computed values of $U_i$ differ from the truth by at most~$l$, on
11647 level~$l$, hence $U\submin$ and $U\submax$ will be at most $3l$ in error.
11648 If $\beta$ is an upper bound on the absolute error in the computed
11649 components of $\Delta=(|delx|,|dely|)$ on level~$l$, we will replace
11650 the test `$X\submin-U\submax\L|delx|$' by the more liberal test
11651 `$X\submin-U\submax\L|delx|+|tol|$', where $|tol|=6l+\beta$.
11652
11653 More accuracy is obtained if we try the algorithm first with |tol=0|;
11654 the more liberal tolerance is used only if an exact approach fails.
11655 It is convenient to do this double-take by letting `3' in the preceding
11656 paragraph be a parameter, which is first 0, then 3.
11657
11658 @<Glob...@>=
11659 unsigned int tol_step; /* either 0 or 3, usually */
11660
11661 @ We shall use an explicit stack to implement the recursive bisection
11662 method described above. The |bisect_stack| array will contain numerous 5-word
11663 packets like $(U_1,U_2,U_3,U\submin,U\submax)$, as well as 20-word packets
11664 comprising the 5-word packets for $U$, $V$, $X$, and~$Y$.
11665
11666 The following macros define the allocation of stack positions to
11667 the quantities needed for bisection-intersection.
11668
11669 @d stack_1(A) mp->bisect_stack[(A)] /* $U_1$, $V_1$, $X_1$, or $Y_1$ */
11670 @d stack_2(A) mp->bisect_stack[(A)+1] /* $U_2$, $V_2$, $X_2$, or $Y_2$ */
11671 @d stack_3(A) mp->bisect_stack[(A)+2] /* $U_3$, $V_3$, $X_3$, or $Y_3$ */
11672 @d stack_min(A) mp->bisect_stack[(A)+3]
11673   /* $U\submin$, $V\submin$, $X\submin$, or $Y\submin$ */
11674 @d stack_max(A) mp->bisect_stack[(A)+4]
11675   /* $U\submax$, $V\submax$, $X\submax$, or $Y\submax$ */
11676 @d int_packets 20 /* number of words to represent $U_k$, $V_k$, $X_k$, and $Y_k$ */
11677 @#
11678 @d u_packet(A) ((A)-5)
11679 @d v_packet(A) ((A)-10)
11680 @d x_packet(A) ((A)-15)
11681 @d y_packet(A) ((A)-20)
11682 @d l_packets (mp->bisect_ptr-int_packets)
11683 @d r_packets mp->bisect_ptr
11684 @d ul_packet u_packet(l_packets) /* base of $U'_k$ variables */
11685 @d vl_packet v_packet(l_packets) /* base of $V'_k$ variables */
11686 @d xl_packet x_packet(l_packets) /* base of $X'_k$ variables */
11687 @d yl_packet y_packet(l_packets) /* base of $Y'_k$ variables */
11688 @d ur_packet u_packet(r_packets) /* base of $U''_k$ variables */
11689 @d vr_packet v_packet(r_packets) /* base of $V''_k$ variables */
11690 @d xr_packet x_packet(r_packets) /* base of $X''_k$ variables */
11691 @d yr_packet y_packet(r_packets) /* base of $Y''_k$ variables */
11692 @#
11693 @d u1l stack_1(ul_packet) /* $U'_1$ */
11694 @d u2l stack_2(ul_packet) /* $U'_2$ */
11695 @d u3l stack_3(ul_packet) /* $U'_3$ */
11696 @d v1l stack_1(vl_packet) /* $V'_1$ */
11697 @d v2l stack_2(vl_packet) /* $V'_2$ */
11698 @d v3l stack_3(vl_packet) /* $V'_3$ */
11699 @d x1l stack_1(xl_packet) /* $X'_1$ */
11700 @d x2l stack_2(xl_packet) /* $X'_2$ */
11701 @d x3l stack_3(xl_packet) /* $X'_3$ */
11702 @d y1l stack_1(yl_packet) /* $Y'_1$ */
11703 @d y2l stack_2(yl_packet) /* $Y'_2$ */
11704 @d y3l stack_3(yl_packet) /* $Y'_3$ */
11705 @d u1r stack_1(ur_packet) /* $U''_1$ */
11706 @d u2r stack_2(ur_packet) /* $U''_2$ */
11707 @d u3r stack_3(ur_packet) /* $U''_3$ */
11708 @d v1r stack_1(vr_packet) /* $V''_1$ */
11709 @d v2r stack_2(vr_packet) /* $V''_2$ */
11710 @d v3r stack_3(vr_packet) /* $V''_3$ */
11711 @d x1r stack_1(xr_packet) /* $X''_1$ */
11712 @d x2r stack_2(xr_packet) /* $X''_2$ */
11713 @d x3r stack_3(xr_packet) /* $X''_3$ */
11714 @d y1r stack_1(yr_packet) /* $Y''_1$ */
11715 @d y2r stack_2(yr_packet) /* $Y''_2$ */
11716 @d y3r stack_3(yr_packet) /* $Y''_3$ */
11717 @#
11718 @d stack_dx mp->bisect_stack[mp->bisect_ptr] /* stacked value of |delx| */
11719 @d stack_dy mp->bisect_stack[mp->bisect_ptr+1] /* stacked value of |dely| */
11720 @d stack_tol mp->bisect_stack[mp->bisect_ptr+2] /* stacked value of |tol| */
11721 @d stack_uv mp->bisect_stack[mp->bisect_ptr+3] /* stacked value of |uv| */
11722 @d stack_xy mp->bisect_stack[mp->bisect_ptr+4] /* stacked value of |xy| */
11723 @d int_increment (int_packets+int_packets+5) /* number of stack words per level */
11724
11725 @<Glob...@>=
11726 integer *bisect_stack;
11727 integer bisect_ptr;
11728
11729 @ @<Allocate or initialize ...@>=
11730 mp->bisect_stack = xmalloc((bistack_size+1),sizeof(integer));
11731
11732 @ @<Dealloc variables@>=
11733 xfree(mp->bisect_stack);
11734
11735 @ @<Check the ``constant''...@>=
11736 if ( int_packets+17*int_increment>bistack_size ) mp->bad=19;
11737
11738 @ Computation of the min and max is a tedious but fairly fast sequence of
11739 instructions; exactly four comparisons are made in each branch.
11740
11741 @d set_min_max(A) 
11742   if ( stack_1((A))<0 ) {
11743     if ( stack_3((A))>=0 ) {
11744       if ( stack_2((A))<0 ) stack_min((A))=stack_1((A))+stack_2((A));
11745       else stack_min((A))=stack_1((A));
11746       stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11747       if ( stack_max((A))<0 ) stack_max((A))=0;
11748     } else { 
11749       stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11750       if ( stack_min((A))>stack_1((A)) ) stack_min((A))=stack_1((A));
11751       stack_max((A))=stack_1((A))+stack_2((A));
11752       if ( stack_max((A))<0 ) stack_max((A))=0;
11753     }
11754   } else if ( stack_3((A))<=0 ) {
11755     if ( stack_2((A))>0 ) stack_max((A))=stack_1((A))+stack_2((A));
11756     else stack_max((A))=stack_1((A));
11757     stack_min((A))=stack_1((A))+stack_2((A))+stack_3((A));
11758     if ( stack_min((A))>0 ) stack_min((A))=0;
11759   } else  { 
11760     stack_max((A))=stack_1((A))+stack_2((A))+stack_3((A));
11761     if ( stack_max((A))<stack_1((A)) ) stack_max((A))=stack_1((A));
11762     stack_min((A))=stack_1((A))+stack_2((A));
11763     if ( stack_min((A))>0 ) stack_min((A))=0;
11764   }
11765
11766 @ It's convenient to keep the current values of $l$, $t_1$, and $t_2$ in
11767 the integer form $2^l+2^lt_1$ and $2^l+2^lt_2$. The |cubic_intersection|
11768 routine uses global variables |cur_t| and |cur_tt| for this purpose;
11769 after successful completion, |cur_t| and |cur_tt| will contain |unity|
11770 plus the |scaled| values of $t_1$ and~$t_2$.
11771
11772 The values of |cur_t| and |cur_tt| will be set to zero if |cubic_intersection|
11773 finds no intersection. The routine gives up and gives an approximate answer
11774 if it has backtracked
11775 more than 5000 times (otherwise there are cases where several minutes
11776 of fruitless computation would be possible).
11777
11778 @d max_patience 5000
11779
11780 @<Glob...@>=
11781 integer cur_t;integer cur_tt; /* controls and results of |cubic_intersection| */
11782 integer time_to_go; /* this many backtracks before giving up */
11783 integer max_t; /* maximum of $2^{l+1}$ so far achieved */
11784
11785 @ The given cubics $B(w_0,w_1,w_2,w_3;t)$ and
11786 $B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes |(p,mp_link(p))|
11787 and |(pp,mp_link(pp))|, respectively.
11788
11789 @c 
11790 static void mp_cubic_intersection (MP mp,pointer p, pointer pp) {
11791   pointer q,qq; /* |mp_link(p)|, |mp_link(pp)| */
11792   mp->time_to_go=max_patience; mp->max_t=2;
11793   @<Initialize for intersections at level zero@>;
11794 CONTINUE:
11795   while (1) { 
11796     if ( mp->delx-mp->tol<=stack_max(x_packet(mp->xy))-stack_min(u_packet(mp->uv)))
11797     if ( mp->delx+mp->tol>=stack_min(x_packet(mp->xy))-stack_max(u_packet(mp->uv)))
11798     if ( mp->dely-mp->tol<=stack_max(y_packet(mp->xy))-stack_min(v_packet(mp->uv)))
11799     if ( mp->dely+mp->tol>=stack_min(y_packet(mp->xy))-stack_max(v_packet(mp->uv))) 
11800     { 
11801       if ( mp->cur_t>=mp->max_t ){ 
11802         if ( mp->max_t==two ) { /* we've done 17 bisections */ 
11803            mp->cur_t=halfp(mp->cur_t+1); 
11804                mp->cur_tt=halfp(mp->cur_tt+1); 
11805            return;
11806         }
11807         mp->max_t+=mp->max_t; mp->appr_t=mp->cur_t; mp->appr_tt=mp->cur_tt;
11808       }
11809       @<Subdivide for a new level of intersection@>;
11810       goto CONTINUE;
11811     }
11812     if ( mp->time_to_go>0 ) {
11813       decr(mp->time_to_go);
11814     } else { 
11815       while ( mp->appr_t<unity ) { 
11816         mp->appr_t+=mp->appr_t; mp->appr_tt+=mp->appr_tt;
11817       }
11818       mp->cur_t=mp->appr_t; mp->cur_tt=mp->appr_tt; return;
11819     }
11820     @<Advance to the next pair |(cur_t,cur_tt)|@>;
11821   }
11822 }
11823
11824 @ The following variables are global, although they are used only by
11825 |cubic_intersection|, because it is necessary on some machines to
11826 split |cubic_intersection| up into two procedures.
11827
11828 @<Glob...@>=
11829 integer delx;integer dely; /* the components of $\Delta=2^l(w_0-z_0)$ */
11830 integer tol; /* bound on the uncertainty in the overlap test */
11831 integer uv;
11832 integer xy; /* pointers to the current packets of interest */
11833 integer three_l; /* |tol_step| times the bisection level */
11834 integer appr_t;integer appr_tt; /* best approximations known to the answers */
11835
11836 @ We shall assume that the coordinates are sufficiently non-extreme that
11837 integer overflow will not occur.
11838 @^overflow in arithmetic@>
11839
11840 @<Initialize for intersections at level zero@>=
11841 q=mp_link(p); qq=mp_link(pp); mp->bisect_ptr=int_packets;
11842 u1r=right_x(p)-x_coord(p); u2r=left_x(q)-right_x(p);
11843 u3r=x_coord(q)-left_x(q); set_min_max(ur_packet);
11844 v1r=right_y(p)-y_coord(p); v2r=left_y(q)-right_y(p);
11845 v3r=y_coord(q)-left_y(q); set_min_max(vr_packet);
11846 x1r=right_x(pp)-x_coord(pp); x2r=left_x(qq)-right_x(pp);
11847 x3r=x_coord(qq)-left_x(qq); set_min_max(xr_packet);
11848 y1r=right_y(pp)-y_coord(pp); y2r=left_y(qq)-right_y(pp);
11849 y3r=y_coord(qq)-left_y(qq); set_min_max(yr_packet);
11850 mp->delx=x_coord(p)-x_coord(pp); mp->dely=y_coord(p)-y_coord(pp);
11851 mp->tol=0; mp->uv=r_packets; mp->xy=r_packets; 
11852 mp->three_l=0; mp->cur_t=1; mp->cur_tt=1
11853
11854 @ @<Subdivide for a new level of intersection@>=
11855 stack_dx=mp->delx; stack_dy=mp->dely; stack_tol=mp->tol; 
11856 stack_uv=mp->uv; stack_xy=mp->xy;
11857 mp->bisect_ptr=mp->bisect_ptr+int_increment;
11858 mp->cur_t+=mp->cur_t; mp->cur_tt+=mp->cur_tt;
11859 u1l=stack_1(u_packet(mp->uv)); u3r=stack_3(u_packet(mp->uv));
11860 u2l=half(u1l+stack_2(u_packet(mp->uv)));
11861 u2r=half(u3r+stack_2(u_packet(mp->uv)));
11862 u3l=half(u2l+u2r); u1r=u3l;
11863 set_min_max(ul_packet); set_min_max(ur_packet);
11864 v1l=stack_1(v_packet(mp->uv)); v3r=stack_3(v_packet(mp->uv));
11865 v2l=half(v1l+stack_2(v_packet(mp->uv)));
11866 v2r=half(v3r+stack_2(v_packet(mp->uv)));
11867 v3l=half(v2l+v2r); v1r=v3l;
11868 set_min_max(vl_packet); set_min_max(vr_packet);
11869 x1l=stack_1(x_packet(mp->xy)); x3r=stack_3(x_packet(mp->xy));
11870 x2l=half(x1l+stack_2(x_packet(mp->xy)));
11871 x2r=half(x3r+stack_2(x_packet(mp->xy)));
11872 x3l=half(x2l+x2r); x1r=x3l;
11873 set_min_max(xl_packet); set_min_max(xr_packet);
11874 y1l=stack_1(y_packet(mp->xy)); y3r=stack_3(y_packet(mp->xy));
11875 y2l=half(y1l+stack_2(y_packet(mp->xy)));
11876 y2r=half(y3r+stack_2(y_packet(mp->xy)));
11877 y3l=half(y2l+y2r); y1r=y3l;
11878 set_min_max(yl_packet); set_min_max(yr_packet);
11879 mp->uv=l_packets; mp->xy=l_packets;
11880 mp->delx+=mp->delx; mp->dely+=mp->dely;
11881 mp->tol=mp->tol-mp->three_l+mp->tol_step; 
11882 mp->tol+=mp->tol; mp->three_l=mp->three_l+mp->tol_step
11883
11884 @ @<Advance to the next pair |(cur_t,cur_tt)|@>=
11885 NOT_FOUND: 
11886 if ( odd(mp->cur_tt) ) {
11887   if ( odd(mp->cur_t) ) {
11888      @<Descend to the previous level and |goto not_found|@>;
11889   } else { 
11890     incr(mp->cur_t);
11891     mp->delx=mp->delx+stack_1(u_packet(mp->uv))+stack_2(u_packet(mp->uv))
11892       +stack_3(u_packet(mp->uv));
11893     mp->dely=mp->dely+stack_1(v_packet(mp->uv))+stack_2(v_packet(mp->uv))
11894       +stack_3(v_packet(mp->uv));
11895     mp->uv=mp->uv+int_packets; /* switch from |l_packets| to |r_packets| */
11896     decr(mp->cur_tt); mp->xy=mp->xy-int_packets; 
11897          /* switch from |r_packets| to |l_packets| */
11898     mp->delx=mp->delx+stack_1(x_packet(mp->xy))+stack_2(x_packet(mp->xy))
11899       +stack_3(x_packet(mp->xy));
11900     mp->dely=mp->dely+stack_1(y_packet(mp->xy))+stack_2(y_packet(mp->xy))
11901       +stack_3(y_packet(mp->xy));
11902   }
11903 } else { 
11904   incr(mp->cur_tt); mp->tol=mp->tol+mp->three_l;
11905   mp->delx=mp->delx-stack_1(x_packet(mp->xy))-stack_2(x_packet(mp->xy))
11906     -stack_3(x_packet(mp->xy));
11907   mp->dely=mp->dely-stack_1(y_packet(mp->xy))-stack_2(y_packet(mp->xy))
11908     -stack_3(y_packet(mp->xy));
11909   mp->xy=mp->xy+int_packets; /* switch from |l_packets| to |r_packets| */
11910 }
11911
11912 @ @<Descend to the previous level...@>=
11913
11914   mp->cur_t=halfp(mp->cur_t); mp->cur_tt=halfp(mp->cur_tt);
11915   if ( mp->cur_t==0 ) return;
11916   mp->bisect_ptr=mp->bisect_ptr-int_increment; 
11917   mp->three_l=mp->three_l-mp->tol_step;
11918   mp->delx=stack_dx; mp->dely=stack_dy; mp->tol=stack_tol; 
11919   mp->uv=stack_uv; mp->xy=stack_xy;
11920   goto NOT_FOUND;
11921 }
11922
11923 @ The |path_intersection| procedure is much simpler.
11924 It invokes |cubic_intersection| in lexicographic order until finding a
11925 pair of cubics that intersect. The final intersection times are placed in
11926 |cur_t| and~|cur_tt|.
11927
11928 @c 
11929 static void mp_path_intersection (MP mp,pointer h, pointer hh) {
11930   pointer p,pp; /* link registers that traverse the given paths */
11931   integer n,nn; /* integer parts of intersection times, minus |unity| */
11932   @<Change one-point paths into dead cycles@>;
11933   mp->tol_step=0;
11934   do {  
11935     n=-unity; p=h;
11936     do {  
11937       if ( right_type(p)!=mp_endpoint ) { 
11938         nn=-unity; pp=hh;
11939         do {  
11940           if ( right_type(pp)!=mp_endpoint )  { 
11941             mp_cubic_intersection(mp, p,pp);
11942             if ( mp->cur_t>0 ) { 
11943               mp->cur_t=mp->cur_t+n; mp->cur_tt=mp->cur_tt+nn; 
11944               return;
11945             }
11946           }
11947           nn=nn+unity; pp=mp_link(pp);
11948         } while (pp!=hh);
11949       }
11950       n=n+unity; p=mp_link(p);
11951     } while (p!=h);
11952     mp->tol_step=mp->tol_step+3;
11953   } while (mp->tol_step<=3);
11954   mp->cur_t=-unity; mp->cur_tt=-unity;
11955 }
11956
11957 @ @<Change one-point paths...@>=
11958 if ( right_type(h)==mp_endpoint ) {
11959   right_x(h)=x_coord(h); left_x(h)=x_coord(h);
11960   right_y(h)=y_coord(h); left_y(h)=y_coord(h); right_type(h)=mp_explicit;
11961 }
11962 if ( right_type(hh)==mp_endpoint ) {
11963   right_x(hh)=x_coord(hh); left_x(hh)=x_coord(hh);
11964   right_y(hh)=y_coord(hh); left_y(hh)=y_coord(hh); right_type(hh)=mp_explicit;
11965 }
11966
11967 @* \[24] Dynamic linear equations.
11968 \MP\ users define variables implicitly by stating equations that should be
11969 satisfied; the computer is supposed to be smart enough to solve those equations.
11970 And indeed, the computer tries valiantly to do so, by distinguishing five
11971 different types of numeric values:
11972
11973 \smallskip\hang
11974 |type(p)=mp_known| is the nice case, when |value(p)| is the |scaled| value
11975 of the variable whose address is~|p|.
11976
11977 \smallskip\hang
11978 |type(p)=mp_dependent| means that |value(p)| is not present, but |dep_list(p)|
11979 points to a {\sl dependency list\/} that expresses the value of variable~|p|
11980 as a |scaled| number plus a sum of independent variables with |fraction|
11981 coefficients.
11982
11983 \smallskip\hang
11984 |type(p)=mp_independent| means that |value(p)=64s+m|, where |s>0| is a ``serial
11985 number'' reflecting the time this variable was first used in an equation;
11986 also |0<=m<64|, and each dependent variable
11987 that refers to this one is actually referring to the future value of
11988 this variable times~$2^m$. (Usually |m=0|, but higher degrees of
11989 scaling are sometimes needed to keep the coefficients in dependency lists
11990 from getting too large. The value of~|m| will always be even.)
11991
11992 \smallskip\hang
11993 |type(p)=mp_numeric_type| means that variable |p| hasn't appeared in an
11994 equation before, but it has been explicitly declared to be numeric.
11995
11996 \smallskip\hang
11997 |type(p)=undefined| means that variable |p| hasn't appeared before.
11998
11999 \smallskip\noindent
12000 We have actually discussed these five types in the reverse order of their
12001 history during a computation: Once |known|, a variable never again
12002 becomes |dependent|; once |dependent|, it almost never again becomes
12003 |mp_independent|; once |mp_independent|, it never again becomes |mp_numeric_type|;
12004 and once |mp_numeric_type|, it never again becomes |undefined| (except
12005 of course when the user specifically decides to scrap the old value
12006 and start again). A backward step may, however, take place: Sometimes
12007 a |dependent| variable becomes |mp_independent| again, when one of the
12008 independent variables it depends on is reverting to |undefined|.
12009
12010
12011 The next patch detects overflow of independent-variable serial
12012 numbers. Diagnosed and patched by Thorsten Dahlheimer.
12013
12014 @d s_scale 64 /* the serial numbers are multiplied by this factor */
12015 @d new_indep(A)  /* create a new independent variable */
12016   { if ( mp->serial_no>el_gordo-s_scale )
12017     mp_fatal_error(mp, "variable instance identifiers exhausted");
12018   type((A))=mp_independent; mp->serial_no=mp->serial_no+s_scale;
12019   value((A))=mp->serial_no;
12020   }
12021
12022 @<Glob...@>=
12023 integer serial_no; /* the most recent serial number, times |s_scale| */
12024
12025 @ @<Make variable |q+s| newly independent@>=new_indep(q+s)
12026
12027 @ But how are dependency lists represented? It's simple: The linear combination
12028 $\alpha_1v_1+\cdots+\alpha_kv_k+\beta$ appears in |k+1| value nodes. If
12029 |q=dep_list(p)| points to this list, and if |k>0|, then |value(q)=
12030 @t$\alpha_1$@>| (which is a |fraction|); |info(q)| points to the location
12031 of $\alpha_1$; and |mp_link(p)| points to the dependency list
12032 $\alpha_2v_2+\cdots+\alpha_kv_k+\beta$. On the other hand if |k=0|,
12033 then |value(q)=@t$\beta$@>| (which is |scaled|) and |info(q)=null|.
12034 The independent variables $v_1$, \dots,~$v_k$ have been sorted so that
12035 they appear in decreasing order of their |value| fields (i.e., of
12036 their serial numbers). \ (It is convenient to use decreasing order,
12037 since |value(null)=0|. If the independent variables were not sorted by
12038 serial number but by some other criterion, such as their location in |mem|,
12039 the equation-solving mechanism would be too system-dependent, because
12040 the ordering can affect the computed results.)
12041
12042 The |link| field in the node that contains the constant term $\beta$ is
12043 called the {\sl final link\/} of the dependency list. \MP\ maintains
12044 a doubly-linked master list of all dependency lists, in terms of a permanently
12045 allocated node
12046 in |mem| called |dep_head|. If there are no dependencies, we have
12047 |mp_link(dep_head)=dep_head| and |prev_dep(dep_head)=dep_head|;
12048 otherwise |mp_link(dep_head)| points to the first dependent variable, say~|p|,
12049 and |prev_dep(p)=dep_head|. We have |type(p)=mp_dependent|, and |dep_list(p)|
12050 points to its dependency list. If the final link of that dependency list
12051 occurs in location~|q|, then |mp_link(q)| points to the next dependent
12052 variable (say~|r|); and we have |prev_dep(r)=q|, etc.
12053
12054 @d dep_list(A) mp_link(value_loc((A)))
12055   /* half of the |value| field in a |dependent| variable */
12056 @d prev_dep(A) info(value_loc((A)))
12057   /* the other half; makes a doubly linked list */
12058 @d dep_node_size 2 /* the number of words per dependency node */
12059
12060 @<Initialize table entries...@>= mp->serial_no=0;
12061 mp_link(dep_head)=dep_head; prev_dep(dep_head)=dep_head;
12062 info(dep_head)=null; dep_list(dep_head)=null;
12063
12064 @ Actually the description above contains a little white lie. There's
12065 another kind of variable called |mp_proto_dependent|, which is
12066 just like a |dependent| one except that the $\alpha$ coefficients
12067 in its dependency list are |scaled| instead of being fractions.
12068 Proto-dependency lists are mixed with dependency lists in the
12069 nodes reachable from |dep_head|.
12070
12071 @ Here is a procedure that prints a dependency list in symbolic form.
12072 The second parameter should be either |dependent| or |mp_proto_dependent|,
12073 to indicate the scaling of the coefficients.
12074
12075 @<Declarations@>=
12076 static void mp_print_dependency (MP mp,pointer p, quarterword t);
12077
12078 @ @c
12079 void mp_print_dependency (MP mp,pointer p, quarterword t) {
12080   integer v; /* a coefficient */
12081   pointer pp,q; /* for list manipulation */
12082   pp=p;
12083   while (true) { 
12084     v=abs(value(p)); q=info(p);
12085     if ( q==null ) { /* the constant term */
12086       if ( (v!=0)||(p==pp) ) {
12087          if ( value(p)>0 ) if ( p!=pp ) mp_print_char(mp, xord('+'));
12088          mp_print_scaled(mp, value(p));
12089       }
12090       return;
12091     }
12092     @<Print the coefficient, unless it's $\pm1.0$@>;
12093     if ( type(q)!=mp_independent ) mp_confusion(mp, "dep");
12094 @:this can't happen dep}{\quad dep@>
12095     mp_print_variable_name(mp, q); v=value(q) % s_scale;
12096     while ( v>0 ) { mp_print(mp, "*4"); v=v-2; }
12097     p=mp_link(p);
12098   }
12099 }
12100
12101 @ @<Print the coefficient, unless it's $\pm1.0$@>=
12102 if ( value(p)<0 ) mp_print_char(mp, xord('-'));
12103 else if ( p!=pp ) mp_print_char(mp, xord('+'));
12104 if ( t==mp_dependent ) v=mp_round_fraction(mp, v);
12105 if ( v!=unity ) mp_print_scaled(mp, v)
12106
12107 @ The maximum absolute value of a coefficient in a given dependency list
12108 is returned by the following simple function.
12109
12110 @c 
12111 static fraction mp_max_coef (MP mp,pointer p) {
12112   fraction x; /* the maximum so far */
12113   x=0;
12114   while ( info(p)!=null ) {
12115     if ( abs(value(p))>x ) x=abs(value(p));
12116     p=mp_link(p);
12117   }
12118   return x;
12119 }
12120
12121 @ One of the main operations needed on dependency lists is to add a multiple
12122 of one list to the other; we call this |p_plus_fq|, where |p| and~|q| point
12123 to dependency lists and |f| is a fraction.
12124
12125 If the coefficient of any independent variable becomes |coef_bound| or
12126 more, in absolute value, this procedure changes the type of that variable
12127 to `|independent_needing_fix|', and sets the global variable |fix_needed|
12128 to~|true|. The value of $|coef_bound|=\mu$ is chosen so that
12129 $\mu^2+\mu<8$; this means that the numbers we deal with won't
12130 get too large. (Instead of the ``optimum'' $\mu=(\sqrt{33}-1)/2\approx
12131 2.3723$, the safer value 7/3 is taken as the threshold.)
12132
12133 The changes mentioned in the preceding paragraph are actually done only if
12134 the global variable |watch_coefs| is |true|. But it usually is; in fact,
12135 it is |false| only when \MP\ is making a dependency list that will soon
12136 be equated to zero.
12137
12138 Several procedures that act on dependency lists, including |p_plus_fq|,
12139 set the global variable |dep_final| to the final (constant term) node of
12140 the dependency list that they produce.
12141
12142 @d coef_bound 04525252525 /* |fraction| approximation to 7/3 */
12143 @d independent_needing_fix 0
12144
12145 @<Glob...@>=
12146 boolean fix_needed; /* does at least one |independent| variable need scaling? */
12147 boolean watch_coefs; /* should we scale coefficients that exceed |coef_bound|? */
12148 pointer dep_final; /* location of the constant term and final link */
12149
12150 @ @<Set init...@>=
12151 mp->fix_needed=false; mp->watch_coefs=true;
12152
12153 @ The |p_plus_fq| procedure has a fourth parameter, |t|, that should be
12154 set to |mp_proto_dependent| if |p| is a proto-dependency list. In this
12155 case |f| will be |scaled|, not a |fraction|. Similarly, the fifth parameter~|tt|
12156 should be |mp_proto_dependent| if |q| is a proto-dependency list.
12157
12158 List |q| is unchanged by the operation; but list |p| is totally destroyed.
12159
12160 The final link of the dependency list or proto-dependency list returned
12161 by |p_plus_fq| is the same as the original final link of~|p|. Indeed, the
12162 constant term of the result will be located in the same |mem| location
12163 as the original constant term of~|p|.
12164
12165 Coefficients of the result are assumed to be zero if they are less than
12166 a certain threshold. This compensates for inevitable rounding errors,
12167 and tends to make more variables `|known|'. The threshold is approximately
12168 $10^{-5}$ in the case of normal dependency lists, $10^{-4}$ for
12169 proto-dependencies.
12170
12171 @d fraction_threshold 2685 /* a |fraction| coefficient less than this is zeroed */
12172 @d half_fraction_threshold 1342 /* half of |fraction_threshold| */
12173 @d scaled_threshold 8 /* a |scaled| coefficient less than this is zeroed */
12174 @d half_scaled_threshold 4 /* half of |scaled_threshold| */
12175
12176 @<Declarations@>=
12177 static pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
12178                       pointer q, quarterword t, quarterword tt) ;
12179
12180 @ @c
12181 pointer mp_p_plus_fq ( MP mp, pointer p, integer f, 
12182                       pointer q, quarterword t, quarterword tt) {
12183   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
12184   pointer r,s; /* for list manipulation */
12185   integer threshold; /* defines a neighborhood of zero */
12186   integer v; /* temporary register */
12187   if ( t==mp_dependent ) threshold=fraction_threshold;
12188   else threshold=scaled_threshold;
12189   r=temp_head; pp=info(p); qq=info(q);
12190   while (1) {
12191     if ( pp==qq ) {
12192       if ( pp==null ) {
12193        break;
12194       } else {
12195         @<Contribute a term from |p|, plus |f| times the
12196           corresponding term from |q|@>
12197       }
12198     } else if ( value(pp)<value(qq) ) {
12199       @<Contribute a term from |q|, multiplied by~|f|@>
12200     } else { 
12201      mp_link(r)=p; r=p; p=mp_link(p); pp=info(p);
12202     }
12203   }
12204   if ( t==mp_dependent )
12205     value(p)=mp_slow_add(mp, value(p),mp_take_fraction(mp, value(q),f));
12206   else  
12207     value(p)=mp_slow_add(mp, value(p),mp_take_scaled(mp, value(q),f));
12208   mp_link(r)=p; mp->dep_final=p; 
12209   return mp_link(temp_head);
12210 }
12211
12212 @ @<Contribute a term from |p|, plus |f|...@>=
12213
12214   if ( tt==mp_dependent ) v=value(p)+mp_take_fraction(mp, f,value(q));
12215   else v=value(p)+mp_take_scaled(mp, f,value(q));
12216   value(p)=v; s=p; p=mp_link(p);
12217   if ( abs(v)<threshold ) {
12218     mp_free_node(mp, s,dep_node_size);
12219   } else {
12220     if ( (abs(v)>=coef_bound)  && mp->watch_coefs ) { 
12221       type(qq)=independent_needing_fix; mp->fix_needed=true;
12222     }
12223     mp_link(r)=s; r=s;
12224   };
12225   pp=info(p); q=mp_link(q); qq=info(q);
12226 }
12227
12228 @ @<Contribute a term from |q|, multiplied by~|f|@>=
12229
12230   if ( tt==mp_dependent ) v=mp_take_fraction(mp, f,value(q));
12231   else v=mp_take_scaled(mp, f,value(q));
12232   if ( abs(v)>halfp(threshold) ) { 
12233     s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=v;
12234     if ( (abs(v)>=coef_bound) && mp->watch_coefs ) { 
12235       type(qq)=independent_needing_fix; mp->fix_needed=true;
12236     }
12237     mp_link(r)=s; r=s;
12238   }
12239   q=mp_link(q); qq=info(q);
12240 }
12241
12242 @ It is convenient to have another subroutine for the special case
12243 of |p_plus_fq| when |f=1.0|. In this routine lists |p| and |q| are
12244 both of the same type~|t| (either |dependent| or |mp_proto_dependent|).
12245
12246 @c 
12247 static pointer mp_p_plus_q (MP mp,pointer p, pointer q, quarterword t) {
12248   pointer pp,qq; /* |info(p)| and |info(q)|, respectively */
12249   pointer r,s; /* for list manipulation */
12250   integer threshold; /* defines a neighborhood of zero */
12251   integer v; /* temporary register */
12252   if ( t==mp_dependent ) threshold=fraction_threshold;
12253   else threshold=scaled_threshold;
12254   r=temp_head; pp=info(p); qq=info(q);
12255   while (1) {
12256     if ( pp==qq ) {
12257       if ( pp==null ) {
12258         break;
12259       } else {
12260         @<Contribute a term from |p|, plus the
12261           corresponding term from |q|@>
12262       }
12263     } else { 
12264           if ( value(pp)<value(qq) ) {
12265         s=mp_get_node(mp, dep_node_size); info(s)=qq; value(s)=value(q);
12266         q=mp_link(q); qq=info(q); mp_link(r)=s; r=s;
12267       } else { 
12268         mp_link(r)=p; r=p; p=mp_link(p); pp=info(p);
12269       }
12270     }
12271   }
12272   value(p)=mp_slow_add(mp, value(p),value(q));
12273   mp_link(r)=p; mp->dep_final=p; 
12274   return mp_link(temp_head);
12275 }
12276
12277 @ @<Contribute a term from |p|, plus the...@>=
12278
12279   v=value(p)+value(q);
12280   value(p)=v; s=p; p=mp_link(p); pp=info(p);
12281   if ( abs(v)<threshold ) {
12282     mp_free_node(mp, s,dep_node_size);
12283   } else { 
12284     if ( (abs(v)>=coef_bound ) && mp->watch_coefs ) {
12285       type(qq)=independent_needing_fix; mp->fix_needed=true;
12286     }
12287     mp_link(r)=s; r=s;
12288   }
12289   q=mp_link(q); qq=info(q);
12290 }
12291
12292 @ A somewhat simpler routine will multiply a dependency list
12293 by a given constant~|v|. The constant is either a |fraction| less than
12294 |fraction_one|, or it is |scaled|. In the latter case we might be forced to
12295 convert a dependency list to a proto-dependency list.
12296 Parameters |t0| and |t1| are the list types before and after;
12297 they should agree unless |t0=mp_dependent| and |t1=mp_proto_dependent|
12298 and |v_is_scaled=true|.
12299
12300 @c 
12301 static pointer mp_p_times_v (MP mp,pointer p, integer v, quarterword t0,
12302                          quarterword t1, boolean v_is_scaled) {
12303   pointer r,s; /* for list manipulation */
12304   integer w; /* tentative coefficient */
12305   integer threshold;
12306   boolean scaling_down;
12307   if ( t0!=t1 ) scaling_down=true; else scaling_down=(!v_is_scaled);
12308   if ( t1==mp_dependent ) threshold=half_fraction_threshold;
12309   else threshold=half_scaled_threshold;
12310   r=temp_head;
12311   while ( info(p)!=null ) {    
12312     if ( scaling_down ) w=mp_take_fraction(mp, v,value(p));
12313     else w=mp_take_scaled(mp, v,value(p));
12314     if ( abs(w)<=threshold ) { 
12315       s=mp_link(p); mp_free_node(mp, p,dep_node_size); p=s;
12316     } else {
12317       if ( abs(w)>=coef_bound ) { 
12318         mp->fix_needed=true; type(info(p))=independent_needing_fix;
12319       }
12320       mp_link(r)=p; r=p; value(p)=w; p=mp_link(p);
12321     }
12322   }
12323   mp_link(r)=p;
12324   if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
12325   else value(p)=mp_take_fraction(mp, value(p),v);
12326   return mp_link(temp_head);
12327 }
12328
12329 @ Similarly, we sometimes need to divide a dependency list
12330 by a given |scaled| constant.
12331
12332 @<Declarations@>=
12333 static pointer mp_p_over_v (MP mp,pointer p, scaled v, quarterword 
12334   t0, quarterword t1) ;
12335
12336 @ @c
12337 pointer mp_p_over_v (MP mp,pointer p, scaled v, quarterword 
12338   t0, quarterword t1) {
12339   pointer r,s; /* for list manipulation */
12340   integer w; /* tentative coefficient */
12341   integer threshold;
12342   boolean scaling_down;
12343   if ( t0!=t1 ) scaling_down=true; else scaling_down=false;
12344   if ( t1==mp_dependent ) threshold=half_fraction_threshold;
12345   else threshold=half_scaled_threshold;
12346   r=temp_head;
12347   while ( info( p)!=null ) {
12348     if ( scaling_down ) {
12349       if ( abs(v)<02000000 ) w=mp_make_scaled(mp, value(p),v*010000);
12350       else w=mp_make_scaled(mp, mp_round_fraction(mp, value(p)),v);
12351     } else {
12352       w=mp_make_scaled(mp, value(p),v);
12353     }
12354     if ( abs(w)<=threshold ) {
12355       s=mp_link(p); mp_free_node(mp, p,dep_node_size); p=s;
12356     } else { 
12357       if ( abs(w)>=coef_bound ) {
12358          mp->fix_needed=true; type(info(p))=independent_needing_fix;
12359       }
12360       mp_link(r)=p; r=p; value(p)=w; p=mp_link(p);
12361     }
12362   }
12363   mp_link(r)=p; value(p)=mp_make_scaled(mp, value(p),v);
12364   return mp_link(temp_head);
12365 }
12366
12367 @ Here's another utility routine for dependency lists. When an independent
12368 variable becomes dependent, we want to remove it from all existing
12369 dependencies. The |p_with_x_becoming_q| function computes the
12370 dependency list of~|p| after variable~|x| has been replaced by~|q|.
12371
12372 This procedure has basically the same calling conventions as |p_plus_fq|:
12373 List~|q| is unchanged; list~|p| is destroyed; the constant node and the
12374 final link are inherited from~|p|; and the fourth parameter tells whether
12375 or not |p| is |mp_proto_dependent|. However, the global variable |dep_final|
12376 is not altered if |x| does not occur in list~|p|.
12377
12378 @c 
12379 static pointer mp_p_with_x_becoming_q (MP mp,pointer p,
12380            pointer x, pointer q, quarterword t) {
12381   pointer r,s; /* for list manipulation */
12382   integer v; /* coefficient of |x| */
12383   integer sx; /* serial number of |x| */
12384   s=p; r=temp_head; sx=value(x);
12385   while ( value(info(s))>sx ) { r=s; s=mp_link(s); };
12386   if ( info(s)!=x ) { 
12387     return p;
12388   } else { 
12389     mp_link(temp_head)=p; mp_link(r)=mp_link(s); v=value(s);
12390     mp_free_node(mp, s,dep_node_size);
12391     return mp_p_plus_fq(mp, mp_link(temp_head),v,q,t,mp_dependent);
12392   }
12393 }
12394
12395 @ Here's a simple procedure that reports an error when a variable
12396 has just received a known value that's out of the required range.
12397
12398 @<Declarations@>=
12399 static void mp_val_too_big (MP mp,scaled x) ;
12400
12401 @ @c void mp_val_too_big (MP mp,scaled x) { 
12402   if ( mp->internal[mp_warning_check]>0 ) { 
12403     print_err("Value is too large ("); mp_print_scaled(mp, x); mp_print_char(mp, xord(')'));
12404 @.Value is too large@>
12405     help4("The equation I just processed has given some variable",
12406       "a value of 4096 or more. Continue and I'll try to cope",
12407       "with that big value; but it might be dangerous.",
12408       "(Set warningcheck:=0 to suppress this message.)");
12409     mp_error(mp);
12410   }
12411 }
12412
12413 @ When a dependent variable becomes known, the following routine
12414 removes its dependency list. Here |p| points to the variable, and
12415 |q| points to the dependency list (which is one node long).
12416
12417 @<Declarations@>=
12418 static void mp_make_known (MP mp,pointer p, pointer q) ;
12419
12420 @ @c void mp_make_known (MP mp,pointer p, pointer q) {
12421   int t; /* the previous type */
12422   prev_dep(mp_link(q))=prev_dep(p);
12423   mp_link(prev_dep(p))=mp_link(q); t=type(p);
12424   type(p)=mp_known; value(p)=value(q); mp_free_node(mp, q,dep_node_size);
12425   if ( abs(value(p))>=fraction_one ) mp_val_too_big(mp, value(p));
12426   if (( mp->internal[mp_tracing_equations]>0) && mp_interesting(mp, p) ) {
12427     mp_begin_diagnostic(mp); mp_print_nl(mp, "#### ");
12428 @:]]]\#\#\#\#_}{\.{\#\#\#\#}@>
12429     mp_print_variable_name(mp, p); 
12430     mp_print_char(mp, xord('=')); mp_print_scaled(mp, value(p));
12431     mp_end_diagnostic(mp, false);
12432   }
12433   if (( mp->cur_exp==p ) && mp->cur_type==t ) {
12434     mp->cur_type=mp_known; mp->cur_exp=value(p);
12435     mp_free_node(mp, p,value_node_size);
12436   }
12437 }
12438
12439 @ The |fix_dependencies| routine is called into action when |fix_needed|
12440 has been triggered. The program keeps a list~|s| of independent variables
12441 whose coefficients must be divided by~4.
12442
12443 In unusual cases, this fixup process might reduce one or more coefficients
12444 to zero, so that a variable will become known more or less by default.
12445
12446 @<Declarations@>=
12447 static void mp_fix_dependencies (MP mp);
12448
12449 @ @c 
12450 static void mp_fix_dependencies (MP mp) {
12451   pointer p,q,r,s,t; /* list manipulation registers */
12452   pointer x; /* an independent variable */
12453   r=mp_link(dep_head); s=null;
12454   while ( r!=dep_head ){ 
12455     t=r;
12456     @<Run through the dependency list for variable |t|, fixing
12457       all nodes, and ending with final link~|q|@>;
12458     r=mp_link(q);
12459     if ( q==dep_list(t) ) mp_make_known(mp, t,q);
12460   }
12461   while ( s!=null ) { 
12462     p=mp_link(s); x=info(s); free_avail(s); s=p;
12463     type(x)=mp_independent; value(x)=value(x)+2;
12464   }
12465   mp->fix_needed=false;
12466 }
12467
12468 @ @d independent_being_fixed 1 /* this variable already appears in |s| */
12469
12470 @<Run through the dependency list for variable |t|...@>=
12471 r=value_loc(t); /* |mp_link(r)=dep_list(t)| */
12472 while (1) { 
12473   q=mp_link(r); x=info(q);
12474   if ( x==null ) break;
12475   if ( type(x)<=independent_being_fixed ) {
12476     if ( type(x)<independent_being_fixed ) {
12477       p=mp_get_avail(mp); mp_link(p)=s; s=p;
12478       info(s)=x; type(x)=independent_being_fixed;
12479     }
12480     value(q)=value(q) / 4;
12481     if ( value(q)==0 ) {
12482       mp_link(r)=mp_link(q); mp_free_node(mp, q,dep_node_size); q=r;
12483     }
12484   }
12485   r=q;
12486 }
12487
12488
12489 @ The |new_dep| routine installs a dependency list~|p| into the value node~|q|,
12490 linking it into the list of all known dependencies. We assume that
12491 |dep_final| points to the final node of list~|p|.
12492
12493 @c 
12494 static void mp_new_dep (MP mp,pointer q, pointer p) {
12495   pointer r; /* what used to be the first dependency */
12496   dep_list(q)=p; prev_dep(q)=dep_head;
12497   r=mp_link(dep_head); mp_link(mp->dep_final)=r; prev_dep(r)=mp->dep_final;
12498   mp_link(dep_head)=q;
12499 }
12500
12501 @ Here is one of the ways a dependency list gets started.
12502 The |const_dependency| routine produces a list that has nothing but
12503 a constant term.
12504
12505 @c static pointer mp_const_dependency (MP mp, scaled v) {
12506   mp->dep_final=mp_get_node(mp, dep_node_size);
12507   value(mp->dep_final)=v; info(mp->dep_final)=null;
12508   return mp->dep_final;
12509 }
12510
12511 @ And here's a more interesting way to start a dependency list from scratch:
12512 The parameter to |single_dependency| is the location of an
12513 independent variable~|x|, and the result is the simple dependency list
12514 `|x+0|'.
12515
12516 In the unlikely event that the given independent variable has been doubled so
12517 often that we can't refer to it with a nonzero coefficient,
12518 |single_dependency| returns the simple list `0'.  This case can be
12519 recognized by testing that the returned list pointer is equal to
12520 |dep_final|.
12521
12522 @c 
12523 static pointer mp_single_dependency (MP mp,pointer p) {
12524   pointer q; /* the new dependency list */
12525   integer m; /* the number of doublings */
12526   m=value(p) % s_scale;
12527   if ( m>28 ) {
12528     return mp_const_dependency(mp, 0);
12529   } else { 
12530     q=mp_get_node(mp, dep_node_size);
12531     value(q)=(integer)two_to_the(28-m); info(q)=p;
12532     mp_link(q)=mp_const_dependency(mp, 0);
12533     return q;
12534   }
12535 }
12536
12537 @ We sometimes need to make an exact copy of a dependency list.
12538
12539 @c 
12540 static pointer mp_copy_dep_list (MP mp,pointer p) {
12541   pointer q; /* the new dependency list */
12542   q=mp_get_node(mp, dep_node_size); mp->dep_final=q;
12543   while (1) { 
12544     info(mp->dep_final)=info(p); value(mp->dep_final)=value(p);
12545     if ( info(mp->dep_final)==null ) break;
12546     mp_link(mp->dep_final)=mp_get_node(mp, dep_node_size);
12547     mp->dep_final=mp_link(mp->dep_final); p=mp_link(p);
12548   }
12549   return q;
12550 }
12551
12552 @ But how do variables normally become known? Ah, now we get to the heart of the
12553 equation-solving mechanism. The |linear_eq| procedure is given a |dependent|
12554 or |mp_proto_dependent| list,~|p|, in which at least one independent variable
12555 appears. It equates this list to zero, by choosing an independent variable
12556 with the largest coefficient and making it dependent on the others. The
12557 newly dependent variable is eliminated from all current dependencies,
12558 thereby possibly making other dependent variables known.
12559
12560 The given list |p| is, of course, totally destroyed by all this processing.
12561
12562 @c 
12563 static void mp_linear_eq (MP mp, pointer p, quarterword t) {
12564   pointer q,r,s; /* for link manipulation */
12565   pointer x; /* the variable that loses its independence */
12566   integer n; /* the number of times |x| had been halved */
12567   integer v; /* the coefficient of |x| in list |p| */
12568   pointer prev_r; /* lags one step behind |r| */
12569   pointer final_node; /* the constant term of the new dependency list */
12570   integer w; /* a tentative coefficient */
12571    @<Find a node |q| in list |p| whose coefficient |v| is largest@>;
12572   x=info(q); n=value(x) % s_scale;
12573   @<Divide list |p| by |-v|, removing node |q|@>;
12574   if ( mp->internal[mp_tracing_equations]>0 ) {
12575     @<Display the new dependency@>;
12576   }
12577   @<Simplify all existing dependencies by substituting for |x|@>;
12578   @<Change variable |x| from |independent| to |dependent| or |known|@>;
12579   if ( mp->fix_needed ) mp_fix_dependencies(mp);
12580 }
12581
12582 @ @<Find a node |q| in list |p| whose coefficient |v| is largest@>=
12583 q=p; r=mp_link(p); v=value(q);
12584 while ( info(r)!=null ) { 
12585   if ( abs(value(r))>abs(v) ) { q=r; v=value(r); };
12586   r=mp_link(r);
12587 }
12588
12589 @ Here we want to change the coefficients from |scaled| to |fraction|,
12590 except in the constant term. In the common case of a trivial equation
12591 like `\.{x=3.14}', we will have |v=-fraction_one|, |q=p|, and |t=mp_dependent|.
12592
12593 @<Divide list |p| by |-v|, removing node |q|@>=
12594 s=temp_head; mp_link(s)=p; r=p;
12595 do { 
12596   if ( r==q ) {
12597     mp_link(s)=mp_link(r); mp_free_node(mp, r,dep_node_size);
12598   } else  { 
12599     w=mp_make_fraction(mp, value(r),v);
12600     if ( abs(w)<=half_fraction_threshold ) {
12601       mp_link(s)=mp_link(r); mp_free_node(mp, r,dep_node_size);
12602     } else { 
12603       value(r)=-w; s=r;
12604     }
12605   }
12606   r=mp_link(s);
12607 } while (info(r)!=null);
12608 if ( t==mp_proto_dependent ) {
12609   value(r)=-mp_make_scaled(mp, value(r),v);
12610 } else if ( v!=-fraction_one ) {
12611   value(r)=-mp_make_fraction(mp, value(r),v);
12612 }
12613 final_node=r; p=mp_link(temp_head)
12614
12615 @ @<Display the new dependency@>=
12616 if ( mp_interesting(mp, x) ) {
12617   mp_begin_diagnostic(mp); mp_print_nl(mp, "## "); 
12618   mp_print_variable_name(mp, x);
12619 @:]]]\#\#_}{\.{\#\#}@>
12620   w=n;
12621   while ( w>0 ) { mp_print(mp, "*4"); w=w-2;  };
12622   mp_print_char(mp, xord('=')); mp_print_dependency(mp, p,mp_dependent); 
12623   mp_end_diagnostic(mp, false);
12624 }
12625
12626 @ @<Simplify all existing dependencies by substituting for |x|@>=
12627 prev_r=dep_head; r=mp_link(dep_head);
12628 while ( r!=dep_head ) {
12629   s=dep_list(r); q=mp_p_with_x_becoming_q(mp, s,x,p,type(r));
12630   if ( info(q)==null ) {
12631     mp_make_known(mp, r,q);
12632   } else { 
12633     dep_list(r)=q;
12634     do {  q=mp_link(q); } while (info(q)!=null);
12635     prev_r=q;
12636   }
12637   r=mp_link(prev_r);
12638 }
12639
12640 @ @<Change variable |x| from |independent| to |dependent| or |known|@>=
12641 if ( n>0 ) @<Divide list |p| by $2^n$@>;
12642 if ( info(p)==null ) {
12643   type(x)=mp_known;
12644   value(x)=value(p);
12645   if ( abs(value(x))>=fraction_one ) mp_val_too_big(mp, value(x));
12646   mp_free_node(mp, p,dep_node_size);
12647   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) {
12648     mp->cur_exp=value(x); mp->cur_type=mp_known;
12649     mp_free_node(mp, x,value_node_size);
12650   }
12651 } else { 
12652   type(x)=mp_dependent; mp->dep_final=final_node; mp_new_dep(mp, x,p);
12653   if ( mp->cur_exp==x ) if ( mp->cur_type==mp_independent ) mp->cur_type=mp_dependent;
12654 }
12655
12656 @ @<Divide list |p| by $2^n$@>=
12657
12658   s=temp_head; mp_link(temp_head)=p; r=p;
12659   do {  
12660     if ( n>30 ) w=0;
12661     else w=value(r) / two_to_the(n);
12662     if ( (abs(w)<=half_fraction_threshold)&&(info(r)!=null) ) {
12663       mp_link(s)=mp_link(r);
12664       mp_free_node(mp, r,dep_node_size);
12665     } else { 
12666       value(r)=w; s=r;
12667     }
12668     r=mp_link(s);
12669   } while (info(s)!=null);
12670   p=mp_link(temp_head);
12671 }
12672
12673 @ The |check_mem| procedure, which is used only when \MP\ is being
12674 debugged, makes sure that the current dependency lists are well formed.
12675
12676 @<Check the list of linear dependencies@>=
12677 q=dep_head; p=mp_link(q);
12678 while ( p!=dep_head ) {
12679   if ( prev_dep(p)!=q ) {
12680     mp_print_nl(mp, "Bad PREVDEP at "); mp_print_int(mp, p);
12681 @.Bad PREVDEP...@>
12682   }
12683   p=dep_list(p);
12684   while (1) {
12685     r=info(p); q=p; p=mp_link(q);
12686     if ( r==null ) break;
12687     if ( value(info(p))>=value(r) ) {
12688       mp_print_nl(mp, "Out of order at "); mp_print_int(mp, p);
12689 @.Out of order...@>
12690     }
12691   }
12692 }
12693
12694 @* \[25] Dynamic nonlinear equations.
12695 Variables of numeric type are maintained by the general scheme of
12696 independent, dependent, and known values that we have just studied;
12697 and the components of pair and transform variables are handled in the
12698 same way. But \MP\ also has five other types of values: \&{boolean},
12699 \&{string}, \&{pen}, \&{path}, and \&{picture}; what about them?
12700
12701 Equations are allowed between nonlinear quantities, but only in a
12702 simple form. Two variables that haven't yet been assigned values are
12703 either equal to each other, or they're not.
12704
12705 Before a boolean variable has received a value, its type is |mp_unknown_boolean|;
12706 similarly, there are variables whose type is |mp_unknown_string|, |mp_unknown_pen|,
12707 |mp_unknown_path|, and |mp_unknown_picture|. In such cases the value is either
12708 |null| (which means that no other variables are equivalent to this one), or
12709 it points to another variable of the same undefined type. The pointers in the
12710 latter case form a cycle of nodes, which we shall call a ``ring.''
12711 Rings of undefined variables may include capsules, which arise as
12712 intermediate results within expressions or as \&{expr} parameters to macros.
12713
12714 When one member of a ring receives a value, the same value is given to
12715 all the other members. In the case of paths and pictures, this implies
12716 making separate copies of a potentially large data structure; users should
12717 restrain their enthusiasm for such generality, unless they have lots and
12718 lots of memory space.
12719
12720 @ The following procedure is called when a capsule node is being
12721 added to a ring (e.g., when an unknown variable is mentioned in an expression).
12722
12723 @c 
12724 static pointer mp_new_ring_entry (MP mp,pointer p) {
12725   pointer q; /* the new capsule node */
12726   q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
12727   type(q)=type(p);
12728   if ( value(p)==null ) value(q)=p; else value(q)=value(p);
12729   value(p)=q;
12730   return q;
12731 }
12732
12733 @ Conversely, we might delete a capsule or a variable before it becomes known.
12734 The following procedure simply detaches a quantity from its ring,
12735 without recycling the storage.
12736
12737 @<Declarations@>=
12738 static void mp_ring_delete (MP mp,pointer p);
12739
12740 @ @c
12741 void mp_ring_delete (MP mp,pointer p) {
12742   pointer q; 
12743   q=value(p);
12744   if ( q!=null ) if ( q!=p ){ 
12745     while ( value(q)!=p ) q=value(q);
12746     value(q)=value(p);
12747   }
12748 }
12749
12750 @ Eventually there might be an equation that assigns values to all of the
12751 variables in a ring. The |nonlinear_eq| subroutine does the necessary
12752 propagation of values.
12753
12754 If the parameter |flush_p| is |true|, node |p| itself needn't receive a
12755 value, it will soon be recycled.
12756
12757 @c 
12758 static void mp_nonlinear_eq (MP mp,integer v, pointer p, boolean flush_p) {
12759   quarterword t; /* the type of ring |p| */
12760   pointer q,r; /* link manipulation registers */
12761   t=type(p)-unknown_tag; q=value(p);
12762   if ( flush_p ) type(p)=mp_vacuous; else p=q;
12763   do {  
12764     r=value(q); type(q)=t;
12765     switch (t) {
12766     case mp_boolean_type: value(q)=v; break;
12767     case mp_string_type: value(q)=v; add_str_ref(v); break;
12768     case mp_pen_type: value(q)=copy_pen(v); break;
12769     case mp_path_type: value(q)=mp_copy_path(mp, v); break;
12770     case mp_picture_type: value(q)=v; add_edge_ref(v); break;
12771     } /* there ain't no more cases */
12772     q=r;
12773   } while (q!=p);
12774 }
12775
12776 @ If two members of rings are equated, and if they have the same type,
12777 the |ring_merge| procedure is called on to make them equivalent.
12778
12779 @c 
12780 static void mp_ring_merge (MP mp,pointer p, pointer q) {
12781   pointer r; /* traverses one list */
12782   r=value(p);
12783   while ( r!=p ) {
12784     if ( r==q ) {
12785       @<Exclaim about a redundant equation@>;
12786       return;
12787     };
12788     r=value(r);
12789   }
12790   r=value(p); value(p)=value(q); value(q)=r;
12791 }
12792
12793 @ @<Exclaim about a redundant equation@>=
12794
12795   print_err("Redundant equation");
12796 @.Redundant equation@>
12797   help2("I already knew that this equation was true.",
12798         "But perhaps no harm has been done; let's continue.");
12799   mp_put_get_error(mp);
12800 }
12801
12802 @* \[26] Introduction to the syntactic routines.
12803 Let's pause a moment now and try to look at the Big Picture.
12804 The \MP\ program consists of three main parts: syntactic routines,
12805 semantic routines, and output routines. The chief purpose of the
12806 syntactic routines is to deliver the user's input to the semantic routines,
12807 while parsing expressions and locating operators and operands. The
12808 semantic routines act as an interpreter responding to these operators,
12809 which may be regarded as commands. And the output routines are
12810 periodically called on to produce compact font descriptions that can be
12811 used for typesetting or for making interim proof drawings. We have
12812 discussed the basic data structures and many of the details of semantic
12813 operations, so we are good and ready to plunge into the part of \MP\ that
12814 actually controls the activities.
12815
12816 Our current goal is to come to grips with the |get_next| procedure,
12817 which is the keystone of \MP's input mechanism. Each call of |get_next|
12818 sets the value of three variables |cur_cmd|, |cur_mod|, and |cur_sym|,
12819 representing the next input token.
12820 $$\vbox{\halign{#\hfil\cr
12821   \hbox{|cur_cmd| denotes a command code from the long list of codes
12822    given earlier;}\cr
12823   \hbox{|cur_mod| denotes a modifier of the command code;}\cr
12824   \hbox{|cur_sym| is the hash address of the symbolic token that was
12825    just scanned,}\cr
12826   \hbox{\qquad or zero in the case of a numeric or string
12827    or capsule token.}\cr}}$$
12828 Underlying this external behavior of |get_next| is all the machinery
12829 necessary to convert from character files to tokens. At a given time we
12830 may be only partially finished with the reading of several files (for
12831 which \&{input} was specified), and partially finished with the expansion
12832 of some user-defined macros and/or some macro parameters, and partially
12833 finished reading some text that the user has inserted online,
12834 and so on. When reading a character file, the characters must be
12835 converted to tokens; comments and blank spaces must
12836 be removed, numeric and string tokens must be evaluated.
12837
12838 To handle these situations, which might all be present simultaneously,
12839 \MP\ uses various stacks that hold information about the incomplete
12840 activities, and there is a finite state control for each level of the
12841 input mechanism. These stacks record the current state of an implicitly
12842 recursive process, but the |get_next| procedure is not recursive.
12843
12844 @<Glob...@>=
12845 integer cur_cmd; /* current command set by |get_next| */
12846 integer cur_mod; /* operand of current command */
12847 halfword cur_sym; /* hash address of current symbol */
12848
12849 @ The |print_cmd_mod| routine prints a symbolic interpretation of a
12850 command code and its modifier.
12851 It consists of a rather tedious sequence of print
12852 commands, and most of it is essentially an inverse to the |primitive|
12853 routine that enters a \MP\ primitive into |hash| and |eqtb|. Therefore almost
12854 all of this procedure appears elsewhere in the program, together with the
12855 corresponding |primitive| calls.
12856
12857 @<Declarations@>=
12858 static void mp_print_cmd_mod (MP mp,integer c, integer m) ;
12859
12860 @ @c
12861 void mp_print_cmd_mod (MP mp,integer c, integer m) { 
12862  switch (c) {
12863   @<Cases of |print_cmd_mod| for symbolic printing of primitives@>
12864   default: mp_print(mp, "[unknown command code!]"); break;
12865   }
12866 }
12867
12868 @ Here is a procedure that displays a given command in braces, in the
12869 user's transcript file.
12870
12871 @d show_cur_cmd_mod mp_show_cmd_mod(mp, mp->cur_cmd,mp->cur_mod)
12872
12873 @c 
12874 static void mp_show_cmd_mod (MP mp,integer c, integer m) { 
12875   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
12876   mp_print_cmd_mod(mp, c,m); mp_print_char(mp, xord('}'));
12877   mp_end_diagnostic(mp, false);
12878 }
12879
12880 @* \[27] Input stacks and states.
12881 The state of \MP's input mechanism appears in the input stack, whose
12882 entries are records with five fields, called |index|, |start|, |loc|,
12883 |limit|, and |name|. The top element of this stack is maintained in a
12884 global variable for which no subscripting needs to be done; the other
12885 elements of the stack appear in an array. Hence the stack is declared thus:
12886
12887 @<Types...@>=
12888 typedef struct {
12889   quarterword index_field;
12890   halfword start_field, loc_field, limit_field, name_field;
12891 } in_state_record;
12892
12893 @ @<Glob...@>=
12894 in_state_record *input_stack;
12895 integer input_ptr; /* first unused location of |input_stack| */
12896 integer max_in_stack; /* largest value of |input_ptr| when pushing */
12897 in_state_record cur_input; /* the ``top'' input state */
12898 int stack_size; /* maximum number of simultaneous input sources */
12899
12900 @ @<Allocate or initialize ...@>=
12901 mp->stack_size = 300;
12902 mp->input_stack = xmalloc((mp->stack_size+1),sizeof(in_state_record));
12903
12904 @ @<Dealloc variables@>=
12905 xfree(mp->input_stack);
12906
12907 @ We've already defined the special variable |loc==cur_input.loc_field|
12908 in our discussion of basic input-output routines. The other components of
12909 |cur_input| are defined in the same way:
12910
12911 @d iindex mp->cur_input.index_field /* reference for buffer information */
12912 @d start mp->cur_input.start_field /* starting position in |buffer| */
12913 @d limit mp->cur_input.limit_field /* end of current line in |buffer| */
12914 @d name mp->cur_input.name_field /* name of the current file */
12915
12916 @ Let's look more closely now at the five control variables
12917 (|index|,~|start|,~|loc|,~|limit|,~|name|),
12918 assuming that \MP\ is reading a line of characters that have been input
12919 from some file or from the user's terminal. There is an array called
12920 |buffer| that acts as a stack of all lines of characters that are
12921 currently being read from files, including all lines on subsidiary
12922 levels of the input stack that are not yet completed. \MP\ will return to
12923 the other lines when it is finished with the present input file.
12924
12925 (Incidentally, on a machine with byte-oriented addressing, it would be
12926 appropriate to combine |buffer| with the |str_pool| array,
12927 letting the buffer entries grow downward from the top of the string pool
12928 and checking that these two tables don't bump into each other.)
12929
12930 The line we are currently working on begins in position |start| of the
12931 buffer; the next character we are about to read is |buffer[loc]|; and
12932 |limit| is the location of the last character present. We always have
12933 |loc<=limit|. For convenience, |buffer[limit]| has been set to |"%"|, so
12934 that the end of a line is easily sensed.
12935
12936 The |name| variable is a string number that designates the name of
12937 the current file, if we are reading an ordinary text file.  Special codes
12938 |is_term..max_spec_src| indicate other sources of input text.
12939
12940 @d is_term 0 /* |name| value when reading from the terminal for normal input */
12941 @d is_read 1 /* |name| value when executing a \&{readstring} or \&{readfrom} */
12942 @d is_scantok 2 /* |name| value when reading text generated by \&{scantokens} */
12943 @d max_spec_src is_scantok
12944
12945 @ Additional information about the current line is available via the
12946 |index| variable, which counts how many lines of characters are present
12947 in the buffer below the current level. We have |index=0| when reading
12948 from the terminal and prompting the user for each line; then if the user types,
12949 e.g., `\.{input figs}', we will have |index=1| while reading
12950 the file \.{figs.mp}. However, it does not follow that |index| is the
12951 same as the input stack pointer, since many of the levels on the input
12952 stack may come from token lists and some |index| values may correspond
12953 to \.{MPX} files that are not currently on the stack.
12954
12955 The global variable |in_open| is equal to the highest |index| value counting
12956 \.{MPX} files but excluding token-list input levels.  Thus, the number of
12957 partially read lines in the buffer is |in_open+1| and we have |in_open>=index|
12958 when we are not reading a token list.
12959
12960 If we are not currently reading from the terminal,
12961 we are reading from the file variable |input_file[index]|. We use
12962 the notation |terminal_input| as a convenient abbreviation for |name=is_term|,
12963 and |cur_file| as an abbreviation for |input_file[index]|.
12964
12965 When \MP\ is not reading from the terminal, the global variable |line| contains
12966 the line number in the current file, for use in error messages. More precisely,
12967 |line| is a macro for |line_stack[index]| and the |line_stack| array gives
12968 the line number for each file in the |input_file| array.
12969
12970 When an \.{MPX} file is opened the file name is stored in the |mpx_name|
12971 array so that the name doesn't get lost when the file is temporarily removed
12972 from the input stack.
12973 Thus when |input_file[k]| is an \.{MPX} file, its name is |mpx_name[k]|
12974 and it contains translated \TeX\ pictures for |input_file[k-1]|.
12975 Since this is not an \.{MPX} file, we have
12976 $$ \hbox{|mpx_name[k-1]<=absent|}. $$
12977 This |name| field is set to |finished| when |input_file[k]| is completely
12978 read.
12979
12980 If more information about the input state is needed, it can be
12981 included in small arrays like those shown here. For example,
12982 the current page or segment number in the input file might be put
12983 into a variable |page|, that is really a macro for the current entry
12984 in `\ignorespaces|page_stack:array[0..max_in_open] of integer|\unskip'
12985 by analogy with |line_stack|.
12986 @^system dependencies@>
12987
12988 @d terminal_input (name==is_term) /* are we reading from the terminal? */
12989 @d cur_file mp->input_file[iindex] /* the current |void *| variable */
12990 @d line mp->line_stack[iindex] /* current line number in the current source file */
12991 @d in_name mp->iname_stack[iindex] /* a string used to construct \.{MPX} file names */
12992 @d in_area mp->iarea_stack[iindex] /* another string for naming \.{MPX} files */
12993 @d absent 1 /* |name_field| value for unused |mpx_in_stack| entries */
12994 @d mpx_reading (mp->mpx_name[iindex]>absent)
12995   /* when reading a file, is it an \.{MPX} file? */
12996 @d mpx_finished 0
12997   /* |name_field| value when the corresponding \.{MPX} file is finished */
12998
12999 @<Glob...@>=
13000 integer in_open; /* the number of lines in the buffer, less one */
13001 unsigned int open_parens; /* the number of open text files */
13002 void  * *input_file ;
13003 integer *line_stack ; /* the line number for each file */
13004 char *  *iname_stack; /* used for naming \.{MPX} files */
13005 char *  *iarea_stack; /* used for naming \.{MPX} files */
13006 halfword*mpx_name  ;
13007
13008 @ @<Allocate or ...@>=
13009 mp->input_file  = xmalloc((mp->max_in_open+1),sizeof(void *));
13010 mp->line_stack  = xmalloc((mp->max_in_open+1),sizeof(integer));
13011 mp->iname_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
13012 mp->iarea_stack = xmalloc((mp->max_in_open+1),sizeof(char *));
13013 mp->mpx_name    = xmalloc((mp->max_in_open+1),sizeof(halfword));
13014 {
13015   int k;
13016   for (k=0;k<=mp->max_in_open;k++) {
13017     mp->iname_stack[k] =NULL;
13018     mp->iarea_stack[k] =NULL;
13019   }
13020 }
13021
13022 @ @<Dealloc variables@>=
13023 {
13024   int l;
13025   for (l=0;l<=mp->max_in_open;l++) {
13026     xfree(mp->iname_stack[l]);
13027     xfree(mp->iarea_stack[l]);
13028   }
13029 }
13030 xfree(mp->input_file);
13031 xfree(mp->line_stack);
13032 xfree(mp->iname_stack);
13033 xfree(mp->iarea_stack);
13034 xfree(mp->mpx_name);
13035
13036
13037 @ However, all this discussion about input state really applies only to the
13038 case that we are inputting from a file. There is another important case,
13039 namely when we are currently getting input from a token list. In this case
13040 |iindex>max_in_open|, and the conventions about the other state variables
13041 are different:
13042
13043 \yskip\hang|loc| is a pointer to the current node in the token list, i.e.,
13044 the node that will be read next. If |loc=null|, the token list has been
13045 fully read.
13046
13047 \yskip\hang|start| points to the first node of the token list; this node
13048 may or may not contain a reference count, depending on the type of token
13049 list involved.
13050
13051 \yskip\hang|token_type|, which takes the place of |iindex| in the
13052 discussion above, is a code number that explains what kind of token list
13053 is being scanned.
13054
13055 \yskip\hang|name| points to the |eqtb| address of the control sequence
13056 being expanded, if the current token list is a macro not defined by
13057 \&{vardef}. Macros defined by \&{vardef} have |name=null|; their name
13058 can be deduced by looking at their first two parameters.
13059
13060 \yskip\hang|param_start|, which takes the place of |limit|, tells where
13061 the parameters of the current macro or loop text begin in the |param_stack|.
13062
13063 \yskip\noindent The |token_type| can take several values, depending on
13064 where the current token list came from:
13065
13066 \yskip
13067 \indent|forever_text|, if the token list being scanned is the body of
13068 a \&{forever} loop;
13069
13070 \indent|loop_text|, if the token list being scanned is the body of
13071 a \&{for} or \&{forsuffixes} loop;
13072
13073 \indent|parameter|, if a \&{text} or \&{suffix} parameter is being scanned;
13074
13075 \indent|backed_up|, if the token list being scanned has been inserted as
13076 `to be read again'.
13077
13078 \indent|inserted|, if the token list being scanned has been inserted as
13079 part of error recovery;
13080
13081 \indent|macro|, if the expansion of a user-defined symbolic token is being
13082 scanned.
13083
13084 \yskip\noindent
13085 The token list begins with a reference count if and only if |token_type=
13086 macro|.
13087 @^reference counts@>
13088
13089 @d token_type iindex /* type of current token list */
13090 @d token_state (iindex>(int)mp->max_in_open) /* are we scanning a token list? */
13091 @d file_state (iindex<=(int)mp->max_in_open) /* are we scanning a file line? */
13092 @d param_start limit /* base of macro parameters in |param_stack| */
13093 @d forever_text (mp->max_in_open+1) /* |token_type| code for loop texts */
13094 @d loop_text (mp->max_in_open+2) /* |token_type| code for loop texts */
13095 @d parameter (mp->max_in_open+3) /* |token_type| code for parameter texts */
13096 @d backed_up (mp->max_in_open+4) /* |token_type| code for texts to be reread */
13097 @d inserted (mp->max_in_open+5) /* |token_type| code for inserted texts */
13098 @d macro (mp->max_in_open+6) /* |token_type| code for macro replacement texts */
13099
13100 @ The |param_stack| is an auxiliary array used to hold pointers to the token
13101 lists for parameters at the current level and subsidiary levels of input.
13102 This stack grows at a different rate from the others.
13103
13104 @<Glob...@>=
13105 pointer *param_stack;  /* token list pointers for parameters */
13106 integer param_ptr; /* first unused entry in |param_stack| */
13107 integer max_param_stack;  /* largest value of |param_ptr| */
13108
13109 @ @<Allocate or initialize ...@>=
13110 mp->param_stack = xmalloc((mp->param_size+1),sizeof(pointer));
13111
13112 @ @<Dealloc variables@>=
13113 xfree(mp->param_stack);
13114
13115 @ Notice that the |line| isn't valid when |token_state| is true because it
13116 depends on |iindex|.  If we really need to know the line number for the
13117 topmost file in the iindex stack we use the following function.  If a page
13118 number or other information is needed, this routine should be modified to
13119 compute it as well.
13120 @^system dependencies@>
13121
13122 @<Declarations@>=
13123 static integer mp_true_line (MP mp) ;
13124
13125 @ @c
13126 integer mp_true_line (MP mp) {
13127   int k; /* an index into the input stack */
13128   if ( file_state && (name>max_spec_src) ) {
13129     return line;
13130   } else { 
13131     k=mp->input_ptr;
13132     while ((k>0) &&
13133            ((mp->input_stack[(k-1)].index_field>mp->max_in_open)||
13134             (mp->input_stack[(k-1)].name_field<=max_spec_src))) {
13135       decr(k);
13136     }
13137     return (k>0 ? mp->line_stack[(k-1)] : 0 );
13138   }
13139 }
13140
13141 @ Thus, the ``current input state'' can be very complicated indeed; there
13142 can be many levels and each level can arise in a variety of ways. The
13143 |show_context| procedure, which is used by \MP's error-reporting routine to
13144 print out the current input state on all levels down to the most recent
13145 line of characters from an input file, illustrates most of these conventions.
13146 The global variable |file_ptr| contains the lowest level that was
13147 displayed by this procedure.
13148
13149 @<Glob...@>=
13150 integer file_ptr; /* shallowest level shown by |show_context| */
13151
13152 @ The status at each level is indicated by printing two lines, where the first
13153 line indicates what was read so far and the second line shows what remains
13154 to be read. The context is cropped, if necessary, so that the first line
13155 contains at most |half_error_line| characters, and the second contains
13156 at most |error_line|. Non-current input levels whose |token_type| is
13157 `|backed_up|' are shown only if they have not been fully read.
13158
13159 @c void mp_show_context (MP mp) { /* prints where the scanner is */
13160   unsigned old_setting; /* saved |selector| setting */
13161   @<Local variables for formatting calculations@>
13162   mp->file_ptr=mp->input_ptr; mp->input_stack[mp->file_ptr]=mp->cur_input;
13163   /* store current state */
13164   while (1) { 
13165     mp->cur_input=mp->input_stack[mp->file_ptr]; /* enter into the context */
13166     @<Display the current context@>;
13167     if ( file_state )
13168       if ( (name>max_spec_src) || (mp->file_ptr==0) ) break;
13169     decr(mp->file_ptr);
13170   }
13171   mp->cur_input=mp->input_stack[mp->input_ptr]; /* restore original state */
13172 }
13173
13174 @ @<Display the current context@>=
13175 if ( (mp->file_ptr==mp->input_ptr) || file_state ||
13176    (token_type!=backed_up) || (loc!=null) ) {
13177     /* we omit backed-up token lists that have already been read */
13178   mp->tally=0; /* get ready to count characters */
13179   old_setting=mp->selector;
13180   if ( file_state ) {
13181     @<Print location of current line@>;
13182     @<Pseudoprint the line@>;
13183   } else { 
13184     @<Print type of token list@>;
13185     @<Pseudoprint the token list@>;
13186   }
13187   mp->selector=old_setting; /* stop pseudoprinting */
13188   @<Print two lines using the tricky pseudoprinted information@>;
13189 }
13190
13191 @ This routine should be changed, if necessary, to give the best possible
13192 indication of where the current line resides in the input file.
13193 For example, on some systems it is best to print both a page and line number.
13194 @^system dependencies@>
13195
13196 @<Print location of current line@>=
13197 if ( name>max_spec_src ) {
13198   mp_print_nl(mp, "l."); mp_print_int(mp, mp_true_line(mp));
13199 } else if ( terminal_input ) {
13200   if ( mp->file_ptr==0 ) mp_print_nl(mp, "<*>");
13201   else mp_print_nl(mp, "<insert>");
13202 } else if ( name==is_scantok ) {
13203   mp_print_nl(mp, "<scantokens>");
13204 } else {
13205   mp_print_nl(mp, "<read>");
13206 }
13207 mp_print_char(mp, xord(' '))
13208
13209 @ Can't use case statement here because the |token_type| is not
13210 a constant expression.
13211
13212 @<Print type of token list@>=
13213 {
13214   if(token_type==forever_text) {
13215     mp_print_nl(mp, "<forever> ");
13216   } else if (token_type==loop_text) {
13217     @<Print the current loop value@>;
13218   } else if (token_type==parameter) {
13219     mp_print_nl(mp, "<argument> "); 
13220   } else if (token_type==backed_up) { 
13221     if ( loc==null ) mp_print_nl(mp, "<recently read> ");
13222     else mp_print_nl(mp, "<to be read again> ");
13223   } else if (token_type==inserted) {
13224     mp_print_nl(mp, "<inserted text> ");
13225   } else if (token_type==macro) {
13226     mp_print_ln(mp);
13227     if ( name!=null ) mp_print_text(name);
13228     else @<Print the name of a \&{vardef}'d macro@>;
13229     mp_print(mp, "->");
13230   } else {
13231     mp_print_nl(mp, "?");/* this should never happen */
13232 @.?\relax@>
13233   }
13234 }
13235
13236 @ The parameter that corresponds to a loop text is either a token list
13237 (in the case of \&{forsuffixes}) or a ``capsule'' (in the case of \&{for}).
13238 We'll discuss capsules later; for now, all we need to know is that
13239 the |link| field in a capsule parameter is |void| and that
13240 |print_exp(p,0)| displays the value of capsule~|p| in abbreviated form.
13241
13242 @<Print the current loop value@>=
13243 { mp_print_nl(mp, "<for("); p=mp->param_stack[param_start];
13244   if ( p!=null ) {
13245     if ( mp_link(p)==mp_void ) mp_print_exp(mp, p,0); /* we're in a \&{for} loop */
13246     else mp_show_token_list(mp, p,null,20,mp->tally);
13247   }
13248   mp_print(mp, ")> ");
13249 }
13250
13251 @ The first two parameters of a macro defined by \&{vardef} will be token
13252 lists representing the macro's prefix and ``at point.'' By putting these
13253 together, we get the macro's full name.
13254
13255 @<Print the name of a \&{vardef}'d macro@>=
13256 { p=mp->param_stack[param_start];
13257   if ( p==null ) {
13258     mp_show_token_list(mp, mp->param_stack[param_start+1],null,20,mp->tally);
13259   } else { 
13260     q=p;
13261     while ( mp_link(q)!=null ) q=mp_link(q);
13262     mp_link(q)=mp->param_stack[param_start+1];
13263     mp_show_token_list(mp, p,null,20,mp->tally);
13264     mp_link(q)=null;
13265   }
13266 }
13267
13268 @ Now it is necessary to explain a little trick. We don't want to store a long
13269 string that corresponds to a token list, because that string might take up
13270 lots of memory; and we are printing during a time when an error message is
13271 being given, so we dare not do anything that might overflow one of \MP's
13272 tables. So `pseudoprinting' is the answer: We enter a mode of printing
13273 that stores characters into a buffer of length |error_line|, where character
13274 $k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
13275 |k<trick_count|, otherwise character |k| is dropped. Initially we set
13276 |tally:=0| and |trick_count:=1000000|; then when we reach the
13277 point where transition from line 1 to line 2 should occur, we
13278 set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
13279 tally+1+error_line-half_error_line)|. At the end of the
13280 pseudoprinting, the values of |first_count|, |tally|, and
13281 |trick_count| give us all the information we need to print the two lines,
13282 and all of the necessary text is in |trick_buf|.
13283
13284 Namely, let |l| be the length of the descriptive information that appears
13285 on the first line. The length of the context information gathered for that
13286 line is |k=first_count|, and the length of the context information
13287 gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
13288 where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
13289 descriptive information on line~1, and set |n:=l+k|; here |n| is the
13290 length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
13291 and print `\.{...}' followed by
13292 $$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
13293 where subscripts of |trick_buf| are circular modulo |error_line|. The
13294 second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
13295 unless |n+m>error_line|; in the latter case, further cropping is done.
13296 This is easier to program than to explain.
13297
13298 @<Local variables for formatting...@>=
13299 int i; /* index into |buffer| */
13300 integer l; /* length of descriptive information on line 1 */
13301 integer m; /* context information gathered for line 2 */
13302 int n; /* length of line 1 */
13303 integer p; /* starting or ending place in |trick_buf| */
13304 integer q; /* temporary index */
13305
13306 @ The following code tells the print routines to gather
13307 the desired information.
13308
13309 @d begin_pseudoprint { 
13310   l=mp->tally; mp->tally=0; mp->selector=pseudo;
13311   mp->trick_count=1000000;
13312 }
13313 @d set_trick_count {
13314   mp->first_count=mp->tally;
13315   mp->trick_count=mp->tally+1+mp->error_line-mp->half_error_line;
13316   if ( mp->trick_count<mp->error_line ) mp->trick_count=mp->error_line;
13317 }
13318
13319 @ And the following code uses the information after it has been gathered.
13320
13321 @<Print two lines using the tricky pseudoprinted information@>=
13322 if ( mp->trick_count==1000000 ) set_trick_count;
13323   /* |set_trick_count| must be performed */
13324 if ( mp->tally<mp->trick_count ) m=mp->tally-mp->first_count;
13325 else m=mp->trick_count-mp->first_count; /* context on line 2 */
13326 if ( l+mp->first_count<=mp->half_error_line ) {
13327   p=0; n=l+mp->first_count;
13328 } else  { 
13329   mp_print(mp, "..."); p=l+mp->first_count-mp->half_error_line+3;
13330   n=mp->half_error_line;
13331 }
13332 for (q=p;q<=mp->first_count-1;q++) {
13333   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13334 }
13335 mp_print_ln(mp);
13336 for (q=1;q<=n;q++) {
13337   mp_print_char(mp, xord(' ')); /* print |n| spaces to begin line~2 */
13338 }
13339 if ( m+n<=mp->error_line ) p=mp->first_count+m; 
13340 else p=mp->first_count+(mp->error_line-n-3);
13341 for (q=mp->first_count;q<=p-1;q++) {
13342   mp_print_char(mp, mp->trick_buf[q % mp->error_line]);
13343 }
13344 if ( m+n>mp->error_line ) mp_print(mp, "...")
13345
13346 @ But the trick is distracting us from our current goal, which is to
13347 understand the input state. So let's concentrate on the data structures that
13348 are being pseudoprinted as we finish up the |show_context| procedure.
13349
13350 @<Pseudoprint the line@>=
13351 begin_pseudoprint;
13352 if ( limit>0 ) {
13353   for (i=start;i<=limit-1;i++) {
13354     if ( i==loc ) set_trick_count;
13355     mp_print_str(mp, mp->buffer[i]);
13356   }
13357 }
13358
13359 @ @<Pseudoprint the token list@>=
13360 begin_pseudoprint;
13361 if ( token_type!=macro ) mp_show_token_list(mp, start,loc,100000,0);
13362 else mp_show_macro(mp, start,loc,100000)
13363
13364 @ Here is the missing piece of |show_token_list| that is activated when the
13365 token beginning line~2 is about to be shown:
13366
13367 @<Do magic computation@>=set_trick_count
13368
13369 @* \[28] Maintaining the input stacks.
13370 The following subroutines change the input status in commonly needed ways.
13371
13372 First comes |push_input|, which stores the current state and creates a
13373 new level (having, initially, the same properties as the old).
13374
13375 @d push_input  { /* enter a new input level, save the old */
13376   if ( mp->input_ptr>mp->max_in_stack ) {
13377     mp->max_in_stack=mp->input_ptr;
13378     if ( mp->input_ptr==mp->stack_size ) {
13379       int l = (mp->stack_size+(mp->stack_size/4));
13380       XREALLOC(mp->input_stack, l, in_state_record);
13381       mp->stack_size = l;
13382     }         
13383   }
13384   mp->input_stack[mp->input_ptr]=mp->cur_input; /* stack the record */
13385   incr(mp->input_ptr);
13386 }
13387
13388 @ And of course what goes up must come down.
13389
13390 @d pop_input { /* leave an input level, re-enter the old */
13391     decr(mp->input_ptr); mp->cur_input=mp->input_stack[mp->input_ptr];
13392   }
13393
13394 @ Here is a procedure that starts a new level of token-list input, given
13395 a token list |p| and its type |t|. If |t=macro|, the calling routine should
13396 set |name|, reset~|loc|, and increase the macro's reference count.
13397
13398 @d back_list(A) mp_begin_token_list(mp, (A),backed_up) /* backs up a simple token list */
13399
13400 @c 
13401 static void mp_begin_token_list (MP mp,pointer p, quarterword t)  { 
13402   push_input; start=p; token_type=t;
13403   param_start=mp->param_ptr; loc=p;
13404 }
13405
13406 @ When a token list has been fully scanned, the following computations
13407 should be done as we leave that level of input.
13408 @^inner loop@>
13409
13410 @c 
13411 static void mp_end_token_list (MP mp) { /* leave a token-list input level */
13412   pointer p; /* temporary register */
13413   if ( token_type>=backed_up ) { /* token list to be deleted */
13414     if ( token_type<=inserted ) { 
13415       mp_flush_token_list(mp, start); goto DONE;
13416     } else {
13417       mp_delete_mac_ref(mp, start); /* update reference count */
13418     }
13419   }
13420   while ( mp->param_ptr>param_start ) { /* parameters must be flushed */
13421     decr(mp->param_ptr);
13422     p=mp->param_stack[mp->param_ptr];
13423     if ( p!=null ) {
13424       if ( mp_link(p)==mp_void ) { /* it's an \&{expr} parameter */
13425         mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
13426       } else {
13427         mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
13428       }
13429     }
13430   }
13431 DONE: 
13432   pop_input; check_interrupt;
13433 }
13434
13435 @ The contents of |cur_cmd,cur_mod,cur_sym| are placed into an equivalent
13436 token by the |cur_tok| routine.
13437 @^inner loop@>
13438
13439 @c @<Declare the procedure called |make_exp_copy|@>
13440 static pointer mp_cur_tok (MP mp) {
13441   pointer p; /* a new token node */
13442   quarterword save_type; /* |cur_type| to be restored */
13443   integer save_exp; /* |cur_exp| to be restored */
13444   if ( mp->cur_sym==0 ) {
13445     if ( mp->cur_cmd==capsule_token ) {
13446       save_type=mp->cur_type; save_exp=mp->cur_exp;
13447       mp_make_exp_copy(mp, mp->cur_mod); p=mp_stash_cur_exp(mp); mp_link(p)=null;
13448       mp->cur_type=save_type; mp->cur_exp=save_exp;
13449     } else { 
13450       p=mp_get_node(mp, token_node_size);
13451       value(p)=mp->cur_mod; name_type(p)=mp_token;
13452       if ( mp->cur_cmd==numeric_token ) type(p)=mp_known;
13453       else type(p)=mp_string_type;
13454     }
13455   } else { 
13456     fast_get_avail(p); info(p)=mp->cur_sym;
13457   }
13458   return p;
13459 }
13460
13461 @ Sometimes \MP\ has read too far and wants to ``unscan'' what it has
13462 seen. The |back_input| procedure takes care of this by putting the token
13463 just scanned back into the input stream, ready to be read again.
13464 If |cur_sym<>0|, the values of |cur_cmd| and |cur_mod| are irrelevant.
13465
13466 @<Declarations@>= 
13467 static void mp_back_input (MP mp);
13468
13469 @ @c void mp_back_input (MP mp) {/* undoes one token of input */
13470   pointer p; /* a token list of length one */
13471   p=mp_cur_tok(mp);
13472   while ( token_state &&(loc==null) ) 
13473     mp_end_token_list(mp); /* conserve stack space */
13474   back_list(p);
13475 }
13476
13477 @ The |back_error| routine is used when we want to restore or replace an
13478 offending token just before issuing an error message.  We disable interrupts
13479 during the call of |back_input| so that the help message won't be lost.
13480
13481 @ @c static void mp_back_error (MP mp) { /* back up one token and call |error| */
13482   mp->OK_to_interrupt=false; 
13483   mp_back_input(mp); 
13484   mp->OK_to_interrupt=true; mp_error(mp);
13485 }
13486 static void mp_ins_error (MP mp) { /* back up one inserted token and call |error| */
13487   mp->OK_to_interrupt=false; 
13488   mp_back_input(mp); token_type=inserted;
13489   mp->OK_to_interrupt=true; mp_error(mp);
13490 }
13491
13492 @ The |begin_file_reading| procedure starts a new level of input for lines
13493 of characters to be read from a file, or as an insertion from the
13494 terminal. It does not take care of opening the file, nor does it set |loc|
13495 or |limit| or |line|.
13496 @^system dependencies@>
13497
13498 @c void mp_begin_file_reading (MP mp) { 
13499   if ( mp->in_open==mp->max_in_open ) 
13500     mp_overflow(mp, "text input levels",mp->max_in_open);
13501 @:MetaPost capacity exceeded text input levels}{\quad text input levels@>
13502   if ( mp->first==mp->buf_size ) 
13503     mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size/4)));
13504   incr(mp->in_open); push_input; iindex=mp->in_open;
13505   mp->mpx_name[iindex]=absent;
13506   start=(halfword)mp->first;
13507   name=is_term; /* |terminal_input| is now |true| */
13508 }
13509
13510 @ Conversely, the variables must be downdated when such a level of input
13511 is finished.  Any associated \.{MPX} file must also be closed and popped
13512 off the file stack.
13513
13514 @c static void mp_end_file_reading (MP mp) { 
13515   if ( mp->in_open>iindex ) {
13516     if ( (mp->mpx_name[mp->in_open]==absent)||(name<=max_spec_src) ) {
13517       mp_confusion(mp, "endinput");
13518 @:this can't happen endinput}{\quad endinput@>
13519     } else { 
13520       (mp->close_file)(mp,mp->input_file[mp->in_open]); /* close an \.{MPX} file */
13521       delete_str_ref(mp->mpx_name[mp->in_open]);
13522       decr(mp->in_open);
13523     }
13524   }
13525   mp->first=(size_t)start;
13526   if ( iindex!=mp->in_open ) mp_confusion(mp, "endinput");
13527   if ( name>max_spec_src ) {
13528     (mp->close_file)(mp,cur_file);
13529     delete_str_ref(name);
13530     xfree(in_name); 
13531     xfree(in_area);
13532   }
13533   pop_input; decr(mp->in_open);
13534 }
13535
13536 @ Here is a function that tries to resume input from an \.{MPX} file already
13537 associated with the current input file.  It returns |false| if this doesn't
13538 work.
13539
13540 @c static boolean mp_begin_mpx_reading (MP mp) { 
13541   if ( mp->in_open!=iindex+1 ) {
13542      return false;
13543   } else { 
13544     if ( mp->mpx_name[mp->in_open]<=absent ) mp_confusion(mp, "mpx");
13545 @:this can't happen mpx}{\quad mpx@>
13546     if ( mp->first==mp->buf_size ) 
13547       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size/4)));
13548     push_input; iindex=mp->in_open;
13549     start=(halfword)mp->first;
13550     name=mp->mpx_name[mp->in_open]; add_str_ref(name);
13551     @<Put an empty line in the input buffer@>;
13552     return true;
13553   }
13554 }
13555
13556 @ This procedure temporarily stops reading an \.{MPX} file.
13557
13558 @c static void mp_end_mpx_reading (MP mp) { 
13559   if ( mp->in_open!=iindex ) mp_confusion(mp, "mpx");
13560 @:this can't happen mpx}{\quad mpx@>
13561   if ( loc<limit ) {
13562     @<Complain that we are not at the end of a line in the \.{MPX} file@>;
13563   }
13564   mp->first=(size_t)start;
13565   pop_input;
13566 }
13567
13568 @ Here we enforce a restriction that simplifies the input stacks considerably.
13569 This should not inconvenience the user because \.{MPX} files are generated
13570 by an auxiliary program called \.{DVItoMP}.
13571
13572 @ @<Complain that we are not at the end of a line in the \.{MPX} file@>=
13573
13574 print_err("`mpxbreak' must be at the end of a line");
13575 help4("This file contains picture expressions for btex...etex",
13576   "blocks.  Such files are normally generated automatically",
13577   "but this one seems to be messed up.  I'm going to ignore",
13578   "the rest of this line.");
13579 mp_error(mp);
13580 }
13581
13582 @ In order to keep the stack from overflowing during a long sequence of
13583 inserted `\.{show}' commands, the following routine removes completed
13584 error-inserted lines from memory.
13585
13586 @c void mp_clear_for_error_prompt (MP mp) { 
13587   while ( file_state && terminal_input &&
13588     (mp->input_ptr>0)&&(loc==limit) ) mp_end_file_reading(mp);
13589   mp_print_ln(mp); clear_terminal;
13590 }
13591
13592 @ To get \MP's whole input mechanism going, we perform the following
13593 actions.
13594
13595 @<Initialize the input routines@>=
13596 { mp->input_ptr=0; mp->max_in_stack=0;
13597   mp->in_open=0; mp->open_parens=0; mp->max_buf_stack=0;
13598   mp->param_ptr=0; mp->max_param_stack=0;
13599   mp->first=1;
13600   start=1; iindex=0; line=0; name=is_term;
13601   mp->mpx_name[0]=absent;
13602   mp->force_eof=false;
13603   if ( ! mp_init_terminal(mp) ) mp_jump_out(mp);
13604   limit=(halfword)mp->last; mp->first=mp->last+1; 
13605   /* |init_terminal| has set |loc| and |last| */
13606 }
13607
13608 @* \[29] Getting the next token.
13609 The heart of \MP's input mechanism is the |get_next| procedure, which
13610 we shall develop in the next few sections of the program. Perhaps we
13611 shouldn't actually call it the ``heart,'' however; it really acts as \MP's
13612 eyes and mouth, reading the source files and gobbling them up. And it also
13613 helps \MP\ to regurgitate stored token lists that are to be processed again.
13614
13615 The main duty of |get_next| is to input one token and to set |cur_cmd|
13616 and |cur_mod| to that token's command code and modifier. Furthermore, if
13617 the input token is a symbolic token, that token's |hash| address
13618 is stored in |cur_sym|; otherwise |cur_sym| is set to zero.
13619
13620 Underlying this simple description is a certain amount of complexity
13621 because of all the cases that need to be handled.
13622 However, the inner loop of |get_next| is reasonably short and fast.
13623
13624 @ Before getting into |get_next|, we need to consider a mechanism by which
13625 \MP\ helps keep errors from propagating too far. Whenever the program goes
13626 into a mode where it keeps calling |get_next| repeatedly until a certain
13627 condition is met, it sets |scanner_status| to some value other than |normal|.
13628 Then if an input file ends, or if an `\&{outer}' symbol appears,
13629 an appropriate error recovery will be possible.
13630
13631 The global variable |warning_info| helps in this error recovery by providing
13632 additional information. For example, |warning_info| might indicate the
13633 name of a macro whose replacement text is being scanned.
13634
13635 @d normal 0 /* |scanner_status| at ``quiet times'' */
13636 @d skipping 1 /* |scanner_status| when false conditional text is being skipped */
13637 @d flushing 2 /* |scanner_status| when junk after a statement is being ignored */
13638 @d absorbing 3 /* |scanner_status| when a \&{text} parameter is being scanned */
13639 @d var_defining 4 /* |scanner_status| when a \&{vardef} is being scanned */
13640 @d op_defining 5 /* |scanner_status| when a macro \&{def} is being scanned */
13641 @d loop_defining 6 /* |scanner_status| when a \&{for} loop is being scanned */
13642 @d tex_flushing 7 /* |scanner_status| when skipping \TeX\ material */
13643
13644 @<Glob...@>=
13645 integer scanner_status; /* are we scanning at high speed? */
13646 integer warning_info; /* if so, what else do we need to know,
13647     in case an error occurs? */
13648
13649 @ @<Initialize the input routines@>=
13650 mp->scanner_status=normal;
13651
13652 @ The following subroutine
13653 is called when an `\&{outer}' symbolic token has been scanned or
13654 when the end of a file has been reached. These two cases are distinguished
13655 by |cur_sym|, which is zero at the end of a file.
13656
13657 @c
13658 static boolean mp_check_outer_validity (MP mp) {
13659   pointer p; /* points to inserted token list */
13660   if ( mp->scanner_status==normal ) {
13661     return true;
13662   } else if ( mp->scanner_status==tex_flushing ) {
13663     @<Check if the file has ended while flushing \TeX\ material and set the
13664       result value for |check_outer_validity|@>;
13665   } else { 
13666     mp->deletions_allowed=false;
13667     @<Back up an outer symbolic token so that it can be reread@>;
13668     if ( mp->scanner_status>skipping ) {
13669       @<Tell the user what has run away and try to recover@>;
13670     } else { 
13671       print_err("Incomplete if; all text was ignored after line ");
13672 @.Incomplete if...@>
13673       mp_print_int(mp, mp->warning_info);
13674       help3("A forbidden `outer' token occurred in skipped text.",
13675         "This kind of error happens when you say `if...' and forget",
13676         "the matching `fi'. I've inserted a `fi'; this might work.");
13677       if ( mp->cur_sym==0 ) 
13678         mp->help_line[2]="The file ended while I was skipping conditional text.";
13679       mp->cur_sym=frozen_fi; mp_ins_error(mp);
13680     }
13681     mp->deletions_allowed=true; 
13682         return false;
13683   }
13684 }
13685
13686 @ @<Check if the file has ended while flushing \TeX\ material and set...@>=
13687 if ( mp->cur_sym!=0 ) { 
13688    return true;
13689 } else { 
13690   mp->deletions_allowed=false;
13691   print_err("TeX mode didn't end; all text was ignored after line ");
13692   mp_print_int(mp, mp->warning_info);
13693   help2("The file ended while I was looking for the `etex' to",
13694         "finish this TeX material.  I've inserted `etex' now.");
13695   mp->cur_sym = frozen_etex;
13696   mp_ins_error(mp);
13697   mp->deletions_allowed=true;
13698   return false;
13699 }
13700
13701 @ @<Back up an outer symbolic token so that it can be reread@>=
13702 if ( mp->cur_sym!=0 ) {
13703   p=mp_get_avail(mp); info(p)=mp->cur_sym;
13704   back_list(p); /* prepare to read the symbolic token again */
13705 }
13706
13707 @ @<Tell the user what has run away...@>=
13708
13709   mp_runaway(mp); /* print the definition-so-far */
13710   if ( mp->cur_sym==0 ) {
13711     print_err("File ended");
13712 @.File ended while scanning...@>
13713   } else { 
13714     print_err("Forbidden token found");
13715 @.Forbidden token found...@>
13716   }
13717   mp_print(mp, " while scanning ");
13718   help4("I suspect you have forgotten an `enddef',",
13719     "causing me to read past where you wanted me to stop.",
13720     "I'll try to recover; but if the error is serious,",
13721     "you'd better type `E' or `X' now and fix your file.");
13722   switch (mp->scanner_status) {
13723     @<Complete the error message,
13724       and set |cur_sym| to a token that might help recover from the error@>
13725   } /* there are no other cases */
13726   mp_ins_error(mp);
13727 }
13728
13729 @ As we consider various kinds of errors, it is also appropriate to
13730 change the first line of the help message just given; |help_line[3]|
13731 points to the string that might be changed.
13732
13733 @<Complete the error message,...@>=
13734 case flushing: 
13735   mp_print(mp, "to the end of the statement");
13736   mp->help_line[3]="A previous error seems to have propagated,";
13737   mp->cur_sym=frozen_semicolon;
13738   break;
13739 case absorbing: 
13740   mp_print(mp, "a text argument");
13741   mp->help_line[3]="It seems that a right delimiter was left out,";
13742   if ( mp->warning_info==0 ) {
13743     mp->cur_sym=frozen_end_group;
13744   } else { 
13745     mp->cur_sym=frozen_right_delimiter;
13746     equiv(frozen_right_delimiter)=mp->warning_info;
13747   }
13748   break;
13749 case var_defining:
13750 case op_defining: 
13751   mp_print(mp, "the definition of ");
13752   if ( mp->scanner_status==op_defining ) 
13753      mp_print_text(mp->warning_info);
13754   else 
13755      mp_print_variable_name(mp, mp->warning_info);
13756   mp->cur_sym=frozen_end_def;
13757   break;
13758 case loop_defining: 
13759   mp_print(mp, "the text of a "); 
13760   mp_print_text(mp->warning_info);
13761   mp_print(mp, " loop");
13762   mp->help_line[3]="I suspect you have forgotten an `endfor',";
13763   mp->cur_sym=frozen_end_for;
13764   break;
13765
13766 @ The |runaway| procedure displays the first part of the text that occurred
13767 when \MP\ began its special |scanner_status|, if that text has been saved.
13768
13769 @<Declarations@>=
13770 static void mp_runaway (MP mp) ;
13771
13772 @ @c
13773 void mp_runaway (MP mp) { 
13774   if ( mp->scanner_status>flushing ) { 
13775      mp_print_nl(mp, "Runaway ");
13776          switch (mp->scanner_status) { 
13777          case absorbing: mp_print(mp, "text?"); break;
13778          case var_defining: 
13779      case op_defining: mp_print(mp,"definition?"); break;
13780      case loop_defining: mp_print(mp, "loop?"); break;
13781      } /* there are no other cases */
13782      mp_print_ln(mp); 
13783      mp_show_token_list(mp, mp_link(hold_head),null,mp->error_line-10,0);
13784   }
13785 }
13786
13787 @ We need to mention a procedure that may be called by |get_next|.
13788
13789 @<Declarations@>= 
13790 static void mp_firm_up_the_line (MP mp);
13791
13792 @ And now we're ready to take the plunge into |get_next| itself.
13793 Note that the behavior depends on the |scanner_status| because percent signs
13794 and double quotes need to be passed over when skipping TeX material.
13795
13796 @c 
13797 void mp_get_next (MP mp) {
13798   /* sets |cur_cmd|, |cur_mod|, |cur_sym| to next token */
13799 @^inner loop@>
13800   /*restart*/ /* go here to get the next input token */
13801   /*exit*/ /* go here when the next input token has been got */
13802   /*|common_ending|*/ /* go here to finish getting a symbolic token */
13803   /*found*/ /* go here when the end of a symbolic token has been found */
13804   /*switch*/ /* go here to branch on the class of an input character */
13805   /*|start_numeric_token|,|start_decimal_token|,|fin_numeric_token|,|done|*/
13806     /* go here at crucial stages when scanning a number */
13807   int k; /* an index into |buffer| */
13808   ASCII_code c; /* the current character in the buffer */
13809   int class; /* its class number */
13810   integer n,f; /* registers for decimal-to-binary conversion */
13811 RESTART: 
13812   mp->cur_sym=0;
13813   if ( file_state ) {
13814     @<Input from external file; |goto restart| if no input found,
13815     or |return| if a non-symbolic token is found@>;
13816   } else {
13817     @<Input from token list; |goto restart| if end of list or
13818       if a parameter needs to be expanded,
13819       or |return| if a non-symbolic token is found@>;
13820   }
13821 COMMON_ENDING: 
13822   @<Finish getting the symbolic token in |cur_sym|;
13823    |goto restart| if it is illegal@>;
13824 }
13825
13826 @ When a symbolic token is declared to be `\&{outer}', its command code
13827 is increased by |outer_tag|.
13828 @^inner loop@>
13829
13830 @<Finish getting the symbolic token in |cur_sym|...@>=
13831 mp->cur_cmd=eq_type(mp->cur_sym); mp->cur_mod=equiv(mp->cur_sym);
13832 if ( mp->cur_cmd>=outer_tag ) {
13833   if ( mp_check_outer_validity(mp) ) 
13834     mp->cur_cmd=mp->cur_cmd-outer_tag;
13835   else 
13836     goto RESTART;
13837 }
13838
13839 @ A percent sign appears in |buffer[limit]|; this makes it unnecessary
13840 to have a special test for end-of-line.
13841 @^inner loop@>
13842
13843 @<Input from external file;...@>=
13844
13845 SWITCH: 
13846   c=mp->buffer[loc]; incr(loc); class=mp->char_class[c];
13847   switch (class) {
13848   case digit_class: goto START_NUMERIC_TOKEN; break;
13849   case period_class: 
13850     class=mp->char_class[mp->buffer[loc]];
13851     if ( class>period_class ) {
13852       goto SWITCH;
13853     } else if ( class<period_class ) { /* |class=digit_class| */
13854       n=0; goto START_DECIMAL_TOKEN;
13855     }
13856 @:. }{\..\ token@>
13857     break;
13858   case space_class: goto SWITCH; break;
13859   case percent_class: 
13860     if ( mp->scanner_status==tex_flushing ) {
13861       if ( loc<limit ) goto SWITCH;
13862     }
13863     @<Move to next line of file, or |goto restart| if there is no next line@>;
13864     check_interrupt;
13865     goto SWITCH;
13866     break;
13867   case string_class: 
13868     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13869     else @<Get a string token and |return|@>;
13870     break;
13871   case isolated_classes: 
13872     k=loc-1; goto FOUND; break;
13873   case invalid_class: 
13874     if ( mp->scanner_status==tex_flushing ) goto SWITCH;
13875     else @<Decry the invalid character and |goto restart|@>;
13876     break;
13877   default: break; /* letters, etc. */
13878   }
13879   k=loc-1;
13880   while ( mp->char_class[mp->buffer[loc]]==class ) incr(loc);
13881   goto FOUND;
13882 START_NUMERIC_TOKEN:
13883   @<Get the integer part |n| of a numeric token;
13884     set |f:=0| and |goto fin_numeric_token| if there is no decimal point@>;
13885 START_DECIMAL_TOKEN:
13886   @<Get the fraction part |f| of a numeric token@>;
13887 FIN_NUMERIC_TOKEN:
13888   @<Pack the numeric and fraction parts of a numeric token
13889     and |return|@>;
13890 FOUND: 
13891   mp->cur_sym=mp_id_lookup(mp, k,loc-k);
13892 }
13893
13894 @ We go to |restart| instead of to |SWITCH|, because we might enter
13895 |token_state| after the error has been dealt with
13896 (cf.\ |clear_for_error_prompt|).
13897
13898 @<Decry the invalid...@>=
13899
13900   print_err("Text line contains an invalid character");
13901 @.Text line contains...@>
13902   help2("A funny symbol that I can\'t read has just been input.",
13903         "Continue, and I'll forget that it ever happened.");
13904   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13905   goto RESTART;
13906 }
13907
13908 @ @<Get a string token and |return|@>=
13909
13910   if ( mp->buffer[loc]=='"' ) {
13911     mp->cur_mod=null_str;
13912   } else { 
13913     k=loc; mp->buffer[limit+1]=xord('"');
13914     do {  
13915      incr(loc);
13916     } while (mp->buffer[loc]!='"');
13917     if ( loc>limit ) {
13918       @<Decry the missing string delimiter and |goto restart|@>;
13919     }
13920     if ( loc==k+1 ) {
13921       mp->cur_mod=mp->buffer[k];
13922     } else { 
13923       str_room(loc-k);
13924       do {  
13925         append_char(mp->buffer[k]); incr(k);
13926       } while (k!=loc);
13927       mp->cur_mod=mp_make_string(mp);
13928     }
13929   }
13930   incr(loc); mp->cur_cmd=string_token; 
13931   return;
13932 }
13933
13934 @ We go to |restart| after this error message, not to |SWITCH|,
13935 because the |clear_for_error_prompt| routine might have reinstated
13936 |token_state| after |error| has finished.
13937
13938 @<Decry the missing string delimiter and |goto restart|@>=
13939
13940   loc=limit; /* the next character to be read on this line will be |"%"| */
13941   print_err("Incomplete string token has been flushed");
13942 @.Incomplete string token...@>
13943   help3("Strings should finish on the same line as they began.",
13944     "I've deleted the partial string; you might want to",
13945     "insert another by typing, e.g., `I\"new string\"'.");
13946   mp->deletions_allowed=false; mp_error(mp);
13947   mp->deletions_allowed=true; 
13948   goto RESTART;
13949 }
13950
13951 @ @<Get the integer part |n| of a numeric token...@>=
13952 n=c-'0';
13953 while ( mp->char_class[mp->buffer[loc]]==digit_class ) {
13954   if ( n<32768 ) n=10*n+mp->buffer[loc]-'0';
13955   incr(loc);
13956 }
13957 if ( mp->buffer[loc]=='.' ) 
13958   if ( mp->char_class[mp->buffer[loc+1]]==digit_class ) 
13959     goto DONE;
13960 f=0; 
13961 goto FIN_NUMERIC_TOKEN;
13962 DONE: incr(loc)
13963
13964 @ @<Get the fraction part |f| of a numeric token@>=
13965 k=0;
13966 do { 
13967   if ( k<17 ) { /* digits for |k>=17| cannot affect the result */
13968     mp->dig[k]=mp->buffer[loc]-'0'; incr(k);
13969   }
13970   incr(loc);
13971 } while (mp->char_class[mp->buffer[loc]]==digit_class);
13972 f=mp_round_decimals(mp, k);
13973 if ( f==unity ) {
13974   incr(n); f=0;
13975 }
13976
13977 @ @<Pack the numeric and fraction parts of a numeric token and |return|@>=
13978 if ( n<32768 ) {
13979   @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>;
13980 } else if ( mp->scanner_status!=tex_flushing ) {
13981   print_err("Enormous number has been reduced");
13982 @.Enormous number...@>
13983   help2("I can\'t handle numbers bigger than 32767.99998;",
13984         "so I've changed your constant to that maximum amount.");
13985   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
13986   mp->cur_mod=el_gordo;
13987 }
13988 mp->cur_cmd=numeric_token; return
13989
13990 @ @<Set |cur_mod:=n*unity+f| and check if it is uncomfortably large@>=
13991
13992   mp->cur_mod=n*unity+f;
13993   if ( mp->cur_mod>=fraction_one ) {
13994     if ( (mp->internal[mp_warning_check]>0) &&
13995          (mp->scanner_status!=tex_flushing) ) {
13996       print_err("Number is too large (");
13997       mp_print_scaled(mp, mp->cur_mod);
13998       mp_print_char(mp, xord(')'));
13999       help3("It is at least 4096. Continue and I'll try to cope",
14000       "with that big value; but it might be dangerous.",
14001       "(Set warningcheck:=0 to suppress this message.)");
14002       mp_error(mp);
14003     }
14004   }
14005 }
14006
14007 @ Let's consider now what happens when |get_next| is looking at a token list.
14008 @^inner loop@>
14009
14010 @<Input from token list;...@>=
14011 if ( loc>=mp->hi_mem_min ) { /* one-word token */
14012   mp->cur_sym=info(loc); loc=mp_link(loc); /* move to next */
14013   if ( mp->cur_sym>=expr_base ) {
14014     if ( mp->cur_sym>=suffix_base ) {
14015       @<Insert a suffix or text parameter and |goto restart|@>;
14016     } else { 
14017       mp->cur_cmd=capsule_token;
14018       mp->cur_mod=mp->param_stack[param_start+mp->cur_sym-(expr_base)];
14019       mp->cur_sym=0; return;
14020     }
14021   }
14022 } else if ( loc>null ) {
14023   @<Get a stored numeric or string or capsule token and |return|@>
14024 } else { /* we are done with this token list */
14025   mp_end_token_list(mp); goto RESTART; /* resume previous level */
14026 }
14027
14028 @ @<Insert a suffix or text parameter...@>=
14029
14030   if ( mp->cur_sym>=text_base ) mp->cur_sym=mp->cur_sym-mp->param_size;
14031   /* |param_size=text_base-suffix_base| */
14032   mp_begin_token_list(mp,
14033                       mp->param_stack[param_start+mp->cur_sym-(suffix_base)],
14034                       parameter);
14035   goto RESTART;
14036 }
14037
14038 @ @<Get a stored numeric or string or capsule token...@>=
14039
14040   if ( name_type(loc)==mp_token ) {
14041     mp->cur_mod=value(loc);
14042     if ( type(loc)==mp_known ) {
14043       mp->cur_cmd=numeric_token;
14044     } else { 
14045       mp->cur_cmd=string_token; add_str_ref(mp->cur_mod);
14046     }
14047   } else { 
14048     mp->cur_mod=loc; mp->cur_cmd=capsule_token;
14049   };
14050   loc=mp_link(loc); return;
14051 }
14052
14053 @ All of the easy branches of |get_next| have now been taken care of.
14054 There is one more branch.
14055
14056 @<Move to next line of file, or |goto restart|...@>=
14057 if ( name>max_spec_src) {
14058   @<Read next line of file into |buffer|, or
14059     |goto restart| if the file has ended@>;
14060 } else { 
14061   if ( mp->input_ptr>0 ) {
14062      /* text was inserted during error recovery or by \&{scantokens} */
14063     mp_end_file_reading(mp); goto RESTART; /* resume previous level */
14064   }
14065   if (mp->job_name == NULL && ( mp->selector<log_only || mp->selector>=write_file))  
14066     mp_open_log_file(mp);
14067   if ( mp->interaction>mp_nonstop_mode ) {
14068     if ( limit==start ) /* previous line was empty */
14069       mp_print_nl(mp, "(Please type a command or say `end')");
14070 @.Please type...@>
14071     mp_print_ln(mp); mp->first=(size_t)start;
14072     prompt_input("*"); /* input on-line into |buffer| */
14073 @.*\relax@>
14074     limit=(halfword)mp->last; mp->buffer[limit]=xord('%');
14075     mp->first=(size_t)(limit+1); loc=start;
14076   } else {
14077     mp_fatal_error(mp, "*** (job aborted, no legal end found)");
14078 @.job aborted@>
14079     /* nonstop mode, which is intended for overnight batch processing,
14080        never waits for on-line input */
14081   }
14082 }
14083
14084 @ The global variable |force_eof| is normally |false|; it is set |true|
14085 by an \&{endinput} command.
14086
14087 @<Glob...@>=
14088 boolean force_eof; /* should the next \&{input} be aborted early? */
14089
14090 @ We must decrement |loc| in order to leave the buffer in a valid state
14091 when an error condition causes us to |goto restart| without calling
14092 |end_file_reading|.
14093
14094 @<Read next line of file into |buffer|, or
14095   |goto restart| if the file has ended@>=
14096
14097   incr(line); mp->first=(size_t)start;
14098   if ( ! mp->force_eof ) {
14099     if ( mp_input_ln(mp, cur_file ) ) /* not end of file */
14100       mp_firm_up_the_line(mp); /* this sets |limit| */
14101     else 
14102       mp->force_eof=true;
14103   };
14104   if ( mp->force_eof ) {
14105     mp->force_eof=false;
14106     decr(loc);
14107     if ( mpx_reading ) {
14108       @<Complain that the \.{MPX} file ended unexpectly; then set
14109         |cur_sym:=frozen_mpx_break| and |goto comon_ending|@>;
14110     } else { 
14111       mp_print_char(mp, xord(')')); decr(mp->open_parens);
14112       update_terminal; /* show user that file has been read */
14113       mp_end_file_reading(mp); /* resume previous level */
14114       if ( mp_check_outer_validity(mp) ) goto  RESTART;  
14115       else goto RESTART;
14116     }
14117   }
14118   mp->buffer[limit]=xord('%'); mp->first=(size_t)(limit+1); loc=start; /* ready to read */
14119 }
14120
14121 @ We should never actually come to the end of an \.{MPX} file because such
14122 files should have an \&{mpxbreak} after the translation of the last
14123 \&{btex}$\,\ldots\,$\&{etex} block.
14124
14125 @<Complain that the \.{MPX} file ended unexpectly; then set...@>=
14126
14127   mp->mpx_name[iindex]=mpx_finished;
14128   print_err("mpx file ended unexpectedly");
14129   help4("The file had too few picture expressions for btex...etex",
14130     "blocks.  Such files are normally generated automatically",
14131     "but this one got messed up.  You might want to insert a",
14132     "picture expression now.");
14133   mp->deletions_allowed=false; mp_error(mp); mp->deletions_allowed=true;
14134   mp->cur_sym=frozen_mpx_break; goto COMMON_ENDING;
14135 }
14136
14137 @ Sometimes we want to make it look as though we have just read a blank line
14138 without really doing so.
14139
14140 @<Put an empty line in the input buffer@>=
14141 mp->last=mp->first; limit=(halfword)mp->last; 
14142   /* simulate |input_ln| and |firm_up_the_line| */
14143 mp->buffer[limit]=xord('%'); mp->first=(size_t)(limit+1); loc=start
14144
14145 @ If the user has set the |mp_pausing| parameter to some positive value,
14146 and if nonstop mode has not been selected, each line of input is displayed
14147 on the terminal and the transcript file, followed by `\.{=>}'.
14148 \MP\ waits for a response. If the response is null (i.e., if nothing is
14149 typed except perhaps a few blank spaces), the original
14150 line is accepted as it stands; otherwise the line typed is
14151 used instead of the line in the file.
14152
14153 @c void mp_firm_up_the_line (MP mp) {
14154   size_t k; /* an index into |buffer| */
14155   limit=(halfword)mp->last;
14156   if ((!mp->noninteractive)   
14157       && (mp->internal[mp_pausing]>0 )
14158       && (mp->interaction>mp_nonstop_mode )) {
14159     wake_up_terminal; mp_print_ln(mp);
14160     if ( start<limit ) {
14161       for (k=(size_t)start;k<=(size_t)(limit-1);k++) {
14162         mp_print_str(mp, mp->buffer[k]);
14163       } 
14164     }
14165     mp->first=(size_t)limit; prompt_input("=>"); /* wait for user response */
14166 @.=>@>
14167     if ( mp->last>mp->first ) {
14168       for (k=mp->first;k<=mp->last-1;k++) { /* move line down in buffer */
14169         mp->buffer[k+start-mp->first]=mp->buffer[k];
14170       }
14171       limit=(halfword)(start+mp->last-mp->first);
14172     }
14173   }
14174 }
14175
14176 @* \[30] Dealing with \TeX\ material.
14177 The \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}$\,\ldots\,$\&{etex}
14178 features need to be implemented at a low level in the scanning process
14179 so that \MP\ can stay in synch with the a preprocessor that treats
14180 blocks of \TeX\ material as they occur in the input file without trying
14181 to expand \MP\ macros.  Thus we need a special version of |get_next|
14182 that does not expand macros and such but does handle \&{btex},
14183 \&{verbatimtex}, etc.
14184
14185 The special version of |get_next| is called |get_t_next|.  It works by flushing
14186 \&{btex}$\,\ldots\,$\&{etex} and \&{verbatimtex}\allowbreak
14187 $\,\ldots\,$\&{etex} blocks, switching to the \.{MPX} file when it sees
14188 \&{btex}, and switching back when it sees \&{mpxbreak}.
14189
14190 @d btex_code 0
14191 @d verbatim_code 1
14192
14193 @ @<Put each...@>=
14194 mp_primitive(mp, "btex",start_tex,btex_code);
14195 @:btex_}{\&{btex} primitive@>
14196 mp_primitive(mp, "verbatimtex",start_tex,verbatim_code);
14197 @:verbatimtex_}{\&{verbatimtex} primitive@>
14198 mp_primitive(mp, "etex",etex_marker,0); mp->eqtb[frozen_etex]=mp->eqtb[mp->cur_sym];
14199 @:etex_}{\&{etex} primitive@>
14200 mp_primitive(mp, "mpxbreak",mpx_break,0); mp->eqtb[frozen_mpx_break]=mp->eqtb[mp->cur_sym];
14201 @:mpx_break_}{\&{mpxbreak} primitive@>
14202
14203 @ @<Cases of |print_cmd...@>=
14204 case start_tex: if ( m==btex_code ) mp_print(mp, "btex");
14205   else mp_print(mp, "verbatimtex"); break;
14206 case etex_marker: mp_print(mp, "etex"); break;
14207 case mpx_break: mp_print(mp, "mpxbreak"); break;
14208
14209 @ Actually, |get_t_next| is a macro that avoids procedure overhead except
14210 in the unusual case where \&{btex}, \&{verbatimtex}, \&{etex}, or \&{mpxbreak}
14211 is encountered.
14212
14213 @d get_t_next {mp_get_next(mp); if ( mp->cur_cmd<=max_pre_command ) mp_t_next(mp); }
14214
14215 @<Declarations@>=
14216 static void mp_start_mpx_input (MP mp);
14217
14218 @ @c 
14219 static void mp_t_next (MP mp) {
14220   int old_status; /* saves the |scanner_status| */
14221   integer old_info; /* saves the |warning_info| */
14222   while ( mp->cur_cmd<=max_pre_command ) {
14223     if ( mp->cur_cmd==mpx_break ) {
14224       if ( ! file_state || (mp->mpx_name[iindex]==absent) ) {
14225         @<Complain about a misplaced \&{mpxbreak}@>;
14226       } else { 
14227         mp_end_mpx_reading(mp); 
14228         goto TEX_FLUSH;
14229       }
14230     } else if ( mp->cur_cmd==start_tex ) {
14231       if ( token_state || (name<=max_spec_src) ) {
14232         @<Complain that we are not reading a file@>;
14233       } else if ( mpx_reading ) {
14234         @<Complain that \.{MPX} files cannot contain \TeX\ material@>;
14235       } else if ( (mp->cur_mod!=verbatim_code)&&
14236                   (mp->mpx_name[iindex]!=mpx_finished) ) {
14237         if ( ! mp_begin_mpx_reading(mp) ) mp_start_mpx_input(mp);
14238       } else {
14239         goto TEX_FLUSH;
14240       }
14241     } else {
14242        @<Complain about a misplaced \&{etex}@>;
14243     }
14244     goto COMMON_ENDING;
14245   TEX_FLUSH: 
14246     @<Flush the \TeX\ material@>;
14247   COMMON_ENDING: 
14248     mp_get_next(mp);
14249   }
14250 }
14251
14252 @ We could be in the middle of an operation such as skipping false conditional
14253 text when \TeX\ material is encountered, so we must be careful to save the
14254 |scanner_status|.
14255
14256 @<Flush the \TeX\ material@>=
14257 old_status=mp->scanner_status;
14258 old_info=mp->warning_info;
14259 mp->scanner_status=tex_flushing;
14260 mp->warning_info=line;
14261 do {  mp_get_next(mp); } while (mp->cur_cmd!=etex_marker);
14262 mp->scanner_status=old_status;
14263 mp->warning_info=old_info
14264
14265 @ @<Complain that \.{MPX} files cannot contain \TeX\ material@>=
14266 { print_err("An mpx file cannot contain btex or verbatimtex blocks");
14267 help4("This file contains picture expressions for btex...etex",
14268   "blocks.  Such files are normally generated automatically",
14269   "but this one seems to be messed up.  I'll just keep going",
14270   "and hope for the best.");
14271 mp_error(mp);
14272 }
14273
14274 @ @<Complain that we are not reading a file@>=
14275 { print_err("You can only use `btex' or `verbatimtex' in a file");
14276 help3("I'll have to ignore this preprocessor command because it",
14277   "only works when there is a file to preprocess.  You might",
14278   "want to delete everything up to the next `etex`.");
14279 mp_error(mp);
14280 }
14281
14282 @ @<Complain about a misplaced \&{mpxbreak}@>=
14283 { print_err("Misplaced mpxbreak");
14284 help2("I'll ignore this preprocessor command because it",
14285       "doesn't belong here");
14286 mp_error(mp);
14287 }
14288
14289 @ @<Complain about a misplaced \&{etex}@>=
14290 { print_err("Extra etex will be ignored");
14291 help1("There is no btex or verbatimtex for this to match");
14292 mp_error(mp);
14293 }
14294
14295 @* \[31] Scanning macro definitions.
14296 \MP\ has a variety of ways to tuck tokens away into token lists for later
14297 use: Macros can be defined with \&{def}, \&{vardef}, \&{primarydef}, etc.;
14298 repeatable code can be defined with \&{for}, \&{forever}, \&{forsuffixes}.
14299 All such operations are handled by the routines in this part of the program.
14300
14301 The modifier part of each command code is zero for the ``ending delimiters''
14302 like \&{enddef} and \&{endfor}.
14303
14304 @d start_def 1 /* command modifier for \&{def} */
14305 @d var_def 2 /* command modifier for \&{vardef} */
14306 @d end_def 0 /* command modifier for \&{enddef} */
14307 @d start_forever 1 /* command modifier for \&{forever} */
14308 @d end_for 0 /* command modifier for \&{endfor} */
14309
14310 @<Put each...@>=
14311 mp_primitive(mp, "def",macro_def,start_def);
14312 @:def_}{\&{def} primitive@>
14313 mp_primitive(mp, "vardef",macro_def,var_def);
14314 @:var_def_}{\&{vardef} primitive@>
14315 mp_primitive(mp, "primarydef",macro_def,secondary_primary_macro);
14316 @:primary_def_}{\&{primarydef} primitive@>
14317 mp_primitive(mp, "secondarydef",macro_def,tertiary_secondary_macro);
14318 @:secondary_def_}{\&{secondarydef} primitive@>
14319 mp_primitive(mp, "tertiarydef",macro_def,expression_tertiary_macro);
14320 @:tertiary_def_}{\&{tertiarydef} primitive@>
14321 mp_primitive(mp, "enddef",macro_def,end_def); mp->eqtb[frozen_end_def]=mp->eqtb[mp->cur_sym];
14322 @:end_def_}{\&{enddef} primitive@>
14323 @#
14324 mp_primitive(mp, "for",iteration,expr_base);
14325 @:for_}{\&{for} primitive@>
14326 mp_primitive(mp, "forsuffixes",iteration,suffix_base);
14327 @:for_suffixes_}{\&{forsuffixes} primitive@>
14328 mp_primitive(mp, "forever",iteration,start_forever);
14329 @:forever_}{\&{forever} primitive@>
14330 mp_primitive(mp, "endfor",iteration,end_for); mp->eqtb[frozen_end_for]=mp->eqtb[mp->cur_sym];
14331 @:end_for_}{\&{endfor} primitive@>
14332
14333 @ @<Cases of |print_cmd...@>=
14334 case macro_def:
14335   if ( m<=var_def ) {
14336     if ( m==start_def ) mp_print(mp, "def");
14337     else if ( m<start_def ) mp_print(mp, "enddef");
14338     else mp_print(mp, "vardef");
14339   } else if ( m==secondary_primary_macro ) { 
14340     mp_print(mp, "primarydef");
14341   } else if ( m==tertiary_secondary_macro ) { 
14342     mp_print(mp, "secondarydef");
14343   } else { 
14344     mp_print(mp, "tertiarydef");
14345   }
14346   break;
14347 case iteration: 
14348   if ( m<=start_forever ) {
14349     if ( m==start_forever ) mp_print(mp, "forever"); 
14350     else mp_print(mp, "endfor");
14351   } else if ( m==expr_base ) {
14352     mp_print(mp, "for"); 
14353   } else { 
14354     mp_print(mp, "forsuffixes");
14355   }
14356   break;
14357
14358 @ Different macro-absorbing operations have different syntaxes, but they
14359 also have a lot in common. There is a list of special symbols that are to
14360 be replaced by parameter tokens; there is a special command code that
14361 ends the definition; the quotation conventions are identical.  Therefore
14362 it makes sense to have most of the work done by a single subroutine. That
14363 subroutine is called |scan_toks|.
14364
14365 The first parameter to |scan_toks| is the command code that will
14366 terminate scanning (either |macro_def| or |iteration|).
14367
14368 The second parameter, |subst_list|, points to a (possibly empty) list
14369 of two-word nodes whose |info| and |value| fields specify symbol tokens
14370 before and after replacement. The list will be returned to free storage
14371 by |scan_toks|.
14372
14373 The third parameter is simply appended to the token list that is built.
14374 And the final parameter tells how many of the special operations
14375 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#} are to be replaced by suffix parameters.
14376 When such parameters are present, they are called \.{(SUFFIX0)},
14377 \.{(SUFFIX1)}, and \.{(SUFFIX2)}.
14378
14379 @c static pointer mp_scan_toks (MP mp,command_code terminator, pointer 
14380   subst_list, pointer tail_end, quarterword suffix_count) {
14381   pointer p; /* tail of the token list being built */
14382   pointer q; /* temporary for link management */
14383   integer balance; /* left delimiters minus right delimiters */
14384   p=hold_head; balance=1; mp_link(hold_head)=null;
14385   while (1) { 
14386     get_t_next;
14387     if ( mp->cur_sym>0 ) {
14388       @<Substitute for |cur_sym|, if it's on the |subst_list|@>;
14389       if ( mp->cur_cmd==terminator ) {
14390         @<Adjust the balance; |break| if it's zero@>;
14391       } else if ( mp->cur_cmd==macro_special ) {
14392         @<Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}@>;
14393       }
14394     }
14395     mp_link(p)=mp_cur_tok(mp); p=mp_link(p);
14396   }
14397   mp_link(p)=tail_end; mp_flush_node_list(mp, subst_list);
14398   return mp_link(hold_head);
14399 }
14400
14401 @ @<Substitute for |cur_sym|...@>=
14402
14403   q=subst_list;
14404   while ( q!=null ) {
14405     if ( info(q)==mp->cur_sym ) {
14406       mp->cur_sym=value(q); mp->cur_cmd=relax; break;
14407     }
14408     q=mp_link(q);
14409   }
14410 }
14411
14412 @ @<Adjust the balance; |break| if it's zero@>=
14413 if ( mp->cur_mod>0 ) {
14414   incr(balance);
14415 } else { 
14416   decr(balance);
14417   if ( balance==0 )
14418     break;
14419 }
14420
14421 @ Four commands are intended to be used only within macro texts: \&{quote},
14422 \.{\#\AT!}, \.{\AT!}, and \.{\AT!\#}. They are variants of a single command
14423 code called |macro_special|.
14424
14425 @d quote 0 /* |macro_special| modifier for \&{quote} */
14426 @d macro_prefix 1 /* |macro_special| modifier for \.{\#\AT!} */
14427 @d macro_at 2 /* |macro_special| modifier for \.{\AT!} */
14428 @d macro_suffix 3 /* |macro_special| modifier for \.{\AT!\#} */
14429
14430 @<Put each...@>=
14431 mp_primitive(mp, "quote",macro_special,quote);
14432 @:quote_}{\&{quote} primitive@>
14433 mp_primitive(mp, "#@@",macro_special,macro_prefix);
14434 @:]]]\#\AT!_}{\.{\#\AT!} primitive@>
14435 mp_primitive(mp, "@@",macro_special,macro_at);
14436 @:]]]\AT!_}{\.{\AT!} primitive@>
14437 mp_primitive(mp, "@@#",macro_special,macro_suffix);
14438 @:]]]\AT!\#_}{\.{\AT!\#} primitive@>
14439
14440 @ @<Cases of |print_cmd...@>=
14441 case macro_special: 
14442   switch (m) {
14443   case macro_prefix: mp_print(mp, "#@@"); break;
14444   case macro_at: mp_print_char(mp, xord('@@')); break;
14445   case macro_suffix: mp_print(mp, "@@#"); break;
14446   default: mp_print(mp, "quote"); break;
14447   }
14448   break;
14449
14450 @ @<Handle quoted...@>=
14451
14452   if ( mp->cur_mod==quote ) { get_t_next; } 
14453   else if ( mp->cur_mod<=suffix_count ) 
14454     mp->cur_sym=suffix_base-1+mp->cur_mod;
14455 }
14456
14457 @ Here is a routine that's used whenever a token will be redefined. If
14458 the user's token is unredefinable, the `|frozen_inaccessible|' token is
14459 substituted; the latter is redefinable but essentially impossible to use,
14460 hence \MP's tables won't get fouled up.
14461
14462 @c static void mp_get_symbol (MP mp) { /* sets |cur_sym| to a safe symbol */
14463 RESTART: 
14464   get_t_next;
14465   if ( (mp->cur_sym==0)||(mp->cur_sym>(integer)frozen_inaccessible) ) {
14466     print_err("Missing symbolic token inserted");
14467 @.Missing symbolic token...@>
14468     help3("Sorry: You can\'t redefine a number, string, or expr.",
14469       "I've inserted an inaccessible symbol so that your",
14470       "definition will be completed without mixing me up too badly.");
14471     if ( mp->cur_sym>0 )
14472       mp->help_line[2]="Sorry: You can\'t redefine my error-recovery tokens.";
14473     else if ( mp->cur_cmd==string_token ) 
14474       delete_str_ref(mp->cur_mod);
14475     mp->cur_sym=frozen_inaccessible; mp_ins_error(mp); goto RESTART;
14476   }
14477 }
14478
14479 @ Before we actually redefine a symbolic token, we need to clear away its
14480 former value, if it was a variable. The following stronger version of
14481 |get_symbol| does that.
14482
14483 @c static void mp_get_clear_symbol (MP mp) { 
14484   mp_get_symbol(mp); mp_clear_symbol(mp, mp->cur_sym,false);
14485 }
14486
14487 @ Here's another little subroutine; it checks that an equals sign
14488 or assignment sign comes along at the proper place in a macro definition.
14489
14490 @c static void mp_check_equals (MP mp) { 
14491   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
14492      mp_missing_err(mp, "=");
14493 @.Missing `='@>
14494     help5("The next thing in this `def' should have been `=',",
14495           "because I've already looked at the definition heading.",
14496           "But don't worry; I'll pretend that an equals sign",
14497           "was present. Everything from here to `enddef'",
14498           "will be the replacement text of this macro.");
14499     mp_back_error(mp);
14500   }
14501 }
14502
14503 @ A \&{primarydef}, \&{secondarydef}, or \&{tertiarydef} is rather easily
14504 handled now that we have |scan_toks|.  In this case there are
14505 two parameters, which will be \.{EXPR0} and \.{EXPR1} (i.e.,
14506 |expr_base| and |expr_base+1|).
14507
14508 @c static void mp_make_op_def (MP mp) {
14509   command_code m; /* the type of definition */
14510   pointer p,q,r; /* for list manipulation */
14511   m=mp->cur_mod;
14512   mp_get_symbol(mp); q=mp_get_node(mp, token_node_size);
14513   info(q)=mp->cur_sym; value(q)=expr_base;
14514   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym;
14515   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
14516   info(p)=mp->cur_sym; value(p)=expr_base+1; mp_link(p)=q;
14517   get_t_next; mp_check_equals(mp);
14518   mp->scanner_status=op_defining; q=mp_get_avail(mp); ref_count(q)=null;
14519   r=mp_get_avail(mp); mp_link(q)=r; info(r)=general_macro;
14520   mp_link(r)=mp_scan_toks(mp, macro_def,p,null,0);
14521   mp->scanner_status=normal; eq_type(mp->warning_info)=m;
14522   equiv(mp->warning_info)=q; mp_get_x_next(mp);
14523 }
14524
14525 @ Parameters to macros are introduced by the keywords \&{expr},
14526 \&{suffix}, \&{text}, \&{primary}, \&{secondary}, and \&{tertiary}.
14527
14528 @<Put each...@>=
14529 mp_primitive(mp, "expr",param_type,expr_base);
14530 @:expr_}{\&{expr} primitive@>
14531 mp_primitive(mp, "suffix",param_type,suffix_base);
14532 @:suffix_}{\&{suffix} primitive@>
14533 mp_primitive(mp, "text",param_type,text_base);
14534 @:text_}{\&{text} primitive@>
14535 mp_primitive(mp, "primary",param_type,primary_macro);
14536 @:primary_}{\&{primary} primitive@>
14537 mp_primitive(mp, "secondary",param_type,secondary_macro);
14538 @:secondary_}{\&{secondary} primitive@>
14539 mp_primitive(mp, "tertiary",param_type,tertiary_macro);
14540 @:tertiary_}{\&{tertiary} primitive@>
14541
14542 @ @<Cases of |print_cmd...@>=
14543 case param_type:
14544   if ( m>=expr_base ) {
14545     if ( m==expr_base ) mp_print(mp, "expr");
14546     else if ( m==suffix_base ) mp_print(mp, "suffix");
14547     else mp_print(mp, "text");
14548   } else if ( m<secondary_macro ) {
14549     mp_print(mp, "primary");
14550   } else if ( m==secondary_macro ) {
14551     mp_print(mp, "secondary");
14552   } else {
14553     mp_print(mp, "tertiary");
14554   }
14555   break;
14556
14557 @ Let's turn next to the more complex processing associated with \&{def}
14558 and \&{vardef}. When the following procedure is called, |cur_mod|
14559 should be either |start_def| or |var_def|.
14560
14561 @c 
14562 static void mp_scan_def (MP mp) {
14563   int m; /* the type of definition */
14564   int n; /* the number of special suffix parameters */
14565   int k; /* the total number of parameters */
14566   int c; /* the kind of macro we're defining */
14567   pointer r; /* parameter-substitution list */
14568   pointer q; /* tail of the macro token list */
14569   pointer p; /* temporary storage */
14570   halfword base; /* |expr_base|, |suffix_base|, or |text_base| */
14571   pointer l_delim,r_delim; /* matching delimiters */
14572   m=mp->cur_mod; c=general_macro; mp_link(hold_head)=null;
14573   q=mp_get_avail(mp); ref_count(q)=null; r=null;
14574   @<Scan the token or variable to be defined;
14575     set |n|, |scanner_status|, and |warning_info|@>;
14576   k=n;
14577   if ( mp->cur_cmd==left_delimiter ) {
14578     @<Absorb delimited parameters, putting them into lists |q| and |r|@>;
14579   }
14580   if ( mp->cur_cmd==param_type ) {
14581     @<Absorb undelimited parameters, putting them into list |r|@>;
14582   }
14583   mp_check_equals(mp);
14584   p=mp_get_avail(mp); info(p)=c; mp_link(q)=p;
14585   @<Attach the replacement text to the tail of node |p|@>;
14586   mp->scanner_status=normal; mp_get_x_next(mp);
14587 }
14588
14589 @ We don't put `|frozen_end_group|' into the replacement text of
14590 a \&{vardef}, because the user may want to redefine `\.{endgroup}'.
14591
14592 @<Attach the replacement text to the tail of node |p|@>=
14593 if ( m==start_def ) {
14594   mp_link(p)=mp_scan_toks(mp, macro_def,r,null,n);
14595 } else { 
14596   q=mp_get_avail(mp); info(q)=mp->bg_loc; mp_link(p)=q;
14597   p=mp_get_avail(mp); info(p)=mp->eg_loc;
14598   mp_link(q)=mp_scan_toks(mp, macro_def,r,p,n);
14599 }
14600 if ( mp->warning_info==bad_vardef ) 
14601   mp_flush_token_list(mp, value(bad_vardef))
14602
14603 @ @<Glob...@>=
14604 int bg_loc;
14605 int eg_loc; /* hash addresses of `\.{begingroup}' and `\.{endgroup}' */
14606
14607 @ @<Scan the token or variable to be defined;...@>=
14608 if ( m==start_def ) {
14609   mp_get_clear_symbol(mp); mp->warning_info=mp->cur_sym; get_t_next;
14610   mp->scanner_status=op_defining; n=0;
14611   eq_type(mp->warning_info)=defined_macro; equiv(mp->warning_info)=q;
14612 } else { 
14613   p=mp_scan_declared_variable(mp);
14614   mp_flush_variable(mp, equiv(info(p)),mp_link(p),true);
14615   mp->warning_info=mp_find_variable(mp, p); mp_flush_list(mp, p);
14616   if ( mp->warning_info==null ) @<Change to `\.{a bad variable}'@>;
14617   mp->scanner_status=var_defining; n=2;
14618   if ( mp->cur_cmd==macro_special ) if ( mp->cur_mod==macro_suffix ) {/* \.{\AT!\#} */
14619     n=3; get_t_next;
14620   }
14621   type(mp->warning_info)=mp_unsuffixed_macro-2+n; value(mp->warning_info)=q;
14622 } /* |mp_suffixed_macro=mp_unsuffixed_macro+1| */
14623
14624 @ @<Change to `\.{a bad variable}'@>=
14625
14626   print_err("This variable already starts with a macro");
14627 @.This variable already...@>
14628   help2("After `vardef a' you can\'t say `vardef a.b'.",
14629         "So I'll have to discard this definition.");
14630   mp_error(mp); mp->warning_info=bad_vardef;
14631 }
14632
14633 @ @<Initialize table entries...@>=
14634 name_type(bad_vardef)=mp_root; mp_link(bad_vardef)=frozen_bad_vardef;
14635 equiv(frozen_bad_vardef)=bad_vardef; eq_type(frozen_bad_vardef)=tag_token;
14636
14637 @ @<Absorb delimited parameters, putting them into lists |q| and |r|@>=
14638 do {  
14639   l_delim=mp->cur_sym; r_delim=mp->cur_mod; get_t_next;
14640   if ( (mp->cur_cmd==param_type)&&(mp->cur_mod>=expr_base) ) {
14641    base=mp->cur_mod;
14642   } else { 
14643     print_err("Missing parameter type; `expr' will be assumed");
14644 @.Missing parameter type@>
14645     help1("You should've had `expr' or `suffix' or `text' here.");
14646     mp_back_error(mp); base=expr_base;
14647   }
14648   @<Absorb parameter tokens for type |base|@>;
14649   mp_check_delimiter(mp, l_delim,r_delim);
14650   get_t_next;
14651 } while (mp->cur_cmd==left_delimiter)
14652
14653 @ @<Absorb parameter tokens for type |base|@>=
14654 do { 
14655   mp_link(q)=mp_get_avail(mp); q=mp_link(q); info(q)=base+k;
14656   mp_get_symbol(mp); p=mp_get_node(mp, token_node_size); 
14657   value(p)=base+k; info(p)=mp->cur_sym;
14658   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14659 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
14660   incr(k); mp_link(p)=r; r=p; get_t_next;
14661 } while (mp->cur_cmd==comma)
14662
14663 @ @<Absorb undelimited parameters, putting them into list |r|@>=
14664
14665   p=mp_get_node(mp, token_node_size);
14666   if ( mp->cur_mod<expr_base ) {
14667     c=mp->cur_mod; value(p)=expr_base+k;
14668   } else { 
14669     value(p)=mp->cur_mod+k;
14670     if ( mp->cur_mod==expr_base ) c=expr_macro;
14671     else if ( mp->cur_mod==suffix_base ) c=suffix_macro;
14672     else c=text_macro;
14673   }
14674   if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14675   incr(k); mp_get_symbol(mp); info(p)=mp->cur_sym; mp_link(p)=r; r=p; get_t_next;
14676   if ( c==expr_macro ) if ( mp->cur_cmd==of_token ) {
14677     c=of_macro; p=mp_get_node(mp, token_node_size);
14678     if ( k==mp->param_size ) mp_overflow(mp, "parameter stack size",mp->param_size);
14679     value(p)=expr_base+k; mp_get_symbol(mp); info(p)=mp->cur_sym;
14680     mp_link(p)=r; r=p; get_t_next;
14681   }
14682 }
14683
14684 @* \[32] Expanding the next token.
14685 Only a few command codes |<min_command| can possibly be returned by
14686 |get_t_next|; in increasing order, they are
14687 |if_test|, |fi_or_else|, |input|, |iteration|, |repeat_loop|,
14688 |exit_test|, |relax|, |scan_tokens|, |expand_after|, and |defined_macro|.
14689
14690 \MP\ usually gets the next token of input by saying |get_x_next|. This is
14691 like |get_t_next| except that it keeps getting more tokens until
14692 finding |cur_cmd>=min_command|. In other words, |get_x_next| expands
14693 macros and removes conditionals or iterations or input instructions that
14694 might be present.
14695
14696 It follows that |get_x_next| might invoke itself recursively. In fact,
14697 there is massive recursion, since macro expansion can involve the
14698 scanning of arbitrarily complex expressions, which in turn involve
14699 macro expansion and conditionals, etc.
14700 @^recursion@>
14701
14702 Therefore it's necessary to declare a whole bunch of |forward|
14703 procedures at this point, and to insert some other procedures
14704 that will be invoked by |get_x_next|.
14705
14706 @<Declarations@>= 
14707 static void mp_scan_primary (MP mp);
14708 static void mp_scan_secondary (MP mp);
14709 static void mp_scan_tertiary (MP mp);
14710 static void mp_scan_expression (MP mp);
14711 static void mp_scan_suffix (MP mp);
14712 static void mp_get_boolean (MP mp);
14713 static void mp_pass_text (MP mp);
14714 static void mp_conditional (MP mp);
14715 static void mp_start_input (MP mp);
14716 static void mp_begin_iteration (MP mp);
14717 static void mp_resume_iteration (MP mp);
14718 static void mp_stop_iteration (MP mp);
14719
14720 @ An auxiliary subroutine called |expand| is used by |get_x_next|
14721 when it has to do exotic expansion commands.
14722
14723 @c 
14724 static void mp_expand (MP mp) {
14725   pointer p; /* for list manipulation */
14726   size_t k; /* something that we hope is |<=buf_size| */
14727   pool_pointer j; /* index into |str_pool| */
14728   if ( mp->internal[mp_tracing_commands]>unity ) 
14729     if ( mp->cur_cmd!=defined_macro )
14730       show_cur_cmd_mod;
14731   switch (mp->cur_cmd)  {
14732   case if_test:
14733     mp_conditional(mp); /* this procedure is discussed in Part 36 below */
14734     break;
14735   case fi_or_else:
14736     @<Terminate the current conditional and skip to \&{fi}@>;
14737     break;
14738   case input:
14739     @<Initiate or terminate input from a file@>;
14740     break;
14741   case iteration:
14742     if ( mp->cur_mod==end_for ) {
14743       @<Scold the user for having an extra \&{endfor}@>;
14744     } else {
14745       mp_begin_iteration(mp); /* this procedure is discussed in Part 37 below */
14746     }
14747     break;
14748   case repeat_loop: 
14749     @<Repeat a loop@>;
14750     break;
14751   case exit_test: 
14752     @<Exit a loop if the proper time has come@>;
14753     break;
14754   case relax: 
14755     break;
14756   case expand_after: 
14757     @<Expand the token after the next token@>;
14758     break;
14759   case scan_tokens: 
14760     @<Put a string into the input buffer@>;
14761     break;
14762   case defined_macro:
14763    mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14764    break;
14765   }; /* there are no other cases */
14766 }
14767
14768 @ @<Scold the user...@>=
14769
14770   print_err("Extra `endfor'");
14771 @.Extra `endfor'@>
14772   help2("I'm not currently working on a for loop,",
14773         "so I had better not try to end anything.");
14774   mp_error(mp);
14775 }
14776
14777 @ The processing of \&{input} involves the |start_input| subroutine,
14778 which will be declared later; the processing of \&{endinput} is trivial.
14779
14780 @<Put each...@>=
14781 mp_primitive(mp, "input",input,0);
14782 @:input_}{\&{input} primitive@>
14783 mp_primitive(mp, "endinput",input,1);
14784 @:end_input_}{\&{endinput} primitive@>
14785
14786 @ @<Cases of |print_cmd_mod|...@>=
14787 case input: 
14788   if ( m==0 ) mp_print(mp, "input");
14789   else mp_print(mp, "endinput");
14790   break;
14791
14792 @ @<Initiate or terminate input...@>=
14793 if ( mp->cur_mod>0 ) mp->force_eof=true;
14794 else mp_start_input(mp)
14795
14796 @ We'll discuss the complicated parts of loop operations later. For now
14797 it suffices to know that there's a global variable called |loop_ptr|
14798 that will be |null| if no loop is in progress.
14799
14800 @<Repeat a loop@>=
14801 { while ( token_state &&(loc==null) ) 
14802     mp_end_token_list(mp); /* conserve stack space */
14803   if ( mp->loop_ptr==null ) {
14804     print_err("Lost loop");
14805 @.Lost loop@>
14806     help2("I'm confused; after exiting from a loop, I still seem",
14807           "to want to repeat it. I'll try to forget the problem.");
14808     mp_error(mp);
14809   } else {
14810     mp_resume_iteration(mp); /* this procedure is in Part 37 below */
14811   }
14812 }
14813
14814 @ @<Exit a loop if the proper time has come@>=
14815 { mp_get_boolean(mp);
14816   if ( mp->internal[mp_tracing_commands]>unity ) 
14817     mp_show_cmd_mod(mp, nullary,mp->cur_exp);
14818   if ( mp->cur_exp==true_code ) {
14819     if ( mp->loop_ptr==null ) {
14820       print_err("No loop is in progress");
14821 @.No loop is in progress@>
14822       help1("Why say `exitif' when there's nothing to exit from?");
14823       if ( mp->cur_cmd==semicolon ) mp_error(mp); else mp_back_error(mp);
14824     } else {
14825      @<Exit prematurely from an iteration@>;
14826     }
14827   } else if ( mp->cur_cmd!=semicolon ) {
14828     mp_missing_err(mp, ";");
14829 @.Missing `;'@>
14830     help2("After `exitif <boolean exp>' I expect to see a semicolon.",
14831           "I shall pretend that one was there."); mp_back_error(mp);
14832   }
14833 }
14834
14835 @ Here we use the fact that |forever_text| is the only |token_type| that
14836 is less than |loop_text|.
14837
14838 @<Exit prematurely...@>=
14839 { p=null;
14840   do {  
14841     if ( file_state ) {
14842       mp_end_file_reading(mp);
14843     } else { 
14844       if ( token_type<=loop_text ) p=start;
14845       mp_end_token_list(mp);
14846     }
14847   } while (p==null);
14848   if ( p!=info(mp->loop_ptr) ) mp_fatal_error(mp, "*** (loop confusion)");
14849 @.loop confusion@>
14850   mp_stop_iteration(mp); /* this procedure is in Part 34 below */
14851 }
14852
14853 @ @<Expand the token after the next token@>=
14854 { get_t_next;
14855   p=mp_cur_tok(mp); get_t_next;
14856   if ( mp->cur_cmd<min_command ) mp_expand(mp); 
14857   else mp_back_input(mp);
14858   back_list(p);
14859 }
14860
14861 @ @<Put a string into the input buffer@>=
14862 { mp_get_x_next(mp); mp_scan_primary(mp);
14863   if ( mp->cur_type!=mp_string_type ) {
14864     mp_disp_err(mp, null,"Not a string");
14865 @.Not a string@>
14866     help2("I'm going to flush this expression, since",
14867           "scantokens should be followed by a known string.");
14868     mp_put_get_flush_error(mp, 0);
14869   } else { 
14870     mp_back_input(mp);
14871     if ( length(mp->cur_exp)>0 )
14872        @<Pretend we're reading a new one-line file@>;
14873   }
14874 }
14875
14876 @ @<Pretend we're reading a new one-line file@>=
14877 { mp_begin_file_reading(mp); name=is_scantok;
14878   k=mp->first+length(mp->cur_exp);
14879   if ( k>=mp->max_buf_stack ) {
14880     while ( k>=mp->buf_size ) {
14881       mp_reallocate_buffer(mp,(mp->buf_size+(mp->buf_size/4)));
14882     }
14883     mp->max_buf_stack=k+1;
14884   }
14885   j=mp->str_start[mp->cur_exp]; limit=(halfword)k;
14886   while ( mp->first<(size_t)limit ) {
14887     mp->buffer[mp->first]=mp->str_pool[j]; incr(j); incr(mp->first);
14888   }
14889   mp->buffer[limit]=xord('%'); mp->first=(size_t)(limit+1); loc=start; 
14890   mp_flush_cur_exp(mp, 0);
14891 }
14892
14893 @ Here finally is |get_x_next|.
14894
14895 The expression scanning routines to be considered later
14896 communicate via the global quantities |cur_type| and |cur_exp|;
14897 we must be very careful to save and restore these quantities while
14898 macros are being expanded.
14899 @^inner loop@>
14900
14901 @<Declarations@>=
14902 static void mp_get_x_next (MP mp);
14903
14904 @ @c void mp_get_x_next (MP mp) {
14905   pointer save_exp; /* a capsule to save |cur_type| and |cur_exp| */
14906   get_t_next;
14907   if ( mp->cur_cmd<min_command ) {
14908     save_exp=mp_stash_cur_exp(mp);
14909     do {  
14910       if ( mp->cur_cmd==defined_macro ) 
14911         mp_macro_call(mp, mp->cur_mod,null,mp->cur_sym);
14912       else 
14913         mp_expand(mp);
14914       get_t_next;
14915      } while (mp->cur_cmd<min_command);
14916      mp_unstash_cur_exp(mp, save_exp); /* that restores |cur_type| and |cur_exp| */
14917   }
14918 }
14919
14920 @ Now let's consider the |macro_call| procedure, which is used to start up
14921 all user-defined macros. Since the arguments to a macro might be expressions,
14922 |macro_call| is recursive.
14923 @^recursion@>
14924
14925 The first parameter to |macro_call| points to the reference count of the
14926 token list that defines the macro. The second parameter contains any
14927 arguments that have already been parsed (see below).  The third parameter
14928 points to the symbolic token that names the macro. If the third parameter
14929 is |null|, the macro was defined by \&{vardef}, so its name can be
14930 reconstructed from the prefix and ``at'' arguments found within the
14931 second parameter.
14932
14933 What is this second parameter? It's simply a linked list of one-word items,
14934 whose |info| fields point to the arguments. In other words, if |arg_list=null|,
14935 no arguments have been scanned yet; otherwise |info(arg_list)| points to
14936 the first scanned argument, and |mp_link(arg_list)| points to the list of
14937 further arguments (if any).
14938
14939 Arguments of type \&{expr} are so-called capsules, which we will
14940 discuss later when we concentrate on expressions; they can be
14941 recognized easily because their |link| field is |void|. Arguments of type
14942 \&{suffix} and \&{text} are token lists without reference counts.
14943
14944 @ After argument scanning is complete, the arguments are moved to the
14945 |param_stack|. (They can't be put on that stack any sooner, because
14946 the stack is growing and shrinking in unpredictable ways as more arguments
14947 are being acquired.)  Then the macro body is fed to the scanner; i.e.,
14948 the replacement text of the macro is placed at the top of the \MP's
14949 input stack, so that |get_t_next| will proceed to read it next.
14950
14951 @<Declarations@>=
14952 static void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14953                     pointer macro_name) ;
14954
14955 @ @c
14956 void mp_macro_call (MP mp,pointer def_ref, pointer arg_list, 
14957                     pointer macro_name) {
14958   /* invokes a user-defined control sequence */
14959   pointer r; /* current node in the macro's token list */
14960   pointer p,q; /* for list manipulation */
14961   integer n; /* the number of arguments */
14962   pointer tail = 0; /* tail of the argument list */
14963   pointer l_delim=0,r_delim=0; /* a delimiter pair */
14964   r=mp_link(def_ref); add_mac_ref(def_ref);
14965   if ( arg_list==null ) {
14966     n=0;
14967   } else {
14968    @<Determine the number |n| of arguments already supplied,
14969     and set |tail| to the tail of |arg_list|@>;
14970   }
14971   if ( mp->internal[mp_tracing_macros]>0 ) {
14972     @<Show the text of the macro being expanded, and the existing arguments@>;
14973   }
14974   @<Scan the remaining arguments, if any; set |r| to the first token
14975     of the replacement text@>;
14976   @<Feed the arguments and replacement text to the scanner@>;
14977 }
14978
14979 @ @<Show the text of the macro...@>=
14980 mp_begin_diagnostic(mp); mp_print_ln(mp); 
14981 mp_print_macro_name(mp, arg_list,macro_name);
14982 if ( n==3 ) mp_print(mp, "@@#"); /* indicate a suffixed macro */
14983 mp_show_macro(mp, def_ref,null,100000);
14984 if ( arg_list!=null ) {
14985   n=0; p=arg_list;
14986   do {  
14987     q=info(p);
14988     mp_print_arg(mp, q,n,0);
14989     incr(n); p=mp_link(p);
14990   } while (p!=null);
14991 }
14992 mp_end_diagnostic(mp, false)
14993
14994
14995 @ @<Declarations@>=
14996 static void mp_print_macro_name (MP mp,pointer a, pointer n);
14997
14998 @ @c
14999 void mp_print_macro_name (MP mp,pointer a, pointer n) {
15000   pointer p,q; /* they traverse the first part of |a| */
15001   if ( n!=null ) {
15002     mp_print_text(n);
15003   } else  { 
15004     p=info(a);
15005     if ( p==null ) {
15006       mp_print_text(info(info(mp_link(a))));
15007     } else { 
15008       q=p;
15009       while ( mp_link(q)!=null ) q=mp_link(q);
15010       mp_link(q)=info(mp_link(a));
15011       mp_show_token_list(mp, p,null,1000,0);
15012       mp_link(q)=null;
15013     }
15014   }
15015 }
15016
15017 @ @<Declarations@>=
15018 static void mp_print_arg (MP mp,pointer q, integer n, pointer b) ;
15019
15020 @ @c
15021 void mp_print_arg (MP mp,pointer q, integer n, pointer b) {
15022   if ( mp_link(q)==mp_void ) mp_print_nl(mp, "(EXPR");
15023   else if ( (b<text_base)&&(b!=text_macro) ) mp_print_nl(mp, "(SUFFIX");
15024   else mp_print_nl(mp, "(TEXT");
15025   mp_print_int(mp, n); mp_print(mp, ")<-");
15026   if ( mp_link(q)==mp_void ) mp_print_exp(mp, q,1);
15027   else mp_show_token_list(mp, q,null,1000,0);
15028 }
15029
15030 @ @<Determine the number |n| of arguments already supplied...@>=
15031 {  
15032   n=1; tail=arg_list;
15033   while ( mp_link(tail)!=null ) { 
15034     incr(n); tail=mp_link(tail);
15035   }
15036 }
15037
15038 @ @<Scan the remaining arguments, if any; set |r|...@>=
15039 mp->cur_cmd=comma+1; /* anything |<>comma| will do */
15040 while ( info(r)>=expr_base ) { 
15041   @<Scan the delimited argument represented by |info(r)|@>;
15042   r=mp_link(r);
15043 }
15044 if ( mp->cur_cmd==comma ) {
15045   print_err("Too many arguments to ");
15046 @.Too many arguments...@>
15047   mp_print_macro_name(mp, arg_list,macro_name); mp_print_char(mp, xord(';'));
15048   mp_print_nl(mp, "  Missing `"); mp_print_text(r_delim);
15049 @.Missing `)'...@>
15050   mp_print(mp, "' has been inserted");
15051   help3("I'm going to assume that the comma I just read was a",
15052    "right delimiter, and then I'll begin expanding the macro.",
15053    "You might want to delete some tokens before continuing.");
15054   mp_error(mp);
15055 }
15056 if ( info(r)!=general_macro ) {
15057   @<Scan undelimited argument(s)@>;
15058 }
15059 r=mp_link(r)
15060
15061 @ At this point, the reader will find it advisable to review the explanation
15062 of token list format that was presented earlier, paying special attention to
15063 the conventions that apply only at the beginning of a macro's token list.
15064
15065 On the other hand, the reader will have to take the expression-parsing
15066 aspects of the following program on faith; we will explain |cur_type|
15067 and |cur_exp| later. (Several things in this program depend on each other,
15068 and it's necessary to jump into the circle somewhere.)
15069
15070 @<Scan the delimited argument represented by |info(r)|@>=
15071 if ( mp->cur_cmd!=comma ) {
15072   mp_get_x_next(mp);
15073   if ( mp->cur_cmd!=left_delimiter ) {
15074     print_err("Missing argument to ");
15075 @.Missing argument...@>
15076     mp_print_macro_name(mp, arg_list,macro_name);
15077     help3("That macro has more parameters than you thought.",
15078      "I'll continue by pretending that each missing argument",
15079      "is either zero or null.");
15080     if ( info(r)>=suffix_base ) {
15081       mp->cur_exp=null; mp->cur_type=mp_token_list;
15082     } else { 
15083       mp->cur_exp=0; mp->cur_type=mp_known;
15084     }
15085     mp_back_error(mp); mp->cur_cmd=right_delimiter; 
15086     goto FOUND;
15087   }
15088   l_delim=mp->cur_sym; r_delim=mp->cur_mod;
15089 }
15090 @<Scan the argument represented by |info(r)|@>;
15091 if ( mp->cur_cmd!=comma ) 
15092   @<Check that the proper right delimiter was present@>;
15093 FOUND:  
15094 @<Append the current expression to |arg_list|@>
15095
15096 @ @<Check that the proper right delim...@>=
15097 if ( (mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
15098   if ( info(mp_link(r))>=expr_base ) {
15099     mp_missing_err(mp, ",");
15100 @.Missing `,'@>
15101     help3("I've finished reading a macro argument and am about to",
15102       "read another; the arguments weren't delimited correctly.",
15103       "You might want to delete some tokens before continuing.");
15104     mp_back_error(mp); mp->cur_cmd=comma;
15105   } else { 
15106     mp_missing_err(mp, str(text(r_delim)));
15107 @.Missing `)'@>
15108     help2("I've gotten to the end of the macro parameter list.",
15109           "You might want to delete some tokens before continuing.");
15110     mp_back_error(mp);
15111   }
15112 }
15113
15114 @ A \&{suffix} or \&{text} parameter will have been scanned as
15115 a token list pointed to by |cur_exp|, in which case we will have
15116 |cur_type=token_list|.
15117
15118 @<Append the current expression to |arg_list|@>=
15119
15120   p=mp_get_avail(mp);
15121   if ( mp->cur_type==mp_token_list ) info(p)=mp->cur_exp;
15122   else info(p)=mp_stash_cur_exp(mp);
15123   if ( mp->internal[mp_tracing_macros]>0 ) {
15124     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,info(r)); 
15125     mp_end_diagnostic(mp, false);
15126   }
15127   if ( arg_list==null ) arg_list=p;
15128   else mp_link(tail)=p;
15129   tail=p; incr(n);
15130 }
15131
15132 @ @<Scan the argument represented by |info(r)|@>=
15133 if ( info(r)>=text_base ) {
15134   mp_scan_text_arg(mp, l_delim,r_delim);
15135 } else { 
15136   mp_get_x_next(mp);
15137   if ( info(r)>=suffix_base ) mp_scan_suffix(mp);
15138   else mp_scan_expression(mp);
15139 }
15140
15141 @ The parameters to |scan_text_arg| are either a pair of delimiters
15142 or zero; the latter case is for undelimited text arguments, which
15143 end with the first semicolon or \&{endgroup} or \&{end} that is not
15144 contained in a group.
15145
15146 @<Declarations@>=
15147 static void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) ;
15148
15149 @ @c
15150 void mp_scan_text_arg (MP mp,pointer l_delim, pointer r_delim) {
15151   integer balance; /* excess of |l_delim| over |r_delim| */
15152   pointer p; /* list tail */
15153   mp->warning_info=l_delim; mp->scanner_status=absorbing;
15154   p=hold_head; balance=1; mp_link(hold_head)=null;
15155   while (1)  { 
15156     get_t_next;
15157     if ( l_delim==0 ) {
15158       @<Adjust the balance for an undelimited argument; |break| if done@>;
15159     } else {
15160           @<Adjust the balance for a delimited argument; |break| if done@>;
15161     }
15162     mp_link(p)=mp_cur_tok(mp); p=mp_link(p);
15163   }
15164   mp->cur_exp=mp_link(hold_head); mp->cur_type=mp_token_list;
15165   mp->scanner_status=normal;
15166 }
15167
15168 @ @<Adjust the balance for a delimited argument...@>=
15169 if ( mp->cur_cmd==right_delimiter ) { 
15170   if ( mp->cur_mod==l_delim ) { 
15171     decr(balance);
15172     if ( balance==0 ) break;
15173   }
15174 } else if ( mp->cur_cmd==left_delimiter ) {
15175   if ( mp->cur_mod==r_delim ) incr(balance);
15176 }
15177
15178 @ @<Adjust the balance for an undelimited...@>=
15179 if ( end_of_statement ) { /* |cur_cmd=semicolon|, |end_group|, or |stop| */
15180   if ( balance==1 ) { break; }
15181   else  { if ( mp->cur_cmd==end_group ) decr(balance); }
15182 } else if ( mp->cur_cmd==begin_group ) { 
15183   incr(balance); 
15184 }
15185
15186 @ @<Scan undelimited argument(s)@>=
15187
15188   if ( info(r)<text_macro ) {
15189     mp_get_x_next(mp);
15190     if ( info(r)!=suffix_macro ) {
15191       if ( (mp->cur_cmd==equals)||(mp->cur_cmd==assignment) ) mp_get_x_next(mp);
15192     }
15193   }
15194   switch (info(r)) {
15195   case primary_macro:mp_scan_primary(mp); break;
15196   case secondary_macro:mp_scan_secondary(mp); break;
15197   case tertiary_macro:mp_scan_tertiary(mp); break;
15198   case expr_macro:mp_scan_expression(mp); break;
15199   case of_macro:
15200     @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>;
15201     break;
15202   case suffix_macro:
15203     @<Scan a suffix with optional delimiters@>;
15204     break;
15205   case text_macro:mp_scan_text_arg(mp, 0,0); break;
15206   } /* there are no other cases */
15207   mp_back_input(mp); 
15208   @<Append the current expression to |arg_list|@>;
15209 }
15210
15211 @ @<Scan an expression followed by `\&{of} $\langle$primary$\rangle$'@>=
15212
15213   mp_scan_expression(mp); p=mp_get_avail(mp); info(p)=mp_stash_cur_exp(mp);
15214   if ( mp->internal[mp_tracing_macros]>0 ) { 
15215     mp_begin_diagnostic(mp); mp_print_arg(mp, info(p),n,0); 
15216     mp_end_diagnostic(mp, false);
15217   }
15218   if ( arg_list==null ) arg_list=p; else mp_link(tail)=p;
15219   tail=p;incr(n);
15220   if ( mp->cur_cmd!=of_token ) {
15221     mp_missing_err(mp, "of"); mp_print(mp, " for ");
15222 @.Missing `of'@>
15223     mp_print_macro_name(mp, arg_list,macro_name);
15224     help1("I've got the first argument; will look now for the other.");
15225     mp_back_error(mp);
15226   }
15227   mp_get_x_next(mp); mp_scan_primary(mp);
15228 }
15229
15230 @ @<Scan a suffix with optional delimiters@>=
15231
15232   if ( mp->cur_cmd!=left_delimiter ) {
15233     l_delim=null;
15234   } else { 
15235     l_delim=mp->cur_sym; r_delim=mp->cur_mod; mp_get_x_next(mp);
15236   };
15237   mp_scan_suffix(mp);
15238   if ( l_delim!=null ) {
15239     if ((mp->cur_cmd!=right_delimiter)||(mp->cur_mod!=l_delim) ) {
15240       mp_missing_err(mp, str(text(r_delim)));
15241 @.Missing `)'@>
15242       help2("I've gotten to the end of the macro parameter list.",
15243             "You might want to delete some tokens before continuing.");
15244       mp_back_error(mp);
15245     }
15246     mp_get_x_next(mp);
15247   }
15248 }
15249
15250 @ Before we put a new token list on the input stack, it is wise to clean off
15251 all token lists that have recently been depleted. Then a user macro that ends
15252 with a call to itself will not require unbounded stack space.
15253
15254 @<Feed the arguments and replacement text to the scanner@>=
15255 while ( token_state &&(loc==null) ) mp_end_token_list(mp); /* conserve stack space */
15256 if ( mp->param_ptr+n>mp->max_param_stack ) {
15257   mp->max_param_stack=mp->param_ptr+n;
15258   if ( mp->max_param_stack>mp->param_size )
15259     mp_overflow(mp, "parameter stack size",mp->param_size);
15260 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
15261 }
15262 mp_begin_token_list(mp, def_ref,macro); name=macro_name; loc=r;
15263 if ( n>0 ) {
15264   p=arg_list;
15265   do {  
15266    mp->param_stack[mp->param_ptr]=info(p); incr(mp->param_ptr); p=mp_link(p);
15267   } while (p!=null);
15268   mp_flush_list(mp, arg_list);
15269 }
15270
15271 @ It's sometimes necessary to put a single argument onto |param_stack|.
15272 The |stack_argument| subroutine does this.
15273
15274 @c 
15275 static void mp_stack_argument (MP mp,pointer p) { 
15276   if ( mp->param_ptr==mp->max_param_stack ) {
15277     incr(mp->max_param_stack);
15278     if ( mp->max_param_stack>mp->param_size )
15279       mp_overflow(mp, "parameter stack size",mp->param_size);
15280 @:MetaPost capacity exceeded parameter stack size}{\quad parameter stack size@>
15281   }
15282   mp->param_stack[mp->param_ptr]=p; incr(mp->param_ptr);
15283 }
15284
15285 @* \[33] Conditional processing.
15286 Let's consider now the way \&{if} commands are handled.
15287
15288 Conditions can be inside conditions, and this nesting has a stack
15289 that is independent of other stacks.
15290 Four global variables represent the top of the condition stack:
15291 |cond_ptr| points to pushed-down entries, if~any; |cur_if| tells whether
15292 we are processing \&{if} or \&{elseif}; |if_limit| specifies
15293 the largest code of a |fi_or_else| command that is syntactically legal;
15294 and |if_line| is the line number at which the current conditional began.
15295
15296 If no conditions are currently in progress, the condition stack has the
15297 special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
15298 Otherwise |cond_ptr| points to a two-word node; the |type|, |name_type|, and
15299 |link| fields of the first word contain |if_limit|, |cur_if|, and
15300 |cond_ptr| at the next level, and the second word contains the
15301 corresponding |if_line|.
15302
15303 @d if_node_size 2 /* number of words in stack entry for conditionals */
15304 @d if_line_field(A) mp->mem[(A)+1].cint
15305 @d if_code 1 /* code for \&{if} being evaluated */
15306 @d fi_code 2 /* code for \&{fi} */
15307 @d else_code 3 /* code for \&{else} */
15308 @d else_if_code 4 /* code for \&{elseif} */
15309
15310 @<Glob...@>=
15311 pointer cond_ptr; /* top of the condition stack */
15312 integer if_limit; /* upper bound on |fi_or_else| codes */
15313 quarterword cur_if; /* type of conditional being worked on */
15314 integer if_line; /* line where that conditional began */
15315
15316 @ @<Set init...@>=
15317 mp->cond_ptr=null; mp->if_limit=normal; mp->cur_if=0; mp->if_line=0;
15318
15319 @ @<Put each...@>=
15320 mp_primitive(mp, "if",if_test,if_code);
15321 @:if_}{\&{if} primitive@>
15322 mp_primitive(mp, "fi",fi_or_else,fi_code); mp->eqtb[frozen_fi]=mp->eqtb[mp->cur_sym];
15323 @:fi_}{\&{fi} primitive@>
15324 mp_primitive(mp, "else",fi_or_else,else_code);
15325 @:else_}{\&{else} primitive@>
15326 mp_primitive(mp, "elseif",fi_or_else,else_if_code);
15327 @:else_if_}{\&{elseif} primitive@>
15328
15329 @ @<Cases of |print_cmd_mod|...@>=
15330 case if_test:
15331 case fi_or_else: 
15332   switch (m) {
15333   case if_code:mp_print(mp, "if"); break;
15334   case fi_code:mp_print(mp, "fi");  break;
15335   case else_code:mp_print(mp, "else"); break;
15336   default: mp_print(mp, "elseif"); break;
15337   }
15338   break;
15339
15340 @ Here is a procedure that ignores text until coming to an \&{elseif},
15341 \&{else}, or \&{fi} at level zero of $\&{if}\ldots\&{fi}$
15342 nesting. After it has acted, |cur_mod| will indicate the token that
15343 was found.
15344
15345 \MP's smallest two command codes are |if_test| and |fi_or_else|; this
15346 makes the skipping process a bit simpler.
15347
15348 @c 
15349 void mp_pass_text (MP mp) {
15350   integer l = 0;
15351   mp->scanner_status=skipping;
15352   mp->warning_info=mp_true_line(mp);
15353   while (1)  { 
15354     get_t_next;
15355     if ( mp->cur_cmd<=fi_or_else ) {
15356       if ( mp->cur_cmd<fi_or_else ) {
15357         incr(l);
15358       } else { 
15359         if ( l==0 ) break;
15360         if ( mp->cur_mod==fi_code ) decr(l);
15361       }
15362     } else {
15363       @<Decrease the string reference count,
15364        if the current token is a string@>;
15365     }
15366   }
15367   mp->scanner_status=normal;
15368 }
15369
15370 @ @<Decrease the string reference count...@>=
15371 if ( mp->cur_cmd==string_token ) { delete_str_ref(mp->cur_mod); }
15372
15373 @ When we begin to process a new \&{if}, we set |if_limit:=if_code|; then
15374 if \&{elseif} or \&{else} or \&{fi} occurs before the current \&{if}
15375 condition has been evaluated, a colon will be inserted.
15376 A construction like `\.{if fi}' would otherwise get \MP\ confused.
15377
15378 @<Push the condition stack@>=
15379 { p=mp_get_node(mp, if_node_size); mp_link(p)=mp->cond_ptr; type(p)=mp->if_limit;
15380   name_type(p)=mp->cur_if; if_line_field(p)=mp->if_line;
15381   mp->cond_ptr=p; mp->if_limit=if_code; mp->if_line=mp_true_line(mp); 
15382   mp->cur_if=if_code;
15383 }
15384
15385 @ @<Pop the condition stack@>=
15386 { p=mp->cond_ptr; mp->if_line=if_line_field(p);
15387   mp->cur_if=name_type(p); mp->if_limit=type(p); mp->cond_ptr=mp_link(p);
15388   mp_free_node(mp, p,if_node_size);
15389 }
15390
15391 @ Here's a procedure that changes the |if_limit| code corresponding to
15392 a given value of |cond_ptr|.
15393
15394 @c 
15395 static void mp_change_if_limit (MP mp,quarterword l, pointer p) {
15396   pointer q;
15397   if ( p==mp->cond_ptr ) {
15398     mp->if_limit=l; /* that's the easy case */
15399   } else  { 
15400     q=mp->cond_ptr;
15401     while (1) { 
15402       if ( q==null ) mp_confusion(mp, "if");
15403 @:this can't happen if}{\quad if@>
15404       if ( mp_link(q)==p ) { 
15405         type(q)=l; return;
15406       }
15407       q=mp_link(q);
15408     }
15409   }
15410 }
15411
15412 @ The user is supposed to put colons into the proper parts of conditional
15413 statements. Therefore, \MP\ has to check for their presence.
15414
15415 @c 
15416 static void mp_check_colon (MP mp) { 
15417   if ( mp->cur_cmd!=colon ) { 
15418     mp_missing_err(mp, ":");
15419 @.Missing `:'@>
15420     help2("There should've been a colon after the condition.",
15421           "I shall pretend that one was there.");
15422     mp_back_error(mp);
15423   }
15424 }
15425
15426 @ A condition is started when the |get_x_next| procedure encounters
15427 an |if_test| command; in that case |get_x_next| calls |conditional|,
15428 which is a recursive procedure.
15429 @^recursion@>
15430
15431 @c 
15432 void mp_conditional (MP mp) {
15433   pointer save_cond_ptr; /* |cond_ptr| corresponding to this conditional */
15434   int new_if_limit; /* future value of |if_limit| */
15435   pointer p; /* temporary register */
15436   @<Push the condition stack@>; 
15437   save_cond_ptr=mp->cond_ptr;
15438 RESWITCH: 
15439   mp_get_boolean(mp); new_if_limit=else_if_code;
15440   if ( mp->internal[mp_tracing_commands]>unity ) {
15441     @<Display the boolean value of |cur_exp|@>;
15442   }
15443 FOUND: 
15444   mp_check_colon(mp);
15445   if ( mp->cur_exp==true_code ) {
15446     mp_change_if_limit(mp, new_if_limit,save_cond_ptr);
15447     return; /* wait for \&{elseif}, \&{else}, or \&{fi} */
15448   };
15449   @<Skip to \&{elseif} or \&{else} or \&{fi}, then |goto done|@>;
15450 DONE: 
15451   mp->cur_if=mp->cur_mod; mp->if_line=mp_true_line(mp);
15452   if ( mp->cur_mod==fi_code ) {
15453     @<Pop the condition stack@>
15454   } else if ( mp->cur_mod==else_if_code ) {
15455     goto RESWITCH;
15456   } else  { 
15457     mp->cur_exp=true_code; new_if_limit=fi_code; mp_get_x_next(mp); 
15458     goto FOUND;
15459   }
15460 }
15461
15462 @ In a construction like `\&{if} \&{if} \&{true}: $0=1$: \\{foo}
15463 \&{else}: \\{bar} \&{fi}', the first \&{else}
15464 that we come to after learning that the \&{if} is false is not the
15465 \&{else} we're looking for. Hence the following curious logic is needed.
15466
15467 @<Skip to \&{elseif}...@>=
15468 while (1) { 
15469   mp_pass_text(mp);
15470   if ( mp->cond_ptr==save_cond_ptr ) goto DONE;
15471   else if ( mp->cur_mod==fi_code ) @<Pop the condition stack@>;
15472 }
15473
15474
15475 @ @<Display the boolean value...@>=
15476 { mp_begin_diagnostic(mp);
15477   if ( mp->cur_exp==true_code ) mp_print(mp, "{true}");
15478   else mp_print(mp, "{false}");
15479   mp_end_diagnostic(mp, false);
15480 }
15481
15482 @ The processing of conditionals is complete except for the following
15483 code, which is actually part of |get_x_next|. It comes into play when
15484 \&{elseif}, \&{else}, or \&{fi} is scanned.
15485
15486 @<Terminate the current conditional and skip to \&{fi}@>=
15487 if ( mp->cur_mod>mp->if_limit ) {
15488   if ( mp->if_limit==if_code ) { /* condition not yet evaluated */
15489     mp_missing_err(mp, ":");
15490 @.Missing `:'@>
15491     mp_back_input(mp); mp->cur_sym=frozen_colon; mp_ins_error(mp);
15492   } else  { 
15493     print_err("Extra "); mp_print_cmd_mod(mp, fi_or_else,mp->cur_mod);
15494 @.Extra else@>
15495 @.Extra elseif@>
15496 @.Extra fi@>
15497     help1("I'm ignoring this; it doesn't match any if.");
15498     mp_error(mp);
15499   }
15500 } else  { 
15501   while ( mp->cur_mod!=fi_code ) mp_pass_text(mp); /* skip to \&{fi} */
15502   @<Pop the condition stack@>;
15503 }
15504
15505 @* \[34] Iterations.
15506 To bring our treatment of |get_x_next| to a close, we need to consider what
15507 \MP\ does when it sees \&{for}, \&{forsuffixes}, and \&{forever}.
15508
15509 There's a global variable |loop_ptr| that keeps track of the \&{for} loops
15510 that are currently active. If |loop_ptr=null|, no loops are in progress;
15511 otherwise |info(loop_ptr)| points to the iterative text of the current
15512 (innermost) loop, and |mp_link(loop_ptr)| points to the data for any other
15513 loops that enclose the current one.
15514
15515 A loop-control node also has two other fields, called |loop_type| and
15516 |loop_list|, whose contents depend on the type of loop:
15517
15518 \yskip\indent|loop_type(loop_ptr)=null| means that |loop_list(loop_ptr)|
15519 points to a list of one-word nodes whose |info| fields point to the
15520 remaining argument values of a suffix list and expression list.
15521
15522 \yskip\indent|loop_type(loop_ptr)=mp_void| means that the current loop is
15523 `\&{forever}'.
15524
15525 \yskip\indent|loop_type(loop_ptr)=progression_flag| means that
15526 |p=loop_list(loop_ptr)| points to a ``progression node'' and |value(p)|,
15527 |step_size(p)|, and |final_value(p)| contain the data for an arithmetic
15528 progression.
15529
15530 \yskip\indent|loop_type(loop_ptr)=p>mp_void| means that |p| points to an edge
15531 header and |loop_list(loop_ptr)| points into the graphical object list for
15532 that edge header.
15533
15534 \yskip\noindent In the case of a progression node, the first word is not used
15535 because the link field of words in the dynamic memory area cannot be arbitrary.
15536
15537 @d loop_list_loc(A) ((A)+1) /* where the |loop_list| field resides */
15538 @d loop_type(A) info(loop_list_loc((A))) /* the type of \&{for} loop */
15539 @d loop_list(A) mp_link(loop_list_loc((A))) /* the remaining list elements */
15540 @d loop_node_size 2 /* the number of words in a loop control node */
15541 @d progression_node_size 4 /* the number of words in a progression node */
15542 @d step_size(A) mp->mem[(A)+2].sc /* the step size in an arithmetic progression */
15543 @d final_value(A) mp->mem[(A)+3].sc /* the final value in an arithmetic progression */
15544 @d progression_flag (null+2)
15545   /* |loop_type| value when |loop_list| points to a progression node */
15546
15547 @<Glob...@>=
15548 pointer loop_ptr; /* top of the loop-control-node stack */
15549
15550 @ @<Set init...@>=
15551 mp->loop_ptr=null;
15552
15553 @ If the expressions that define an arithmetic progression in
15554 a \&{for} loop don't have known numeric values, the |bad_for|
15555 subroutine screams at the user.
15556
15557 @c 
15558 static void mp_bad_for (MP mp, const char * s) {
15559   mp_disp_err(mp, null,"Improper "); /* show the bad expression above the message */
15560 @.Improper...replaced by 0@>
15561   mp_print(mp, s); mp_print(mp, " has been replaced by 0");
15562   help4("When you say `for x=a step b until c',",
15563     "the initial value `a' and the step size `b'",
15564     "and the final value `c' must have known numeric values.",
15565     "I'm zeroing this one. Proceed, with fingers crossed.");
15566   mp_put_get_flush_error(mp, 0);
15567 }
15568
15569 @ Here's what \MP\ does when \&{for}, \&{forsuffixes}, or \&{forever}
15570 has just been scanned. (This code requires slight familiarity with
15571 expression-parsing routines that we have not yet discussed; but it seems
15572 to belong in the present part of the program, even though the original author
15573 didn't write it until later. The reader may wish to come back to it.)
15574
15575 @c void mp_begin_iteration (MP mp) {
15576   halfword m; /* |expr_base| (\&{for}) or |suffix_base| (\&{forsuffixes}) */
15577   halfword n; /* hash address of the current symbol */
15578   pointer s; /* the new loop-control node */
15579   pointer p; /* substitution list for |scan_toks| */
15580   pointer q;  /* link manipulation register */
15581   pointer pp; /* a new progression node */
15582   m=mp->cur_mod; n=mp->cur_sym; s=mp_get_node(mp, loop_node_size);
15583   if ( m==start_forever ){ 
15584     loop_type(s)=mp_void; p=null; mp_get_x_next(mp);
15585   } else { 
15586     mp_get_symbol(mp); p=mp_get_node(mp, token_node_size);
15587     info(p)=mp->cur_sym; value(p)=m;
15588     mp_get_x_next(mp);
15589     if ( mp->cur_cmd==within_token ) {
15590       @<Set up a picture iteration@>;
15591     } else { 
15592       @<Check for the |"="| or |":="| in a loop header@>;
15593       @<Scan the values to be used in the loop@>;
15594     }
15595   }
15596   @<Check for the presence of a colon@>;
15597   @<Scan the loop text and put it on the loop control stack@>;
15598   mp_resume_iteration(mp);
15599 }
15600
15601 @ @<Check for the |"="| or |":="| in a loop header@>=
15602 if ( (mp->cur_cmd!=equals)&&(mp->cur_cmd!=assignment) ) { 
15603   mp_missing_err(mp, "=");
15604 @.Missing `='@>
15605   help3("The next thing in this loop should have been `=' or `:='.",
15606     "But don't worry; I'll pretend that an equals sign",
15607     "was present, and I'll look for the values next.");
15608   mp_back_error(mp);
15609 }
15610
15611 @ @<Check for the presence of a colon@>=
15612 if ( mp->cur_cmd!=colon ) { 
15613   mp_missing_err(mp, ":");
15614 @.Missing `:'@>
15615   help3("The next thing in this loop should have been a `:'.",
15616     "So I'll pretend that a colon was present;",
15617     "everything from here to `endfor' will be iterated.");
15618   mp_back_error(mp);
15619 }
15620
15621 @ We append a special |frozen_repeat_loop| token in place of the
15622 `\&{endfor}' at the end of the loop. This will come through \MP's scanner
15623 at the proper time to cause the loop to be repeated.
15624
15625 (If the user tries some shenanigan like `\&{for} $\ldots$ \&{let} \&{endfor}',
15626 he will be foiled by the |get_symbol| routine, which keeps frozen
15627 tokens unchanged. Furthermore the |frozen_repeat_loop| is an \&{outer}
15628 token, so it won't be lost accidentally.)
15629
15630 @ @<Scan the loop text...@>=
15631 q=mp_get_avail(mp); info(q)=frozen_repeat_loop;
15632 mp->scanner_status=loop_defining; mp->warning_info=n;
15633 info(s)=mp_scan_toks(mp, iteration,p,q,0); mp->scanner_status=normal;
15634 mp_link(s)=mp->loop_ptr; mp->loop_ptr=s
15635
15636 @ @<Initialize table...@>=
15637 eq_type(frozen_repeat_loop)=repeat_loop+outer_tag;
15638 text(frozen_repeat_loop)=intern(" ENDFOR");
15639
15640 @ The loop text is inserted into \MP's scanning apparatus by the
15641 |resume_iteration| routine.
15642
15643 @c void mp_resume_iteration (MP mp) {
15644   pointer p,q; /* link registers */
15645   p=loop_type(mp->loop_ptr);
15646   if ( p==progression_flag ) { 
15647     p=loop_list(mp->loop_ptr); /* now |p| points to a progression node */
15648     mp->cur_exp=value(p);
15649     if ( @<The arithmetic progression has ended@> ) {
15650       mp_stop_iteration(mp);
15651       return;
15652     }
15653     mp->cur_type=mp_known; q=mp_stash_cur_exp(mp); /* make |q| an \&{expr} argument */
15654     value(p)=mp->cur_exp+step_size(p); /* set |value(p)| for the next iteration */
15655   } else if ( p==null ) { 
15656     p=loop_list(mp->loop_ptr);
15657     if ( p==null ) {
15658       mp_stop_iteration(mp);
15659       return;
15660     }
15661     loop_list(mp->loop_ptr)=mp_link(p); q=info(p); free_avail(p);
15662   } else if ( p==mp_void ) { 
15663     mp_begin_token_list(mp, info(mp->loop_ptr),forever_text); return;
15664   } else {
15665     @<Make |q| a capsule containing the next picture component from
15666       |loop_list(loop_ptr)| or |goto not_found|@>;
15667   }
15668   mp_begin_token_list(mp, info(mp->loop_ptr),loop_text);
15669   mp_stack_argument(mp, q);
15670   if ( mp->internal[mp_tracing_commands]>unity ) {
15671      @<Trace the start of a loop@>;
15672   }
15673   return;
15674 NOT_FOUND:
15675   mp_stop_iteration(mp);
15676 }
15677
15678 @ @<The arithmetic progression has ended@>=
15679 ((step_size(p)>0)&&(mp->cur_exp>final_value(p)))||
15680  ((step_size(p)<0)&&(mp->cur_exp<final_value(p)))
15681
15682 @ @<Trace the start of a loop@>=
15683
15684   mp_begin_diagnostic(mp); mp_print_nl(mp, "{loop value=");
15685 @.loop value=n@>
15686   if ( (q!=null)&&(mp_link(q)==mp_void) ) mp_print_exp(mp, q,1);
15687   else mp_show_token_list(mp, q,null,50,0);
15688   mp_print_char(mp, xord('}')); mp_end_diagnostic(mp, false);
15689 }
15690
15691 @ @<Make |q| a capsule containing the next picture component from...@>=
15692 { q=loop_list(mp->loop_ptr);
15693   if ( q==null ) goto NOT_FOUND;
15694   skip_component(q) goto NOT_FOUND;
15695   mp->cur_exp=mp_copy_objects(mp, loop_list(mp->loop_ptr),q);
15696   mp_init_bbox(mp, mp->cur_exp);
15697   mp->cur_type=mp_picture_type;
15698   loop_list(mp->loop_ptr)=q;
15699   q=mp_stash_cur_exp(mp);
15700 }
15701
15702 @ A level of loop control disappears when |resume_iteration| has decided
15703 not to resume, or when an \&{exitif} construction has removed the loop text
15704 from the input stack.
15705
15706 @c void mp_stop_iteration (MP mp) {
15707   pointer p,q; /* the usual */
15708   p=loop_type(mp->loop_ptr);
15709   if ( p==progression_flag )  {
15710     mp_free_node(mp, loop_list(mp->loop_ptr),progression_node_size);
15711   } else if ( p==null ){ 
15712     q=loop_list(mp->loop_ptr);
15713     while ( q!=null ) {
15714       p=info(q);
15715       if ( p!=null ) {
15716         if ( mp_link(p)==mp_void ) { /* it's an \&{expr} parameter */
15717           mp_recycle_value(mp, p); mp_free_node(mp, p,value_node_size);
15718         } else {
15719           mp_flush_token_list(mp, p); /* it's a \&{suffix} or \&{text} parameter */
15720         }
15721       }
15722       p=q; q=mp_link(q); free_avail(p);
15723     }
15724   } else if ( p>progression_flag ) {
15725     delete_edge_ref(p);
15726   }
15727   p=mp->loop_ptr; mp->loop_ptr=mp_link(p); mp_flush_token_list(mp, info(p));
15728   mp_free_node(mp, p,loop_node_size);
15729 }
15730
15731 @ Now that we know all about loop control, we can finish up
15732 the missing portion of |begin_iteration| and we'll be done.
15733
15734 The following code is performed after the `\.=' has been scanned in
15735 a \&{for} construction (if |m=expr_base|) or a \&{forsuffixes} construction
15736 (if |m=suffix_base|).
15737
15738 @<Scan the values to be used in the loop@>=
15739 loop_type(s)=null; q=loop_list_loc(s); mp_link(q)=null; /* |mp_link(q)=loop_list(s)| */
15740 do {  
15741   mp_get_x_next(mp);
15742   if ( m!=expr_base ) {
15743     mp_scan_suffix(mp);
15744   } else { 
15745     if ( mp->cur_cmd>=colon ) if ( mp->cur_cmd<=comma ) 
15746           goto CONTINUE;
15747     mp_scan_expression(mp);
15748     if ( mp->cur_cmd==step_token ) if ( q==loop_list_loc(s) ) {
15749       @<Prepare for step-until construction and |break|@>;
15750     }
15751     mp->cur_exp=mp_stash_cur_exp(mp);
15752   }
15753   mp_link(q)=mp_get_avail(mp); q=mp_link(q); 
15754   info(q)=mp->cur_exp; mp->cur_type=mp_vacuous;
15755 CONTINUE:
15756   ;
15757 } while (mp->cur_cmd==comma)
15758
15759 @ @<Prepare for step-until construction and |break|@>=
15760
15761   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "initial value");
15762   pp=mp_get_node(mp, progression_node_size); value(pp)=mp->cur_exp;
15763   mp_get_x_next(mp); mp_scan_expression(mp);
15764   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "step size");
15765   step_size(pp)=mp->cur_exp;
15766   if ( mp->cur_cmd!=until_token ) { 
15767     mp_missing_err(mp, "until");
15768 @.Missing `until'@>
15769     help2("I assume you meant to say `until' after `step'.",
15770           "So I'll look for the final value and colon next.");
15771     mp_back_error(mp);
15772   }
15773   mp_get_x_next(mp); mp_scan_expression(mp);
15774   if ( mp->cur_type!=mp_known ) mp_bad_for(mp, "final value");
15775   final_value(pp)=mp->cur_exp; loop_list(s)=pp;
15776   loop_type(s)=progression_flag; 
15777   break;
15778 }
15779
15780 @ The last case is when we have just seen ``\&{within}'', and we need to
15781 parse a picture expression and prepare to iterate over it.
15782
15783 @<Set up a picture iteration@>=
15784 { mp_get_x_next(mp);
15785   mp_scan_expression(mp);
15786   @<Make sure the current expression is a known picture@>;
15787   loop_type(s)=mp->cur_exp; mp->cur_type=mp_vacuous;
15788   q=mp_link(dummy_loc(mp->cur_exp));
15789   if ( q!= null ) 
15790     if ( is_start_or_stop(q) )
15791       if ( mp_skip_1component(mp, q)==null ) q=mp_link(q);
15792   loop_list(s)=q;
15793 }
15794
15795 @ @<Make sure the current expression is a known picture@>=
15796 if ( mp->cur_type!=mp_picture_type ) {
15797   mp_disp_err(mp, null,"Improper iteration spec has been replaced by nullpicture");
15798   help1("When you say `for x in p', p must be a known picture.");
15799   mp_put_get_flush_error(mp, mp_get_node(mp, edge_header_size));
15800   mp_init_edges(mp, mp->cur_exp); mp->cur_type=mp_picture_type;
15801 }
15802
15803 @* \[35] File names.
15804 It's time now to fret about file names.  Besides the fact that different
15805 operating systems treat files in different ways, we must cope with the
15806 fact that completely different naming conventions are used by different
15807 groups of people. The following programs show what is required for one
15808 particular operating system; similar routines for other systems are not
15809 difficult to devise.
15810 @^system dependencies@>
15811
15812 \MP\ assumes that a file name has three parts: the name proper; its
15813 ``extension''; and a ``file area'' where it is found in an external file
15814 system.  The extension of an input file is assumed to be
15815 `\.{.mp}' unless otherwise specified; it is `\.{.log}' on the
15816 transcript file that records each run of \MP; it is `\.{.tfm}' on the font
15817 metric files that describe characters in any fonts created by \MP; it is
15818 `\.{.ps}' or `.{\it nnn}' for some number {\it nnn} on the \ps\ output files;
15819 and it is `\.{.mem}' on the mem files written by \.{INIMP} to initialize \MP.
15820 The file area can be arbitrary on input files, but files are usually
15821 output to the user's current area.  If an input file cannot be
15822 found on the specified area, \MP\ will look for it on a special system
15823 area; this special area is intended for commonly used input files.
15824
15825 Simple uses of \MP\ refer only to file names that have no explicit
15826 extension or area. For example, a person usually says `\.{input} \.{cmr10}'
15827 instead of `\.{input} \.{cmr10.new}'. Simple file
15828 names are best, because they make the \MP\ source files portable;
15829 whenever a file name consists entirely of letters and digits, it should be
15830 treated in the same way by all implementations of \MP. However, users
15831 need the ability to refer to other files in their environment, especially
15832 when responding to error messages concerning unopenable files; therefore
15833 we want to let them use the syntax that appears in their favorite
15834 operating system.
15835
15836 @ \MP\ uses the same conventions that have proved to be satisfactory for
15837 \TeX\ and \MF. In order to isolate the system-dependent aspects of file names,
15838 @^system dependencies@>
15839 the system-independent parts of \MP\ are expressed in terms
15840 of three system-dependent
15841 procedures called |begin_name|, |more_name|, and |end_name|. In
15842 essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
15843 the system-independent driver program does the operations
15844 $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n);
15845 \,|end_name|.$$
15846 These three procedures communicate with each other via global variables.
15847 Afterwards the file name will appear in the string pool as three strings
15848 called |cur_name|\penalty10000\hskip-.05em,
15849 |cur_area|, and |cur_ext|; the latter two are null (i.e.,
15850 |""|), unless they were explicitly specified by the user.
15851
15852 Actually the situation is slightly more complicated, because \MP\ needs
15853 to know when the file name ends. The |more_name| routine is a function
15854 (with side effects) that returns |true| on the calls |more_name|$(c_1)$,
15855 \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
15856 returns |false|; or, it returns |true| and $c_n$ is the last character
15857 on the current input line. In other words,
15858 |more_name| is supposed to return |true| unless it is sure that the
15859 file name has been completely scanned; and |end_name| is supposed to be able
15860 to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
15861 whether $|more_name|(c_n)$ returned |true| or |false|.
15862
15863 @<Glob...@>=
15864 char * cur_name; /* name of file just scanned */
15865 char * cur_area; /* file area just scanned, or \.{""} */
15866 char * cur_ext; /* file extension just scanned, or \.{""} */
15867
15868 @ It is easier to maintain reference counts if we assign initial values.
15869
15870 @<Set init...@>=
15871 mp->cur_name=xstrdup(""); 
15872 mp->cur_area=xstrdup(""); 
15873 mp->cur_ext=xstrdup("");
15874
15875 @ @<Dealloc variables@>=
15876 xfree(mp->cur_area);
15877 xfree(mp->cur_name);
15878 xfree(mp->cur_ext);
15879
15880 @ The file names we shall deal with for illustrative purposes have the
15881 following structure:  If the name contains `\.>' or `\.:', the file area
15882 consists of all characters up to and including the final such character;
15883 otherwise the file area is null.  If the remaining file name contains
15884 `\..', the file extension consists of all such characters from the first
15885 remaining `\..' to the end, otherwise the file extension is null.
15886 @^system dependencies@>
15887
15888 We can scan such file names easily by using two global variables that keep track
15889 of the occurrences of area and extension delimiters.  Note that these variables
15890 cannot be of type |pool_pointer| because a string pool compaction could occur
15891 while scanning a file name.
15892
15893 @<Glob...@>=
15894 integer area_delimiter;
15895   /* most recent `\.>' or `\.:' relative to |str_start[str_ptr]| */
15896 integer ext_delimiter; /* the relevant `\..', if any */
15897
15898 @ Here now is the first of the system-dependent routines for file name scanning.
15899 @^system dependencies@>
15900
15901 The file name length is limited to |file_name_size|. That is good, because
15902 in the current configuration we cannot call |mp_do_compaction| while a name 
15903 is being scanned, |mp->area_delimiter| and |mp->ext_delimiter| are direct
15904 offsets into |mp->str_pool|. I am not in a great hurry to fix this, because 
15905 calling |str_room()| just once is more efficient anyway. TODO.
15906
15907 @<Declarations@>=
15908 static void mp_begin_name (MP mp);
15909 static boolean mp_more_name (MP mp, ASCII_code c);
15910 static void mp_end_name (MP mp);
15911
15912 @ @c
15913 void mp_begin_name (MP mp) { 
15914   xfree(mp->cur_name); 
15915   xfree(mp->cur_area); 
15916   xfree(mp->cur_ext);
15917   mp->area_delimiter=-1; 
15918   mp->ext_delimiter=-1;
15919   str_room(file_name_size); 
15920 }
15921
15922 @ And here's the second.
15923 @^system dependencies@>
15924
15925 @c 
15926 boolean mp_more_name (MP mp, ASCII_code c) {
15927   if (c==' ') {
15928     return false;
15929   } else { 
15930     if ( (c=='>')||(c==':') ) { 
15931       mp->area_delimiter=mp->pool_ptr; 
15932       mp->ext_delimiter=-1;
15933     } else if ( (c=='.')&&(mp->ext_delimiter<0) ) {
15934       mp->ext_delimiter=mp->pool_ptr;
15935     }
15936     append_char(c); /* contribute |c| to the current string */
15937     return true;
15938   }
15939 }
15940
15941 @ The third.
15942 @^system dependencies@>
15943
15944 @d copy_pool_segment(A,B,C) { 
15945       A = xmalloc(C+1,sizeof(char)); 
15946       strncpy(A,(char *)(mp->str_pool+B),C);  
15947       A[C] = 0;}
15948
15949 @c
15950 void mp_end_name (MP mp) {
15951   pool_pointer s; /* length of area, name, and extension */
15952   unsigned int len;
15953   /* "my/w.mp" */
15954   s = mp->str_start[mp->str_ptr];
15955   if ( mp->area_delimiter<0 ) {    
15956     mp->cur_area=xstrdup("");
15957   } else {
15958     len = (unsigned)(mp->area_delimiter-s); 
15959     copy_pool_segment(mp->cur_area,s,len);
15960     s += len+1;
15961   }
15962   if ( mp->ext_delimiter<0 ) {
15963     mp->cur_ext=xstrdup("");
15964     len = (unsigned)(mp->pool_ptr-s); 
15965   } else {
15966     copy_pool_segment(mp->cur_ext,mp->ext_delimiter,(size_t)(mp->pool_ptr-mp->ext_delimiter));
15967     len = (unsigned)(mp->ext_delimiter-s);
15968   }
15969   copy_pool_segment(mp->cur_name,s,len);
15970   mp->pool_ptr=s; /* don't need this partial string */
15971 }
15972
15973 @ Conversely, here is a routine that takes three strings and prints a file
15974 name that might have produced them. (The routine is system dependent, because
15975 some operating systems put the file area last instead of first.)
15976 @^system dependencies@>
15977
15978 @<Basic printing...@>=
15979 static void mp_print_file_name (MP mp, char * n, char * a, char * e) { 
15980   mp_print(mp, a); mp_print(mp, n); mp_print(mp, e);
15981 }
15982
15983 @ Another system-dependent routine is needed to convert three internal
15984 \MP\ strings
15985 to the |name_of_file| value that is used to open files. The present code
15986 allows both lowercase and uppercase letters in the file name.
15987 @^system dependencies@>
15988
15989 @d append_to_name(A) { c=xord((int)(A)); 
15990   if ( k<file_name_size ) {
15991     mp->name_of_file[k]=(char)xchr(c);
15992     incr(k);
15993   }
15994 }
15995
15996 @ @c
15997 void mp_pack_file_name (MP mp, const char *n, const char *a, const char *e) {
15998   integer k; /* number of positions filled in |name_of_file| */
15999   ASCII_code c; /* character being packed */
16000   const char *j; /* a character  index */
16001   k=0;
16002   assert(n!=NULL);
16003   if (a!=NULL) {
16004     for (j=a;*j!='\0';j++) { append_to_name(*j); }
16005   }
16006   for (j=n;*j!='\0';j++) { append_to_name(*j); }
16007   if (e!=NULL) {
16008     for (j=e;*j!='\0';j++) { append_to_name(*j); }
16009   }
16010   mp->name_of_file[k]=0;
16011   mp->name_length=k; 
16012 }
16013
16014 @ @<Internal library declarations@>=
16015 void mp_pack_file_name (MP mp, const char *n, const char *a, const char *e) ;
16016
16017 @ @<Option variables@>=
16018 char *mem_name; /* for commandline */
16019
16020 @ @<Find constant sizes@>=
16021 mp->mem_name = xstrdup(opt->mem_name);
16022 if (mp->mem_name) {
16023   size_t l = strlen(mp->mem_name);
16024   if (l>4) {
16025     char *test = strstr(mp->mem_name,".mem");
16026     if (test == mp->mem_name+l-4) {
16027       *test = 0;
16028     }
16029   }
16030 }
16031
16032
16033 @ @<Dealloc variables@>=
16034 xfree(mp->mem_name);
16035
16036 @ This part of the program becomes active when a ``virgin'' \MP\ is
16037 trying to get going, just after the preliminary initialization, or
16038 when the user is substituting another mem file by typing `\.\&' after
16039 the initial `\.{**}' prompt.  The buffer contains the first line of
16040 input in |buffer[loc..(last-1)]|, where |loc<last| and |buffer[loc]<>""|.
16041
16042 @<Declarations@>=
16043 static boolean mp_open_mem_name (MP mp) ;
16044 static boolean mp_open_mem_file (MP mp) ;
16045
16046 @ @c
16047 boolean mp_open_mem_name (MP mp) {
16048   if (mp->mem_name!=NULL) {
16049     size_t l = strlen(mp->mem_name);
16050     char *s = xstrdup (mp->mem_name);
16051     if (l>4) {
16052       char *test = strstr(s,".mem");
16053       if (test == NULL || test != s+l-4) {
16054         s = xrealloc (s, l+5, 1);       
16055         strcat (s, ".mem");
16056       }
16057     } else {
16058       s = xrealloc (s, l+5, 1);
16059       strcat (s, ".mem");
16060     }
16061     mp->mem_file = (mp->open_file)(mp,s, "r", mp_filetype_memfile);
16062     xfree(s);
16063     if ( mp->mem_file ) return true;
16064   }
16065   return false;
16066 }
16067 boolean mp_open_mem_file (MP mp) {
16068   if (mp->mem_file != NULL)
16069     return true;
16070   if (mp_open_mem_name(mp)) 
16071     return true;
16072   if (mp_xstrcmp(mp->mem_name, "plain")) {
16073     wake_up_terminal;
16074     wterm_ln("Sorry, I can\'t find that mem file; will try PLAIN.");
16075 @.Sorry, I can't find...@>
16076     update_terminal;
16077     /* now pull out all the stops: try for the system \.{plain} file */
16078     xfree(mp->mem_name);
16079     mp->mem_name = xstrdup("plain");
16080     if (mp_open_mem_name(mp))
16081       return true;
16082   }
16083   wake_up_terminal;
16084   wterm_ln("I can\'t find the PLAIN mem file!");
16085 @.I can't find PLAIN...@>
16086 @.plain@>
16087   return false;
16088 }
16089
16090 @ Operating systems often make it possible to determine the exact name (and
16091 possible version number) of a file that has been opened. The following routine,
16092 which simply makes a \MP\ string from the value of |name_of_file|, should
16093 ideally be changed to deduce the full name of file~|f|, which is the file
16094 most recently opened, if it is possible to do this.
16095 @^system dependencies@>
16096
16097 @<Declarations@>=
16098 #define mp_a_make_name_string(A,B)  mp_make_name_string(A)
16099 #define mp_b_make_name_string(A,B)  mp_make_name_string(A)
16100 #define mp_w_make_name_string(A,B)  mp_make_name_string(A)
16101
16102 @ @c 
16103 static str_number mp_make_name_string (MP mp) {
16104   int k; /* index into |name_of_file| */
16105   str_room(mp->name_length);
16106   for (k=0;k<mp->name_length;k++) {
16107     append_char(xord((int)mp->name_of_file[k]));
16108   }
16109   return mp_make_string(mp);
16110 }
16111
16112 @ Now let's consider the ``driver''
16113 routines by which \MP\ deals with file names
16114 in a system-independent manner.  First comes a procedure that looks for a
16115 file name in the input by taking the information from the input buffer.
16116 (We can't use |get_next|, because the conversion to tokens would
16117 destroy necessary information.)
16118
16119 This procedure doesn't allow semicolons or percent signs to be part of
16120 file names, because of other conventions of \MP.
16121 {\sl The {\logos METAFONT\/}book} doesn't
16122 use semicolons or percents immediately after file names, but some users
16123 no doubt will find it natural to do so; therefore system-dependent
16124 changes to allow such characters in file names should probably
16125 be made with reluctance, and only when an entire file name that
16126 includes special characters is ``quoted'' somehow.
16127 @^system dependencies@>
16128
16129 @c 
16130 static void mp_scan_file_name (MP mp) { 
16131   mp_begin_name(mp);
16132   while ( mp->buffer[loc]==' ' ) incr(loc);
16133   while (1) { 
16134     if ( (mp->buffer[loc]==';')||(mp->buffer[loc]=='%') ) break;
16135     if ( ! mp_more_name(mp, mp->buffer[loc]) ) break;
16136     incr(loc);
16137   }
16138   mp_end_name(mp);
16139 }
16140
16141 @ Here is another version that takes its input from a string.
16142
16143 @<Declare subroutines for parsing file names@>=
16144 void mp_str_scan_file (MP mp,  str_number s) ;
16145
16146 @ @c
16147 void mp_str_scan_file (MP mp,  str_number s) {
16148   pool_pointer p,q; /* current position and stopping point */
16149   mp_begin_name(mp);
16150   p=mp->str_start[s]; q=str_stop(s);
16151   while ( p<q ){ 
16152     if ( ! mp_more_name(mp, mp->str_pool[p]) ) break;
16153     incr(p);
16154   }
16155   mp_end_name(mp);
16156 }
16157
16158 @ And one that reads from a |char*|.
16159
16160 @<Declare subroutines for parsing file names@>=
16161 extern void mp_ptr_scan_file (MP mp,  char *s);
16162
16163 @ @c
16164 void mp_ptr_scan_file (MP mp,  char *s) {
16165   char *p, *q; /* current position and stopping point */
16166   mp_begin_name(mp);
16167   p=s; q=p+strlen(s);
16168   while ( p<q ){ 
16169     if ( ! mp_more_name(mp, xord((int)(*p)))) break;
16170     p++;
16171   }
16172   mp_end_name(mp);
16173 }
16174
16175
16176 @ The global variable |job_name| contains the file name that was first
16177 \&{input} by the user. This name is extended by `\.{.log}' and `\.{ps}' and
16178 `\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's output files.
16179
16180 @<Glob...@>=
16181 boolean log_opened; /* has the transcript file been opened? */
16182 char *log_name; /* full name of the log file */
16183
16184 @ @<Option variables@>=
16185 char *job_name; /* principal file name */
16186
16187 @ Initially |job_name=NULL|; it becomes nonzero as soon as the true name is known.
16188 We have |job_name=NULL| if and only if the `\.{log}' file has not been opened,
16189 except of course for a short time just after |job_name| has become nonzero.
16190
16191 @<Allocate or ...@>=
16192 mp->job_name=mp_xstrdup(mp, opt->job_name); 
16193 if (opt->noninteractive && opt->ini_version) {
16194   if (mp->job_name == NULL)
16195     mp->job_name=mp_xstrdup(mp,mp->mem_name); 
16196   if (mp->job_name != NULL) {
16197     size_t l = strlen(mp->job_name);
16198     if (l>4) {
16199       char *test = strstr(mp->job_name,".mem");
16200       if (test == mp->job_name+l-4)
16201         *test = 0;
16202     }
16203   }
16204 }
16205 mp->log_opened=false;
16206
16207 @ @<Dealloc variables@>=
16208 xfree(mp->job_name);
16209
16210 @ Here is a routine that manufactures the output file names, assuming that
16211 |job_name<>0|. It ignores and changes the current settings of |cur_area|
16212 and |cur_ext|.
16213
16214 @d pack_cur_name mp_pack_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext)
16215
16216 @<Declarations@>=
16217 static void mp_pack_job_name (MP mp, const char *s) ;
16218
16219 @ @c 
16220 void mp_pack_job_name (MP mp, const char  *s) { /* |s = ".log"|, |".mem"|, |".ps"|, or .\\{nnn} */
16221   xfree(mp->cur_name); mp->cur_name=xstrdup(mp->job_name);
16222   xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16223   xfree(mp->cur_ext);  mp->cur_ext=xstrdup(s);
16224   pack_cur_name;
16225 }
16226
16227 @ If some trouble arises when \MP\ tries to open a file, the following
16228 routine calls upon the user to supply another file name. Parameter~|s|
16229 is used in the error message to identify the type of file; parameter~|e|
16230 is the default extension if none is given. Upon exit from the routine,
16231 variables |cur_name|, |cur_area|, |cur_ext|, and |name_of_file| are
16232 ready for another attempt at file opening.
16233
16234 @<Declarations@>=
16235 static void mp_prompt_file_name (MP mp, const char * s, const char * e) ;
16236
16237 @ @c void mp_prompt_file_name (MP mp, const char * s, const char * e) {
16238   size_t k; /* index into |buffer| */
16239   char * saved_cur_name;
16240   if ( mp->interaction==mp_scroll_mode ) 
16241         wake_up_terminal;
16242   if (strcmp(s,"input file name")==0) {
16243         print_err("I can\'t find file `");
16244 @.I can't find file x@>
16245   } else {
16246         print_err("I can\'t write on file `");
16247 @.I can't write on file x@>
16248   }
16249   mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext); 
16250   mp_print(mp, "'.");
16251   if (strcmp(e,"")==0) 
16252         mp_show_context(mp);
16253   mp_print_nl(mp, "Please type another "); mp_print(mp, s);
16254 @.Please type...@>
16255   if (mp->noninteractive || mp->interaction<mp_scroll_mode )
16256     mp_fatal_error(mp, "*** (job aborted, file error in nonstop mode)");
16257 @.job aborted, file error...@>
16258   saved_cur_name = xstrdup(mp->cur_name);
16259   clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
16260   if (strcmp(mp->cur_ext,"")==0) 
16261         mp->cur_ext=xstrdup(e);
16262   if (strlen(mp->cur_name)==0) {
16263     mp->cur_name=saved_cur_name;
16264   } else {
16265     xfree(saved_cur_name);
16266   }
16267   pack_cur_name;
16268 }
16269
16270 @ @<Scan file name in the buffer@>=
16271
16272   mp_begin_name(mp); k=mp->first;
16273   while ( (mp->buffer[k]==' ')&&(k<mp->last) ) incr(k);
16274   while (1) { 
16275     if ( k==mp->last ) break;
16276     if ( ! mp_more_name(mp, mp->buffer[k]) ) break;
16277     incr(k);
16278   }
16279   mp_end_name(mp);
16280 }
16281
16282 @ The |open_log_file| routine is used to open the transcript file and to help
16283 it catch up to what has previously been printed on the terminal.
16284
16285 @c void mp_open_log_file (MP mp) {
16286   unsigned old_setting; /* previous |selector| setting */
16287   int k; /* index into |months| and |buffer| */
16288   int l; /* end of first input line */
16289   integer m; /* the current month */
16290   const char *months="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; 
16291     /* abbreviations of month names */
16292   old_setting=mp->selector;
16293   if ( mp->job_name==NULL ) {
16294      mp->job_name=xstrdup("mpout");
16295   }
16296   mp_pack_job_name(mp,".log");
16297   while ( ! mp_a_open_out(mp, &mp->log_file, mp_filetype_log) ) {
16298     @<Try to get a different log file name@>;
16299   }
16300   mp->log_name=xstrdup(mp->name_of_file);
16301   mp->selector=log_only; mp->log_opened=true;
16302   @<Print the banner line, including the date and time@>;
16303   mp->input_stack[mp->input_ptr]=mp->cur_input; 
16304     /* make sure bottom level is in memory */
16305   if (!mp->noninteractive) {
16306     mp_print_nl(mp, "**");
16307 @.**@>
16308     l=mp->input_stack[0].limit_field-1; /* last position of first line */
16309     for (k=0;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
16310     mp_print_ln(mp); /* now the transcript file contains the first line of input */
16311   }
16312   mp->selector=old_setting+2; /* |log_only| or |term_and_log| */
16313 }
16314
16315 @ @<Dealloc variables@>=
16316 xfree(mp->log_name);
16317
16318 @ Sometimes |open_log_file| is called at awkward moments when \MP\ is
16319 unable to print error messages or even to |show_context|.
16320 The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
16321 routine will not be invoked because |log_opened| will be false.
16322
16323 The normal idea of |mp_batch_mode| is that nothing at all should be written
16324 on the terminal. However, in the unusual case that
16325 no log file could be opened, we make an exception and allow
16326 an explanatory message to be seen.
16327
16328 Incidentally, the program always refers to the log file as a `\.{transcript
16329 file}', because some systems cannot use the extension `\.{.log}' for
16330 this file.
16331
16332 @<Try to get a different log file name@>=
16333 {  
16334   mp->selector=term_only;
16335   mp_prompt_file_name(mp, "transcript file name",".log");
16336 }
16337
16338 @ @<Print the banner...@>=
16339
16340   wlog(mp->banner);
16341   mp_print(mp, mp->mem_ident); mp_print(mp, "  ");
16342   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_day])); 
16343   mp_print_char(mp, xord(' '));
16344   m=mp_round_unscaled(mp, mp->internal[mp_month]);
16345   for (k=3*m-3;k<3*m;k++) { wlog_chr((unsigned char)months[k]); }
16346   mp_print_char(mp, xord(' ')); 
16347   mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_year])); 
16348   mp_print_char(mp, xord(' '));
16349   m=mp_round_unscaled(mp, mp->internal[mp_time]);
16350   mp_print_dd(mp, m / 60); mp_print_char(mp, xord(':')); mp_print_dd(mp, m % 60);
16351 }
16352
16353 @ The |try_extension| function tries to open an input file determined by
16354 |cur_name|, |cur_area|, and the argument |ext|.  It returns |false| if it
16355 can't find the file in |cur_area| or the appropriate system area.
16356
16357 @c
16358 static boolean mp_try_extension (MP mp, const char *ext) { 
16359   mp_pack_file_name(mp, mp->cur_name,mp->cur_area, ext);
16360   in_name=xstrdup(mp->cur_name); 
16361   in_area=xstrdup(mp->cur_area);
16362   if ( mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16363     return true;
16364   } else { 
16365     mp_pack_file_name(mp, mp->cur_name,NULL,ext);
16366     return mp_a_open_in(mp, &cur_file, mp_filetype_program);
16367   }
16368 }
16369
16370 @ Let's turn now to the procedure that is used to initiate file reading
16371 when an `\.{input}' command is being processed.
16372
16373 @c void mp_start_input (MP mp) { /* \MP\ will \.{input} something */
16374   char *fname = NULL;
16375   @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>;
16376   while (1) { 
16377     mp_begin_file_reading(mp); /* set up |cur_file| and new level of input */
16378     if ( strlen(mp->cur_ext)==0 ) {
16379       if ( mp_try_extension(mp, ".mp") ) break;
16380       else if ( mp_try_extension(mp, "") ) break;
16381       else if ( mp_try_extension(mp, ".mf") ) break;
16382       /* |else do_nothing; | */
16383     } else if ( mp_try_extension(mp, mp->cur_ext) ) {
16384       break;
16385     }
16386     mp_end_file_reading(mp); /* remove the level that didn't work */
16387     mp_prompt_file_name(mp, "input file name","");
16388   }
16389   name=mp_a_make_name_string(mp, cur_file);
16390   fname = xstrdup(mp->name_of_file);
16391   if ( mp->job_name==NULL ) {
16392     mp->job_name=xstrdup(mp->cur_name); 
16393     mp_open_log_file(mp);
16394   } /* |open_log_file| doesn't |show_context|, so |limit|
16395         and |loc| needn't be set to meaningful values yet */
16396   if ( ((int)mp->term_offset+(int)strlen(fname)) > (mp->max_print_line-2)) mp_print_ln(mp);
16397   else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, xord(' '));
16398   mp_print_char(mp, xord('(')); incr(mp->open_parens); mp_print(mp, fname); 
16399   xfree(fname);
16400   update_terminal;
16401   @<Flush |name| and replace it with |cur_name| if it won't be needed@>;
16402   @<Read the first line of the new file@>;
16403 }
16404
16405 @ This code should be omitted if |a_make_name_string| returns something other
16406 than just a copy of its argument and the full file name is needed for opening
16407 \.{MPX} files or implementing the switch-to-editor option.
16408 @^system dependencies@>
16409
16410 @<Flush |name| and replace it with |cur_name| if it won't be needed@>=
16411 mp_flush_string(mp, name); name=rts(mp->cur_name); xfree(mp->cur_name)
16412
16413 @ If the file is empty, it is considered to contain a single blank line,
16414 so there is no need to test the return value.
16415
16416 @<Read the first line...@>=
16417
16418   line=1;
16419   (void)mp_input_ln(mp, cur_file ); 
16420   mp_firm_up_the_line(mp);
16421   mp->buffer[limit]=xord('%'); mp->first=(size_t)(limit+1); loc=start;
16422 }
16423
16424 @ @<Put the desired file name in |(cur_name,cur_ext,cur_area)|@>=
16425 while ( token_state &&(loc==null) ) mp_end_token_list(mp);
16426 if ( token_state ) { 
16427   print_err("File names can't appear within macros");
16428 @.File names can't...@>
16429   help3("Sorry...I've converted what follows to tokens,",
16430     "possibly garbaging the name you gave.",
16431     "Please delete the tokens and insert the name again.");
16432   mp_error(mp);
16433 }
16434 if ( file_state ) {
16435   mp_scan_file_name(mp);
16436 } else { 
16437    xfree(mp->cur_name); mp->cur_name=xstrdup(""); 
16438    xfree(mp->cur_ext);  mp->cur_ext =xstrdup(""); 
16439    xfree(mp->cur_area); mp->cur_area=xstrdup(""); 
16440 }
16441
16442 @ The following simple routine starts reading the \.{MPX} file associated
16443 with the current input file.
16444
16445 @c void mp_start_mpx_input (MP mp) {
16446   char *origname = NULL; /* a copy of nameoffile */
16447   mp_pack_file_name(mp, in_name, in_area, ".mpx");
16448   @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16449     |goto not_found| if there is a problem@>;
16450   mp_begin_file_reading(mp);
16451   if ( ! mp_a_open_in(mp, &cur_file, mp_filetype_program) ) {
16452     mp_end_file_reading(mp);
16453     goto NOT_FOUND;
16454   }
16455   name=mp_a_make_name_string(mp, cur_file);
16456   mp->mpx_name[iindex]=name; add_str_ref(name);
16457   @<Read the first line of the new file@>;
16458   xfree(origname);
16459   return;
16460 NOT_FOUND: 
16461     @<Explain that the \.{MPX} file can't be read and |succumb|@>;
16462   xfree(origname);
16463 }
16464
16465 @ This should ideally be changed to do whatever is necessary to create the
16466 \.{MPX} file given by |name_of_file| if it does not exist or if it is out
16467 of date.  This requires invoking \.{MPtoTeX} on the |origname| and passing
16468 the results through \TeX\ and \.{DVItoMP}.  (It is possible to use a
16469 completely different typesetting program if suitable postprocessor is
16470 available to perform the function of \.{DVItoMP}.)
16471 @^system dependencies@>
16472
16473 @ @<Exported types@>=
16474 typedef int (*mp_run_make_mpx_command)(MP mp, char *origname, char *mtxname);
16475
16476 @ @<Option variables@>=
16477 mp_run_make_mpx_command run_make_mpx;
16478
16479 @ @<Allocate or initialize ...@>=
16480 set_callback_option(run_make_mpx);
16481
16482 @ @<Declarations@>=
16483 static int mp_run_make_mpx (MP mp, char *origname, char *mtxname);
16484
16485 @ The default does nothing.
16486 @c 
16487 int mp_run_make_mpx (MP mp, char *origname, char *mtxname) {
16488   (void)mp;
16489   (void)origname;
16490   (void)mtxname;
16491   return false;
16492 }
16493
16494 @ @<Try to make sure |name_of_file| refers to a valid \.{MPX} file and
16495   |goto not_found| if there is a problem@>=
16496 origname = mp_xstrdup(mp,mp->name_of_file);
16497 *(origname+strlen(origname)-1)=0; /* drop the x */
16498 if (!(mp->run_make_mpx)(mp, origname, mp->name_of_file))
16499   goto NOT_FOUND 
16500
16501 @ @<Explain that the \.{MPX} file can't be read and |succumb|@>=
16502 if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16503 mp_print_nl(mp, ">> ");
16504 mp_print(mp, origname);
16505 mp_print_nl(mp, ">> ");
16506 mp_print(mp, mp->name_of_file);
16507 mp_print_nl(mp, "! Unable to make mpx file");
16508 help4("The two files given above are one of your source files",
16509   "and an auxiliary file I need to read to find out what your",
16510   "btex..etex blocks mean. If you don't know why I had trouble,",
16511   "try running it manually through MPtoTeX, TeX, and DVItoMP");
16512 succumb;
16513
16514 @ The last file-opening commands are for files accessed via the \&{readfrom}
16515 @:read_from_}{\&{readfrom} primitive@>
16516 operator and the \&{write} command.  Such files are stored in separate arrays.
16517 @:write_}{\&{write} primitive@>
16518
16519 @<Types in the outer block@>=
16520 typedef unsigned int readf_index; /* |0..max_read_files| */
16521 typedef unsigned int write_index;  /* |0..max_write_files| */
16522
16523 @ @<Glob...@>=
16524 readf_index max_read_files; /* maximum number of simultaneously open \&{readfrom} files */
16525 void ** rd_file; /* \&{readfrom} files */
16526 char ** rd_fname; /* corresponding file name or 0 if file not open */
16527 readf_index read_files; /* number of valid entries in the above arrays */
16528 write_index max_write_files; /* maximum number of simultaneously open \&{write} */
16529 void ** wr_file; /* \&{write} files */
16530 char ** wr_fname; /* corresponding file name or 0 if file not open */
16531 write_index write_files; /* number of valid entries in the above arrays */
16532
16533 @ @<Allocate or initialize ...@>=
16534 mp->max_read_files=8;
16535 mp->rd_file = xmalloc((mp->max_read_files+1),sizeof(void *));
16536 mp->rd_fname = xmalloc((mp->max_read_files+1),sizeof(char *));
16537 memset(mp->rd_fname, 0, sizeof(char *)*(mp->max_read_files+1));
16538 mp->max_write_files=8;
16539 mp->wr_file = xmalloc((mp->max_write_files+1),sizeof(void *));
16540 mp->wr_fname = xmalloc((mp->max_write_files+1),sizeof(char *));
16541 memset(mp->wr_fname, 0, sizeof(char *)*(mp->max_write_files+1));
16542
16543
16544 @ This routine starts reading the file named by string~|s| without setting
16545 |loc|, |limit|, or |name|.  It returns |false| if the file is empty or cannot
16546 be opened.  Otherwise it updates |rd_file[n]| and |rd_fname[n]|.
16547
16548 @c 
16549 static boolean mp_start_read_input (MP mp,char *s, readf_index  n) {
16550   mp_ptr_scan_file(mp, s);
16551   pack_cur_name;
16552   mp_begin_file_reading(mp);
16553   if ( ! mp_a_open_in(mp, &mp->rd_file[n], (int)(mp_filetype_text+n)) ) 
16554         goto NOT_FOUND;
16555   if ( ! mp_input_ln(mp, mp->rd_file[n] ) ) {
16556     (mp->close_file)(mp,mp->rd_file[n]); 
16557         goto NOT_FOUND; 
16558   }
16559   mp->rd_fname[n]=xstrdup(s);
16560   return true;
16561 NOT_FOUND: 
16562   mp_end_file_reading(mp);
16563   return false;
16564 }
16565
16566 @ Open |wr_file[n]| using file name~|s| and update |wr_fname[n]|.
16567
16568 @<Declarations@>=
16569 static void mp_open_write_file (MP mp, char *s, readf_index  n) ;
16570
16571 @ @c void mp_open_write_file (MP mp,char *s, readf_index  n) {
16572   mp_ptr_scan_file(mp, s);
16573   pack_cur_name;
16574   while ( ! mp_a_open_out(mp, &mp->wr_file[n], (int)(mp_filetype_text+n)) )
16575     mp_prompt_file_name(mp, "file name for write output","");
16576   mp->wr_fname[n]=xstrdup(s);
16577 }
16578
16579
16580 @* \[36] Introduction to the parsing routines.
16581 We come now to the central nervous system that sparks many of \MP's activities.
16582 By evaluating expressions, from their primary constituents to ever larger
16583 subexpressions, \MP\ builds the structures that ultimately define complete
16584 pictures or fonts of type.
16585
16586 Four mutually recursive subroutines are involved in this process: We call them
16587 $$\hbox{|scan_primary|, |scan_secondary|, |scan_tertiary|,
16588 and |scan_expression|.}$$
16589 @^recursion@>
16590 Each of them is parameterless and begins with the first token to be scanned
16591 already represented in |cur_cmd|, |cur_mod|, and |cur_sym|. After execution,
16592 the value of the primary or secondary or tertiary or expression that was
16593 found will appear in the global variables |cur_type| and |cur_exp|. The
16594 token following the expression will be represented in |cur_cmd|, |cur_mod|,
16595 and |cur_sym|.
16596
16597 Technically speaking, the parsing algorithms are ``LL(1),'' more or less;
16598 backup mechanisms have been added in order to provide reasonable error
16599 recovery.
16600
16601 @<Glob...@>=
16602 quarterword cur_type; /* the type of the expression just found */
16603 integer cur_exp; /* the value of the expression just found */
16604
16605 @ @<Set init...@>=
16606 mp->cur_exp=0;
16607
16608 @ Many different kinds of expressions are possible, so it is wise to have
16609 precise descriptions of what |cur_type| and |cur_exp| mean in all cases:
16610
16611 \smallskip\hang
16612 |cur_type=mp_vacuous| means that this expression didn't turn out to have a
16613 value at all, because it arose from a \&{begingroup}$\,\ldots\,$\&{endgroup}
16614 construction in which there was no expression before the \&{endgroup}.
16615 In this case |cur_exp| has some irrelevant value.
16616
16617 \smallskip\hang
16618 |cur_type=mp_boolean_type| means that |cur_exp| is either |true_code|
16619 or |false_code|.
16620
16621 \smallskip\hang
16622 |cur_type=mp_unknown_boolean| means that |cur_exp| points to a capsule
16623 node that is in 
16624 a ring of equivalent booleans whose value has not yet been defined.
16625
16626 \smallskip\hang
16627 |cur_type=mp_string_type| means that |cur_exp| is a string number (i.e., an
16628 integer in the range |0<=cur_exp<str_ptr|). That string's reference count
16629 includes this particular reference.
16630
16631 \smallskip\hang
16632 |cur_type=mp_unknown_string| means that |cur_exp| points to a capsule
16633 node that is in
16634 a ring of equivalent strings whose value has not yet been defined.
16635
16636 \smallskip\hang
16637 |cur_type=mp_pen_type| means that |cur_exp| points to a node in a pen.  Nobody
16638 else points to any of the nodes in this pen.  The pen may be polygonal or
16639 elliptical.
16640
16641 \smallskip\hang
16642 |cur_type=mp_unknown_pen| means that |cur_exp| points to a capsule
16643 node that is in
16644 a ring of equivalent pens whose value has not yet been defined.
16645
16646 \smallskip\hang
16647 |cur_type=mp_path_type| means that |cur_exp| points to a the first node of
16648 a path; nobody else points to this particular path. The control points of
16649 the path will have been chosen.
16650
16651 \smallskip\hang
16652 |cur_type=mp_unknown_path| means that |cur_exp| points to a capsule
16653 node that is in
16654 a ring of equivalent paths whose value has not yet been defined.
16655
16656 \smallskip\hang
16657 |cur_type=mp_picture_type| means that |cur_exp| points to an edge header node.
16658 There may be other pointers to this particular set of edges.  The header node
16659 contains a reference count that includes this particular reference.
16660
16661 \smallskip\hang
16662 |cur_type=mp_unknown_picture| means that |cur_exp| points to a capsule
16663 node that is in
16664 a ring of equivalent pictures whose value has not yet been defined.
16665
16666 \smallskip\hang
16667 |cur_type=mp_transform_type| means that |cur_exp| points to a |mp_transform_type|
16668 capsule node. The |value| part of this capsule
16669 points to a transform node that contains six numeric values,
16670 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16671
16672 \smallskip\hang
16673 |cur_type=mp_color_type| means that |cur_exp| points to a |color_type|
16674 capsule node. The |value| part of this capsule
16675 points to a color node that contains three numeric values,
16676 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16677
16678 \smallskip\hang
16679 |cur_type=mp_cmykcolor_type| means that |cur_exp| points to a |mp_cmykcolor_type|
16680 capsule node. The |value| part of this capsule
16681 points to a color node that contains four numeric values,
16682 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16683
16684 \smallskip\hang
16685 |cur_type=mp_pair_type| means that |cur_exp| points to a capsule
16686 node whose type is |mp_pair_type|. The |value| part of this capsule
16687 points to a pair node that contains two numeric values,
16688 each of which is |independent|, |dependent|, |mp_proto_dependent|, or |known|.
16689
16690 \smallskip\hang
16691 |cur_type=mp_known| means that |cur_exp| is a |scaled| value.
16692
16693 \smallskip\hang
16694 |cur_type=mp_dependent| means that |cur_exp| points to a capsule node whose type
16695 is |dependent|. The |dep_list| field in this capsule points to the associated
16696 dependency list.
16697
16698 \smallskip\hang
16699 |cur_type=mp_proto_dependent| means that |cur_exp| points to a |mp_proto_dependent|
16700 capsule node. The |dep_list| field in this capsule
16701 points to the associated dependency list.
16702
16703 \smallskip\hang
16704 |cur_type=independent| means that |cur_exp| points to a capsule node
16705 whose type is |independent|. This somewhat unusual case can arise, for
16706 example, in the expression
16707 `$x+\&{begingroup}\penalty0\,\&{string}\,x; 0\,\&{endgroup}$'.
16708
16709 \smallskip\hang
16710 |cur_type=mp_token_list| means that |cur_exp| points to a linked list of
16711 tokens. 
16712
16713 \smallskip\noindent
16714 The possible settings of |cur_type| have been listed here in increasing
16715 numerical order. Notice that |cur_type| will never be |mp_numeric_type| or
16716 |suffixed_macro| or |mp_unsuffixed_macro|, although variables of those types
16717 are allowed.  Conversely, \MP\ has no variables of type |mp_vacuous| or
16718 |token_list|.
16719
16720 @ Capsules are two-word nodes that have a similar meaning
16721 to |cur_type| and |cur_exp|. Such nodes have |name_type=capsule|,
16722 and their |type| field is one of the possibilities for |cur_type| listed above.
16723 Also |link<=void| in capsules that aren't part of a token list.
16724
16725 The |value| field of a capsule is, in most cases, the value that
16726 corresponds to its |type|, as |cur_exp| corresponds to |cur_type|.
16727 However, when |cur_exp| would point to a capsule,
16728 no extra layer of indirection is present; the |value|
16729 field is what would have been called |value(cur_exp)| if it had not been
16730 encapsulated.  Furthermore, if the type is |dependent| or
16731 |mp_proto_dependent|, the |value| field of a capsule is replaced by
16732 |dep_list| and |prev_dep| fields, since dependency lists in capsules are
16733 always part of the general |dep_list| structure.
16734
16735 The |get_x_next| routine is careful not to change the values of |cur_type|
16736 and |cur_exp| when it gets an expanded token. However, |get_x_next| might
16737 call a macro, which might parse an expression, which might execute lots of
16738 commands in a group; hence it's possible that |cur_type| might change
16739 from, say, |mp_unknown_boolean| to |mp_boolean_type|, or from |dependent| to
16740 |known| or |independent|, during the time |get_x_next| is called. The
16741 programs below are careful to stash sensitive intermediate results in
16742 capsules, so that \MP's generality doesn't cause trouble.
16743
16744 Here's a procedure that illustrates these conventions. It takes
16745 the contents of $(|cur_type|\kern-.3pt,|cur_exp|\kern-.3pt)$
16746 and stashes them away in a
16747 capsule. It is not used when |cur_type=mp_token_list|.
16748 After the operation, |cur_type=mp_vacuous|; hence there is no need to
16749 copy path lists or to update reference counts, etc.
16750
16751 The special link |mp_void| is put on the capsule returned by
16752 |stash_cur_exp|, because this procedure is used to store macro parameters
16753 that must be easily distinguishable from token lists.
16754
16755 @<Declare the stashing/unstashing routines@>=
16756 static pointer mp_stash_cur_exp (MP mp) {
16757   pointer p; /* the capsule that will be returned */
16758   switch (mp->cur_type) {
16759   case unknown_types:
16760   case mp_transform_type:
16761   case mp_color_type:
16762   case mp_pair_type:
16763   case mp_dependent:
16764   case mp_proto_dependent:
16765   case mp_independent: 
16766   case mp_cmykcolor_type:
16767     p=mp->cur_exp;
16768     break;
16769   default: 
16770     p=mp_get_node(mp, value_node_size); name_type(p)=mp_capsule;
16771     type(p)=mp->cur_type; value(p)=mp->cur_exp;
16772     break;
16773   }
16774   mp->cur_type=mp_vacuous; mp_link(p)=mp_void; 
16775   return p;
16776 }
16777
16778 @ The inverse of |stash_cur_exp| is the following procedure, which
16779 deletes an unnecessary capsule and puts its contents into |cur_type|
16780 and |cur_exp|.
16781
16782 The program steps of \MP\ can be divided into two categories: those in
16783 which |cur_type| and |cur_exp| are ``alive'' and those in which they are
16784 ``dead,'' in the sense that |cur_type| and |cur_exp| contain relevant
16785 information or not. It's important not to ignore them when they're alive,
16786 and it's important not to pay attention to them when they're dead.
16787
16788 There's also an intermediate category: If |cur_type=mp_vacuous|, then
16789 |cur_exp| is irrelevant, hence we can proceed without caring if |cur_type|
16790 and |cur_exp| are alive or dead. In such cases we say that |cur_type|
16791 and |cur_exp| are {\sl dormant}. It is permissible to call |get_x_next|
16792 only when they are alive or dormant.
16793
16794 The \\{stash} procedure above assumes that |cur_type| and |cur_exp|
16795 are alive or dormant. The \\{unstash} procedure assumes that they are
16796 dead or dormant; it resuscitates them.
16797
16798 @<Declare the stashing/unstashing...@>=
16799 static void mp_unstash_cur_exp (MP mp,pointer p) ;
16800
16801 @ @c
16802 void mp_unstash_cur_exp (MP mp,pointer p) { 
16803   mp->cur_type=type(p);
16804   switch (mp->cur_type) {
16805   case unknown_types:
16806   case mp_transform_type:
16807   case mp_color_type:
16808   case mp_pair_type:
16809   case mp_dependent: 
16810   case mp_proto_dependent:
16811   case mp_independent:
16812   case mp_cmykcolor_type: 
16813     mp->cur_exp=p;
16814     break;
16815   default:
16816     mp->cur_exp=value(p);
16817     mp_free_node(mp, p,value_node_size);
16818     break;
16819   }
16820 }
16821
16822 @ The following procedure prints the values of expressions in an
16823 abbreviated format. If its first parameter |p| is null, the value of
16824 |(cur_type,cur_exp)| is displayed; otherwise |p| should be a capsule
16825 containing the desired value. The second parameter controls the amount of
16826 output. If it is~0, dependency lists will be abbreviated to
16827 `\.{linearform}' unless they consist of a single term.  If it is greater
16828 than~1, complicated structures (pens, pictures, and paths) will be displayed
16829 in full.
16830 @.linearform@>
16831
16832 @<Declarations@>=
16833 @<Declare the procedure called |print_dp|@>
16834 @<Declare the stashing/unstashing routines@>
16835 static void mp_print_exp (MP mp,pointer p, quarterword verbosity) ;
16836
16837 @ @c
16838 void mp_print_exp (MP mp,pointer p, quarterword verbosity) {
16839   boolean restore_cur_exp; /* should |cur_exp| be restored? */
16840   quarterword t; /* the type of the expression */
16841   pointer q; /* a big node being displayed */
16842   integer v=0; /* the value of the expression */
16843   if ( p!=null ) {
16844     restore_cur_exp=false;
16845   } else { 
16846     p=mp_stash_cur_exp(mp); restore_cur_exp=true;
16847   }
16848   t=type(p);
16849   if ( t<mp_dependent ) v=value(p); else if ( t<mp_independent ) v=dep_list(p);
16850   @<Print an abbreviated value of |v| with format depending on |t|@>;
16851   if ( restore_cur_exp ) mp_unstash_cur_exp(mp, p);
16852 }
16853
16854 @ @<Print an abbreviated value of |v| with format depending on |t|@>=
16855 switch (t) {
16856 case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
16857 case mp_boolean_type:
16858   if ( v==true_code ) mp_print(mp, "true"); else mp_print(mp, "false");
16859   break;
16860 case unknown_types: case mp_numeric_type:
16861   @<Display a variable that's been declared but not defined@>;
16862   break;
16863 case mp_string_type:
16864   mp_print_char(mp, xord('"')); mp_print_str(mp, v); mp_print_char(mp, xord('"'));
16865   break;
16866 case mp_pen_type: case mp_path_type: case mp_picture_type:
16867   @<Display a complex type@>;
16868   break;
16869 case mp_transform_type: case mp_color_type: case mp_pair_type: case mp_cmykcolor_type:
16870   if ( v==null ) mp_print_type(mp, t);
16871   else @<Display a big node@>;
16872   break;
16873 case mp_known:mp_print_scaled(mp, v); break;
16874 case mp_dependent: case mp_proto_dependent:
16875   mp_print_dp(mp, t,v,verbosity);
16876   break;
16877 case mp_independent:mp_print_variable_name(mp, p); break;
16878 default: mp_confusion(mp, "exp"); break;
16879 @:this can't happen exp}{\quad exp@>
16880 }
16881
16882 @ @<Display a big node@>=
16883
16884   mp_print_char(mp, xord('(')); q=v+mp->big_node_size[t];
16885   do {  
16886     if ( type(v)==mp_known ) mp_print_scaled(mp, value(v));
16887     else if ( type(v)==mp_independent ) mp_print_variable_name(mp, v);
16888     else mp_print_dp(mp, type(v),dep_list(v),verbosity);
16889     v=v+2;
16890     if ( v!=q ) mp_print_char(mp, xord(','));
16891   } while (v!=q);
16892   mp_print_char(mp, xord(')'));
16893 }
16894
16895 @ Values of type \&{picture}, \&{path}, and \&{pen} are displayed verbosely
16896 in the log file only, unless the user has given a positive value to
16897 \\{tracingonline}.
16898
16899 @<Display a complex type@>=
16900 if ( verbosity<=1 ) {
16901   mp_print_type(mp, t);
16902 } else { 
16903   if ( mp->selector==term_and_log )
16904    if ( mp->internal[mp_tracing_online]<=0 ) {
16905     mp->selector=term_only;
16906     mp_print_type(mp, t); mp_print(mp, " (see the transcript file)");
16907     mp->selector=term_and_log;
16908   };
16909   switch (t) {
16910   case mp_pen_type:mp_print_pen(mp, v,"",false); break;
16911   case mp_path_type:mp_print_path(mp, v,"",false); break;
16912   case mp_picture_type:mp_print_edges(mp, v,"",false); break;
16913   } /* there are no other cases */
16914 }
16915
16916 @ @<Declare the procedure called |print_dp|@>=
16917 static void mp_print_dp (MP mp, quarterword t, pointer p, 
16918                   quarterword verbosity)  {
16919   pointer q; /* the node following |p| */
16920   q=mp_link(p);
16921   if ( (info(q)==null) || (verbosity>0) ) mp_print_dependency(mp, p,t);
16922   else mp_print(mp, "linearform");
16923 }
16924
16925 @ The displayed name of a variable in a ring will not be a capsule unless
16926 the ring consists entirely of capsules.
16927
16928 @<Display a variable that's been declared but not defined@>=
16929 { mp_print_type(mp, t);
16930 if ( v!=null )
16931   { mp_print_char(mp, xord(' '));
16932   while ( (name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
16933   mp_print_variable_name(mp, v);
16934   };
16935 }
16936
16937 @ When errors are detected during parsing, it is often helpful to
16938 display an expression just above the error message, using |exp_err|
16939 or |disp_err| instead of |print_err|.
16940
16941 @d exp_err(A) mp_disp_err(mp, null,(A)) /* displays the current expression */
16942
16943 @<Declarations@>=
16944 static void mp_disp_err (MP mp,pointer p, const char *s) ;
16945
16946 @ @c
16947 void mp_disp_err (MP mp,pointer p, const char *s) { 
16948   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
16949   mp_print_nl(mp, ">> ");
16950 @.>>@>
16951   mp_print_exp(mp, p,1); /* ``medium verbose'' printing of the expression */
16952   if (strlen(s)>0) { 
16953     mp_print_nl(mp, "! "); mp_print(mp, s);
16954 @.!\relax@>
16955   }
16956 }
16957
16958 @ If |cur_type| and |cur_exp| contain relevant information that should
16959 be recycled, we will use the following procedure, which changes |cur_type|
16960 to |known| and stores a given value in |cur_exp|. We can think of |cur_type|
16961 and |cur_exp| as either alive or dormant after this has been done,
16962 because |cur_exp| will not contain a pointer value.
16963
16964 @ @c 
16965 static void mp_flush_cur_exp (MP mp,scaled v) { 
16966   switch (mp->cur_type) {
16967   case unknown_types: case mp_transform_type: case mp_color_type: case mp_pair_type:
16968   case mp_dependent: case mp_proto_dependent: case mp_independent: case mp_cmykcolor_type:
16969     mp_recycle_value(mp, mp->cur_exp); 
16970     mp_free_node(mp, mp->cur_exp,value_node_size);
16971     break;
16972   case mp_string_type:
16973     delete_str_ref(mp->cur_exp); break;
16974   case mp_pen_type: case mp_path_type: 
16975     mp_toss_knot_list(mp, mp->cur_exp); break;
16976   case mp_picture_type:
16977     delete_edge_ref(mp->cur_exp); break;
16978   default: 
16979     break;
16980   }
16981   mp->cur_type=mp_known; mp->cur_exp=v;
16982 }
16983
16984 @ There's a much more general procedure that is capable of releasing
16985 the storage associated with any two-word value packet.
16986
16987 @<Declarations@>=
16988 static void mp_recycle_value (MP mp,pointer p) ;
16989
16990 @ @c 
16991 static void mp_recycle_value (MP mp,pointer p) {
16992   quarterword t; /* a type code */
16993   integer vv; /* another value */
16994   pointer q,r,s,pp; /* link manipulation registers */
16995   integer v=0; /* a value */
16996   t=type(p);
16997   if ( t<mp_dependent ) v=value(p);
16998   switch (t) {
16999   case undefined: case mp_vacuous: case mp_boolean_type: case mp_known:
17000   case mp_numeric_type:
17001     break;
17002   case unknown_types:
17003     mp_ring_delete(mp, p); break;
17004   case mp_string_type:
17005     delete_str_ref(v); break;
17006   case mp_path_type: case mp_pen_type:
17007     mp_toss_knot_list(mp, v); break;
17008   case mp_picture_type:
17009     delete_edge_ref(v); break;
17010   case mp_cmykcolor_type: case mp_pair_type: case mp_color_type:
17011   case mp_transform_type:
17012     @<Recycle a big node@>; break; 
17013   case mp_dependent: case mp_proto_dependent:
17014     @<Recycle a dependency list@>; break;
17015   case mp_independent:
17016     @<Recycle an independent variable@>; break;
17017   case mp_token_list: case mp_structured:
17018     mp_confusion(mp, "recycle"); break;
17019 @:this can't happen recycle}{\quad recycle@>
17020   case mp_unsuffixed_macro: case mp_suffixed_macro:
17021     mp_delete_mac_ref(mp, value(p)); break;
17022   } /* there are no other cases */
17023   type(p)=undefined;
17024 }
17025
17026 @ @<Recycle a big node@>=
17027 if ( v!=null ){ 
17028   q=v+mp->big_node_size[t];
17029   do {  
17030     q=q-2; mp_recycle_value(mp, q);
17031   } while (q!=v);
17032   mp_free_node(mp, v,mp->big_node_size[t]);
17033 }
17034
17035 @ @<Recycle a dependency list@>=
17036
17037   q=dep_list(p);
17038   while ( info(q)!=null ) q=mp_link(q);
17039   mp_link(prev_dep(p))=mp_link(q);
17040   prev_dep(mp_link(q))=prev_dep(p);
17041   mp_link(q)=null; mp_flush_node_list(mp, dep_list(p));
17042 }
17043
17044 @ When an independent variable disappears, it simply fades away, unless
17045 something depends on it. In the latter case, a dependent variable whose
17046 coefficient of dependence is maximal will take its place.
17047 The relevant algorithm is due to Ignacio~A. Zabala, who implemented it
17048 as part of his Ph.D. thesis (Stanford University, December 1982).
17049 @^Zabala Salelles, Ignacio Andr\'es@>
17050
17051 For example, suppose that variable $x$ is being recycled, and that the
17052 only variables depending on~$x$ are $y=2x+a$ and $z=x+b$. In this case
17053 we want to make $y$ independent and $z=.5y-.5a+b$; no other variables
17054 will depend on~$y$. If $\\{tracingequations}>0$ in this situation,
17055 we will print `\.{\#\#\# -2x=-y+a}'.
17056
17057 There's a slight complication, however: An independent variable $x$
17058 can occur both in dependency lists and in proto-dependency lists.
17059 This makes it necessary to be careful when deciding which coefficient
17060 is maximal.
17061
17062 Furthermore, this complication is not so slight when
17063 a proto-dependent variable is chosen to become independent. For example,
17064 suppose that $y=2x+100a$ is proto-dependent while $z=x+b$ is dependent;
17065 then we must change $z=.5y-50a+b$ to a proto-dependency, because of the
17066 large coefficient `50'.
17067
17068 In order to deal with these complications without wasting too much time,
17069 we shall link together the occurrences of~$x$ among all the linear
17070 dependencies, maintaining separate lists for the dependent and
17071 proto-dependent cases.
17072
17073 @<Recycle an independent variable@>=
17074
17075   mp->max_c[mp_dependent]=0; mp->max_c[mp_proto_dependent]=0;
17076   mp->max_link[mp_dependent]=null; mp->max_link[mp_proto_dependent]=null;
17077   q=mp_link(dep_head);
17078   while ( q!=dep_head ) { 
17079     s=value_loc(q); /* now |mp_link(s)=dep_list(q)| */
17080     while (1) { 
17081       r=mp_link(s);
17082       if ( info(r)==null ) break;
17083       if ( info(r)!=p ) { 
17084         s=r;
17085       } else  { 
17086         t=type(q); mp_link(s)=mp_link(r); info(r)=q;
17087         if ( abs(value(r))>mp->max_c[t] ) {
17088           @<Record a new maximum coefficient of type |t|@>;
17089         } else { 
17090           mp_link(r)=mp->max_link[t]; mp->max_link[t]=r;
17091         }
17092       }
17093     } 
17094     q=mp_link(r);
17095   }
17096   if ( (mp->max_c[mp_dependent]>0)||(mp->max_c[mp_proto_dependent]>0) ) {
17097     @<Choose a dependent variable to take the place of the disappearing
17098     independent variable, and change all remaining dependencies
17099     accordingly@>;
17100   }
17101 }
17102
17103 @ The code for independency removal makes use of three two-word arrays.
17104
17105 @<Glob...@>=
17106 integer max_c[mp_proto_dependent+1];  /* max coefficient magnitude */
17107 pointer max_ptr[mp_proto_dependent+1]; /* where |p| occurs with |max_c| */
17108 pointer max_link[mp_proto_dependent+1]; /* other occurrences of |p| */
17109
17110 @ @<Record a new maximum coefficient...@>=
17111
17112   if ( mp->max_c[t]>0 ) {
17113     mp_link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
17114   }
17115   mp->max_c[t]=abs(value(r)); mp->max_ptr[t]=r;
17116 }
17117
17118 @ @<Choose a dependent...@>=
17119
17120   if ( (mp->max_c[mp_dependent] / 010000) >= mp->max_c[mp_proto_dependent] )
17121     t=mp_dependent;
17122   else 
17123     t=mp_proto_dependent;
17124   @<Determine the dependency list |s| to substitute for the independent
17125     variable~|p|@>;
17126   t=mp_dependent+mp_proto_dependent-t; /* complement |t| */
17127   if ( mp->max_c[t]>0 ) { /* we need to pick up an unchosen dependency */ 
17128     mp_link(mp->max_ptr[t])=mp->max_link[t]; mp->max_link[t]=mp->max_ptr[t];
17129   }
17130   if ( t!=mp_dependent ) { @<Substitute new dependencies in place of |p|@>; }
17131   else { @<Substitute new proto-dependencies in place of |p|@>;}
17132   mp_flush_node_list(mp, s);
17133   if ( mp->fix_needed ) mp_fix_dependencies(mp);
17134   check_arith;
17135 }
17136
17137 @ Let |s=max_ptr[t]|. At this point we have $|value|(s)=\pm|max_c|[t]$,
17138 and |info(s)| points to the dependent variable~|pp| of type~|t| from
17139 whose dependency list we have removed node~|s|. We must reinsert
17140 node~|s| into the dependency list, with coefficient $-1.0$, and with
17141 |pp| as the new independent variable. Since |pp| will have a larger serial
17142 number than any other variable, we can put node |s| at the head of the
17143 list.
17144
17145 @<Determine the dep...@>=
17146 s=mp->max_ptr[t]; pp=info(s); v=value(s);
17147 if ( t==mp_dependent ) value(s)=-fraction_one; else value(s)=-unity;
17148 r=dep_list(pp); mp_link(s)=r;
17149 while ( info(r)!=null ) r=mp_link(r);
17150 q=mp_link(r); mp_link(r)=null;
17151 prev_dep(q)=prev_dep(pp); mp_link(prev_dep(pp))=q;
17152 new_indep(pp);
17153 if ( mp->cur_exp==pp ) if ( mp->cur_type==t ) mp->cur_type=mp_independent;
17154 if ( mp->internal[mp_tracing_equations]>0 ) { 
17155   @<Show the transformed dependency@>; 
17156 }
17157
17158 @ Now $(-v)$ times the formerly independent variable~|p| is being replaced
17159 by the dependency list~|s|.
17160
17161 @<Show the transformed...@>=
17162 if ( mp_interesting(mp, p) ) {
17163   mp_begin_diagnostic(mp); mp_print_nl(mp, "### ");
17164 @:]]]\#\#\#_}{\.{\#\#\#}@>
17165   if ( v>0 ) mp_print_char(mp, xord('-'));
17166   if ( t==mp_dependent ) vv=mp_round_fraction(mp, mp->max_c[mp_dependent]);
17167   else vv=mp->max_c[mp_proto_dependent];
17168   if ( vv!=unity ) mp_print_scaled(mp, vv);
17169   mp_print_variable_name(mp, p);
17170   while ( value(p) % s_scale>0 ) {
17171     mp_print(mp, "*4"); value(p)=value(p)-2;
17172   }
17173   if ( t==mp_dependent ) mp_print_char(mp, xord('=')); else mp_print(mp, " = ");
17174   mp_print_dependency(mp, s,t);
17175   mp_end_diagnostic(mp, false);
17176 }
17177
17178 @ Finally, there are dependent and proto-dependent variables whose
17179 dependency lists must be brought up to date.
17180
17181 @<Substitute new dependencies...@>=
17182 for (t=mp_dependent;t<=mp_proto_dependent;t++){ 
17183   r=mp->max_link[t];
17184   while ( r!=null ) {
17185     q=info(r);
17186     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
17187      mp_make_fraction(mp, value(r),-v),s,t,mp_dependent);
17188     if ( dep_list(q)==mp->dep_final ) mp_make_known(mp, q,mp->dep_final);
17189     q=r; r=mp_link(r); mp_free_node(mp, q,dep_node_size);
17190   }
17191 }
17192
17193 @ @<Substitute new proto...@>=
17194 for (t=mp_dependent;t<=mp_proto_dependent;t++) {
17195   r=mp->max_link[t];
17196   while ( r!=null ) {
17197     q=info(r);
17198     if ( t==mp_dependent ) { /* for safety's sake, we change |q| to |mp_proto_dependent| */
17199       if ( mp->cur_exp==q ) if ( mp->cur_type==mp_dependent )
17200         mp->cur_type=mp_proto_dependent;
17201       dep_list(q)=mp_p_over_v(mp, dep_list(q),unity,
17202          mp_dependent,mp_proto_dependent);
17203       type(q)=mp_proto_dependent; 
17204       value(r)=mp_round_fraction(mp, value(r));
17205     }
17206     dep_list(q)=mp_p_plus_fq(mp, dep_list(q),
17207        mp_make_scaled(mp, value(r),-v),s,
17208        mp_proto_dependent,mp_proto_dependent);
17209     if ( dep_list(q)==mp->dep_final ) 
17210        mp_make_known(mp, q,mp->dep_final);
17211     q=r; r=mp_link(r); mp_free_node(mp, q,dep_node_size);
17212   }
17213 }
17214
17215 @ Here are some routines that provide handy combinations of actions
17216 that are often needed during error recovery. For example,
17217 `|flush_error|' flushes the current expression, replaces it by
17218 a given value, and calls |error|.
17219
17220 Errors often are detected after an extra token has already been scanned.
17221 The `\\{put\_get}' routines put that token back before calling |error|;
17222 then they get it back again. (Or perhaps they get another token, if
17223 the user has changed things.)
17224
17225 @<Declarations@>=
17226 static void mp_flush_error (MP mp,scaled v);
17227 static void mp_put_get_error (MP mp);
17228 static void mp_put_get_flush_error (MP mp,scaled v) ;
17229
17230 @ @c
17231 void mp_flush_error (MP mp,scaled v) { 
17232   mp_error(mp); mp_flush_cur_exp(mp, v); 
17233 }
17234 void mp_put_get_error (MP mp) { 
17235   mp_back_error(mp); mp_get_x_next(mp); 
17236 }
17237 void mp_put_get_flush_error (MP mp,scaled v) { 
17238   mp_put_get_error(mp);
17239   mp_flush_cur_exp(mp, v); 
17240 }
17241
17242 @ A global variable |var_flag| is set to a special command code
17243 just before \MP\ calls |scan_expression|, if the expression should be
17244 treated as a variable when this command code immediately follows. For
17245 example, |var_flag| is set to |assignment| at the beginning of a
17246 statement, because we want to know the {\sl location\/} of a variable at
17247 the left of `\.{:=}', not the {\sl value\/} of that variable.
17248
17249 The |scan_expression| subroutine calls |scan_tertiary|,
17250 which calls |scan_secondary|, which calls |scan_primary|, which sets
17251 |var_flag:=0|. In this way each of the scanning routines ``knows''
17252 when it has been called with a special |var_flag|, but |var_flag| is
17253 usually zero.
17254
17255 A variable preceding a command that equals |var_flag| is converted to a
17256 token list rather than a value. Furthermore, an `\.{=}' sign following an
17257 expression with |var_flag=assignment| is not considered to be a relation
17258 that produces boolean expressions.
17259
17260
17261 @<Glob...@>=
17262 int var_flag; /* command that wants a variable */
17263
17264 @ @<Set init...@>=
17265 mp->var_flag=0;
17266
17267 @* \[37] Parsing primary expressions.
17268 The first parsing routine, |scan_primary|, is also the most complicated one,
17269 since it involves so many different cases. But each case---with one
17270 exception---is fairly simple by itself.
17271
17272 When |scan_primary| begins, the first token of the primary to be scanned
17273 should already appear in |cur_cmd|, |cur_mod|, and |cur_sym|. The values
17274 of |cur_type| and |cur_exp| should be either dead or dormant, as explained
17275 earlier. If |cur_cmd| is not between |min_primary_command| and
17276 |max_primary_command|, inclusive, a syntax error will be signaled.
17277
17278 @<Declare the basic parsing subroutines@>=
17279 void mp_scan_primary (MP mp) {
17280   pointer p,q,r; /* for list manipulation */
17281   quarterword c; /* a primitive operation code */
17282   int my_var_flag; /* initial value of |my_var_flag| */
17283   pointer l_delim,r_delim; /* hash addresses of a delimiter pair */
17284   @<Other local variables for |scan_primary|@>;
17285   my_var_flag=mp->var_flag; mp->var_flag=0;
17286 RESTART:
17287   check_arith;
17288   @<Supply diagnostic information, if requested@>;
17289   switch (mp->cur_cmd) {
17290   case left_delimiter:
17291     @<Scan a delimited primary@>; break;
17292   case begin_group:
17293     @<Scan a grouped primary@>; break;
17294   case string_token:
17295     @<Scan a string constant@>; break;
17296   case numeric_token:
17297     @<Scan a primary that starts with a numeric token@>; break;
17298   case nullary:
17299     @<Scan a nullary operation@>; break;
17300   case unary: case type_name: case cycle: case plus_or_minus:
17301     @<Scan a unary operation@>; break;
17302   case primary_binary:
17303     @<Scan a binary operation with `\&{of}' between its operands@>; break;
17304   case str_op:
17305     @<Convert a suffix to a string@>; break;
17306   case internal_quantity:
17307     @<Scan an internal numeric quantity@>; break;
17308   case capsule_token:
17309     mp_make_exp_copy(mp, mp->cur_mod); break;
17310   case tag_token:
17311     @<Scan a variable primary; |goto restart| if it turns out to be a macro@>; break;
17312   default: 
17313     mp_bad_exp(mp, "A primary"); goto RESTART; break;
17314 @.A primary expression...@>
17315   }
17316   mp_get_x_next(mp); /* the routines |goto done| if they don't want this */
17317 DONE: 
17318   if ( mp->cur_cmd==left_bracket ) {
17319     if ( mp->cur_type>=mp_known ) {
17320       @<Scan a mediation construction@>;
17321     }
17322   }
17323 }
17324
17325
17326
17327 @ Errors at the beginning of expressions are flagged by |bad_exp|.
17328
17329 @c 
17330 static void mp_bad_exp (MP mp, const char * s) {
17331   int save_flag;
17332   print_err(s); mp_print(mp, " expression can't begin with `");
17333   mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); 
17334   mp_print_char(mp, xord('\''));
17335   help4("I'm afraid I need some sort of value in order to continue,",
17336     "so I've tentatively inserted `0'. You may want to",
17337     "delete this zero and insert something else;",
17338     "see Chapter 27 of The METAFONTbook for an example.");
17339 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
17340   mp_back_input(mp); mp->cur_sym=0; mp->cur_cmd=numeric_token; 
17341   mp->cur_mod=0; mp_ins_error(mp);
17342   save_flag=mp->var_flag; mp->var_flag=0; mp_get_x_next(mp);
17343   mp->var_flag=save_flag;
17344 }
17345
17346 @ @<Supply diagnostic information, if requested@>=
17347 #ifdef DEBUG
17348 if ( mp->panicking ) mp_check_mem(mp, false);
17349 #endif
17350 if ( mp->interrupt!=0 ) if ( mp->OK_to_interrupt ) {
17351   mp_back_input(mp); check_interrupt; mp_get_x_next(mp);
17352 }
17353
17354 @ @<Scan a delimited primary@>=
17355
17356   l_delim=mp->cur_sym; r_delim=mp->cur_mod; 
17357   mp_get_x_next(mp); mp_scan_expression(mp);
17358   if ( (mp->cur_cmd==comma) && (mp->cur_type>=mp_known) ) {
17359     @<Scan the rest of a delimited set of numerics@>;
17360   } else {
17361     mp_check_delimiter(mp, l_delim,r_delim);
17362   }
17363 }
17364
17365 @ The |stash_in| subroutine puts the current (numeric) expression into a field
17366 within a ``big node.''
17367
17368 @c 
17369 static void mp_stash_in (MP mp,pointer p) {
17370   pointer q; /* temporary register */
17371   type(p)=mp->cur_type;
17372   if ( mp->cur_type==mp_known ) {
17373     value(p)=mp->cur_exp;
17374   } else { 
17375     if ( mp->cur_type==mp_independent ) {
17376       @<Stash an independent |cur_exp| into a big node@>;
17377     } else { 
17378       mp->mem[value_loc(p)]=mp->mem[value_loc(mp->cur_exp)];
17379       /* |dep_list(p):=dep_list(cur_exp)| and |prev_dep(p):=prev_dep(cur_exp)| */
17380       mp_link(prev_dep(p))=p;
17381     }
17382     mp_free_node(mp, mp->cur_exp,value_node_size);
17383   }
17384   mp->cur_type=mp_vacuous;
17385 }
17386
17387 @ In rare cases the current expression can become |independent|. There
17388 may be many dependency lists pointing to such an independent capsule,
17389 so we can't simply move it into place within a big node. Instead,
17390 we copy it, then recycle it.
17391
17392 @ @<Stash an independent |cur_exp|...@>=
17393
17394   q=mp_single_dependency(mp, mp->cur_exp);
17395   if ( q==mp->dep_final ){ 
17396     type(p)=mp_known; value(p)=0; mp_free_node(mp, q,dep_node_size);
17397   } else { 
17398     type(p)=mp_dependent; mp_new_dep(mp, p,q);
17399   }
17400   mp_recycle_value(mp, mp->cur_exp);
17401 }
17402
17403 @ This code uses the fact that |red_part_loc| and |green_part_loc|
17404 are synonymous with |x_part_loc| and |y_part_loc|.
17405
17406 @<Scan the rest of a delimited set of numerics@>=
17407
17408 p=mp_stash_cur_exp(mp);
17409 mp_get_x_next(mp); mp_scan_expression(mp);
17410 @<Make sure the second part of a pair or color has a numeric type@>;
17411 q=mp_get_node(mp, value_node_size); name_type(q)=mp_capsule;
17412 if ( mp->cur_cmd==comma ) type(q)=mp_color_type;
17413 else type(q)=mp_pair_type;
17414 mp_init_big_node(mp, q); r=value(q);
17415 mp_stash_in(mp, y_part_loc(r));
17416 mp_unstash_cur_exp(mp, p);
17417 mp_stash_in(mp, x_part_loc(r));
17418 if ( mp->cur_cmd==comma ) {
17419   @<Scan the last of a triplet of numerics@>;
17420 }
17421 if ( mp->cur_cmd==comma ) {
17422   type(q)=mp_cmykcolor_type;
17423   mp_init_big_node(mp, q); t=value(q);
17424   mp->mem[cyan_part_loc(t)]=mp->mem[red_part_loc(r)];
17425   value(cyan_part_loc(t))=value(red_part_loc(r));
17426   mp->mem[magenta_part_loc(t)]=mp->mem[green_part_loc(r)];
17427   value(magenta_part_loc(t))=value(green_part_loc(r));
17428   mp->mem[yellow_part_loc(t)]=mp->mem[blue_part_loc(r)];
17429   value(yellow_part_loc(t))=value(blue_part_loc(r));
17430   mp_recycle_value(mp, r);
17431   r=t;
17432   @<Scan the last of a quartet of numerics@>;
17433 }
17434 mp_check_delimiter(mp, l_delim,r_delim);
17435 mp->cur_type=type(q);
17436 mp->cur_exp=q;
17437 }
17438
17439 @ @<Make sure the second part of a pair or color has a numeric type@>=
17440 if ( mp->cur_type<mp_known ) {
17441   exp_err("Nonnumeric ypart has been replaced by 0");
17442 @.Nonnumeric...replaced by 0@>
17443   help4("I've started to scan a pair `(a,b)' or a color `(a,b,c)';",
17444     "but after finding a nice `a' I found a `b' that isn't",
17445     "of numeric type. So I've changed that part to zero.",
17446     "(The b that I didn't like appears above the error message.)");
17447   mp_put_get_flush_error(mp, 0);
17448 }
17449
17450 @ @<Scan the last of a triplet of numerics@>=
17451
17452   mp_get_x_next(mp); mp_scan_expression(mp);
17453   if ( mp->cur_type<mp_known ) {
17454     exp_err("Nonnumeric third part has been replaced by 0");
17455 @.Nonnumeric...replaced by 0@>
17456     help3("I've just scanned a color `(a,b,c)' or cmykcolor(a,b,c,d); but the `c'",
17457       "isn't of numeric type. So I've changed that part to zero.",
17458       "(The c that I didn't like appears above the error message.)");
17459     mp_put_get_flush_error(mp, 0);
17460   }
17461   mp_stash_in(mp, blue_part_loc(r));
17462 }
17463
17464 @ @<Scan the last of a quartet of numerics@>=
17465
17466   mp_get_x_next(mp); mp_scan_expression(mp);
17467   if ( mp->cur_type<mp_known ) {
17468     exp_err("Nonnumeric blackpart has been replaced by 0");
17469 @.Nonnumeric...replaced by 0@>
17470     help3("I've just scanned a cmykcolor `(c,m,y,k)'; but the `k' isn't",
17471       "of numeric type. So I've changed that part to zero.",
17472       "(The k that I didn't like appears above the error message.)");
17473     mp_put_get_flush_error(mp, 0);
17474   }
17475   mp_stash_in(mp, black_part_loc(r));
17476 }
17477
17478 @ The local variable |group_line| keeps track of the line
17479 where a \&{begingroup} command occurred; this will be useful
17480 in an error message if the group doesn't actually end.
17481
17482 @<Other local variables for |scan_primary|@>=
17483 integer group_line; /* where a group began */
17484
17485 @ @<Scan a grouped primary@>=
17486
17487   group_line=mp_true_line(mp);
17488   if ( mp->internal[mp_tracing_commands]>0 ) show_cur_cmd_mod;
17489   save_boundary_item(p);
17490   do {  
17491     mp_do_statement(mp); /* ends with |cur_cmd>=semicolon| */
17492   } while (mp->cur_cmd==semicolon);
17493   if ( mp->cur_cmd!=end_group ) {
17494     print_err("A group begun on line ");
17495 @.A group...never ended@>
17496     mp_print_int(mp, group_line);
17497     mp_print(mp, " never ended");
17498     help2("I saw a `begingroup' back there that hasn't been matched",
17499           "by `endgroup'. So I've inserted `endgroup' now.");
17500     mp_back_error(mp); mp->cur_cmd=end_group;
17501   }
17502   mp_unsave(mp); 
17503     /* this might change |cur_type|, if independent variables are recycled */
17504   if ( mp->internal[mp_tracing_commands]>0 ) show_cur_cmd_mod;
17505 }
17506
17507 @ @<Scan a string constant@>=
17508
17509   mp->cur_type=mp_string_type; mp->cur_exp=mp->cur_mod;
17510 }
17511
17512 @ Later we'll come to procedures that perform actual operations like
17513 addition, square root, and so on; our purpose now is to do the parsing.
17514 But we might as well mention those future procedures now, so that the
17515 suspense won't be too bad:
17516
17517 \smallskip
17518 |do_nullary(c)| does primitive operations that have no operands (e.g.,
17519 `\&{true}' or `\&{pencircle}');
17520
17521 \smallskip
17522 |do_unary(c)| applies a primitive operation to the current expression;
17523
17524 \smallskip
17525 |do_binary(p,c)| applies a primitive operation to the capsule~|p|
17526 and the current expression.
17527
17528 @<Scan a nullary operation@>=mp_do_nullary(mp, mp->cur_mod)
17529
17530 @ @<Scan a unary operation@>=
17531
17532   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_primary(mp); 
17533   mp_do_unary(mp, c); goto DONE;
17534 }
17535
17536 @ A numeric token might be a primary by itself, or it might be the
17537 numerator of a fraction composed solely of numeric tokens, or it might
17538 multiply the primary that follows (provided that the primary doesn't begin
17539 with a plus sign or a minus sign). The code here uses the facts that
17540 |max_primary_command=plus_or_minus| and
17541 |max_primary_command-1=numeric_token|. If a fraction is found that is less
17542 than unity, we try to retain higher precision when we use it in scalar
17543 multiplication.
17544
17545 @<Other local variables for |scan_primary|@>=
17546 scaled num,denom; /* for primaries that are fractions, like `1/2' */
17547
17548 @ @<Scan a primary that starts with a numeric token@>=
17549
17550   mp->cur_exp=mp->cur_mod; mp->cur_type=mp_known; mp_get_x_next(mp);
17551   if ( mp->cur_cmd!=slash ) { 
17552     num=0; denom=0;
17553   } else { 
17554     mp_get_x_next(mp);
17555     if ( mp->cur_cmd!=numeric_token ) { 
17556       mp_back_input(mp);
17557       mp->cur_cmd=slash; mp->cur_mod=over; mp->cur_sym=frozen_slash;
17558       goto DONE;
17559     }
17560     num=mp->cur_exp; denom=mp->cur_mod;
17561     if ( denom==0 ) { @<Protest division by zero@>; }
17562     else { mp->cur_exp=mp_make_scaled(mp, num,denom); }
17563     check_arith; mp_get_x_next(mp);
17564   }
17565   if ( mp->cur_cmd>=min_primary_command ) {
17566    if ( mp->cur_cmd<numeric_token ) { /* in particular, |cur_cmd<>plus_or_minus| */
17567      p=mp_stash_cur_exp(mp); mp_scan_primary(mp);
17568      if ( (abs(num)>=abs(denom))||(mp->cur_type<mp_color_type) ) {
17569        mp_do_binary(mp, p,times);
17570      } else {
17571        mp_frac_mult(mp, num,denom);
17572        mp_free_node(mp, p,value_node_size);
17573      }
17574     }
17575   }
17576   goto DONE;
17577 }
17578
17579 @ @<Protest division...@>=
17580
17581   print_err("Division by zero");
17582 @.Division by zero@>
17583   help1("I'll pretend that you meant to divide by 1."); mp_error(mp);
17584 }
17585
17586 @ @<Scan a binary operation with `\&{of}' between its operands@>=
17587
17588   c=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
17589   if ( mp->cur_cmd!=of_token ) {
17590     mp_missing_err(mp, "of"); mp_print(mp, " for "); 
17591     mp_print_cmd_mod(mp, primary_binary,c);
17592 @.Missing `of'@>
17593     help1("I've got the first argument; will look now for the other.");
17594     mp_back_error(mp);
17595   }
17596   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_primary(mp); 
17597   mp_do_binary(mp, p,c); goto DONE;
17598 }
17599
17600 @ @<Convert a suffix to a string@>=
17601
17602   mp_get_x_next(mp); mp_scan_suffix(mp); 
17603   mp->old_setting=mp->selector; mp->selector=new_string;
17604   mp_show_token_list(mp, mp->cur_exp,null,100000,0); 
17605   mp_flush_token_list(mp, mp->cur_exp);
17606   mp->cur_exp=mp_make_string(mp); mp->selector=mp->old_setting; 
17607   mp->cur_type=mp_string_type;
17608   goto DONE;
17609 }
17610
17611 @ If an internal quantity appears all by itself on the left of an
17612 assignment, we return a token list of length one, containing the address
17613 of the internal quantity plus |hash_end|. (This accords with the conventions
17614 of the save stack, as described earlier.)
17615
17616 @<Scan an internal...@>=
17617
17618   q=mp->cur_mod;
17619   if ( my_var_flag==assignment ) {
17620     mp_get_x_next(mp);
17621     if ( mp->cur_cmd==assignment ) {
17622       mp->cur_exp=mp_get_avail(mp);
17623       info(mp->cur_exp)=q+hash_end; mp->cur_type=mp_token_list; 
17624       goto DONE;
17625     }
17626     mp_back_input(mp);
17627   }
17628   mp->cur_type=mp_known; mp->cur_exp=mp->internal[q];
17629 }
17630
17631 @ The most difficult part of |scan_primary| has been saved for last, since
17632 it was necessary to build up some confidence first. We can now face the task
17633 of scanning a variable.
17634
17635 As we scan a variable, we build a token list containing the relevant
17636 names and subscript values, simultaneously following along in the
17637 ``collective'' structure to see if we are actually dealing with a macro
17638 instead of a value.
17639
17640 The local variables |pre_head| and |post_head| will point to the beginning
17641 of the prefix and suffix lists; |tail| will point to the end of the list
17642 that is currently growing.
17643
17644 Another local variable, |tt|, contains partial information about the
17645 declared type of the variable-so-far. If |tt>=mp_unsuffixed_macro|, the
17646 relation |tt=type(q)| will always hold. If |tt=undefined|, the routine
17647 doesn't bother to update its information about type. And if
17648 |undefined<tt<mp_unsuffixed_macro|, the precise value of |tt| isn't critical.
17649
17650 @ @<Other local variables for |scan_primary|@>=
17651 pointer pre_head,post_head,tail;
17652   /* prefix and suffix list variables */
17653 quarterword tt; /* approximation to the type of the variable-so-far */
17654 pointer t; /* a token */
17655 pointer macro_ref = 0; /* reference count for a suffixed macro */
17656
17657 @ @<Scan a variable primary...@>=
17658
17659   fast_get_avail(pre_head); tail=pre_head; post_head=null; tt=mp_vacuous;
17660   while (1) { 
17661     t=mp_cur_tok(mp); mp_link(tail)=t;
17662     if ( tt!=undefined ) {
17663        @<Find the approximate type |tt| and corresponding~|q|@>;
17664       if ( tt>=mp_unsuffixed_macro ) {
17665         @<Either begin an unsuffixed macro call or
17666           prepare for a suffixed one@>;
17667       }
17668     }
17669     mp_get_x_next(mp); tail=t;
17670     if ( mp->cur_cmd==left_bracket ) {
17671       @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>;
17672     }
17673     if ( mp->cur_cmd>max_suffix_token ) break;
17674     if ( mp->cur_cmd<min_suffix_token ) break;
17675   } /* now |cur_cmd| is |internal_quantity|, |tag_token|, or |numeric_token| */
17676   @<Handle unusual cases that masquerade as variables, and |goto restart|
17677     or |goto done| if appropriate;
17678     otherwise make a copy of the variable and |goto done|@>;
17679 }
17680
17681 @ @<Either begin an unsuffixed macro call or...@>=
17682
17683   mp_link(tail)=null;
17684   if ( tt>mp_unsuffixed_macro ) { /* |tt=mp_suffixed_macro| */
17685     post_head=mp_get_avail(mp); tail=post_head; mp_link(tail)=t;
17686     tt=undefined; macro_ref=value(q); add_mac_ref(macro_ref);
17687   } else {
17688     @<Set up unsuffixed macro call and |goto restart|@>;
17689   }
17690 }
17691
17692 @ @<Scan for a subscript; replace |cur_cmd| by |numeric_token| if found@>=
17693
17694   mp_get_x_next(mp); mp_scan_expression(mp);
17695   if ( mp->cur_cmd!=right_bracket ) {
17696     @<Put the left bracket and the expression back to be rescanned@>;
17697   } else { 
17698     if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17699     mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp; mp->cur_sym=0;
17700   }
17701 }
17702
17703 @ The left bracket that we thought was introducing a subscript might have
17704 actually been the left bracket in a mediation construction like `\.{x[a,b]}'.
17705 So we don't issue an error message at this point; but we do want to back up
17706 so as to avoid any embarrassment about our incorrect assumption.
17707
17708 @<Put the left bracket and the expression back to be rescanned@>=
17709
17710   mp_back_input(mp); /* that was the token following the current expression */
17711   mp_back_expr(mp); mp->cur_cmd=left_bracket; 
17712   mp->cur_mod=0; mp->cur_sym=frozen_left_bracket;
17713 }
17714
17715 @ Here's a routine that puts the current expression back to be read again.
17716
17717 @c 
17718 static void mp_back_expr (MP mp) {
17719   pointer p; /* capsule token */
17720   p=mp_stash_cur_exp(mp); mp_link(p)=null; back_list(p);
17721 }
17722
17723 @ Unknown subscripts lead to the following error message.
17724
17725 @c 
17726 static void mp_bad_subscript (MP mp) { 
17727   exp_err("Improper subscript has been replaced by zero");
17728 @.Improper subscript...@>
17729   help3("A bracketed subscript must have a known numeric value;",
17730     "unfortunately, what I found was the value that appears just",
17731     "above this error message. So I'll try a zero subscript.");
17732   mp_flush_error(mp, 0);
17733 }
17734
17735 @ Every time we call |get_x_next|, there's a chance that the variable we've
17736 been looking at will disappear. Thus, we cannot safely keep |q| pointing
17737 into the variable structure; we need to start searching from the root each time.
17738
17739 @<Find the approximate type |tt| and corresponding~|q|@>=
17740 @^inner loop@>
17741
17742   p=mp_link(pre_head); q=info(p); tt=undefined;
17743   if ( eq_type(q) % outer_tag==tag_token ) {
17744     q=equiv(q);
17745     if ( q==null ) goto DONE2;
17746     while (1) { 
17747       p=mp_link(p);
17748       if ( p==null ) {
17749         tt=type(q); goto DONE2;
17750       };
17751       if ( type(q)!=mp_structured ) goto DONE2;
17752       q=mp_link(attr_head(q)); /* the |collective_subscript| attribute */
17753       if ( p>=mp->hi_mem_min ) { /* it's not a subscript */
17754         do {  q=mp_link(q); } while (! (attr_loc(q)>=info(p)));
17755         if ( attr_loc(q)>info(p) ) goto DONE2;
17756       }
17757     }
17758   }
17759 DONE2:
17760   ;
17761 }
17762
17763 @ How do things stand now? Well, we have scanned an entire variable name,
17764 including possible subscripts and/or attributes; |cur_cmd|, |cur_mod|, and
17765 |cur_sym| represent the token that follows. If |post_head=null|, a
17766 token list for this variable name starts at |mp_link(pre_head)|, with all
17767 subscripts evaluated. But if |post_head<>null|, the variable turned out
17768 to be a suffixed macro; |pre_head| is the head of the prefix list, while
17769 |post_head| is the head of a token list containing both `\.{\AT!}' and
17770 the suffix.
17771
17772 Our immediate problem is to see if this variable still exists. (Variable
17773 structures can change drastically whenever we call |get_x_next|; users
17774 aren't supposed to do this, but the fact that it is possible means that
17775 we must be cautious.)
17776
17777 The following procedure prints an error message when a variable
17778 unexpectedly disappears. Its help message isn't quite right for
17779 our present purposes, but we'll be able to fix that up.
17780
17781 @c 
17782 static void mp_obliterated (MP mp,pointer q) { 
17783   print_err("Variable "); mp_show_token_list(mp, q,null,1000,0);
17784   mp_print(mp, " has been obliterated");
17785 @.Variable...obliterated@>
17786   help5("It seems you did a nasty thing---probably by accident,",
17787      "but nevertheless you nearly hornswoggled me...",
17788      "While I was evaluating the right-hand side of this",
17789      "command, something happened, and the left-hand side",
17790      "is no longer a variable! So I won't change anything.");
17791 }
17792
17793 @ If the variable does exist, we also need to check
17794 for a few other special cases before deciding that a plain old ordinary
17795 variable has, indeed, been scanned.
17796
17797 @<Handle unusual cases that masquerade as variables...@>=
17798 if ( post_head!=null ) {
17799   @<Set up suffixed macro call and |goto restart|@>;
17800 }
17801 q=mp_link(pre_head); free_avail(pre_head);
17802 if ( mp->cur_cmd==my_var_flag ) { 
17803   mp->cur_type=mp_token_list; mp->cur_exp=q; goto DONE;
17804 }
17805 p=mp_find_variable(mp, q);
17806 if ( p!=null ) {
17807   mp_make_exp_copy(mp, p);
17808 } else { 
17809   mp_obliterated(mp, q);
17810   mp->help_line[2]="While I was evaluating the suffix of this variable,";
17811   mp->help_line[1]="something was redefined, and it's no longer a variable!";
17812   mp->help_line[0]="In order to get back on my feet, I've inserted `0' instead.";
17813   mp_put_get_flush_error(mp, 0);
17814 }
17815 mp_flush_node_list(mp, q); 
17816 goto DONE
17817
17818 @ The only complication associated with macro calling is that the prefix
17819 and ``at'' parameters must be packaged in an appropriate list of lists.
17820
17821 @<Set up unsuffixed macro call and |goto restart|@>=
17822
17823   p=mp_get_avail(mp); info(pre_head)=mp_link(pre_head); mp_link(pre_head)=p;
17824   info(p)=t; mp_macro_call(mp, value(q),pre_head,null);
17825   mp_get_x_next(mp); 
17826   goto RESTART;
17827 }
17828
17829 @ If the ``variable'' that turned out to be a suffixed macro no longer exists,
17830 we don't care, because we have reserved a pointer (|macro_ref|) to its
17831 token list.
17832
17833 @<Set up suffixed macro call and |goto restart|@>=
17834
17835   mp_back_input(mp); p=mp_get_avail(mp); q=mp_link(post_head);
17836   info(pre_head)=mp_link(pre_head); mp_link(pre_head)=post_head;
17837   info(post_head)=q; mp_link(post_head)=p; info(p)=mp_link(q); mp_link(q)=null;
17838   mp_macro_call(mp, macro_ref,pre_head,null); decr(ref_count(macro_ref));
17839   mp_get_x_next(mp); goto RESTART;
17840 }
17841
17842 @ Our remaining job is simply to make a copy of the value that has been
17843 found. Some cases are harder than others, but complexity arises solely
17844 because of the multiplicity of possible cases.
17845
17846 @<Declare the procedure called |make_exp_copy|@>=
17847 @<Declare subroutines needed by |make_exp_copy|@>
17848 static void mp_make_exp_copy (MP mp,pointer p) {
17849   pointer q,r,t; /* registers for list manipulation */
17850 RESTART: 
17851   mp->cur_type=type(p);
17852   switch (mp->cur_type) {
17853   case mp_vacuous: case mp_boolean_type: case mp_known:
17854     mp->cur_exp=value(p); break;
17855   case unknown_types:
17856     mp->cur_exp=mp_new_ring_entry(mp, p);
17857     break;
17858   case mp_string_type: 
17859     mp->cur_exp=value(p); add_str_ref(mp->cur_exp);
17860     break;
17861   case mp_picture_type:
17862     mp->cur_exp=value(p);add_edge_ref(mp->cur_exp);
17863     break;
17864   case mp_pen_type:
17865     mp->cur_exp=copy_pen(value(p));
17866     break; 
17867   case mp_path_type:
17868     mp->cur_exp=mp_copy_path(mp, value(p));
17869     break;
17870   case mp_transform_type: case mp_color_type: 
17871   case mp_cmykcolor_type: case mp_pair_type:
17872     @<Copy the big node |p|@>;
17873     break;
17874   case mp_dependent: case mp_proto_dependent:
17875     mp_encapsulate(mp, mp_copy_dep_list(mp, dep_list(p)));
17876     break;
17877   case mp_numeric_type: 
17878     new_indep(p); goto RESTART;
17879     break;
17880   case mp_independent: 
17881     q=mp_single_dependency(mp, p);
17882     if ( q==mp->dep_final ){ 
17883       mp->cur_type=mp_known; mp->cur_exp=0; mp_free_node(mp, q,dep_node_size);
17884     } else { 
17885       mp->cur_type=mp_dependent; mp_encapsulate(mp, q);
17886     }
17887     break;
17888   default: 
17889     mp_confusion(mp, "copy");
17890 @:this can't happen copy}{\quad copy@>
17891     break;
17892   }
17893 }
17894
17895 @ The |encapsulate| subroutine assumes that |dep_final| is the
17896 tail of dependency list~|p|.
17897
17898 @<Declare subroutines needed by |make_exp_copy|@>=
17899 static void mp_encapsulate (MP mp,pointer p) { 
17900   mp->cur_exp=mp_get_node(mp, value_node_size); type(mp->cur_exp)=mp->cur_type;
17901   name_type(mp->cur_exp)=mp_capsule; mp_new_dep(mp, mp->cur_exp,p);
17902 }
17903
17904 @ The most tedious case arises when the user refers to a
17905 \&{pair}, \&{color}, or \&{transform} variable; we must copy several fields,
17906 each of which can be |independent|, |dependent|, |mp_proto_dependent|,
17907 or |known|.
17908
17909 @<Copy the big node |p|@>=
17910
17911   if ( value(p)==null ) 
17912     mp_init_big_node(mp, p);
17913   t=mp_get_node(mp, value_node_size); name_type(t)=mp_capsule; type(t)=mp->cur_type;
17914   mp_init_big_node(mp, t);
17915   q=value(p)+mp->big_node_size[mp->cur_type]; 
17916   r=value(t)+mp->big_node_size[mp->cur_type];
17917   do {  
17918     q=q-2; r=r-2; mp_install(mp, r,q);
17919   } while (q!=value(p));
17920   mp->cur_exp=t;
17921 }
17922
17923 @ The |install| procedure copies a numeric field~|q| into field~|r| of
17924 a big node that will be part of a capsule.
17925
17926 @<Declare subroutines needed by |make_exp_copy|@>=
17927 static void mp_install (MP mp,pointer r, pointer q) {
17928   pointer p; /* temporary register */
17929   if ( type(q)==mp_known ){ 
17930     value(r)=value(q); type(r)=mp_known;
17931   } else  if ( type(q)==mp_independent ) {
17932     p=mp_single_dependency(mp, q);
17933     if ( p==mp->dep_final ) {
17934       type(r)=mp_known; value(r)=0; mp_free_node(mp, p,dep_node_size);
17935     } else  { 
17936       type(r)=mp_dependent; mp_new_dep(mp, r,p);
17937     }
17938   } else {
17939     type(r)=type(q); mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(q)));
17940   }
17941 }
17942
17943 @ Expressions of the form `\.{a[b,c]}' are converted into
17944 `\.{b+a*(c-b)}', without checking the types of \.b~or~\.c,
17945 provided that \.a is numeric.
17946
17947 @<Scan a mediation...@>=
17948
17949   p=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17950   if ( mp->cur_cmd!=comma ) {
17951     @<Put the left bracket and the expression back...@>;
17952     mp_unstash_cur_exp(mp, p);
17953   } else { 
17954     q=mp_stash_cur_exp(mp); mp_get_x_next(mp); mp_scan_expression(mp);
17955     if ( mp->cur_cmd!=right_bracket ) {
17956       mp_missing_err(mp, "]");
17957 @.Missing `]'@>
17958       help3("I've scanned an expression of the form `a[b,c',",
17959       "so a right bracket should have come next.",
17960       "I shall pretend that one was there.");
17961       mp_back_error(mp);
17962     }
17963     r=mp_stash_cur_exp(mp); mp_make_exp_copy(mp, q);
17964     mp_do_binary(mp, r,minus); mp_do_binary(mp, p,times); 
17965     mp_do_binary(mp, q,plus); mp_get_x_next(mp);
17966   }
17967 }
17968
17969 @ Here is a comparatively simple routine that is used to scan the
17970 \&{suffix} parameters of a macro.
17971
17972 @<Declare the basic parsing subroutines@>=
17973 static void mp_scan_suffix (MP mp) {
17974   pointer h,t; /* head and tail of the list being built */
17975   pointer p; /* temporary register */
17976   h=mp_get_avail(mp); t=h;
17977   while (1) { 
17978     if ( mp->cur_cmd==left_bracket ) {
17979       @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>;
17980     }
17981     if ( mp->cur_cmd==numeric_token ) {
17982       p=mp_new_num_tok(mp, mp->cur_mod);
17983     } else if ((mp->cur_cmd==tag_token)||(mp->cur_cmd==internal_quantity) ) {
17984        p=mp_get_avail(mp); info(p)=mp->cur_sym;
17985     } else {
17986       break;
17987     }
17988     mp_link(t)=p; t=p; mp_get_x_next(mp);
17989   }
17990   mp->cur_exp=mp_link(h); free_avail(h); mp->cur_type=mp_token_list;
17991 }
17992
17993 @ @<Scan a bracketed subscript and set |cur_cmd:=numeric_token|@>=
17994
17995   mp_get_x_next(mp); mp_scan_expression(mp);
17996   if ( mp->cur_type!=mp_known ) mp_bad_subscript(mp);
17997   if ( mp->cur_cmd!=right_bracket ) {
17998      mp_missing_err(mp, "]");
17999 @.Missing `]'@>
18000     help3("I've seen a `[' and a subscript value, in a suffix,",
18001       "so a right bracket should have come next.",
18002       "I shall pretend that one was there.");
18003     mp_back_error(mp);
18004   }
18005   mp->cur_cmd=numeric_token; mp->cur_mod=mp->cur_exp;
18006 }
18007
18008 @* \[38] Parsing secondary and higher expressions.
18009
18010 After the intricacies of |scan_primary|\kern-1pt,
18011 the |scan_secondary| routine is
18012 refreshingly simple. It's not trivial, but the operations are relatively
18013 straightforward; the main difficulty is, again, that expressions and data
18014 structures might change drastically every time we call |get_x_next|, so a
18015 cautious approach is mandatory. For example, a macro defined by
18016 \&{primarydef} might have disappeared by the time its second argument has
18017 been scanned; we solve this by increasing the reference count of its token
18018 list, so that the macro can be called even after it has been clobbered.
18019
18020 @<Declare the basic parsing subroutines@>=
18021 static void mp_scan_secondary (MP mp) {
18022   pointer p; /* for list manipulation */
18023   halfword c,d; /* operation codes or modifiers */
18024   pointer mac_name; /* token defined with \&{primarydef} */
18025 RESTART:
18026   if ((mp->cur_cmd<min_primary_command)||
18027       (mp->cur_cmd>max_primary_command) )
18028     mp_bad_exp(mp, "A secondary");
18029 @.A secondary expression...@>
18030   mp_scan_primary(mp);
18031 CONTINUE: 
18032   if ( mp->cur_cmd<=max_secondary_command &&
18033        mp->cur_cmd>=min_secondary_command ) {
18034     p=mp_stash_cur_exp(mp); 
18035     c=mp->cur_mod; d=mp->cur_cmd;
18036     if ( d==secondary_primary_macro ) { 
18037       mac_name=mp->cur_sym; 
18038       add_mac_ref(c);
18039     }
18040     mp_get_x_next(mp); 
18041     mp_scan_primary(mp);
18042     if ( d!=secondary_primary_macro ) {
18043       mp_do_binary(mp, p,c);
18044     } else { 
18045       mp_back_input(mp); 
18046       mp_binary_mac(mp, p,c,mac_name);
18047       decr(ref_count(c)); 
18048       mp_get_x_next(mp); 
18049       goto RESTART;
18050     }
18051     goto CONTINUE;
18052   }
18053 }
18054
18055 @ The following procedure calls a macro that has two parameters,
18056 |p| and |cur_exp|.
18057
18058 @c 
18059 static void mp_binary_mac (MP mp,pointer p, pointer c, pointer n) {
18060   pointer q,r; /* nodes in the parameter list */
18061   q=mp_get_avail(mp); r=mp_get_avail(mp); mp_link(q)=r;
18062   info(q)=p; info(r)=mp_stash_cur_exp(mp);
18063   mp_macro_call(mp, c,q,n);
18064 }
18065
18066 @ The next procedure, |scan_tertiary|, is pretty much the same deal.
18067
18068 @<Declare the basic parsing subroutines@>=
18069 static void mp_scan_tertiary (MP mp) {
18070   pointer p; /* for list manipulation */
18071   halfword c,d; /* operation codes or modifiers */
18072   pointer mac_name; /* token defined with \&{secondarydef} */
18073 RESTART:
18074   if ((mp->cur_cmd<min_primary_command)||
18075       (mp->cur_cmd>max_primary_command) )
18076     mp_bad_exp(mp, "A tertiary");
18077 @.A tertiary expression...@>
18078   mp_scan_secondary(mp);
18079 CONTINUE: 
18080   if ( mp->cur_cmd<=max_tertiary_command ) {
18081     if ( mp->cur_cmd>=min_tertiary_command ) {
18082       p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
18083       if ( d==tertiary_secondary_macro ) { 
18084         mac_name=mp->cur_sym; add_mac_ref(c);
18085       };
18086       mp_get_x_next(mp); mp_scan_secondary(mp);
18087       if ( d!=tertiary_secondary_macro ) {
18088         mp_do_binary(mp, p,c);
18089       } else { 
18090         mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
18091         decr(ref_count(c)); mp_get_x_next(mp); 
18092         goto RESTART;
18093       }
18094       goto CONTINUE;
18095     }
18096   }
18097 }
18098
18099 @ Finally we reach the deepest level in our quartet of parsing routines.
18100 This one is much like the others; but it has an extra complication from
18101 paths, which materialize here.
18102
18103 @d continue_path 25 /* a label inside of |scan_expression| */
18104 @d finish_path 26 /* another */
18105
18106 @<Declare the basic parsing subroutines@>=
18107 static void mp_scan_expression (MP mp) {
18108   pointer p,q,r,pp,qq; /* for list manipulation */
18109   halfword c,d; /* operation codes or modifiers */
18110   int my_var_flag; /* initial value of |var_flag| */
18111   pointer mac_name; /* token defined with \&{tertiarydef} */
18112   boolean cycle_hit; /* did a path expression just end with `\&{cycle}'? */
18113   scaled x,y; /* explicit coordinates or tension at a path join */
18114   int t; /* knot type following a path join */
18115   t=0; y=0; x=0;
18116   my_var_flag=mp->var_flag; mac_name=null;
18117 RESTART:
18118   if ((mp->cur_cmd<min_primary_command)||
18119       (mp->cur_cmd>max_primary_command) )
18120     mp_bad_exp(mp, "An");
18121 @.An expression...@>
18122   mp_scan_tertiary(mp);
18123 CONTINUE: 
18124   if ( mp->cur_cmd<=max_expression_command )
18125     if ( mp->cur_cmd>=min_expression_command ) {
18126       if ( (mp->cur_cmd!=equals)||(my_var_flag!=assignment) ) {
18127         p=mp_stash_cur_exp(mp); c=mp->cur_mod; d=mp->cur_cmd;
18128         if ( d==expression_tertiary_macro ) {
18129           mac_name=mp->cur_sym; add_mac_ref(c);
18130         }
18131         if ( (d<ampersand)||((d==ampersand)&&
18132              ((type(p)==mp_pair_type)||(type(p)==mp_path_type))) ) {
18133           @<Scan a path construction operation;
18134             but |return| if |p| has the wrong type@>;
18135         } else { 
18136           mp_get_x_next(mp); mp_scan_tertiary(mp);
18137           if ( d!=expression_tertiary_macro ) {
18138             mp_do_binary(mp, p,c);
18139           } else  { 
18140             mp_back_input(mp); mp_binary_mac(mp, p,c,mac_name);
18141             decr(ref_count(c)); mp_get_x_next(mp); 
18142             goto RESTART;
18143           }
18144         }
18145         goto CONTINUE;
18146      }
18147   }
18148 }
18149
18150 @ The reader should review the data structure conventions for paths before
18151 hoping to understand the next part of this code.
18152
18153 @<Scan a path construction operation...@>=
18154
18155   cycle_hit=false;
18156   @<Convert the left operand, |p|, into a partial path ending at~|q|;
18157     but |return| if |p| doesn't have a suitable type@>;
18158 CONTINUE_PATH: 
18159   @<Determine the path join parameters;
18160     but |goto finish_path| if there's only a direction specifier@>;
18161   if ( mp->cur_cmd==cycle ) {
18162     @<Get ready to close a cycle@>;
18163   } else { 
18164     mp_scan_tertiary(mp);
18165     @<Convert the right operand, |cur_exp|,
18166       into a partial path from |pp| to~|qq|@>;
18167   }
18168   @<Join the partial paths and reset |p| and |q| to the head and tail
18169     of the result@>;
18170   if ( mp->cur_cmd>=min_expression_command )
18171     if ( mp->cur_cmd<=ampersand ) if ( ! cycle_hit ) goto CONTINUE_PATH;
18172 FINISH_PATH:
18173   @<Choose control points for the path and put the result into |cur_exp|@>;
18174 }
18175
18176 @ @<Convert the left operand, |p|, into a partial path ending at~|q|...@>=
18177
18178   mp_unstash_cur_exp(mp, p);
18179   if ( mp->cur_type==mp_pair_type ) p=mp_new_knot(mp);
18180   else if ( mp->cur_type==mp_path_type ) p=mp->cur_exp;
18181   else return;
18182   q=p;
18183   while ( mp_link(q)!=p ) q=mp_link(q);
18184   if ( left_type(p)!=mp_endpoint ) { /* open up a cycle */
18185     r=mp_copy_knot(mp, p); mp_link(q)=r; q=r;
18186   }
18187   left_type(p)=mp_open; right_type(q)=mp_open;
18188 }
18189
18190 @ A pair of numeric values is changed into a knot node for a one-point path
18191 when \MP\ discovers that the pair is part of a path.
18192
18193 @c 
18194 static pointer mp_new_knot (MP mp) { /* convert a pair to a knot with two endpoints */
18195   pointer q; /* the new node */
18196   q=mp_get_node(mp, knot_node_size); left_type(q)=mp_endpoint;
18197   right_type(q)=mp_endpoint; originator(q)=mp_metapost_user; mp_link(q)=q;
18198   mp_known_pair(mp); x_coord(q)=mp->cur_x; y_coord(q)=mp->cur_y;
18199   return q;
18200 }
18201
18202 @ The |known_pair| subroutine sets |cur_x| and |cur_y| to the components
18203 of the current expression, assuming that the current expression is a
18204 pair of known numerics. Unknown components are zeroed, and the
18205 current expression is flushed.
18206
18207 @<Declarations@>=
18208 static void mp_known_pair (MP mp);
18209
18210 @ @c
18211 void mp_known_pair (MP mp) {
18212   pointer p; /* the pair node */
18213   if ( mp->cur_type!=mp_pair_type ) {
18214     exp_err("Undefined coordinates have been replaced by (0,0)");
18215 @.Undefined coordinates...@>
18216     help5("I need x and y numbers for this part of the path.",
18217        "The value I found (see above) was no good;",
18218        "so I'll try to keep going by using zero instead.",
18219        "(Chapter 27 of The METAFONTbook explains that",
18220 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18221        "you might want to type `I ??" "?' now.)");
18222     mp_put_get_flush_error(mp, 0); mp->cur_x=0; mp->cur_y=0;
18223   } else { 
18224     p=value(mp->cur_exp);
18225      @<Make sure that both |x| and |y| parts of |p| are known;
18226        copy them into |cur_x| and |cur_y|@>;
18227     mp_flush_cur_exp(mp, 0);
18228   }
18229 }
18230
18231 @ @<Make sure that both |x| and |y| parts of |p| are known...@>=
18232 if ( type(x_part_loc(p))==mp_known ) {
18233   mp->cur_x=value(x_part_loc(p));
18234 } else { 
18235   mp_disp_err(mp, x_part_loc(p),
18236     "Undefined x coordinate has been replaced by 0");
18237 @.Undefined coordinates...@>
18238   help5("I need a `known' x value for this part of the path.",
18239     "The value I found (see above) was no good;",
18240     "so I'll try to keep going by using zero instead.",
18241     "(Chapter 27 of The METAFONTbook explains that",
18242 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18243     "you might want to type `I ??" "?' now.)");
18244   mp_put_get_error(mp); mp_recycle_value(mp, x_part_loc(p)); mp->cur_x=0;
18245 }
18246 if ( type(y_part_loc(p))==mp_known ) {
18247   mp->cur_y=value(y_part_loc(p));
18248 } else { 
18249   mp_disp_err(mp, y_part_loc(p),
18250     "Undefined y coordinate has been replaced by 0");
18251   help5("I need a `known' y value for this part of the path.",
18252     "The value I found (see above) was no good;",
18253     "so I'll try to keep going by using zero instead.",
18254     "(Chapter 27 of The METAFONTbook explains that",
18255     "you might want to type `I ??" "?' now.)");
18256   mp_put_get_error(mp); mp_recycle_value(mp, y_part_loc(p)); mp->cur_y=0;
18257 }
18258
18259 @ At this point |cur_cmd| is either |ampersand|, |left_brace|, or |path_join|.
18260
18261 @<Determine the path join parameters...@>=
18262 if ( mp->cur_cmd==left_brace ) {
18263   @<Put the pre-join direction information into node |q|@>;
18264 }
18265 d=mp->cur_cmd;
18266 if ( d==path_join ) {
18267   @<Determine the tension and/or control points@>;
18268 } else if ( d!=ampersand ) {
18269   goto FINISH_PATH;
18270 }
18271 mp_get_x_next(mp);
18272 if ( mp->cur_cmd==left_brace ) {
18273   @<Put the post-join direction information into |x| and |t|@>;
18274 } else if ( right_type(q)!=mp_explicit ) {
18275   t=mp_open; x=0;
18276 }
18277
18278 @ The |scan_direction| subroutine looks at the directional information
18279 that is enclosed in braces, and also scans ahead to the following character.
18280 A type code is returned, either |open| (if the direction was $(0,0)$),
18281 or |curl| (if the direction was a curl of known value |cur_exp|), or
18282 |given| (if the direction is given by the |angle| value that now
18283 appears in |cur_exp|).
18284
18285 There's nothing difficult about this subroutine, but the program is rather
18286 lengthy because a variety of potential errors need to be nipped in the bud.
18287
18288 @c 
18289 static quarterword mp_scan_direction (MP mp) {
18290   int t; /* the type of information found */
18291   scaled x; /* an |x| coordinate */
18292   mp_get_x_next(mp);
18293   if ( mp->cur_cmd==curl_command ) {
18294      @<Scan a curl specification@>;
18295   } else {
18296     @<Scan a given direction@>;
18297   }
18298   if ( mp->cur_cmd!=right_brace ) {
18299     mp_missing_err(mp, "}");
18300 @.Missing `\char`\}'@>
18301     help3("I've scanned a direction spec for part of a path,",
18302       "so a right brace should have come next.",
18303       "I shall pretend that one was there.");
18304     mp_back_error(mp);
18305   }
18306   mp_get_x_next(mp); 
18307   return t;
18308 }
18309
18310 @ @<Scan a curl specification@>=
18311 { mp_get_x_next(mp); mp_scan_expression(mp);
18312 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<0) ){ 
18313   exp_err("Improper curl has been replaced by 1");
18314 @.Improper curl@>
18315   help1("A curl must be a known, nonnegative number.");
18316   mp_put_get_flush_error(mp, unity);
18317 }
18318 t=mp_curl;
18319 }
18320
18321 @ @<Scan a given direction@>=
18322 { mp_scan_expression(mp);
18323   if ( mp->cur_type>mp_pair_type ) {
18324     @<Get given directions separated by commas@>;
18325   } else {
18326     mp_known_pair(mp);
18327   }
18328   if ( (mp->cur_x==0)&&(mp->cur_y==0) )  t=mp_open;
18329   else  { t=mp_given; mp->cur_exp=mp_n_arg(mp, mp->cur_x,mp->cur_y);}
18330 }
18331
18332 @ @<Get given directions separated by commas@>=
18333
18334   if ( mp->cur_type!=mp_known ) {
18335     exp_err("Undefined x coordinate has been replaced by 0");
18336 @.Undefined coordinates...@>
18337     help5("I need a `known' x value for this part of the path.",
18338       "The value I found (see above) was no good;",
18339       "so I'll try to keep going by using zero instead.",
18340       "(Chapter 27 of The METAFONTbook explains that",
18341 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
18342       "you might want to type `I ??" "?' now.)");
18343     mp_put_get_flush_error(mp, 0);
18344   }
18345   x=mp->cur_exp;
18346   if ( mp->cur_cmd!=comma ) {
18347     mp_missing_err(mp, ",");
18348 @.Missing `,'@>
18349     help2("I've got the x coordinate of a path direction;",
18350           "will look for the y coordinate next.");
18351     mp_back_error(mp);
18352   }
18353   mp_get_x_next(mp); mp_scan_expression(mp);
18354   if ( mp->cur_type!=mp_known ) {
18355      exp_err("Undefined y coordinate has been replaced by 0");
18356     help5("I need a `known' y value for this part of the path.",
18357       "The value I found (see above) was no good;",
18358       "so I'll try to keep going by using zero instead.",
18359       "(Chapter 27 of The METAFONTbook explains that",
18360       "you might want to type `I ??" "?' now.)");
18361     mp_put_get_flush_error(mp, 0);
18362   }
18363   mp->cur_y=mp->cur_exp; mp->cur_x=x;
18364 }
18365
18366 @ At this point |right_type(q)| is usually |open|, but it may have been
18367 set to some other value by a previous operation. We must maintain
18368 the value of |right_type(q)| in cases such as
18369 `\.{..\{curl2\}z\{0,0\}..}'.
18370
18371 @<Put the pre-join...@>=
18372
18373   t=mp_scan_direction(mp);
18374   if ( t!=mp_open ) {
18375     right_type(q)=t; right_given(q)=mp->cur_exp;
18376     if ( left_type(q)==mp_open ) {
18377       left_type(q)=t; left_given(q)=mp->cur_exp;
18378     } /* note that |left_given(q)=left_curl(q)| */
18379   }
18380 }
18381
18382 @ Since |left_tension| and |left_y| share the same position in knot nodes,
18383 and since |left_given| is similarly equivalent to |left_x|, we use
18384 |x| and |y| to hold the given direction and tension information when
18385 there are no explicit control points.
18386
18387 @<Put the post-join...@>=
18388
18389   t=mp_scan_direction(mp);
18390   if ( right_type(q)!=mp_explicit ) x=mp->cur_exp;
18391   else t=mp_explicit; /* the direction information is superfluous */
18392 }
18393
18394 @ @<Determine the tension and/or...@>=
18395
18396   mp_get_x_next(mp);
18397   if ( mp->cur_cmd==tension ) {
18398     @<Set explicit tensions@>;
18399   } else if ( mp->cur_cmd==controls ) {
18400     @<Set explicit control points@>;
18401   } else  { 
18402     right_tension(q)=unity; y=unity; mp_back_input(mp); /* default tension */
18403     goto DONE;
18404   };
18405   if ( mp->cur_cmd!=path_join ) {
18406      mp_missing_err(mp, "..");
18407 @.Missing `..'@>
18408     help1("A path join command should end with two dots.");
18409     mp_back_error(mp);
18410   }
18411 DONE:
18412   ;
18413 }
18414
18415 @ @<Set explicit tensions@>=
18416
18417   mp_get_x_next(mp); y=mp->cur_cmd;
18418   if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18419   mp_scan_primary(mp);
18420   @<Make sure that the current expression is a valid tension setting@>;
18421   if ( y==at_least ) negate(mp->cur_exp);
18422   right_tension(q)=mp->cur_exp;
18423   if ( mp->cur_cmd==and_command ) {
18424     mp_get_x_next(mp); y=mp->cur_cmd;
18425     if ( mp->cur_cmd==at_least ) mp_get_x_next(mp);
18426     mp_scan_primary(mp);
18427     @<Make sure that the current expression is a valid tension setting@>;
18428     if ( y==at_least ) negate(mp->cur_exp);
18429   }
18430   y=mp->cur_exp;
18431 }
18432
18433 @ @d min_tension three_quarter_unit
18434
18435 @<Make sure that the current expression is a valid tension setting@>=
18436 if ( (mp->cur_type!=mp_known)||(mp->cur_exp<min_tension) ) {
18437   exp_err("Improper tension has been set to 1");
18438 @.Improper tension@>
18439   help1("The expression above should have been a number >=3/4.");
18440   mp_put_get_flush_error(mp, unity);
18441 }
18442
18443 @ @<Set explicit control points@>=
18444
18445   right_type(q)=mp_explicit; t=mp_explicit; mp_get_x_next(mp); mp_scan_primary(mp);
18446   mp_known_pair(mp); right_x(q)=mp->cur_x; right_y(q)=mp->cur_y;
18447   if ( mp->cur_cmd!=and_command ) {
18448     x=right_x(q); y=right_y(q);
18449   } else { 
18450     mp_get_x_next(mp); mp_scan_primary(mp);
18451     mp_known_pair(mp); x=mp->cur_x; y=mp->cur_y;
18452   }
18453 }
18454
18455 @ @<Convert the right operand, |cur_exp|, into a partial path...@>=
18456
18457   if ( mp->cur_type!=mp_path_type ) pp=mp_new_knot(mp);
18458   else pp=mp->cur_exp;
18459   qq=pp;
18460   while ( mp_link(qq)!=pp ) qq=mp_link(qq);
18461   if ( left_type(pp)!=mp_endpoint ) { /* open up a cycle */
18462     r=mp_copy_knot(mp, pp); mp_link(qq)=r; qq=r;
18463   }
18464   left_type(pp)=mp_open; right_type(qq)=mp_open;
18465 }
18466
18467 @ If a person tries to define an entire path by saying `\.{(x,y)\&cycle}',
18468 we silently change the specification to `\.{(x,y)..cycle}', since a cycle
18469 shouldn't have length zero.
18470
18471 @<Get ready to close a cycle@>=
18472
18473   cycle_hit=true; mp_get_x_next(mp); pp=p; qq=p;
18474   if ( d==ampersand ) if ( p==q ) {
18475     d=path_join; right_tension(q)=unity; y=unity;
18476   }
18477 }
18478
18479 @ @<Join the partial paths and reset |p| and |q|...@>=
18480
18481 if ( d==ampersand ) {
18482   if ( (x_coord(q)!=x_coord(pp))||(y_coord(q)!=y_coord(pp)) ) {
18483     print_err("Paths don't touch; `&' will be changed to `..'");
18484 @.Paths don't touch@>
18485     help3("When you join paths `p&q', the ending point of p",
18486       "must be exactly equal to the starting point of q.",
18487       "So I'm going to pretend that you said `p..q' instead.");
18488     mp_put_get_error(mp); d=path_join; right_tension(q)=unity; y=unity;
18489   }
18490 }
18491 @<Plug an opening in |right_type(pp)|, if possible@>;
18492 if ( d==ampersand ) {
18493   @<Splice independent paths together@>;
18494 } else  { 
18495   @<Plug an opening in |right_type(q)|, if possible@>;
18496   mp_link(q)=pp; left_y(pp)=y;
18497   if ( t!=mp_open ) { left_x(pp)=x; left_type(pp)=t;  };
18498 }
18499 q=qq;
18500 }
18501
18502 @ @<Plug an opening in |right_type(q)|...@>=
18503 if ( right_type(q)==mp_open ) {
18504   if ( (left_type(q)==mp_curl)||(left_type(q)==mp_given) ) {
18505     right_type(q)=left_type(q); right_given(q)=left_given(q);
18506   }
18507 }
18508
18509 @ @<Plug an opening in |right_type(pp)|...@>=
18510 if ( right_type(pp)==mp_open ) {
18511   if ( (t==mp_curl)||(t==mp_given) ) {
18512     right_type(pp)=t; right_given(pp)=x;
18513   }
18514 }
18515
18516 @ @<Splice independent paths together@>=
18517
18518   if ( left_type(q)==mp_open ) if ( right_type(q)==mp_open ) {
18519     left_type(q)=mp_curl; left_curl(q)=unity;
18520   }
18521   if ( right_type(pp)==mp_open ) if ( t==mp_open ) {
18522     right_type(pp)=mp_curl; right_curl(pp)=unity;
18523   }
18524   right_type(q)=right_type(pp); mp_link(q)=mp_link(pp);
18525   right_x(q)=right_x(pp); right_y(q)=right_y(pp);
18526   mp_free_node(mp, pp,knot_node_size);
18527   if ( qq==pp ) qq=q;
18528 }
18529
18530 @ @<Choose control points for the path...@>=
18531 if ( cycle_hit ) { 
18532   if ( d==ampersand ) p=q;
18533 } else  { 
18534   left_type(p)=mp_endpoint;
18535   if ( right_type(p)==mp_open ) { 
18536     right_type(p)=mp_curl; right_curl(p)=unity;
18537   }
18538   right_type(q)=mp_endpoint;
18539   if ( left_type(q)==mp_open ) { 
18540     left_type(q)=mp_curl; left_curl(q)=unity;
18541   }
18542   mp_link(q)=p;
18543 }
18544 mp_make_choices(mp, p);
18545 mp->cur_type=mp_path_type; mp->cur_exp=p
18546
18547 @ Finally, we sometimes need to scan an expression whose value is
18548 supposed to be either |true_code| or |false_code|.
18549
18550 @<Declare the basic parsing subroutines@>=
18551 static void mp_get_boolean (MP mp) { 
18552   mp_get_x_next(mp); mp_scan_expression(mp);
18553   if ( mp->cur_type!=mp_boolean_type ) {
18554     exp_err("Undefined condition will be treated as `false'");
18555 @.Undefined condition...@>
18556     help2("The expression shown above should have had a definite",
18557           "true-or-false value. I'm changing it to `false'.");
18558     mp_put_get_flush_error(mp, false_code); mp->cur_type=mp_boolean_type;
18559   }
18560 }
18561
18562 @* \[39] Doing the operations.
18563 The purpose of parsing is primarily to permit people to avoid piles of
18564 parentheses. But the real work is done after the structure of an expression
18565 has been recognized; that's when new expressions are generated. We
18566 turn now to the guts of \MP, which handles individual operators that
18567 have come through the parsing mechanism.
18568
18569 We'll start with the easy ones that take no operands, then work our way
18570 up to operators with one and ultimately two arguments. In other words,
18571 we will write the three procedures |do_nullary|, |do_unary|, and |do_binary|
18572 that are invoked periodically by the expression scanners.
18573
18574 First let's make sure that all of the primitive operators are in the
18575 hash table. Although |scan_primary| and its relatives made use of the
18576 \\{cmd} code for these operators, the \\{do} routines base everything
18577 on the \\{mod} code. For example, |do_binary| doesn't care whether the
18578 operation it performs is a |primary_binary| or |secondary_binary|, etc.
18579
18580 @<Put each...@>=
18581 mp_primitive(mp, "true",nullary,true_code);
18582 @:true_}{\&{true} primitive@>
18583 mp_primitive(mp, "false",nullary,false_code);
18584 @:false_}{\&{false} primitive@>
18585 mp_primitive(mp, "nullpicture",nullary,null_picture_code);
18586 @:null_picture_}{\&{nullpicture} primitive@>
18587 mp_primitive(mp, "nullpen",nullary,null_pen_code);
18588 @:null_pen_}{\&{nullpen} primitive@>
18589 mp_primitive(mp, "jobname",nullary,job_name_op);
18590 @:job_name_}{\&{jobname} primitive@>
18591 mp_primitive(mp, "readstring",nullary,read_string_op);
18592 @:read_string_}{\&{readstring} primitive@>
18593 mp_primitive(mp, "pencircle",nullary,pen_circle);
18594 @:pen_circle_}{\&{pencircle} primitive@>
18595 mp_primitive(mp, "normaldeviate",nullary,normal_deviate);
18596 @:normal_deviate_}{\&{normaldeviate} primitive@>
18597 mp_primitive(mp, "readfrom",unary,read_from_op);
18598 @:read_from_}{\&{readfrom} primitive@>
18599 mp_primitive(mp, "closefrom",unary,close_from_op);
18600 @:close_from_}{\&{closefrom} primitive@>
18601 mp_primitive(mp, "odd",unary,odd_op);
18602 @:odd_}{\&{odd} primitive@>
18603 mp_primitive(mp, "known",unary,known_op);
18604 @:known_}{\&{known} primitive@>
18605 mp_primitive(mp, "unknown",unary,unknown_op);
18606 @:unknown_}{\&{unknown} primitive@>
18607 mp_primitive(mp, "not",unary,not_op);
18608 @:not_}{\&{not} primitive@>
18609 mp_primitive(mp, "decimal",unary,decimal);
18610 @:decimal_}{\&{decimal} primitive@>
18611 mp_primitive(mp, "reverse",unary,reverse);
18612 @:reverse_}{\&{reverse} primitive@>
18613 mp_primitive(mp, "makepath",unary,make_path_op);
18614 @:make_path_}{\&{makepath} primitive@>
18615 mp_primitive(mp, "makepen",unary,make_pen_op);
18616 @:make_pen_}{\&{makepen} primitive@>
18617 mp_primitive(mp, "oct",unary,oct_op);
18618 @:oct_}{\&{oct} primitive@>
18619 mp_primitive(mp, "hex",unary,hex_op);
18620 @:hex_}{\&{hex} primitive@>
18621 mp_primitive(mp, "ASCII",unary,ASCII_op);
18622 @:ASCII_}{\&{ASCII} primitive@>
18623 mp_primitive(mp, "char",unary,char_op);
18624 @:char_}{\&{char} primitive@>
18625 mp_primitive(mp, "length",unary,length_op);
18626 @:length_}{\&{length} primitive@>
18627 mp_primitive(mp, "turningnumber",unary,turning_op);
18628 @:turning_number_}{\&{turningnumber} primitive@>
18629 mp_primitive(mp, "xpart",unary,x_part);
18630 @:x_part_}{\&{xpart} primitive@>
18631 mp_primitive(mp, "ypart",unary,y_part);
18632 @:y_part_}{\&{ypart} primitive@>
18633 mp_primitive(mp, "xxpart",unary,xx_part);
18634 @:xx_part_}{\&{xxpart} primitive@>
18635 mp_primitive(mp, "xypart",unary,xy_part);
18636 @:xy_part_}{\&{xypart} primitive@>
18637 mp_primitive(mp, "yxpart",unary,yx_part);
18638 @:yx_part_}{\&{yxpart} primitive@>
18639 mp_primitive(mp, "yypart",unary,yy_part);
18640 @:yy_part_}{\&{yypart} primitive@>
18641 mp_primitive(mp, "redpart",unary,red_part);
18642 @:red_part_}{\&{redpart} primitive@>
18643 mp_primitive(mp, "greenpart",unary,green_part);
18644 @:green_part_}{\&{greenpart} primitive@>
18645 mp_primitive(mp, "bluepart",unary,blue_part);
18646 @:blue_part_}{\&{bluepart} primitive@>
18647 mp_primitive(mp, "cyanpart",unary,cyan_part);
18648 @:cyan_part_}{\&{cyanpart} primitive@>
18649 mp_primitive(mp, "magentapart",unary,magenta_part);
18650 @:magenta_part_}{\&{magentapart} primitive@>
18651 mp_primitive(mp, "yellowpart",unary,yellow_part);
18652 @:yellow_part_}{\&{yellowpart} primitive@>
18653 mp_primitive(mp, "blackpart",unary,black_part);
18654 @:black_part_}{\&{blackpart} primitive@>
18655 mp_primitive(mp, "greypart",unary,grey_part);
18656 @:grey_part_}{\&{greypart} primitive@>
18657 mp_primitive(mp, "colormodel",unary,color_model_part);
18658 @:color_model_part_}{\&{colormodel} primitive@>
18659 mp_primitive(mp, "fontpart",unary,font_part);
18660 @:font_part_}{\&{fontpart} primitive@>
18661 mp_primitive(mp, "textpart",unary,text_part);
18662 @:text_part_}{\&{textpart} primitive@>
18663 mp_primitive(mp, "pathpart",unary,path_part);
18664 @:path_part_}{\&{pathpart} primitive@>
18665 mp_primitive(mp, "penpart",unary,pen_part);
18666 @:pen_part_}{\&{penpart} primitive@>
18667 mp_primitive(mp, "dashpart",unary,dash_part);
18668 @:dash_part_}{\&{dashpart} primitive@>
18669 mp_primitive(mp, "sqrt",unary,sqrt_op);
18670 @:sqrt_}{\&{sqrt} primitive@>
18671 mp_primitive(mp, "mexp",unary,mp_m_exp_op);
18672 @:m_exp_}{\&{mexp} primitive@>
18673 mp_primitive(mp, "mlog",unary,mp_m_log_op);
18674 @:m_log_}{\&{mlog} primitive@>
18675 mp_primitive(mp, "sind",unary,sin_d_op);
18676 @:sin_d_}{\&{sind} primitive@>
18677 mp_primitive(mp, "cosd",unary,cos_d_op);
18678 @:cos_d_}{\&{cosd} primitive@>
18679 mp_primitive(mp, "floor",unary,floor_op);
18680 @:floor_}{\&{floor} primitive@>
18681 mp_primitive(mp, "uniformdeviate",unary,uniform_deviate);
18682 @:uniform_deviate_}{\&{uniformdeviate} primitive@>
18683 mp_primitive(mp, "charexists",unary,char_exists_op);
18684 @:char_exists_}{\&{charexists} primitive@>
18685 mp_primitive(mp, "fontsize",unary,font_size);
18686 @:font_size_}{\&{fontsize} primitive@>
18687 mp_primitive(mp, "llcorner",unary,ll_corner_op);
18688 @:ll_corner_}{\&{llcorner} primitive@>
18689 mp_primitive(mp, "lrcorner",unary,lr_corner_op);
18690 @:lr_corner_}{\&{lrcorner} primitive@>
18691 mp_primitive(mp, "ulcorner",unary,ul_corner_op);
18692 @:ul_corner_}{\&{ulcorner} primitive@>
18693 mp_primitive(mp, "urcorner",unary,ur_corner_op);
18694 @:ur_corner_}{\&{urcorner} primitive@>
18695 mp_primitive(mp, "arclength",unary,arc_length);
18696 @:arc_length_}{\&{arclength} primitive@>
18697 mp_primitive(mp, "angle",unary,angle_op);
18698 @:angle_}{\&{angle} primitive@>
18699 mp_primitive(mp, "cycle",cycle,cycle_op);
18700 @:cycle_}{\&{cycle} primitive@>
18701 mp_primitive(mp, "stroked",unary,stroked_op);
18702 @:stroked_}{\&{stroked} primitive@>
18703 mp_primitive(mp, "filled",unary,filled_op);
18704 @:filled_}{\&{filled} primitive@>
18705 mp_primitive(mp, "textual",unary,textual_op);
18706 @:textual_}{\&{textual} primitive@>
18707 mp_primitive(mp, "clipped",unary,clipped_op);
18708 @:clipped_}{\&{clipped} primitive@>
18709 mp_primitive(mp, "bounded",unary,bounded_op);
18710 @:bounded_}{\&{bounded} primitive@>
18711 mp_primitive(mp, "+",plus_or_minus,plus);
18712 @:+ }{\.{+} primitive@>
18713 mp_primitive(mp, "-",plus_or_minus,minus);
18714 @:- }{\.{-} primitive@>
18715 mp_primitive(mp, "*",secondary_binary,times);
18716 @:* }{\.{*} primitive@>
18717 mp_primitive(mp, "/",slash,over); mp->eqtb[frozen_slash]=mp->eqtb[mp->cur_sym];
18718 @:/ }{\.{/} primitive@>
18719 mp_primitive(mp, "++",tertiary_binary,pythag_add);
18720 @:++_}{\.{++} primitive@>
18721 mp_primitive(mp, "+-+",tertiary_binary,pythag_sub);
18722 @:+-+_}{\.{+-+} primitive@>
18723 mp_primitive(mp, "or",tertiary_binary,or_op);
18724 @:or_}{\&{or} primitive@>
18725 mp_primitive(mp, "and",and_command,and_op);
18726 @:and_}{\&{and} primitive@>
18727 mp_primitive(mp, "<",expression_binary,less_than);
18728 @:< }{\.{<} primitive@>
18729 mp_primitive(mp, "<=",expression_binary,less_or_equal);
18730 @:<=_}{\.{<=} primitive@>
18731 mp_primitive(mp, ">",expression_binary,greater_than);
18732 @:> }{\.{>} primitive@>
18733 mp_primitive(mp, ">=",expression_binary,greater_or_equal);
18734 @:>=_}{\.{>=} primitive@>
18735 mp_primitive(mp, "=",equals,equal_to);
18736 @:= }{\.{=} primitive@>
18737 mp_primitive(mp, "<>",expression_binary,unequal_to);
18738 @:<>_}{\.{<>} primitive@>
18739 mp_primitive(mp, "substring",primary_binary,substring_of);
18740 @:substring_}{\&{substring} primitive@>
18741 mp_primitive(mp, "subpath",primary_binary,subpath_of);
18742 @:subpath_}{\&{subpath} primitive@>
18743 mp_primitive(mp, "directiontime",primary_binary,direction_time_of);
18744 @:direction_time_}{\&{directiontime} primitive@>
18745 mp_primitive(mp, "point",primary_binary,point_of);
18746 @:point_}{\&{point} primitive@>
18747 mp_primitive(mp, "precontrol",primary_binary,precontrol_of);
18748 @:precontrol_}{\&{precontrol} primitive@>
18749 mp_primitive(mp, "postcontrol",primary_binary,postcontrol_of);
18750 @:postcontrol_}{\&{postcontrol} primitive@>
18751 mp_primitive(mp, "penoffset",primary_binary,pen_offset_of);
18752 @:pen_offset_}{\&{penoffset} primitive@>
18753 mp_primitive(mp, "arctime",primary_binary,arc_time_of);
18754 @:arc_time_of_}{\&{arctime} primitive@>
18755 mp_primitive(mp, "mpversion",nullary,mp_version);
18756 @:mp_verison_}{\&{mpversion} primitive@>
18757 mp_primitive(mp, "&",ampersand,concatenate);
18758 @:!!!}{\.{\&} primitive@>
18759 mp_primitive(mp, "rotated",secondary_binary,rotated_by);
18760 @:rotated_}{\&{rotated} primitive@>
18761 mp_primitive(mp, "slanted",secondary_binary,slanted_by);
18762 @:slanted_}{\&{slanted} primitive@>
18763 mp_primitive(mp, "scaled",secondary_binary,scaled_by);
18764 @:scaled_}{\&{scaled} primitive@>
18765 mp_primitive(mp, "shifted",secondary_binary,shifted_by);
18766 @:shifted_}{\&{shifted} primitive@>
18767 mp_primitive(mp, "transformed",secondary_binary,transformed_by);
18768 @:transformed_}{\&{transformed} primitive@>
18769 mp_primitive(mp, "xscaled",secondary_binary,x_scaled);
18770 @:x_scaled_}{\&{xscaled} primitive@>
18771 mp_primitive(mp, "yscaled",secondary_binary,y_scaled);
18772 @:y_scaled_}{\&{yscaled} primitive@>
18773 mp_primitive(mp, "zscaled",secondary_binary,z_scaled);
18774 @:z_scaled_}{\&{zscaled} primitive@>
18775 mp_primitive(mp, "infont",secondary_binary,in_font);
18776 @:in_font_}{\&{infont} primitive@>
18777 mp_primitive(mp, "intersectiontimes",tertiary_binary,intersect);
18778 @:intersection_times_}{\&{intersectiontimes} primitive@>
18779 mp_primitive(mp, "envelope",primary_binary,envelope_of);
18780 @:envelope_}{\&{envelope} primitive@>
18781
18782 @ @<Cases of |print_cmd...@>=
18783 case nullary:
18784 case unary:
18785 case primary_binary:
18786 case secondary_binary:
18787 case tertiary_binary:
18788 case expression_binary:
18789 case cycle:
18790 case plus_or_minus:
18791 case slash:
18792 case ampersand:
18793 case equals:
18794 case and_command:
18795   mp_print_op(mp, m);
18796   break;
18797
18798 @ OK, let's look at the simplest \\{do} procedure first.
18799
18800 @c @<Declare nullary action procedure@>
18801 static void mp_do_nullary (MP mp,quarterword c) { 
18802   check_arith;
18803   if ( mp->internal[mp_tracing_commands]>two )
18804     mp_show_cmd_mod(mp, nullary,c);
18805   switch (c) {
18806   case true_code: case false_code: 
18807     mp->cur_type=mp_boolean_type; mp->cur_exp=c;
18808     break;
18809   case null_picture_code: 
18810     mp->cur_type=mp_picture_type;
18811     mp->cur_exp=mp_get_node(mp, edge_header_size); 
18812     mp_init_edges(mp, mp->cur_exp);
18813     break;
18814   case null_pen_code: 
18815     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, 0);
18816     break;
18817   case normal_deviate: 
18818     mp->cur_type=mp_known; mp->cur_exp=mp_norm_rand(mp);
18819     break;
18820   case pen_circle: 
18821     mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, unity);
18822     break;
18823   case job_name_op:  
18824     if ( mp->job_name==NULL ) mp_open_log_file(mp);
18825     mp->cur_type=mp_string_type; mp->cur_exp=rts(mp->job_name);
18826     break;
18827   case mp_version: 
18828     mp->cur_type=mp_string_type; 
18829     mp->cur_exp=intern(metapost_version) ;
18830     break;
18831   case read_string_op:
18832     @<Read a string from the terminal@>;
18833     break;
18834   } /* there are no other cases */
18835   check_arith;
18836 }
18837
18838 @ @<Read a string...@>=
18839
18840   if (mp->noninteractive || mp->interaction<=mp_nonstop_mode )
18841     mp_fatal_error(mp, "*** (cannot readstring in nonstop modes)");
18842   mp_begin_file_reading(mp); name=is_read;
18843   limit=start; prompt_input("");
18844   mp_finish_read(mp);
18845 }
18846
18847 @ @<Declare nullary action procedure@>=
18848 static void mp_finish_read (MP mp) { /* copy |buffer| line to |cur_exp| */
18849   size_t k;
18850   str_room((int)mp->last-start);
18851   for (k=(size_t)start;k<=mp->last-1;k++) {
18852    append_char(mp->buffer[k]);
18853   }
18854   mp_end_file_reading(mp); mp->cur_type=mp_string_type; 
18855   mp->cur_exp=mp_make_string(mp);
18856 }
18857
18858 @ Things get a bit more interesting when there's an operand. The
18859 operand to |do_unary| appears in |cur_type| and |cur_exp|.
18860
18861 @c @<Declare unary action procedures@>
18862 static void mp_do_unary (MP mp,quarterword c) {
18863   pointer p,q,r; /* for list manipulation */
18864   integer x; /* a temporary register */
18865   check_arith;
18866   if ( mp->internal[mp_tracing_commands]>two )
18867     @<Trace the current unary operation@>;
18868   switch (c) {
18869   case plus:
18870     if ( mp->cur_type<mp_color_type ) mp_bad_unary(mp, plus);
18871     break;
18872   case minus:
18873     @<Negate the current expression@>;
18874     break;
18875   @<Additional cases of unary operators@>;
18876   } /* there are no other cases */
18877   check_arith;
18878 }
18879
18880 @ The |nice_pair| function returns |true| if both components of a pair
18881 are known.
18882
18883 @<Declare unary action procedures@>=
18884 static boolean mp_nice_pair (MP mp,integer p, quarterword t) { 
18885   if ( t==mp_pair_type ) {
18886     p=value(p);
18887     if ( type(x_part_loc(p))==mp_known )
18888       if ( type(y_part_loc(p))==mp_known )
18889         return true;
18890   }
18891   return false;
18892 }
18893
18894 @ The |nice_color_or_pair| function is analogous except that it also accepts
18895 fully known colors.
18896
18897 @<Declare unary action procedures@>=
18898 static boolean mp_nice_color_or_pair (MP mp,integer p, quarterword t) {
18899   pointer q,r; /* for scanning the big node */
18900   if ( (t!=mp_pair_type)&&(t!=mp_color_type)&&(t!=mp_cmykcolor_type) ) {
18901     return false;
18902   } else { 
18903     q=value(p);
18904     r=q+mp->big_node_size[type(p)];
18905     do {  
18906       r=r-2;
18907       if ( type(r)!=mp_known )
18908         return false;
18909     } while (r!=q);
18910     return true;
18911   }
18912 }
18913
18914 @ @<Declare unary action...@>=
18915 static void mp_print_known_or_unknown_type (MP mp,quarterword t, integer v) { 
18916   mp_print_char(mp, xord('('));
18917   if ( t>mp_known ) mp_print(mp, "unknown numeric");
18918   else { if ( (t==mp_pair_type)||(t==mp_color_type)||(t==mp_cmykcolor_type) )
18919     if ( ! mp_nice_color_or_pair(mp, v,t) ) mp_print(mp, "unknown ");
18920     mp_print_type(mp, t);
18921   }
18922   mp_print_char(mp, xord(')'));
18923 }
18924
18925 @ @<Declare unary action...@>=
18926 static void mp_bad_unary (MP mp,quarterword c) { 
18927   exp_err("Not implemented: "); mp_print_op(mp, c);
18928 @.Not implemented...@>
18929   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
18930   help3("I'm afraid I don't know how to apply that operation to that",
18931     "particular type. Continue, and I'll simply return the",
18932     "argument (shown above) as the result of the operation.");
18933   mp_put_get_error(mp);
18934 }
18935
18936 @ @<Trace the current unary operation@>=
18937
18938   mp_begin_diagnostic(mp); mp_print_nl(mp, "{"); 
18939   mp_print_op(mp, c); mp_print_char(mp, xord('('));
18940   mp_print_exp(mp, null,0); /* show the operand, but not verbosely */
18941   mp_print(mp, ")}"); mp_end_diagnostic(mp, false);
18942 }
18943
18944 @ Negation is easy except when the current expression
18945 is of type |independent|, or when it is a pair with one or more
18946 |independent| components.
18947
18948 It is tempting to argue that the negative of an independent variable
18949 is an independent variable, hence we don't have to do anything when
18950 negating it. The fallacy is that other dependent variables pointing
18951 to the current expression must change the sign of their
18952 coefficients if we make no change to the current expression.
18953
18954 Instead, we work around the problem by copying the current expression
18955 and recycling it afterwards (cf.~the |stash_in| routine).
18956
18957 @<Negate the current expression@>=
18958 switch (mp->cur_type) {
18959 case mp_color_type:
18960 case mp_cmykcolor_type:
18961 case mp_pair_type:
18962 case mp_independent: 
18963   q=mp->cur_exp; mp_make_exp_copy(mp, q);
18964   if ( mp->cur_type==mp_dependent ) {
18965     mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18966   } else if ( mp->cur_type<=mp_pair_type ) { /* |mp_color_type| or |mp_pair_type| */
18967     p=value(mp->cur_exp);
18968     r=p+mp->big_node_size[mp->cur_type];
18969     do {  
18970       r=r-2;
18971       if ( type(r)==mp_known ) negate(value(r));
18972       else mp_negate_dep_list(mp, dep_list(r));
18973     } while (r!=p);
18974   } /* if |cur_type=mp_known| then |cur_exp=0| */
18975   mp_recycle_value(mp, q); mp_free_node(mp, q,value_node_size);
18976   break;
18977 case mp_dependent:
18978 case mp_proto_dependent:
18979   mp_negate_dep_list(mp, dep_list(mp->cur_exp));
18980   break;
18981 case mp_known:
18982   negate(mp->cur_exp);
18983   break;
18984 default:
18985   mp_bad_unary(mp, minus);
18986   break;
18987 }
18988
18989 @ @<Declare unary action...@>=
18990 static void mp_negate_dep_list (MP mp,pointer p) { 
18991   while (1) { 
18992     negate(value(p));
18993     if ( info(p)==null ) return;
18994     p=mp_link(p);
18995   }
18996 }
18997
18998 @ @<Additional cases of unary operators@>=
18999 case not_op: 
19000   if ( mp->cur_type!=mp_boolean_type ) mp_bad_unary(mp, not_op);
19001   else mp->cur_exp=true_code+false_code-mp->cur_exp;
19002   break;
19003
19004 @ @d three_sixty_units 23592960 /* that's |360*unity| */
19005 @d boolean_reset(A) if ( (A) ) mp->cur_exp=true_code; else mp->cur_exp=false_code
19006
19007 @<Additional cases of unary operators@>=
19008 case sqrt_op:
19009 case mp_m_exp_op:
19010 case mp_m_log_op:
19011 case sin_d_op:
19012 case cos_d_op:
19013 case floor_op:
19014 case  uniform_deviate:
19015 case odd_op:
19016 case char_exists_op:
19017   if ( mp->cur_type!=mp_known ) {
19018     mp_bad_unary(mp, c);
19019   } else {
19020     switch (c) {
19021     case sqrt_op:mp->cur_exp=mp_square_rt(mp, mp->cur_exp);break;
19022     case mp_m_exp_op:mp->cur_exp=mp_m_exp(mp, mp->cur_exp);break;
19023     case mp_m_log_op:mp->cur_exp=mp_m_log(mp, mp->cur_exp);break;
19024     case sin_d_op:
19025     case cos_d_op:
19026       mp_n_sin_cos(mp, (mp->cur_exp % three_sixty_units)*16);
19027       if ( c==sin_d_op ) mp->cur_exp=mp_round_fraction(mp, mp->n_sin);
19028       else mp->cur_exp=mp_round_fraction(mp, mp->n_cos);
19029       break;
19030     case floor_op:mp->cur_exp=mp_floor_scaled(mp, mp->cur_exp);break;
19031     case uniform_deviate:mp->cur_exp=mp_unif_rand(mp, mp->cur_exp);break;
19032     case odd_op: 
19033       boolean_reset(odd(mp_round_unscaled(mp, mp->cur_exp)));
19034       mp->cur_type=mp_boolean_type;
19035       break;
19036     case char_exists_op:
19037       @<Determine if a character has been shipped out@>;
19038       break;
19039     } /* there are no other cases */
19040   }
19041   break;
19042
19043 @ @<Additional cases of unary operators@>=
19044 case angle_op:
19045   if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) ) {
19046     p=value(mp->cur_exp);
19047     x=mp_n_arg(mp, value(x_part_loc(p)),value(y_part_loc(p)));
19048     if ( x>=0 ) mp_flush_cur_exp(mp, (x+8)/ 16);
19049     else mp_flush_cur_exp(mp, -((-x+8)/ 16));
19050   } else {
19051     mp_bad_unary(mp, angle_op);
19052   }
19053   break;
19054
19055 @ If the current expression is a pair, but the context wants it to
19056 be a path, we call |pair_to_path|.
19057
19058 @<Declare unary action...@>=
19059 static void mp_pair_to_path (MP mp) { 
19060   mp->cur_exp=mp_new_knot(mp); 
19061   mp->cur_type=mp_path_type;
19062 }
19063
19064
19065 @d pict_color_type(A) ((mp_link(dummy_loc(mp->cur_exp))!=null) &&
19066                        (has_color(mp_link(dummy_loc(mp->cur_exp)))) &&
19067                        ((color_model(mp_link(dummy_loc(mp->cur_exp)))==A)
19068                         ||
19069                         ((color_model(mp_link(dummy_loc(mp->cur_exp)))==mp_uninitialized_model) &&
19070                         (mp->internal[mp_default_color_model]/unity)==(A))))
19071
19072 @<Additional cases of unary operators@>=
19073 case x_part:
19074 case y_part:
19075   if ( (mp->cur_type==mp_pair_type)||(mp->cur_type==mp_transform_type) )
19076     mp_take_part(mp, c);
19077   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19078   else mp_bad_unary(mp, c);
19079   break;
19080 case xx_part:
19081 case xy_part:
19082 case yx_part:
19083 case yy_part: 
19084   if ( mp->cur_type==mp_transform_type ) mp_take_part(mp, c);
19085   else if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19086   else mp_bad_unary(mp, c);
19087   break;
19088 case red_part:
19089 case green_part:
19090 case blue_part: 
19091   if ( mp->cur_type==mp_color_type ) mp_take_part(mp, c);
19092   else if ( mp->cur_type==mp_picture_type ) {
19093     if pict_color_type(mp_rgb_model) mp_take_pict_part(mp, c);
19094     else mp_bad_color_part(mp, c);
19095   }
19096   else mp_bad_unary(mp, c);
19097   break;
19098 case cyan_part:
19099 case magenta_part:
19100 case yellow_part:
19101 case black_part: 
19102   if ( mp->cur_type==mp_cmykcolor_type) mp_take_part(mp, c); 
19103   else if ( mp->cur_type==mp_picture_type ) {
19104     if pict_color_type(mp_cmyk_model) mp_take_pict_part(mp, c);
19105     else mp_bad_color_part(mp, c);
19106   }
19107   else mp_bad_unary(mp, c);
19108   break;
19109 case grey_part: 
19110   if ( mp->cur_type==mp_known ) mp->cur_exp=value(c);
19111   else if ( mp->cur_type==mp_picture_type ) {
19112     if pict_color_type(mp_grey_model) mp_take_pict_part(mp, c);
19113     else mp_bad_color_part(mp, c);
19114   }
19115   else mp_bad_unary(mp, c);
19116   break;
19117 case color_model_part: 
19118   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19119   else mp_bad_unary(mp, c);
19120   break;
19121
19122 @ @<Declarations@>=
19123 static void mp_bad_color_part(MP mp, quarterword c);
19124
19125 @ @c
19126 static void mp_bad_color_part(MP mp, quarterword c) {
19127   pointer p; /* the big node */
19128   p=mp_link(dummy_loc(mp->cur_exp));
19129   exp_err("Wrong picture color model: "); mp_print_op(mp, c);
19130 @.Wrong picture color model...@>
19131   if (color_model(p)==mp_grey_model)
19132     mp_print(mp, " of grey object");
19133   else if (color_model(p)==mp_cmyk_model)
19134     mp_print(mp, " of cmyk object");
19135   else if (color_model(p)==mp_rgb_model)
19136     mp_print(mp, " of rgb object");
19137   else if (color_model(p)==mp_no_model) 
19138     mp_print(mp, " of marking object");
19139   else 
19140     mp_print(mp," of defaulted object");
19141   help3("You can only ask for the redpart, greenpart, bluepart of a rgb object,",
19142     "the cyanpart, magentapart, yellowpart or blackpart of a cmyk object, ",
19143     "or the greypart of a grey object. No mixing and matching, please.");
19144   mp_error(mp);
19145   if (c==black_part)
19146     mp_flush_cur_exp(mp,unity);
19147   else
19148     mp_flush_cur_exp(mp,0);
19149 }
19150
19151 @ In the following procedure, |cur_exp| points to a capsule, which points to
19152 a big node. We want to delete all but one part of the big node.
19153
19154 @<Declare unary action...@>=
19155 static void mp_take_part (MP mp,quarterword c) {
19156   pointer p; /* the big node */
19157   p=value(mp->cur_exp); value(temp_val)=p; type(temp_val)=mp->cur_type;
19158   mp_link(p)=temp_val; mp_free_node(mp, mp->cur_exp,value_node_size);
19159   mp_make_exp_copy(mp, p+mp->sector_offset[c+mp_x_part_sector-x_part]);
19160   mp_recycle_value(mp, temp_val);
19161 }
19162
19163 @ @<Initialize table entries...@>=
19164 name_type(temp_val)=mp_capsule;
19165
19166 @ @<Additional cases of unary operators@>=
19167 case font_part:
19168 case text_part:
19169 case path_part:
19170 case pen_part:
19171 case dash_part:
19172   if ( mp->cur_type==mp_picture_type ) mp_take_pict_part(mp, c);
19173   else mp_bad_unary(mp, c);
19174   break;
19175
19176 @ @<Declarations@>=
19177 static void mp_scale_edges (MP mp);
19178
19179 @ @<Declare unary action...@>=
19180 static void mp_take_pict_part (MP mp,quarterword c) {
19181   pointer p; /* first graphical object in |cur_exp| */
19182   p=mp_link(dummy_loc(mp->cur_exp));
19183   if ( p!=null ) {
19184     switch (c) {
19185     case x_part: case y_part: case xx_part:
19186     case xy_part: case yx_part: case yy_part:
19187       if ( type(p)==mp_text_code ) mp_flush_cur_exp(mp, text_trans_part(p+c));
19188       else goto NOT_FOUND;
19189       break;
19190     case red_part: case green_part: case blue_part:
19191       if ( has_color(p) ) mp_flush_cur_exp(mp, obj_color_part(p+c));
19192       else goto NOT_FOUND;
19193       break;
19194     case cyan_part: case magenta_part: case yellow_part:
19195     case black_part:
19196       if ( has_color(p) ) {
19197         if ( color_model(p)==mp_uninitialized_model && c==black_part)
19198           mp_flush_cur_exp(mp, unity);
19199         else
19200           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-cyan_part)));
19201       } else goto NOT_FOUND;
19202       break;
19203     case grey_part:
19204       if ( has_color(p) )
19205           mp_flush_cur_exp(mp, obj_color_part(p+c+(red_part-grey_part)));
19206       else goto NOT_FOUND;
19207       break;
19208     case color_model_part:
19209       if ( has_color(p) ) {
19210         if ( color_model(p)==mp_uninitialized_model )
19211           mp_flush_cur_exp(mp, mp->internal[mp_default_color_model]);
19212         else
19213           mp_flush_cur_exp(mp, color_model(p)*unity);
19214       } else goto NOT_FOUND;
19215       break;
19216     @<Handle other cases in |take_pict_part| or |goto not_found|@>;
19217     } /* all cases have been enumerated */
19218     return;
19219   };
19220 NOT_FOUND:
19221   @<Convert the current expression to a null value appropriate
19222     for |c|@>;
19223 }
19224
19225 @ @<Handle other cases in |take_pict_part| or |goto not_found|@>=
19226 case text_part: 
19227   if ( type(p)!=mp_text_code ) goto NOT_FOUND;
19228   else { 
19229     mp_flush_cur_exp(mp, text_p(p));
19230     add_str_ref(mp->cur_exp);
19231     mp->cur_type=mp_string_type;
19232     };
19233   break;
19234 case font_part: 
19235   if ( type(p)!=mp_text_code ) goto NOT_FOUND;
19236   else { 
19237     mp_flush_cur_exp(mp, rts(mp->font_name[font_n(p)])); 
19238     add_str_ref(mp->cur_exp);
19239     mp->cur_type=mp_string_type;
19240   };
19241   break;
19242 case path_part:
19243   if ( type(p)==mp_text_code ) goto NOT_FOUND;
19244   else if ( is_stop(p) ) mp_confusion(mp, "pict");
19245 @:this can't happen pict}{\quad pict@>
19246   else { 
19247     mp_flush_cur_exp(mp, mp_copy_path(mp, path_p(p)));
19248     mp->cur_type=mp_path_type;
19249   }
19250   break;
19251 case pen_part: 
19252   if ( ! has_pen(p) ) goto NOT_FOUND;
19253   else {
19254     if ( pen_p(p)==null ) goto NOT_FOUND;
19255     else { mp_flush_cur_exp(mp, copy_pen(pen_p(p)));
19256       mp->cur_type=mp_pen_type;
19257     };
19258   }
19259   break;
19260 case dash_part: 
19261   if ( type(p)!=mp_stroked_code ) goto NOT_FOUND;
19262   else { if ( dash_p(p)==null ) goto NOT_FOUND;
19263     else { add_edge_ref(dash_p(p));
19264     mp->se_sf=dash_scale(p);
19265     mp->se_pic=dash_p(p);
19266     mp_scale_edges(mp);
19267     mp_flush_cur_exp(mp, mp->se_pic);
19268     mp->cur_type=mp_picture_type;
19269     };
19270   }
19271   break;
19272
19273 @ Since |scale_edges| had to be declared |forward|, it had to be declared as a
19274 parameterless procedure even though it really takes two arguments and updates
19275 one of them.  Hence the following globals are needed.
19276
19277 @<Global...@>=
19278 pointer se_pic;  /* edge header used and updated by |scale_edges| */
19279 scaled se_sf;  /* the scale factor argument to |scale_edges| */
19280
19281 @ @<Convert the current expression to a null value appropriate...@>=
19282 switch (c) {
19283 case text_part: case font_part: 
19284   mp_flush_cur_exp(mp, null_str);
19285   mp->cur_type=mp_string_type;
19286   break;
19287 case path_part: 
19288   mp_flush_cur_exp(mp, mp_get_node(mp, knot_node_size));
19289   left_type(mp->cur_exp)=mp_endpoint;
19290   right_type(mp->cur_exp)=mp_endpoint;
19291   mp_link(mp->cur_exp)=mp->cur_exp;
19292   x_coord(mp->cur_exp)=0;
19293   y_coord(mp->cur_exp)=0;
19294   originator(mp->cur_exp)=mp_metapost_user;
19295   mp->cur_type=mp_path_type;
19296   break;
19297 case pen_part: 
19298   mp_flush_cur_exp(mp, mp_get_pen_circle(mp, 0));
19299   mp->cur_type=mp_pen_type;
19300   break;
19301 case dash_part: 
19302   mp_flush_cur_exp(mp, mp_get_node(mp, edge_header_size));
19303   mp_init_edges(mp, mp->cur_exp);
19304   mp->cur_type=mp_picture_type;
19305   break;
19306 default: 
19307    mp_flush_cur_exp(mp, 0);
19308   break;
19309 }
19310
19311 @ @<Additional cases of unary...@>=
19312 case char_op: 
19313   if ( mp->cur_type!=mp_known ) { 
19314     mp_bad_unary(mp, char_op);
19315   } else { 
19316     mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256; 
19317     mp->cur_type=mp_string_type;
19318     if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
19319   }
19320   break;
19321 case decimal: 
19322   if ( mp->cur_type!=mp_known ) {
19323      mp_bad_unary(mp, decimal);
19324   } else { 
19325     mp->old_setting=mp->selector; mp->selector=new_string;
19326     mp_print_scaled(mp, mp->cur_exp); mp->cur_exp=mp_make_string(mp);
19327     mp->selector=mp->old_setting; mp->cur_type=mp_string_type;
19328   }
19329   break;
19330 case oct_op:
19331 case hex_op:
19332 case ASCII_op: 
19333   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19334   else mp_str_to_num(mp, c);
19335   break;
19336 case font_size: 
19337   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, font_size);
19338   else @<Find the design size of the font whose name is |cur_exp|@>;
19339   break;
19340
19341 @ @<Declare unary action...@>=
19342 static void mp_str_to_num (MP mp,quarterword c) { /* converts a string to a number */
19343   integer n; /* accumulator */
19344   ASCII_code m; /* current character */
19345   pool_pointer k; /* index into |str_pool| */
19346   int b; /* radix of conversion */
19347   boolean bad_char; /* did the string contain an invalid digit? */
19348   if ( c==ASCII_op ) {
19349     if ( length(mp->cur_exp)==0 ) n=-1;
19350     else n=mp->str_pool[mp->str_start[mp->cur_exp]];
19351   } else { 
19352     if ( c==oct_op ) b=8; else b=16;
19353     n=0; bad_char=false;
19354     for (k=mp->str_start[mp->cur_exp];k<=str_stop(mp->cur_exp)-1;k++) {
19355       m=mp->str_pool[k];
19356       if ( (m>='0')&&(m<='9') ) m=m-'0';
19357       else if ( (m>='A')&&(m<='F') ) m=m-'A'+10;
19358       else if ( (m>='a')&&(m<='f') ) m=m-'a'+10;
19359       else  { bad_char=true; m=0; };
19360       if ( (int)m>=b ) { bad_char=true; m=0; };
19361       if ( n<32768 / b ) n=n*b+m; else n=32767;
19362     }
19363     @<Give error messages if |bad_char| or |n>=4096|@>;
19364   }
19365   mp_flush_cur_exp(mp, n*unity);
19366 }
19367
19368 @ @<Give error messages if |bad_char|...@>=
19369 if ( bad_char ) { 
19370   exp_err("String contains illegal digits");
19371 @.String contains illegal digits@>
19372   if ( c==oct_op ) {
19373     help1("I zeroed out characters that weren't in the range 0..7.");
19374   } else  {
19375     help1("I zeroed out characters that weren't hex digits.");
19376   }
19377   mp_put_get_error(mp);
19378 }
19379 if ( (n>4095) ) {
19380   if ( mp->internal[mp_warning_check]>0 ) {
19381     print_err("Number too large ("); 
19382     mp_print_int(mp, n); mp_print_char(mp, xord(')'));
19383 @.Number too large@>
19384     help2("I have trouble with numbers greater than 4095; watch out.",
19385            "(Set warningcheck:=0 to suppress this message.)");
19386     mp_put_get_error(mp);
19387   }
19388 }
19389
19390 @ The length operation is somewhat unusual in that it applies to a variety
19391 of different types of operands.
19392
19393 @<Additional cases of unary...@>=
19394 case length_op: 
19395   switch (mp->cur_type) {
19396   case mp_string_type: mp_flush_cur_exp(mp, length(mp->cur_exp)*unity); break;
19397   case mp_path_type: mp_flush_cur_exp(mp, mp_path_length(mp)); break;
19398   case mp_known: mp->cur_exp=abs(mp->cur_exp); break;
19399   case mp_picture_type: mp_flush_cur_exp(mp, mp_pict_length(mp)); break;
19400   default: 
19401     if ( mp_nice_pair(mp, mp->cur_exp,mp->cur_type) )
19402       mp_flush_cur_exp(mp, mp_pyth_add(mp, 
19403         value(x_part_loc(value(mp->cur_exp))),
19404         value(y_part_loc(value(mp->cur_exp)))));
19405     else mp_bad_unary(mp, c);
19406     break;
19407   }
19408   break;
19409
19410 @ @<Declare unary action...@>=
19411 static scaled mp_path_length (MP mp) { /* computes the length of the current path */
19412   scaled n; /* the path length so far */
19413   pointer p; /* traverser */
19414   p=mp->cur_exp;
19415   if ( left_type(p)==mp_endpoint ) n=-unity; else n=0;
19416   do {  p=mp_link(p); n=n+unity; } while (p!=mp->cur_exp);
19417   return n;
19418 }
19419
19420 @ @<Declare unary action...@>=
19421 static scaled mp_pict_length (MP mp) { 
19422   /* counts interior components in picture |cur_exp| */
19423   scaled n; /* the count so far */
19424   pointer p; /* traverser */
19425   n=0;
19426   p=mp_link(dummy_loc(mp->cur_exp));
19427   if ( p!=null ) {
19428     if ( is_start_or_stop(p) )
19429       if ( mp_skip_1component(mp, p)==null ) p=mp_link(p);
19430     while ( p!=null )  { 
19431       skip_component(p) return n; 
19432       n=n+unity;   
19433     }
19434   }
19435   return n;
19436 }
19437
19438 @ Implement |turningnumber|
19439
19440 @<Additional cases of unary...@>=
19441 case turning_op:
19442   if ( mp->cur_type==mp_pair_type ) mp_flush_cur_exp(mp, 0);
19443   else if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, turning_op);
19444   else if ( left_type(mp->cur_exp)==mp_endpoint )
19445      mp_flush_cur_exp(mp, 0); /* not a cyclic path */
19446   else
19447     mp_flush_cur_exp(mp, mp_turn_cycles_wrapper(mp, mp->cur_exp));
19448   break;
19449
19450 @ The function |an_angle| returns the value of the |angle| primitive, or $0$ if the
19451 argument is |origin|.
19452
19453 @<Declare unary action...@>=
19454 static angle mp_an_angle (MP mp,scaled xpar, scaled ypar) {
19455   if ( (! ((xpar==0) && (ypar==0))) )
19456     return mp_n_arg(mp, xpar,ypar);
19457   return 0;
19458 }
19459
19460
19461 @ The actual turning number is (for the moment) computed in a C function
19462 that receives eight integers corresponding to the four controlling points,
19463 and returns a single angle.  Besides those, we have to account for discrete
19464 moves at the actual points.
19465
19466 @d mp_floor(a) ((a)>=0 ? (int)(a) : -(int)(-(a)))
19467 @d bezier_error (720*(256*256*16))+1
19468 @d mp_sign(v) ((v)>0 ? 1 : ((v)<0 ? -1 : 0 ))
19469 @d mp_out(A) (double)((A)/(256*256*16))
19470 @d divisor (256*256)
19471 @d double2angle(a) (int)mp_floor(a*256.0*256.0*16.0)
19472
19473 @<Declare unary action...@>=
19474 static angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19475             integer CX,integer CY,integer DX,integer DY);
19476
19477 @ @c 
19478 static angle mp_bezier_slope(MP mp, integer AX,integer AY,integer BX,integer BY,
19479             integer CX,integer CY,integer DX,integer DY) {
19480   double a, b, c;
19481   integer deltax,deltay;
19482   double ax,ay,bx,by,cx,cy,dx,dy;
19483   angle xi = 0, xo = 0, xm = 0;
19484   double res = 0;
19485   ax=(double)(AX/divisor);  ay=(double)(AY/divisor);
19486   bx=(double)(BX/divisor);  by=(double)(BY/divisor);
19487   cx=(double)(CX/divisor);  cy=(double)(CY/divisor);
19488   dx=(double)(DX/divisor);  dy=(double)(DY/divisor);
19489
19490   deltax = (BX-AX); deltay = (BY-AY);
19491   if (deltax==0 && deltay == 0) { deltax=(CX-AX); deltay=(CY-AY); }
19492   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19493   xi = mp_an_angle(mp,deltax,deltay);
19494
19495   deltax = (CX-BX); deltay = (CY-BY);
19496   xm = mp_an_angle(mp,deltax,deltay);
19497
19498   deltax = (DX-CX); deltay = (DY-CY);
19499   if (deltax==0 && deltay == 0) { deltax=(DX-BX); deltay=(DY-BY); }
19500   if (deltax==0 && deltay == 0) { deltax=(DX-AX); deltay=(DY-AY); }
19501   xo = mp_an_angle(mp,deltax,deltay);
19502
19503   a = (bx-ax)*(cy-by) - (cx-bx)*(by-ay); /* a = (bp-ap)x(cp-bp); */
19504   b = (bx-ax)*(dy-cy) - (by-ay)*(dx-cx);; /* b = (bp-ap)x(dp-cp);*/
19505   c = (cx-bx)*(dy-cy) - (dx-cx)*(cy-by); /* c = (cp-bp)x(dp-cp);*/
19506
19507   if ((a==0)&&(c==0)) {
19508     res = (b==0 ?  0 :  (mp_out(xo)-mp_out(xi))); 
19509   } else if ((a==0)||(c==0)) {
19510     if ((mp_sign(b) == mp_sign(a)) || (mp_sign(b) == mp_sign(c))) {
19511       res = mp_out(xo)-mp_out(xi); /* ? */
19512       if (res<-180.0) 
19513         res += 360.0;
19514       else if (res>180.0)
19515         res -= 360.0;
19516     } else {
19517       res = mp_out(xo)-mp_out(xi); /* ? */
19518     }
19519   } else if ((mp_sign(a)*mp_sign(c))<0) {
19520     res = mp_out(xo)-mp_out(xi); /* ? */
19521       if (res<-180.0) 
19522         res += 360.0;
19523       else if (res>180.0)
19524         res -= 360.0;
19525   } else {
19526     if (mp_sign(a) == mp_sign(b)) {
19527       res = mp_out(xo)-mp_out(xi); /* ? */
19528       if (res<-180.0) 
19529         res += 360.0;
19530       else if (res>180.0)
19531         res -= 360.0;
19532     } else {
19533       if ((b*b) == (4*a*c)) {
19534         res = (double)bezier_error;
19535       } else if ((b*b) < (4*a*c)) {
19536         res = mp_out(xo)-mp_out(xi); /* ? */
19537         if (res<=0.0 &&res>-180.0) 
19538           res += 360.0;
19539         else if (res>=0.0 && res<180.0)
19540           res -= 360.0;
19541       } else {
19542         res = mp_out(xo)-mp_out(xi);
19543         if (res<-180.0) 
19544           res += 360.0;
19545         else if (res>180.0)
19546           res -= 360.0;
19547       }
19548     }
19549   }
19550   return double2angle(res);
19551 }
19552
19553 @
19554 @d p_nextnext mp_link(mp_link(p))
19555 @d p_next mp_link(p)
19556 @d seven_twenty_deg 05500000000 /* $720\cdot2^{20}$, represents $720^\circ$ */
19557
19558 @<Declare unary action...@>=
19559 static scaled mp_new_turn_cycles (MP mp,pointer c) {
19560   angle res,ang; /*  the angles of intermediate results  */
19561   scaled turns;  /*  the turn counter  */
19562   pointer p;     /*  for running around the path  */
19563   integer xp,yp;   /*  coordinates of next point  */
19564   integer x,y;   /*  helper coordinates  */
19565   angle in_angle,out_angle;     /*  helper angles */
19566   unsigned old_setting; /* saved |selector| setting */
19567   res=0;
19568   turns= 0;
19569   p=c;
19570   old_setting = mp->selector; mp->selector=term_only;
19571   if ( mp->internal[mp_tracing_commands]>unity ) {
19572     mp_begin_diagnostic(mp);
19573     mp_print_nl(mp, "");
19574     mp_end_diagnostic(mp, false);
19575   }
19576   do { 
19577     xp = x_coord(p_next); yp = y_coord(p_next);
19578     ang  = mp_bezier_slope(mp,x_coord(p), y_coord(p), right_x(p), right_y(p),
19579              left_x(p_next), left_y(p_next), xp, yp);
19580     if ( ang>seven_twenty_deg ) {
19581       print_err("Strange path");
19582       mp_error(mp);
19583       mp->selector=old_setting;
19584       return 0;
19585     }
19586     res  = res + ang;
19587     if ( res > one_eighty_deg ) {
19588       res = res - three_sixty_deg;
19589       turns = turns + unity;
19590     }
19591     if ( res <= -one_eighty_deg ) {
19592       res = res + three_sixty_deg;
19593       turns = turns - unity;
19594     }
19595     /*  incoming angle at next point  */
19596     x = left_x(p_next);  y = left_y(p_next);
19597     if ( (xp==x)&&(yp==y) ) { x = right_x(p);  y = right_y(p);  };
19598     if ( (xp==x)&&(yp==y) ) { x = x_coord(p);  y = y_coord(p);  };
19599     in_angle = mp_an_angle(mp, xp - x, yp - y);
19600     /*  outgoing angle at next point  */
19601     x = right_x(p_next);  y = right_y(p_next);
19602     if ( (xp==x)&&(yp==y) ) { x = left_x(p_nextnext);  y = left_y(p_nextnext);  };
19603     if ( (xp==x)&&(yp==y) ) { x = x_coord(p_nextnext); y = y_coord(p_nextnext); };
19604     out_angle = mp_an_angle(mp, x - xp, y- yp);
19605     ang  = (out_angle - in_angle);
19606     reduce_angle(ang);
19607     if ( ang!=0 ) {
19608       res  = res + ang;
19609       if ( res >= one_eighty_deg ) {
19610         res = res - three_sixty_deg;
19611         turns = turns + unity;
19612       };
19613       if ( res <= -one_eighty_deg ) {
19614         res = res + three_sixty_deg;
19615         turns = turns - unity;
19616       };
19617     };
19618     p = mp_link(p);
19619   } while (p!=c);
19620   mp->selector=old_setting;
19621   return turns;
19622 }
19623
19624
19625 @ This code is based on Bogus\l{}av Jackowski's
19626 |emergency_turningnumber| macro, with some minor changes by Taco
19627 Hoekwater. The macro code looked more like this:
19628 {\obeylines
19629 vardef turning\_number primary p =
19630 ~~save res, ang, turns;
19631 ~~res := 0;
19632 ~~if length p <= 2:
19633 ~~~~if Angle ((point 0 of p) - (postcontrol 0 of p)) >= 0:  1  else: -1 fi
19634 ~~else:
19635 ~~~~for t = 0 upto length p-1 :
19636 ~~~~~~angc := Angle ((point t+1 of p)  - (point t of p))
19637 ~~~~~~~~- Angle ((point t of p) - (point t-1 of p));
19638 ~~~~~~if angc > 180: angc := angc - 360; fi;
19639 ~~~~~~if angc < -180: angc := angc + 360; fi;
19640 ~~~~~~res  := res + angc;
19641 ~~~~endfor;
19642 ~~res/360
19643 ~~fi
19644 enddef;}
19645 The general idea is to calculate only the sum of the angles of
19646 straight lines between the points, of a path, not worrying about cusps
19647 or self-intersections in the segments at all. If the segment is not
19648 well-behaved, the result is not necesarily correct. But the old code
19649 was not always correct either, and worse, it sometimes failed for
19650 well-behaved paths as well. All known bugs that were triggered by the
19651 original code no longer occur with this code, and it runs roughly 3
19652 times as fast because the algorithm is much simpler.
19653
19654 @ It is possible to overflow the return value of the |turn_cycles|
19655 function when the path is sufficiently long and winding, but I am not
19656 going to bother testing for that. In any case, it would only return
19657 the looped result value, which is not a big problem.
19658
19659 The macro code for the repeat loop was a bit nicer to look
19660 at than the pascal code, because it could use |point -1 of p|. In
19661 pascal, the fastest way to loop around the path is not to look
19662 backward once, but forward twice. These defines help hide the trick.
19663
19664 @d p_to mp_link(mp_link(p))
19665 @d p_here mp_link(p)
19666 @d p_from p
19667
19668 @<Declare unary action...@>=
19669 static scaled mp_turn_cycles (MP mp,pointer c) {
19670   angle res,ang; /*  the angles of intermediate results  */
19671   scaled turns;  /*  the turn counter  */
19672   pointer p;     /*  for running around the path  */
19673   res=0;  turns= 0; p=c;
19674   do { 
19675     ang  = mp_an_angle (mp, x_coord(p_to) - x_coord(p_here), 
19676                             y_coord(p_to) - y_coord(p_here))
19677         - mp_an_angle (mp, x_coord(p_here) - x_coord(p_from), 
19678                            y_coord(p_here) - y_coord(p_from));
19679     reduce_angle(ang);
19680     res  = res + ang;
19681     if ( res >= three_sixty_deg )  {
19682       res = res - three_sixty_deg;
19683       turns = turns + unity;
19684     };
19685     if ( res <= -three_sixty_deg ) {
19686       res = res + three_sixty_deg;
19687       turns = turns - unity;
19688     };
19689     p = mp_link(p);
19690   } while (p!=c);
19691   return turns;
19692 }
19693
19694 @ @<Declare unary action...@>=
19695 static scaled mp_turn_cycles_wrapper (MP mp,pointer c) {
19696   scaled nval,oval;
19697   scaled saved_t_o; /* tracing\_online saved  */
19698   if ( (mp_link(c)==c)||(mp_link(mp_link(c))==c) ) {
19699     if ( mp_an_angle (mp, x_coord(c) - right_x(c),  y_coord(c) - right_y(c)) > 0 )
19700       return unity;
19701     else
19702       return -unity;
19703   } else {
19704     nval = mp_new_turn_cycles(mp, c);
19705     oval = mp_turn_cycles(mp, c);
19706     if ( nval!=oval ) {
19707       saved_t_o=mp->internal[mp_tracing_online];
19708       mp->internal[mp_tracing_online]=unity;
19709       mp_begin_diagnostic(mp);
19710       mp_print_nl (mp, "Warning: the turningnumber algorithms do not agree."
19711                        " The current computed value is ");
19712       mp_print_scaled(mp, nval);
19713       mp_print(mp, ", but the 'connect-the-dots' algorithm returned ");
19714       mp_print_scaled(mp, oval);
19715       mp_end_diagnostic(mp, false);
19716       mp->internal[mp_tracing_online]=saved_t_o;
19717     }
19718     return nval;
19719   }
19720 }
19721
19722 @ @d type_range(A,B) { 
19723   if ( (mp->cur_type>=(A)) && (mp->cur_type<=(B)) ) 
19724     mp_flush_cur_exp(mp, true_code);
19725   else mp_flush_cur_exp(mp, false_code);
19726   mp->cur_type=mp_boolean_type;
19727   }
19728 @d type_test(A) { 
19729   if ( mp->cur_type==(A) ) mp_flush_cur_exp(mp, true_code);
19730   else mp_flush_cur_exp(mp, false_code);
19731   mp->cur_type=mp_boolean_type;
19732   }
19733
19734 @<Additional cases of unary operators@>=
19735 case mp_boolean_type: 
19736   type_range(mp_boolean_type,mp_unknown_boolean); break;
19737 case mp_string_type: 
19738   type_range(mp_string_type,mp_unknown_string); break;
19739 case mp_pen_type: 
19740   type_range(mp_pen_type,mp_unknown_pen); break;
19741 case mp_path_type: 
19742   type_range(mp_path_type,mp_unknown_path); break;
19743 case mp_picture_type: 
19744   type_range(mp_picture_type,mp_unknown_picture); break;
19745 case mp_transform_type: case mp_color_type: case mp_cmykcolor_type:
19746 case mp_pair_type: 
19747   type_test(c); break;
19748 case mp_numeric_type: 
19749   type_range(mp_known,mp_independent); break;
19750 case known_op: case unknown_op: 
19751   mp_test_known(mp, c); break;
19752
19753 @ @<Declare unary action procedures@>=
19754 static void mp_test_known (MP mp,quarterword c) {
19755   int b; /* is the current expression known? */
19756   pointer p,q; /* locations in a big node */
19757   b=false_code;
19758   switch (mp->cur_type) {
19759   case mp_vacuous: case mp_boolean_type: case mp_string_type:
19760   case mp_pen_type: case mp_path_type: case mp_picture_type:
19761   case mp_known: 
19762     b=true_code;
19763     break;
19764   case mp_transform_type:
19765   case mp_color_type: case mp_cmykcolor_type: case mp_pair_type: 
19766     p=value(mp->cur_exp);
19767     q=p+mp->big_node_size[mp->cur_type];
19768     do {  
19769       q=q-2;
19770       if ( type(q)!=mp_known ) 
19771        goto DONE;
19772     } while (q!=p);
19773     b=true_code;
19774   DONE:  
19775     break;
19776   default: 
19777     break;
19778   }
19779   if ( c==known_op ) mp_flush_cur_exp(mp, b);
19780   else mp_flush_cur_exp(mp, true_code+false_code-b);
19781   mp->cur_type=mp_boolean_type;
19782 }
19783
19784 @ @<Additional cases of unary operators@>=
19785 case cycle_op: 
19786   if ( mp->cur_type!=mp_path_type ) mp_flush_cur_exp(mp, false_code);
19787   else if ( left_type(mp->cur_exp)!=mp_endpoint ) mp_flush_cur_exp(mp, true_code);
19788   else mp_flush_cur_exp(mp, false_code);
19789   mp->cur_type=mp_boolean_type;
19790   break;
19791
19792 @ @<Additional cases of unary operators@>=
19793 case arc_length: 
19794   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19795   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, arc_length);
19796   else mp_flush_cur_exp(mp, mp_get_arc_length(mp, mp->cur_exp));
19797   break;
19798
19799 @ Here we use the fact that |c-filled_op+fill_code| is the desired graphical
19800 object |type|.
19801 @^data structure assumptions@>
19802
19803 @<Additional cases of unary operators@>=
19804 case filled_op:
19805 case stroked_op:
19806 case textual_op:
19807 case clipped_op:
19808 case bounded_op:
19809   if ( mp->cur_type!=mp_picture_type ) mp_flush_cur_exp(mp, false_code);
19810   else if ( mp_link(dummy_loc(mp->cur_exp))==null ) mp_flush_cur_exp(mp, false_code);
19811   else if ( type(mp_link(dummy_loc(mp->cur_exp)))==c+mp_fill_code-filled_op )
19812     mp_flush_cur_exp(mp, true_code);
19813   else mp_flush_cur_exp(mp, false_code);
19814   mp->cur_type=mp_boolean_type;
19815   break;
19816
19817 @ @<Additional cases of unary operators@>=
19818 case make_pen_op: 
19819   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19820   if ( mp->cur_type!=mp_path_type ) mp_bad_unary(mp, make_pen_op);
19821   else { 
19822     mp->cur_type=mp_pen_type;
19823     mp->cur_exp=mp_make_pen(mp, mp->cur_exp,true);
19824   };
19825   break;
19826 case make_path_op: 
19827   if ( mp->cur_type!=mp_pen_type ) mp_bad_unary(mp, make_path_op);
19828   else  { 
19829     mp->cur_type=mp_path_type;
19830     mp_make_path(mp, mp->cur_exp);
19831   };
19832   break;
19833 case reverse: 
19834   if ( mp->cur_type==mp_path_type ) {
19835     p=mp_htap_ypoc(mp, mp->cur_exp);
19836     if ( right_type(p)==mp_endpoint ) p=mp_link(p);
19837     mp_toss_knot_list(mp, mp->cur_exp); mp->cur_exp=p;
19838   } else if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
19839   else mp_bad_unary(mp, reverse);
19840   break;
19841
19842 @ The |pair_value| routine changes the current expression to a
19843 given ordered pair of values.
19844
19845 @<Declare unary action procedures@>=
19846 static void mp_pair_value (MP mp,scaled x, scaled y) {
19847   pointer p; /* a pair node */
19848   p=mp_get_node(mp, value_node_size); 
19849   mp_flush_cur_exp(mp, p); mp->cur_type=mp_pair_type;
19850   type(p)=mp_pair_type; name_type(p)=mp_capsule; mp_init_big_node(mp, p);
19851   p=value(p);
19852   type(x_part_loc(p))=mp_known; value(x_part_loc(p))=x;
19853   type(y_part_loc(p))=mp_known; value(y_part_loc(p))=y;
19854 }
19855
19856 @ @<Additional cases of unary operators@>=
19857 case ll_corner_op: 
19858   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ll_corner_op);
19859   else mp_pair_value(mp, minx,miny);
19860   break;
19861 case lr_corner_op: 
19862   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, lr_corner_op);
19863   else mp_pair_value(mp, maxx,miny);
19864   break;
19865 case ul_corner_op: 
19866   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ul_corner_op);
19867   else mp_pair_value(mp, minx,maxy);
19868   break;
19869 case ur_corner_op: 
19870   if ( ! mp_get_cur_bbox(mp) ) mp_bad_unary(mp, ur_corner_op);
19871   else mp_pair_value(mp, maxx,maxy);
19872   break;
19873
19874 @ Here is a function that sets |minx|, |maxx|, |miny|, |maxy| to the bounding
19875 box of the current expression.  The boolean result is |false| if the expression
19876 has the wrong type.
19877
19878 @<Declare unary action procedures@>=
19879 static boolean mp_get_cur_bbox (MP mp) { 
19880   switch (mp->cur_type) {
19881   case mp_picture_type: 
19882     mp_set_bbox(mp, mp->cur_exp,true);
19883     if ( minx_val(mp->cur_exp)>maxx_val(mp->cur_exp) ) {
19884       minx=0; maxx=0; miny=0; maxy=0;
19885     } else { 
19886       minx=minx_val(mp->cur_exp);
19887       maxx=maxx_val(mp->cur_exp);
19888       miny=miny_val(mp->cur_exp);
19889       maxy=maxy_val(mp->cur_exp);
19890     }
19891     break;
19892   case mp_path_type: 
19893     mp_path_bbox(mp, mp->cur_exp);
19894     break;
19895   case mp_pen_type: 
19896     mp_pen_bbox(mp, mp->cur_exp);
19897     break;
19898   default: 
19899     return false;
19900   }
19901   return true;
19902 }
19903
19904 @ @<Additional cases of unary operators@>=
19905 case read_from_op:
19906 case close_from_op: 
19907   if ( mp->cur_type!=mp_string_type ) mp_bad_unary(mp, c);
19908   else mp_do_read_or_close(mp,c);
19909   break;
19910
19911 @ Here is a routine that interprets |cur_exp| as a file name and tries to read
19912 a line from the file or to close the file.
19913
19914 @<Declare unary action procedures@>=
19915 static void mp_do_read_or_close (MP mp,quarterword c) {
19916   readf_index n,n0; /* indices for searching |rd_fname| */
19917   @<Find the |n| where |rd_fname[n]=cur_exp|; if |cur_exp| must be inserted,
19918     call |start_read_input| and |goto found| or |not_found|@>;
19919   mp_begin_file_reading(mp);
19920   name=is_read;
19921   if ( mp_input_ln(mp, mp->rd_file[n] ) ) 
19922     goto FOUND;
19923   mp_end_file_reading(mp);
19924 NOT_FOUND:
19925   @<Record the end of file and set |cur_exp| to a dummy value@>;
19926   return;
19927 CLOSE_FILE:
19928   mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous; 
19929   return;
19930 FOUND:
19931   mp_flush_cur_exp(mp, 0);
19932   mp_finish_read(mp);
19933 }
19934
19935 @ Free slots in the |rd_file| and |rd_fname| arrays are marked with NULL's in
19936 |rd_fname|.
19937
19938 @<Find the |n| where |rd_fname[n]=cur_exp|...@>=
19939 {   
19940   char *fn;
19941   n=mp->read_files;
19942   n0=mp->read_files;
19943   fn = str(mp->cur_exp);
19944   while (mp_xstrcmp(fn,mp->rd_fname[n])!=0) { 
19945     if ( n>0 ) {
19946       decr(n);
19947     } else if ( c==close_from_op ) {
19948       goto CLOSE_FILE;
19949     } else {
19950       if ( n0==mp->read_files ) {
19951         if ( mp->read_files<mp->max_read_files ) {
19952           incr(mp->read_files);
19953         } else {
19954           void **rd_file;
19955           char **rd_fname;
19956               readf_index l,k;
19957           l = mp->max_read_files + (mp->max_read_files/4);
19958           rd_file = xmalloc((l+1), sizeof(void *));
19959           rd_fname = xmalloc((l+1), sizeof(char *));
19960               for (k=0;k<=l;k++) {
19961             if (k<=mp->max_read_files) {
19962                   rd_file[k]=mp->rd_file[k]; 
19963               rd_fname[k]=mp->rd_fname[k];
19964             } else {
19965               rd_file[k]=0; 
19966               rd_fname[k]=NULL;
19967             }
19968           }
19969               xfree(mp->rd_file); xfree(mp->rd_fname);
19970           mp->max_read_files = l;
19971           mp->rd_file = rd_file;
19972           mp->rd_fname = rd_fname;
19973         }
19974       }
19975       n=n0;
19976       if ( mp_start_read_input(mp,fn,n) ) 
19977         goto FOUND;
19978       else 
19979         goto NOT_FOUND;
19980     }
19981     if ( mp->rd_fname[n]==NULL ) { n0=n; }
19982   } 
19983   if ( c==close_from_op ) { 
19984     (mp->close_file)(mp,mp->rd_file[n]); 
19985     goto NOT_FOUND; 
19986   }
19987 }
19988
19989 @ @<Record the end of file and set |cur_exp| to a dummy value@>=
19990 xfree(mp->rd_fname[n]);
19991 mp->rd_fname[n]=NULL;
19992 if ( n==mp->read_files-1 ) mp->read_files=n;
19993 if ( c==close_from_op ) 
19994   goto CLOSE_FILE;
19995 mp_flush_cur_exp(mp, mp->eof_line);
19996 mp->cur_type=mp_string_type
19997
19998 @ The string denoting end-of-file is a one-byte string at position zero, by definition
19999
20000 @<Glob...@>=
20001 str_number eof_line;
20002
20003 @ @<Set init...@>=
20004 mp->eof_line=0;
20005
20006 @ Finally, we have the operations that combine a capsule~|p|
20007 with the current expression.
20008
20009 @d binary_return  { mp_finish_binary(mp, old_p, old_exp); return; }
20010
20011 @c @<Declare binary action procedures@>
20012 static void mp_finish_binary (MP mp, pointer old_p, pointer old_exp ){
20013   check_arith; 
20014   @<Recycle any sidestepped |independent| capsules@>;
20015 }
20016 static void mp_do_binary (MP mp,pointer p, quarterword c) {
20017   pointer q,r,rr; /* for list manipulation */
20018   pointer old_p,old_exp; /* capsules to recycle */
20019   integer v; /* for numeric manipulation */
20020   check_arith;
20021   if ( mp->internal[mp_tracing_commands]>two ) {
20022     @<Trace the current binary operation@>;
20023   }
20024   @<Sidestep |independent| cases in capsule |p|@>;
20025   @<Sidestep |independent| cases in the current expression@>;
20026   switch (c) {
20027   case plus: case minus:
20028     @<Add or subtract the current expression from |p|@>;
20029     break;
20030   @<Additional cases of binary operators@>;
20031   }; /* there are no other cases */
20032   mp_recycle_value(mp, p); 
20033   mp_free_node(mp, p,value_node_size); /* |return| to avoid this */
20034   mp_finish_binary(mp, old_p, old_exp);
20035 }
20036
20037 @ @<Declare binary action...@>=
20038 static void mp_bad_binary (MP mp,pointer p, quarterword c) { 
20039   mp_disp_err(mp, p,"");
20040   exp_err("Not implemented: ");
20041 @.Not implemented...@>
20042   if ( c>=min_of ) mp_print_op(mp, c);
20043   mp_print_known_or_unknown_type(mp, type(p),p);
20044   if ( c>=min_of ) mp_print(mp, "of"); else mp_print_op(mp, c);
20045   mp_print_known_or_unknown_type(mp, mp->cur_type,mp->cur_exp);
20046   help3("I'm afraid I don't know how to apply that operation to that",
20047        "combination of types. Continue, and I'll return the second",
20048        "argument (see above) as the result of the operation.");
20049   mp_put_get_error(mp);
20050 }
20051 static void mp_bad_envelope_pen (MP mp) {
20052   mp_disp_err(mp, null,"");
20053   exp_err("Not implemented: envelope(elliptical pen)of(path)");
20054 @.Not implemented...@>
20055   help3("I'm afraid I don't know how to apply that operation to that",
20056        "combination of types. Continue, and I'll return the second",
20057        "argument (see above) as the result of the operation.");
20058   mp_put_get_error(mp);
20059 }
20060
20061 @ @<Trace the current binary operation@>=
20062
20063   mp_begin_diagnostic(mp); mp_print_nl(mp, "{(");
20064   mp_print_exp(mp,p,0); /* show the operand, but not verbosely */
20065   mp_print_char(mp,xord(')')); mp_print_op(mp,c); mp_print_char(mp,xord('('));
20066   mp_print_exp(mp,null,0); mp_print(mp,")}"); 
20067   mp_end_diagnostic(mp, false);
20068 }
20069
20070 @ Several of the binary operations are potentially complicated by the
20071 fact that |independent| values can sneak into capsules. For example,
20072 we've seen an instance of this difficulty in the unary operation
20073 of negation. In order to reduce the number of cases that need to be
20074 handled, we first change the two operands (if necessary)
20075 to rid them of |independent| components. The original operands are
20076 put into capsules called |old_p| and |old_exp|, which will be
20077 recycled after the binary operation has been safely carried out.
20078
20079 @<Recycle any sidestepped |independent| capsules@>=
20080 if ( old_p!=null ) { 
20081   mp_recycle_value(mp, old_p); mp_free_node(mp, old_p,value_node_size);
20082 }
20083 if ( old_exp!=null ) {
20084   mp_recycle_value(mp, old_exp); mp_free_node(mp, old_exp,value_node_size);
20085 }
20086
20087 @ A big node is considered to be ``tarnished'' if it contains at least one
20088 independent component. We will define a simple function called `|tarnished|'
20089 that returns |null| if and only if its argument is not tarnished.
20090
20091 @<Sidestep |independent| cases in capsule |p|@>=
20092 switch (type(p)) {
20093 case mp_transform_type:
20094 case mp_color_type:
20095 case mp_cmykcolor_type:
20096 case mp_pair_type: 
20097   old_p=mp_tarnished(mp, p);
20098   break;
20099 case mp_independent: old_p=mp_void; break;
20100 default: old_p=null; break;
20101 }
20102 if ( old_p!=null ) {
20103   q=mp_stash_cur_exp(mp); old_p=p; mp_make_exp_copy(mp, old_p);
20104   p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
20105 }
20106
20107 @ @<Sidestep |independent| cases in the current expression@>=
20108 switch (mp->cur_type) {
20109 case mp_transform_type:
20110 case mp_color_type:
20111 case mp_cmykcolor_type:
20112 case mp_pair_type: 
20113   old_exp=mp_tarnished(mp, mp->cur_exp);
20114   break;
20115 case mp_independent:old_exp=mp_void; break;
20116 default: old_exp=null; break;
20117 }
20118 if ( old_exp!=null ) {
20119   old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20120 }
20121
20122 @ @<Declare binary action...@>=
20123 static pointer mp_tarnished (MP mp,pointer p) {
20124   pointer q; /* beginning of the big node */
20125   pointer r; /* current position in the big node */
20126   q=value(p); r=q+mp->big_node_size[type(p)];
20127   do {  
20128    r=r-2;
20129    if ( type(r)==mp_independent ) return mp_void; 
20130   } while (r!=q);
20131   return null;
20132 }
20133
20134 @ @<Add or subtract the current expression from |p|@>=
20135 if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
20136   mp_bad_binary(mp, p,c);
20137 } else  {
20138   if ((mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
20139     mp_add_or_subtract(mp, p,null,c);
20140   } else {
20141     if ( mp->cur_type!=type(p) )  {
20142       mp_bad_binary(mp, p,c);
20143     } else { 
20144       q=value(p); r=value(mp->cur_exp);
20145       rr=r+mp->big_node_size[mp->cur_type];
20146       while ( r<rr ) { 
20147         mp_add_or_subtract(mp, q,r,c);
20148         q=q+2; r=r+2;
20149       }
20150     }
20151   }
20152 }
20153
20154 @ The first argument to |add_or_subtract| is the location of a value node
20155 in a capsule or pair node that will soon be recycled. The second argument
20156 is either a location within a pair or transform node of |cur_exp|,
20157 or it is null (which means that |cur_exp| itself should be the second
20158 argument).  The third argument is either |plus| or |minus|.
20159
20160 The sum or difference of the numeric quantities will replace the second
20161 operand.  Arithmetic overflow may go undetected; users aren't supposed to
20162 be monkeying around with really big values.
20163 @^overflow in arithmetic@>
20164
20165 @<Declare binary action...@>=
20166 @<Declare the procedure called |dep_finish|@>
20167 static void mp_add_or_subtract (MP mp,pointer p, pointer q, quarterword c) {
20168   quarterword s,t; /* operand types */
20169   pointer r; /* list traverser */
20170   integer v; /* second operand value */
20171   if ( q==null ) { 
20172     t=mp->cur_type;
20173     if ( t<mp_dependent ) v=mp->cur_exp; else v=dep_list(mp->cur_exp);
20174   } else { 
20175     t=type(q);
20176     if ( t<mp_dependent ) v=value(q); else v=dep_list(q);
20177   }
20178   if ( t==mp_known ) {
20179     if ( c==minus ) negate(v);
20180     if ( type(p)==mp_known ) {
20181       v=mp_slow_add(mp, value(p),v);
20182       if ( q==null ) mp->cur_exp=v; else value(q)=v;
20183       return;
20184     }
20185     @<Add a known value to the constant term of |dep_list(p)|@>;
20186   } else  { 
20187     if ( c==minus ) mp_negate_dep_list(mp, v);
20188     @<Add operand |p| to the dependency list |v|@>;
20189   }
20190 }
20191
20192 @ @<Add a known value to the constant term of |dep_list(p)|@>=
20193 r=dep_list(p);
20194 while ( info(r)!=null ) r=mp_link(r);
20195 value(r)=mp_slow_add(mp, value(r),v);
20196 if ( q==null ) {
20197   q=mp_get_node(mp, value_node_size); mp->cur_exp=q; mp->cur_type=type(p);
20198   name_type(q)=mp_capsule;
20199 }
20200 dep_list(q)=dep_list(p); type(q)=type(p);
20201 prev_dep(q)=prev_dep(p); mp_link(prev_dep(p))=q;
20202 type(p)=mp_known; /* this will keep the recycler from collecting non-garbage */
20203
20204 @ We prefer |dependent| lists to |mp_proto_dependent| ones, because it is
20205 nice to retain the extra accuracy of |fraction| coefficients.
20206 But we have to handle both kinds, and mixtures too.
20207
20208 @<Add operand |p| to the dependency list |v|@>=
20209 if ( type(p)==mp_known ) {
20210   @<Add the known |value(p)| to the constant term of |v|@>;
20211 } else { 
20212   s=type(p); r=dep_list(p);
20213   if ( t==mp_dependent ) {
20214     if ( s==mp_dependent ) {
20215       if ( mp_max_coef(mp, r)+mp_max_coef(mp, v)<coef_bound )
20216         v=mp_p_plus_q(mp, v,r,mp_dependent); goto DONE;
20217       } /* |fix_needed| will necessarily be false */
20218       t=mp_proto_dependent; 
20219       v=mp_p_over_v(mp, v,unity,mp_dependent,mp_proto_dependent);
20220     }
20221     if ( s==mp_proto_dependent ) v=mp_p_plus_q(mp, v,r,mp_proto_dependent);
20222     else v=mp_p_plus_fq(mp, v,unity,r,mp_proto_dependent,mp_dependent);
20223  DONE:  
20224     @<Output the answer, |v| (which might have become |known|)@>;
20225   }
20226
20227 @ @<Add the known |value(p)| to the constant term of |v|@>=
20228
20229   while ( info(v)!=null ) v=mp_link(v);
20230   value(v)=mp_slow_add(mp, value(p),value(v));
20231 }
20232
20233 @ @<Output the answer, |v| (which might have become |known|)@>=
20234 if ( q!=null ) mp_dep_finish(mp, v,q,t);
20235 else  { mp->cur_type=t; mp_dep_finish(mp, v,null,t); }
20236
20237 @ Here's the current situation: The dependency list |v| of type |t|
20238 should either be put into the current expression (if |q=null|) or
20239 into location |q| within a pair node (otherwise). The destination (|cur_exp|
20240 or |q|) formerly held a dependency list with the same
20241 final pointer as the list |v|.
20242
20243 @<Declare the procedure called |dep_finish|@>=
20244 static void mp_dep_finish (MP mp, pointer v, pointer q, quarterword t) {
20245   pointer p; /* the destination */
20246   scaled vv; /* the value, if it is |known| */
20247   if ( q==null ) p=mp->cur_exp; else p=q;
20248   dep_list(p)=v; type(p)=t;
20249   if ( info(v)==null ) { 
20250     vv=value(v);
20251     if ( q==null ) { 
20252       mp_flush_cur_exp(mp, vv);
20253     } else  { 
20254       mp_recycle_value(mp, p); type(q)=mp_known; value(q)=vv; 
20255     }
20256   } else if ( q==null ) {
20257     mp->cur_type=t;
20258   }
20259   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20260 }
20261
20262 @ Let's turn now to the six basic relations of comparison.
20263
20264 @<Additional cases of binary operators@>=
20265 case less_than: case less_or_equal: case greater_than:
20266 case greater_or_equal: case equal_to: case unequal_to:
20267   check_arith; /* at this point |arith_error| should be |false|? */
20268   if ( (mp->cur_type>mp_pair_type)&&(type(p)>mp_pair_type) ) {
20269     mp_add_or_subtract(mp, p,null,minus); /* |cur_exp:=(p)-cur_exp| */
20270   } else if ( mp->cur_type!=type(p) ) {
20271     mp_bad_binary(mp, p,c); goto DONE; 
20272   } else if ( mp->cur_type==mp_string_type ) {
20273     mp_flush_cur_exp(mp, mp_str_vs_str(mp, value(p),mp->cur_exp));
20274   } else if ((mp->cur_type==mp_unknown_string)||
20275            (mp->cur_type==mp_unknown_boolean) ) {
20276     @<Check if unknowns have been equated@>;
20277   } else if ( (mp->cur_type<=mp_pair_type)&&(mp->cur_type>=mp_transform_type)) {
20278     @<Reduce comparison of big nodes to comparison of scalars@>;
20279   } else if ( mp->cur_type==mp_boolean_type ) {
20280     mp_flush_cur_exp(mp, mp->cur_exp-value(p));
20281   } else { 
20282     mp_bad_binary(mp, p,c); goto DONE;
20283   }
20284   @<Compare the current expression with zero@>;
20285 DONE:  
20286   mp->arith_error=false; /* ignore overflow in comparisons */
20287   break;
20288
20289 @ @<Compare the current expression with zero@>=
20290 if ( mp->cur_type!=mp_known ) {
20291   if ( mp->cur_type<mp_known ) {
20292     mp_disp_err(mp, p,"");
20293     help1("The quantities shown above have not been equated.")
20294   } else  {
20295     help2("Oh dear. I can\'t decide if the expression above is positive,",
20296           "negative, or zero. So this comparison test won't be `true'.");
20297   }
20298   exp_err("Unknown relation will be considered false");
20299 @.Unknown relation...@>
20300   mp_put_get_flush_error(mp, false_code);
20301 } else {
20302   switch (c) {
20303   case less_than: boolean_reset(mp->cur_exp<0); break;
20304   case less_or_equal: boolean_reset(mp->cur_exp<=0); break;
20305   case greater_than: boolean_reset(mp->cur_exp>0); break;
20306   case greater_or_equal: boolean_reset(mp->cur_exp>=0); break;
20307   case equal_to: boolean_reset(mp->cur_exp==0); break;
20308   case unequal_to: boolean_reset(mp->cur_exp!=0); break;
20309   }; /* there are no other cases */
20310 }
20311 mp->cur_type=mp_boolean_type
20312
20313 @ When two unknown strings are in the same ring, we know that they are
20314 equal. Otherwise, we don't know whether they are equal or not, so we
20315 make no change.
20316
20317 @<Check if unknowns have been equated@>=
20318
20319   q=value(mp->cur_exp);
20320   while ( (q!=mp->cur_exp)&&(q!=p) ) q=value(q);
20321   if ( q==p ) mp_flush_cur_exp(mp, 0);
20322 }
20323
20324 @ @<Reduce comparison of big nodes to comparison of scalars@>=
20325
20326   q=value(p); r=value(mp->cur_exp);
20327   rr=r+mp->big_node_size[mp->cur_type]-2;
20328   while (1) { mp_add_or_subtract(mp, q,r,minus);
20329     if ( type(r)!=mp_known ) break;
20330     if ( value(r)!=0 ) break;
20331     if ( r==rr ) break;
20332     q=q+2; r=r+2;
20333   }
20334   mp_take_part(mp, name_type(r)+x_part-mp_x_part_sector);
20335 }
20336
20337 @ Here we use the sneaky fact that |and_op-false_code=or_op-true_code|.
20338
20339 @<Additional cases of binary operators@>=
20340 case and_op:
20341 case or_op: 
20342   if ( (type(p)!=mp_boolean_type)||(mp->cur_type!=mp_boolean_type) )
20343     mp_bad_binary(mp, p,c);
20344   else if ( value(p)==c+false_code-and_op ) mp->cur_exp=value(p);
20345   break;
20346
20347 @ @<Additional cases of binary operators@>=
20348 case times: 
20349   if ( (mp->cur_type<mp_color_type)||(type(p)<mp_color_type) ) {
20350    mp_bad_binary(mp, p,times);
20351   } else if ( (mp->cur_type==mp_known)||(type(p)==mp_known) ) {
20352     @<Multiply when at least one operand is known@>;
20353   } else if ( (mp_nice_color_or_pair(mp, p,type(p))&&(mp->cur_type>mp_pair_type))
20354       ||(mp_nice_color_or_pair(mp, mp->cur_exp,mp->cur_type)&&
20355           (type(p)>mp_pair_type)) ) {
20356     mp_hard_times(mp, p); 
20357     binary_return;
20358   } else {
20359     mp_bad_binary(mp, p,times);
20360   }
20361   break;
20362
20363 @ @<Multiply when at least one operand is known@>=
20364
20365   if ( type(p)==mp_known ) {
20366     v=value(p); mp_free_node(mp, p,value_node_size); 
20367   } else {
20368     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20369   }
20370   if ( mp->cur_type==mp_known ) {
20371     mp->cur_exp=mp_take_scaled(mp, mp->cur_exp,v);
20372   } else if ( (mp->cur_type==mp_pair_type)||
20373               (mp->cur_type==mp_color_type)||
20374               (mp->cur_type==mp_cmykcolor_type) ) {
20375     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20376     do {  
20377        p=p-2; mp_dep_mult(mp, p,v,true);
20378     } while (p!=value(mp->cur_exp));
20379   } else {
20380     mp_dep_mult(mp, null,v,true);
20381   }
20382   binary_return;
20383 }
20384
20385 @ @<Declare binary action...@>=
20386 static void mp_dep_mult (MP mp,pointer p, integer v, boolean v_is_scaled) {
20387   pointer q; /* the dependency list being multiplied by |v| */
20388   quarterword s,t; /* its type, before and after */
20389   if ( p==null ) {
20390     q=mp->cur_exp;
20391   } else if ( type(p)!=mp_known ) {
20392     q=p;
20393   } else { 
20394     if ( v_is_scaled ) value(p)=mp_take_scaled(mp, value(p),v);
20395     else value(p)=mp_take_fraction(mp, value(p),v);
20396     return;
20397   };
20398   t=type(q); q=dep_list(q); s=t;
20399   if ( t==mp_dependent ) if ( v_is_scaled )
20400     if (mp_ab_vs_cd(mp, mp_max_coef(mp,q),abs(v),coef_bound-1,unity)>=0 ) 
20401       t=mp_proto_dependent;
20402   q=mp_p_times_v(mp, q,v,s,t,v_is_scaled); 
20403   mp_dep_finish(mp, q,p,t);
20404 }
20405
20406 @ Here is a routine that is similar to |times|; but it is invoked only
20407 internally, when |v| is a |fraction| whose magnitude is at most~1,
20408 and when |cur_type>=mp_color_type|.
20409
20410 @c 
20411 static void mp_frac_mult (MP mp,scaled n, scaled d) {
20412   /* multiplies |cur_exp| by |n/d| */
20413   pointer p; /* a pair node */
20414   pointer old_exp; /* a capsule to recycle */
20415   fraction v; /* |n/d| */
20416   if ( mp->internal[mp_tracing_commands]>two ) {
20417     @<Trace the fraction multiplication@>;
20418   }
20419   switch (mp->cur_type) {
20420   case mp_transform_type:
20421   case mp_color_type:
20422   case mp_cmykcolor_type:
20423   case mp_pair_type:
20424    old_exp=mp_tarnished(mp, mp->cur_exp);
20425    break;
20426   case mp_independent: old_exp=mp_void; break;
20427   default: old_exp=null; break;
20428   }
20429   if ( old_exp!=null ) { 
20430      old_exp=mp->cur_exp; mp_make_exp_copy(mp, old_exp);
20431   }
20432   v=mp_make_fraction(mp, n,d);
20433   if ( mp->cur_type==mp_known ) {
20434     mp->cur_exp=mp_take_fraction(mp, mp->cur_exp,v);
20435   } else if ( mp->cur_type<=mp_pair_type ) { 
20436     p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20437     do {  
20438       p=p-2;
20439       mp_dep_mult(mp, p,v,false);
20440     } while (p!=value(mp->cur_exp));
20441   } else {
20442     mp_dep_mult(mp, null,v,false);
20443   }
20444   if ( old_exp!=null ) {
20445     mp_recycle_value(mp, old_exp); 
20446     mp_free_node(mp, old_exp,value_node_size);
20447   }
20448 }
20449
20450 @ @<Trace the fraction multiplication@>=
20451
20452   mp_begin_diagnostic(mp); 
20453   mp_print_nl(mp, "{("); mp_print_scaled(mp,n); mp_print_char(mp,xord('/'));
20454   mp_print_scaled(mp,d); mp_print(mp,")*("); mp_print_exp(mp,null,0); 
20455   mp_print(mp,")}");
20456   mp_end_diagnostic(mp, false);
20457 }
20458
20459 @ The |hard_times| routine multiplies a nice color or pair by a dependency list.
20460
20461 @<Declare binary action procedures@>=
20462 static void mp_hard_times (MP mp,pointer p) {
20463   pointer q; /* a copy of the dependent variable |p| */
20464   pointer r; /* a component of the big node for the nice color or pair */
20465   scaled v; /* the known value for |r| */
20466   if ( type(p)<=mp_pair_type ) { 
20467      q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p); p=q;
20468   }; /* now |cur_type=mp_pair_type| or |cur_type=mp_color_type| */
20469   r=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20470   while (1) { 
20471     r=r-2;
20472     v=value(r);
20473     type(r)=type(p);
20474     if ( r==value(mp->cur_exp) ) 
20475       break;
20476     mp_new_dep(mp, r,mp_copy_dep_list(mp, dep_list(p)));
20477     mp_dep_mult(mp, r,v,true);
20478   }
20479   mp->mem[value_loc(r)]=mp->mem[value_loc(p)];
20480   mp_link(prev_dep(p))=r;
20481   mp_free_node(mp, p,value_node_size);
20482   mp_dep_mult(mp, r,v,true);
20483 }
20484
20485 @ @<Additional cases of binary operators@>=
20486 case over: 
20487   if ( (mp->cur_type!=mp_known)||(type(p)<mp_color_type) ) {
20488     mp_bad_binary(mp, p,over);
20489   } else { 
20490     v=mp->cur_exp; mp_unstash_cur_exp(mp, p);
20491     if ( v==0 ) {
20492       @<Squeal about division by zero@>;
20493     } else { 
20494       if ( mp->cur_type==mp_known ) {
20495         mp->cur_exp=mp_make_scaled(mp, mp->cur_exp,v);
20496       } else if ( mp->cur_type<=mp_pair_type ) { 
20497         p=value(mp->cur_exp)+mp->big_node_size[mp->cur_type];
20498         do {  
20499           p=p-2;  mp_dep_div(mp, p,v);
20500         } while (p!=value(mp->cur_exp));
20501       } else {
20502         mp_dep_div(mp, null,v);
20503       }
20504     }
20505     binary_return;
20506   }
20507   break;
20508
20509 @ @<Declare binary action...@>=
20510 static void mp_dep_div (MP mp,pointer p, scaled v) {
20511   pointer q; /* the dependency list being divided by |v| */
20512   quarterword s,t; /* its type, before and after */
20513   if ( p==null ) q=mp->cur_exp;
20514   else if ( type(p)!=mp_known ) q=p;
20515   else { value(p)=mp_make_scaled(mp, value(p),v); return; };
20516   t=type(q); q=dep_list(q); s=t;
20517   if ( t==mp_dependent )
20518     if ( mp_ab_vs_cd(mp, mp_max_coef(mp,q),unity,coef_bound-1,abs(v))>=0 ) 
20519       t=mp_proto_dependent;
20520   q=mp_p_over_v(mp, q,v,s,t); 
20521   mp_dep_finish(mp, q,p,t);
20522 }
20523
20524 @ @<Squeal about division by zero@>=
20525
20526   exp_err("Division by zero");
20527 @.Division by zero@>
20528   help2("You're trying to divide the quantity shown above the error",
20529         "message by zero. I'm going to divide it by one instead.");
20530   mp_put_get_error(mp);
20531 }
20532
20533 @ @<Additional cases of binary operators@>=
20534 case pythag_add:
20535 case pythag_sub: 
20536    if ( (mp->cur_type==mp_known)&&(type(p)==mp_known) ) {
20537      if ( c==pythag_add ) mp->cur_exp=mp_pyth_add(mp, value(p),mp->cur_exp);
20538      else mp->cur_exp=mp_pyth_sub(mp, value(p),mp->cur_exp);
20539    } else mp_bad_binary(mp, p,c);
20540    break;
20541
20542 @ The next few sections of the program deal with affine transformations
20543 of coordinate data.
20544
20545 @<Additional cases of binary operators@>=
20546 case rotated_by: case slanted_by:
20547 case scaled_by: case shifted_by: case transformed_by:
20548 case x_scaled: case y_scaled: case z_scaled:
20549   if ( type(p)==mp_path_type ) { 
20550     path_trans(c,p); binary_return;
20551   } else if ( type(p)==mp_pen_type ) { 
20552     pen_trans(c,p);
20553     mp->cur_exp=mp_convex_hull(mp, mp->cur_exp); 
20554       /* rounding error could destroy convexity */
20555     binary_return;
20556   } else if ( (type(p)==mp_pair_type)||(type(p)==mp_transform_type) ) {
20557     mp_big_trans(mp, p,c);
20558   } else if ( type(p)==mp_picture_type ) {
20559     mp_do_edges_trans(mp, p,c); binary_return;
20560   } else {
20561     mp_bad_binary(mp, p,c);
20562   }
20563   break;
20564
20565 @ Let |c| be one of the eight transform operators. The procedure call
20566 |set_up_trans(c)| first changes |cur_exp| to a transform that corresponds to
20567 |c| and the original value of |cur_exp|. (In particular, |cur_exp| doesn't
20568 change at all if |c=transformed_by|.)
20569
20570 Then, if all components of the resulting transform are |known|, they are
20571 moved to the global variables |txx|, |txy|, |tyx|, |tyy|, |tx|, |ty|;
20572 and |cur_exp| is changed to the known value zero.
20573
20574 @<Declare binary action...@>=
20575 static void mp_set_up_trans (MP mp,quarterword c) {
20576   pointer p,q,r; /* list manipulation registers */
20577   if ( (c!=transformed_by)||(mp->cur_type!=mp_transform_type) ) {
20578     @<Put the current transform into |cur_exp|@>;
20579   }
20580   @<If the current transform is entirely known, stash it in global variables;
20581     otherwise |return|@>;
20582 }
20583
20584 @ @<Glob...@>=
20585 scaled txx;
20586 scaled txy;
20587 scaled tyx;
20588 scaled tyy;
20589 scaled tx;
20590 scaled ty; /* current transform coefficients */
20591
20592 @ @<Put the current transform...@>=
20593
20594   p=mp_stash_cur_exp(mp); 
20595   mp->cur_exp=mp_id_transform(mp); 
20596   mp->cur_type=mp_transform_type;
20597   q=value(mp->cur_exp);
20598   switch (c) {
20599   @<For each of the eight cases, change the relevant fields of |cur_exp|
20600     and |goto done|;
20601     but do nothing if capsule |p| doesn't have the appropriate type@>;
20602   }; /* there are no other cases */
20603   mp_disp_err(mp, p,"Improper transformation argument");
20604 @.Improper transformation argument@>
20605   help3("The expression shown above has the wrong type,",
20606        "so I can\'t transform anything using it.",
20607        "Proceed, and I'll omit the transformation.");
20608   mp_put_get_error(mp);
20609 DONE: 
20610   mp_recycle_value(mp, p); 
20611   mp_free_node(mp, p,value_node_size);
20612 }
20613
20614 @ @<If the current transform is entirely known, ...@>=
20615 q=value(mp->cur_exp); r=q+transform_node_size;
20616 do {  
20617   r=r-2;
20618   if ( type(r)!=mp_known ) return;
20619 } while (r!=q);
20620 mp->txx=value(xx_part_loc(q));
20621 mp->txy=value(xy_part_loc(q));
20622 mp->tyx=value(yx_part_loc(q));
20623 mp->tyy=value(yy_part_loc(q));
20624 mp->tx=value(x_part_loc(q));
20625 mp->ty=value(y_part_loc(q));
20626 mp_flush_cur_exp(mp, 0)
20627
20628 @ @<For each of the eight cases...@>=
20629 case rotated_by:
20630   if ( type(p)==mp_known )
20631     @<Install sines and cosines, then |goto done|@>;
20632   break;
20633 case slanted_by:
20634   if ( type(p)>mp_pair_type ) { 
20635    mp_install(mp, xy_part_loc(q),p); goto DONE;
20636   };
20637   break;
20638 case scaled_by:
20639   if ( type(p)>mp_pair_type ) { 
20640     mp_install(mp, xx_part_loc(q),p); mp_install(mp, yy_part_loc(q),p); 
20641     goto DONE;
20642   };
20643   break;
20644 case shifted_by:
20645   if ( type(p)==mp_pair_type ) {
20646     r=value(p); mp_install(mp, x_part_loc(q),x_part_loc(r));
20647     mp_install(mp, y_part_loc(q),y_part_loc(r)); goto DONE;
20648   };
20649   break;
20650 case x_scaled:
20651   if ( type(p)>mp_pair_type ) {
20652     mp_install(mp, xx_part_loc(q),p); goto DONE;
20653   };
20654   break;
20655 case y_scaled:
20656   if ( type(p)>mp_pair_type ) {
20657     mp_install(mp, yy_part_loc(q),p); goto DONE;
20658   };
20659   break;
20660 case z_scaled:
20661   if ( type(p)==mp_pair_type )
20662     @<Install a complex multiplier, then |goto done|@>;
20663   break;
20664 case transformed_by:
20665   break;
20666   
20667
20668 @ @<Install sines and cosines, then |goto done|@>=
20669 { mp_n_sin_cos(mp, (value(p) % three_sixty_units)*16);
20670   value(xx_part_loc(q))=mp_round_fraction(mp, mp->n_cos);
20671   value(yx_part_loc(q))=mp_round_fraction(mp, mp->n_sin);
20672   value(xy_part_loc(q))=-value(yx_part_loc(q));
20673   value(yy_part_loc(q))=value(xx_part_loc(q));
20674   goto DONE;
20675 }
20676
20677 @ @<Install a complex multiplier, then |goto done|@>=
20678
20679   r=value(p);
20680   mp_install(mp, xx_part_loc(q),x_part_loc(r));
20681   mp_install(mp, yy_part_loc(q),x_part_loc(r));
20682   mp_install(mp, yx_part_loc(q),y_part_loc(r));
20683   if ( type(y_part_loc(r))==mp_known ) negate(value(y_part_loc(r)));
20684   else mp_negate_dep_list(mp, dep_list(y_part_loc(r)));
20685   mp_install(mp, xy_part_loc(q),y_part_loc(r));
20686   goto DONE;
20687 }
20688
20689 @ Procedure |set_up_known_trans| is like |set_up_trans|, but it
20690 insists that the transformation be entirely known.
20691
20692 @<Declare binary action...@>=
20693 static void mp_set_up_known_trans (MP mp,quarterword c) { 
20694   mp_set_up_trans(mp, c);
20695   if ( mp->cur_type!=mp_known ) {
20696     exp_err("Transform components aren't all known");
20697 @.Transform components...@>
20698     help3("I'm unable to apply a partially specified transformation",
20699       "except to a fully known pair or transform.",
20700       "Proceed, and I'll omit the transformation.");
20701     mp_put_get_flush_error(mp, 0);
20702     mp->txx=unity; mp->txy=0; mp->tyx=0; mp->tyy=unity; 
20703     mp->tx=0; mp->ty=0;
20704   }
20705 }
20706
20707 @ Here's a procedure that applies the transform |txx..ty| to a pair of
20708 coordinates in locations |p| and~|q|.
20709
20710 @<Declare binary action...@>= 
20711 static void mp_trans (MP mp,pointer p, pointer q) {
20712   scaled v; /* the new |x| value */
20713   v=mp_take_scaled(mp, mp->mem[p].sc,mp->txx)+
20714   mp_take_scaled(mp, mp->mem[q].sc,mp->txy)+mp->tx;
20715   mp->mem[q].sc=mp_take_scaled(mp, mp->mem[p].sc,mp->tyx)+
20716   mp_take_scaled(mp, mp->mem[q].sc,mp->tyy)+mp->ty;
20717   mp->mem[p].sc=v;
20718 }
20719
20720 @ The simplest transformation procedure applies a transform to all
20721 coordinates of a path.  The |path_trans(c)(p)| macro applies
20722 a transformation defined by |cur_exp| and the transform operator |c|
20723 to the path~|p|.
20724
20725 @d path_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20726                      mp_unstash_cur_exp(mp, (B)); 
20727                      mp_do_path_trans(mp, mp->cur_exp); }
20728
20729 @<Declare binary action...@>=
20730 static void mp_do_path_trans (MP mp,pointer p) {
20731   pointer q; /* list traverser */
20732   q=p;
20733   do { 
20734     if ( left_type(q)!=mp_endpoint ) 
20735       mp_trans(mp, q+3,q+4); /* that's |left_x| and |left_y| */
20736     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20737     if ( right_type(q)!=mp_endpoint ) 
20738       mp_trans(mp, q+5,q+6); /* that's |right_x| and |right_y| */
20739 @^data structure assumptions@>
20740     q=mp_link(q);
20741   } while (q!=p);
20742 }
20743
20744 @ Transforming a pen is very similar, except that there are no |left_type|
20745 and |right_type| fields.
20746
20747 @d pen_trans(A,B) { mp_set_up_known_trans(mp, (A)); 
20748                     mp_unstash_cur_exp(mp, (B)); 
20749                     mp_do_pen_trans(mp, mp->cur_exp); }
20750
20751 @<Declare binary action...@>=
20752 static void mp_do_pen_trans (MP mp,pointer p) {
20753   pointer q; /* list traverser */
20754   if ( pen_is_elliptical(p) ) {
20755     mp_trans(mp, p+3,p+4); /* that's |left_x| and |left_y| */
20756     mp_trans(mp, p+5,p+6); /* that's |right_x| and |right_y| */
20757   };
20758   q=p;
20759   do { 
20760     mp_trans(mp, q+1,q+2); /* that's |x_coord| and |y_coord| */
20761 @^data structure assumptions@>
20762     q=mp_link(q);
20763   } while (q!=p);
20764 }
20765
20766 @ The next transformation procedure applies to edge structures. It will do
20767 any transformation, but the results may be substandard if the picture contains
20768 text that uses downloaded bitmap fonts.  The binary action procedure is
20769 |do_edges_trans|, but we also need a function that just scales a picture.
20770 That routine is |scale_edges|.  Both it and the underlying routine |edges_trans|
20771 should be thought of as procedures that update an edge structure |h|, except
20772 that they have to return a (possibly new) structure because of the need to call
20773 |private_edges|.
20774
20775 @<Declare binary action...@>=
20776 static pointer mp_edges_trans (MP mp, pointer h) {
20777   pointer q; /* the object being transformed */
20778   pointer r,s; /* for list manipulation */
20779   scaled sx,sy; /* saved transformation parameters */
20780   scaled sqdet; /* square root of determinant for |dash_scale| */
20781   integer sgndet; /* sign of the determinant */
20782   scaled v; /* a temporary value */
20783   h=mp_private_edges(mp, h);
20784   sqdet=mp_sqrt_det(mp, mp->txx,mp->txy,mp->tyx,mp->tyy);
20785   sgndet=mp_ab_vs_cd(mp, mp->txx,mp->tyy,mp->txy,mp->tyx);
20786   if ( dash_list(h)!=null_dash ) {
20787     @<Try to transform the dash list of |h|@>;
20788   }
20789   @<Make the bounding box of |h| unknown if it can't be updated properly
20790     without scanning the whole structure@>;  
20791   q=mp_link(dummy_loc(h));
20792   while ( q!=null ) { 
20793     @<Transform graphical object |q|@>;
20794     q=mp_link(q);
20795   }
20796   return h;
20797 }
20798 static void mp_do_edges_trans (MP mp,pointer p, quarterword c) { 
20799   mp_set_up_known_trans(mp, c);
20800   value(p)=mp_edges_trans(mp, value(p));
20801   mp_unstash_cur_exp(mp, p);
20802 }
20803 static void mp_scale_edges (MP mp) { 
20804   mp->txx=mp->se_sf; mp->tyy=mp->se_sf;
20805   mp->txy=0; mp->tyx=0; mp->tx=0; mp->ty=0;
20806   mp->se_pic=mp_edges_trans(mp, mp->se_pic);
20807 }
20808
20809 @ @<Try to transform the dash list of |h|@>=
20810 if ( (mp->txy!=0)||(mp->tyx!=0)||
20811      (mp->ty!=0)||(abs(mp->txx)!=abs(mp->tyy))) {
20812   mp_flush_dash_list(mp, h);
20813 } else { 
20814   if ( mp->txx<0 ) { @<Reverse the dash list of |h|@>; } 
20815   @<Scale the dash list by |txx| and shift it by |tx|@>;
20816   dash_y(h)=mp_take_scaled(mp, dash_y(h),abs(mp->tyy));
20817 }
20818
20819 @ @<Reverse the dash list of |h|@>=
20820
20821   r=dash_list(h);
20822   dash_list(h)=null_dash;
20823   while ( r!=null_dash ) {
20824     s=r; r=mp_link(r);
20825     v=start_x(s); start_x(s)=stop_x(s); stop_x(s)=v;
20826     mp_link(s)=dash_list(h);
20827     dash_list(h)=s;
20828   }
20829 }
20830
20831 @ @<Scale the dash list by |txx| and shift it by |tx|@>=
20832 r=dash_list(h);
20833 while ( r!=null_dash ) {
20834   start_x(r)=mp_take_scaled(mp, start_x(r),mp->txx)+mp->tx;
20835   stop_x(r)=mp_take_scaled(mp, stop_x(r),mp->txx)+mp->tx;
20836   r=mp_link(r);
20837 }
20838
20839 @ @<Make the bounding box of |h| unknown if it can't be updated properly...@>=
20840 if ( (mp->txx==0)&&(mp->tyy==0) ) {
20841   @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>;
20842 } else if ( (mp->txy!=0)||(mp->tyx!=0) ) {
20843   mp_init_bbox(mp, h);
20844   goto DONE1;
20845 }
20846 if ( minx_val(h)<=maxx_val(h) ) {
20847   @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift by
20848    |(tx,ty)|@>;
20849 }
20850 DONE1:
20851
20852
20853
20854 @ @<Swap the $x$ and $y$ parameters in the bounding box of |h|@>=
20855
20856   v=minx_val(h); minx_val(h)=miny_val(h); miny_val(h)=v;
20857   v=maxx_val(h); maxx_val(h)=maxy_val(h); maxy_val(h)=v;
20858 }
20859
20860 @ The sum ``|txx+txy|'' is whichever of |txx| or |txy| is nonzero.  The other
20861 sum is similar.
20862
20863 @<Scale the bounding box by |txx+txy| and |tyx+tyy|; then shift...@>=
20864
20865   minx_val(h)=mp_take_scaled(mp, minx_val(h),mp->txx+mp->txy)+mp->tx;
20866   maxx_val(h)=mp_take_scaled(mp, maxx_val(h),mp->txx+mp->txy)+mp->tx;
20867   miny_val(h)=mp_take_scaled(mp, miny_val(h),mp->tyx+mp->tyy)+mp->ty;
20868   maxy_val(h)=mp_take_scaled(mp, maxy_val(h),mp->tyx+mp->tyy)+mp->ty;
20869   if ( mp->txx+mp->txy<0 ) {
20870     v=minx_val(h); minx_val(h)=maxx_val(h); maxx_val(h)=v;
20871   }
20872   if ( mp->tyx+mp->tyy<0 ) {
20873     v=miny_val(h); miny_val(h)=maxy_val(h); maxy_val(h)=v;
20874   }
20875 }
20876
20877 @ Now we ready for the main task of transforming the graphical objects in edge
20878 structure~|h|.
20879
20880 @<Transform graphical object |q|@>=
20881 switch (type(q)) {
20882 case mp_fill_code: case mp_stroked_code: 
20883   mp_do_path_trans(mp, path_p(q));
20884   @<Transform |pen_p(q)|, making sure polygonal pens stay counter-clockwise@>;
20885   break;
20886 case mp_start_clip_code: case mp_start_bounds_code: 
20887   mp_do_path_trans(mp, path_p(q));
20888   break;
20889 case mp_text_code: 
20890   r=text_tx_loc(q);
20891   @<Transform the compact transformation starting at |r|@>;
20892   break;
20893 case mp_stop_clip_code: case mp_stop_bounds_code: 
20894   break;
20895 } /* there are no other cases */
20896
20897 @ Note that the shift parameters |(tx,ty)| apply only to the path being stroked.
20898 The |dash_scale| has to be adjusted  to scale the dash lengths in |dash_p(q)|
20899 since the \ps\ output procedures will try to compensate for the transformation
20900 we are applying to |pen_p(q)|.  Since this compensation is based on the square
20901 root of the determinant, |sqdet| is the appropriate factor.
20902
20903 @<Transform |pen_p(q)|, making sure...@>=
20904 if ( pen_p(q)!=null ) {
20905   sx=mp->tx; sy=mp->ty;
20906   mp->tx=0; mp->ty=0;
20907   mp_do_pen_trans(mp, pen_p(q));
20908   if ( ((type(q)==mp_stroked_code)&&(dash_p(q)!=null)) )
20909     dash_scale(q)=mp_take_scaled(mp, dash_scale(q),sqdet);
20910   if ( ! pen_is_elliptical(pen_p(q)) )
20911     if ( sgndet<0 )
20912       pen_p(q)=mp_make_pen(mp, mp_copy_path(mp, pen_p(q)),true); 
20913          /* this unreverses the pen */
20914   mp->tx=sx; mp->ty=sy;
20915 }
20916
20917 @ This uses the fact that transformations are stored in the order
20918 |(tx,ty,txx,txy,tyx,tyy)|.
20919 @^data structure assumptions@>
20920
20921 @<Transform the compact transformation starting at |r|@>=
20922 mp_trans(mp, r,r+1);
20923 sx=mp->tx; sy=mp->ty;
20924 mp->tx=0; mp->ty=0;
20925 mp_trans(mp, r+2,r+4);
20926 mp_trans(mp, r+3,r+5);
20927 mp->tx=sx; mp->ty=sy
20928
20929 @ The hard cases of transformation occur when big nodes are involved,
20930 and when some of their components are unknown.
20931
20932 @<Declare binary action...@>=
20933 @<Declare subroutines needed by |big_trans|@>
20934 static void mp_big_trans (MP mp,pointer p, quarterword c) {
20935   pointer q,r,pp,qq; /* list manipulation registers */
20936   quarterword s; /* size of a big node */
20937   s=mp->big_node_size[type(p)]; q=value(p); r=q+s;
20938   do {  
20939     r=r-2;
20940     if ( type(r)!=mp_known ) {
20941       @<Transform an unknown big node and |return|@>;
20942     }
20943   } while (r!=q);
20944   @<Transform a known big node@>;
20945 } /* node |p| will now be recycled by |do_binary| */
20946
20947 @ @<Transform an unknown big node and |return|@>=
20948
20949   mp_set_up_known_trans(mp, c); mp_make_exp_copy(mp, p); 
20950   r=value(mp->cur_exp);
20951   if ( mp->cur_type==mp_transform_type ) {
20952     mp_bilin1(mp, yy_part_loc(r),mp->tyy,xy_part_loc(q),mp->tyx,0);
20953     mp_bilin1(mp, yx_part_loc(r),mp->tyy,xx_part_loc(q),mp->tyx,0);
20954     mp_bilin1(mp, xy_part_loc(r),mp->txx,yy_part_loc(q),mp->txy,0);
20955     mp_bilin1(mp, xx_part_loc(r),mp->txx,yx_part_loc(q),mp->txy,0);
20956   }
20957   mp_bilin1(mp, y_part_loc(r),mp->tyy,x_part_loc(q),mp->tyx,mp->ty);
20958   mp_bilin1(mp, x_part_loc(r),mp->txx,y_part_loc(q),mp->txy,mp->tx);
20959   return;
20960 }
20961
20962 @ Let |p| point to a two-word value field inside a big node of |cur_exp|,
20963 and let |q| point to a another value field. The |bilin1| procedure
20964 replaces |p| by $p\cdot t+q\cdot u+\delta$.
20965
20966 @<Declare subroutines needed by |big_trans|@>=
20967 static void mp_bilin1 (MP mp, pointer p, scaled t, pointer q, 
20968                 scaled u, scaled delta) {
20969   pointer r; /* list traverser */
20970   if ( t!=unity ) mp_dep_mult(mp, p,t,true);
20971   if ( u!=0 ) {
20972     if ( type(q)==mp_known ) {
20973       delta+=mp_take_scaled(mp, value(q),u);
20974     } else { 
20975       @<Ensure that |type(p)=mp_proto_dependent|@>;
20976       dep_list(p)=mp_p_plus_fq(mp, dep_list(p),u,dep_list(q),
20977                                mp_proto_dependent,type(q));
20978     }
20979   }
20980   if ( type(p)==mp_known ) {
20981     value(p)+=delta;
20982   } else {
20983     r=dep_list(p);
20984     while ( info(r)!=null ) r=mp_link(r);
20985     delta+=value(r);
20986     if ( r!=dep_list(p) ) value(r)=delta;
20987     else { mp_recycle_value(mp, p); type(p)=mp_known; value(p)=delta; };
20988   }
20989   if ( mp->fix_needed ) mp_fix_dependencies(mp);
20990 }
20991
20992 @ @<Ensure that |type(p)=mp_proto_dependent|@>=
20993 if ( type(p)!=mp_proto_dependent ) {
20994   if ( type(p)==mp_known ) 
20995     mp_new_dep(mp, p,mp_const_dependency(mp, value(p)));
20996   else 
20997     dep_list(p)=mp_p_times_v(mp, dep_list(p),unity,mp_dependent,
20998                              mp_proto_dependent,true);
20999   type(p)=mp_proto_dependent;
21000 }
21001
21002 @ @<Transform a known big node@>=
21003 mp_set_up_trans(mp, c);
21004 if ( mp->cur_type==mp_known ) {
21005   @<Transform known by known@>;
21006 } else { 
21007   pp=mp_stash_cur_exp(mp); qq=value(pp);
21008   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
21009   if ( mp->cur_type==mp_transform_type ) {
21010     mp_bilin2(mp, yy_part_loc(r),yy_part_loc(qq),
21011       value(xy_part_loc(q)),yx_part_loc(qq),null);
21012     mp_bilin2(mp, yx_part_loc(r),yy_part_loc(qq),
21013       value(xx_part_loc(q)),yx_part_loc(qq),null);
21014     mp_bilin2(mp, xy_part_loc(r),xx_part_loc(qq),
21015       value(yy_part_loc(q)),xy_part_loc(qq),null);
21016     mp_bilin2(mp, xx_part_loc(r),xx_part_loc(qq),
21017       value(yx_part_loc(q)),xy_part_loc(qq),null);
21018   };
21019   mp_bilin2(mp, y_part_loc(r),yy_part_loc(qq),
21020     value(x_part_loc(q)),yx_part_loc(qq),y_part_loc(qq));
21021   mp_bilin2(mp, x_part_loc(r),xx_part_loc(qq),
21022     value(y_part_loc(q)),xy_part_loc(qq),x_part_loc(qq));
21023   mp_recycle_value(mp, pp); mp_free_node(mp, pp,value_node_size);
21024 }
21025
21026 @ Let |p| be a |mp_proto_dependent| value whose dependency list ends
21027 at |dep_final|. The following procedure adds |v| times another
21028 numeric quantity to~|p|.
21029
21030 @<Declare subroutines needed by |big_trans|@>=
21031 static void mp_add_mult_dep (MP mp,pointer p, scaled v, pointer r) { 
21032   if ( type(r)==mp_known ) {
21033     value(mp->dep_final)+=mp_take_scaled(mp, value(r),v);
21034   } else  { 
21035     dep_list(p)=mp_p_plus_fq(mp, dep_list(p),v,dep_list(r),
21036                                                          mp_proto_dependent,type(r));
21037     if ( mp->fix_needed ) mp_fix_dependencies(mp);
21038   }
21039 }
21040
21041 @ The |bilin2| procedure is something like |bilin1|, but with known
21042 and unknown quantities reversed. Parameter |p| points to a value field
21043 within the big node for |cur_exp|; and |type(p)=mp_known|. Parameters
21044 |t| and~|u| point to value fields elsewhere; so does parameter~|q|,
21045 unless it is |null| (which stands for zero). Location~|p| will be
21046 replaced by $p\cdot t+v\cdot u+q$.
21047
21048 @<Declare subroutines needed by |big_trans|@>=
21049 static void mp_bilin2 (MP mp,pointer p, pointer t, scaled v, 
21050                 pointer u, pointer q) {
21051   scaled vv; /* temporary storage for |value(p)| */
21052   vv=value(p); type(p)=mp_proto_dependent;
21053   mp_new_dep(mp, p,mp_const_dependency(mp, 0)); /* this sets |dep_final| */
21054   if ( vv!=0 ) 
21055     mp_add_mult_dep(mp, p,vv,t); /* |dep_final| doesn't change */
21056   if ( v!=0 ) mp_add_mult_dep(mp, p,v,u);
21057   if ( q!=null ) mp_add_mult_dep(mp, p,unity,q);
21058   if ( dep_list(p)==mp->dep_final ) {
21059     vv=value(mp->dep_final); mp_recycle_value(mp, p);
21060     type(p)=mp_known; value(p)=vv;
21061   }
21062 }
21063
21064 @ @<Transform known by known@>=
21065
21066   mp_make_exp_copy(mp, p); r=value(mp->cur_exp);
21067   if ( mp->cur_type==mp_transform_type ) {
21068     mp_bilin3(mp, yy_part_loc(r),mp->tyy,value(xy_part_loc(q)),mp->tyx,0);
21069     mp_bilin3(mp, yx_part_loc(r),mp->tyy,value(xx_part_loc(q)),mp->tyx,0);
21070     mp_bilin3(mp, xy_part_loc(r),mp->txx,value(yy_part_loc(q)),mp->txy,0);
21071     mp_bilin3(mp, xx_part_loc(r),mp->txx,value(yx_part_loc(q)),mp->txy,0);
21072   }
21073   mp_bilin3(mp, y_part_loc(r),mp->tyy,value(x_part_loc(q)),mp->tyx,mp->ty);
21074   mp_bilin3(mp, x_part_loc(r),mp->txx,value(y_part_loc(q)),mp->txy,mp->tx);
21075 }
21076
21077 @ Finally, in |bilin3| everything is |known|.
21078
21079 @<Declare subroutines needed by |big_trans|@>=
21080 static void mp_bilin3 (MP mp,pointer p, scaled t, 
21081                scaled v, scaled u, scaled delta) { 
21082   if ( t!=unity )
21083     delta+=mp_take_scaled(mp, value(p),t);
21084   else 
21085     delta+=value(p);
21086   if ( u!=0 ) value(p)=delta+mp_take_scaled(mp, v,u);
21087   else value(p)=delta;
21088 }
21089
21090 @ @<Additional cases of binary operators@>=
21091 case concatenate: 
21092   if ( (mp->cur_type==mp_string_type)&&(type(p)==mp_string_type) ) mp_cat(mp, p);
21093   else mp_bad_binary(mp, p,concatenate);
21094   break;
21095 case substring_of: 
21096   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_string_type) )
21097     mp_chop_string(mp, value(p));
21098   else mp_bad_binary(mp, p,substring_of);
21099   break;
21100 case subpath_of: 
21101   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21102   if ( mp_nice_pair(mp, p,type(p))&&(mp->cur_type==mp_path_type) )
21103     mp_chop_path(mp, value(p));
21104   else mp_bad_binary(mp, p,subpath_of);
21105   break;
21106
21107 @ @<Declare binary action...@>=
21108 static void mp_cat (MP mp,pointer p) {
21109   str_number a,b; /* the strings being concatenated */
21110   pool_pointer k; /* index into |str_pool| */
21111   a=value(p); b=mp->cur_exp; str_room(length(a)+length(b));
21112   for (k=mp->str_start[a];k<=str_stop(a)-1;k++) {
21113     append_char(mp->str_pool[k]);
21114   }
21115   for (k=mp->str_start[b];k<=str_stop(b)-1;k++) {
21116     append_char(mp->str_pool[k]);
21117   }
21118   mp->cur_exp=mp_make_string(mp); delete_str_ref(b);
21119 }
21120
21121 @ @<Declare binary action...@>=
21122 static void mp_chop_string (MP mp,pointer p) {
21123   integer a, b; /* start and stop points */
21124   integer l; /* length of the original string */
21125   integer k; /* runs from |a| to |b| */
21126   str_number s; /* the original string */
21127   boolean reversed; /* was |a>b|? */
21128   a=mp_round_unscaled(mp, value(x_part_loc(p)));
21129   b=mp_round_unscaled(mp, value(y_part_loc(p)));
21130   if ( a<=b ) reversed=false;
21131   else  { reversed=true; k=a; a=b; b=k; };
21132   s=mp->cur_exp; l=length(s);
21133   if ( a<0 ) { 
21134     a=0;
21135     if ( b<0 ) b=0;
21136   }
21137   if ( b>l ) { 
21138     b=l;
21139     if ( a>l ) a=l;
21140   }
21141   str_room(b-a);
21142   if ( reversed ) {
21143     for (k=mp->str_start[s]+b-1;k>=mp->str_start[s]+a;k--)  {
21144       append_char(mp->str_pool[k]);
21145     }
21146   } else  {
21147     for (k=mp->str_start[s]+a;k<=mp->str_start[s]+b-1;k++)  {
21148       append_char(mp->str_pool[k]);
21149     }
21150   }
21151   mp->cur_exp=mp_make_string(mp); delete_str_ref(s);
21152 }
21153
21154 @ @<Declare binary action...@>=
21155 static void mp_chop_path (MP mp,pointer p) {
21156   pointer q; /* a knot in the original path */
21157   pointer pp,qq,rr,ss; /* link variables for copies of path nodes */
21158   scaled a,b,k,l; /* indices for chopping */
21159   boolean reversed; /* was |a>b|? */
21160   l=mp_path_length(mp); a=value(x_part_loc(p)); b=value(y_part_loc(p));
21161   if ( a<=b ) reversed=false;
21162   else  { reversed=true; k=a; a=b; b=k; };
21163   @<Dispense with the cases |a<0| and/or |b>l|@>;
21164   q=mp->cur_exp;
21165   while ( a>=unity ) {
21166     q=mp_link(q); a=a-unity; b=b-unity;
21167   }
21168   if ( b==a ) {
21169     @<Construct a path from |pp| to |qq| of length zero@>; 
21170   } else { 
21171     @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>; 
21172   }
21173   left_type(pp)=mp_endpoint; right_type(qq)=mp_endpoint; mp_link(qq)=pp;
21174   mp_toss_knot_list(mp, mp->cur_exp);
21175   if ( reversed ) {
21176     mp->cur_exp=mp_link(mp_htap_ypoc(mp, pp)); mp_toss_knot_list(mp, pp);
21177   } else {
21178     mp->cur_exp=pp;
21179   }
21180 }
21181
21182 @ @<Dispense with the cases |a<0| and/or |b>l|@>=
21183 if ( a<0 ) {
21184   if ( left_type(mp->cur_exp)==mp_endpoint ) {
21185     a=0; if ( b<0 ) b=0;
21186   } else  {
21187     do {  a=a+l; b=b+l; } while (a<0); /* a cycle always has length |l>0| */
21188   }
21189 }
21190 if ( b>l ) {
21191   if ( left_type(mp->cur_exp)==mp_endpoint ) {
21192     b=l; if ( a>l ) a=l;
21193   } else {
21194     while ( a>=l ) { 
21195       a=a-l; b=b-l;
21196     }
21197   }
21198 }
21199
21200 @ @<Construct a path from |pp| to |qq| of length $\lceil b\rceil$@>=
21201
21202   pp=mp_copy_knot(mp, q); qq=pp;
21203   do {  
21204     q=mp_link(q); rr=qq; qq=mp_copy_knot(mp, q); mp_link(rr)=qq; b=b-unity;
21205   } while (b>0);
21206   if ( a>0 ) {
21207     ss=pp; pp=mp_link(pp);
21208     mp_split_cubic(mp, ss,a*010000); pp=mp_link(ss);
21209     mp_free_node(mp, ss,knot_node_size);
21210     if ( rr==ss ) {
21211       b=mp_make_scaled(mp, b,unity-a); rr=pp;
21212     }
21213   }
21214   if ( b<0 ) {
21215     mp_split_cubic(mp, rr,(b+unity)*010000);
21216     mp_free_node(mp, qq,knot_node_size);
21217     qq=mp_link(rr);
21218   }
21219 }
21220
21221 @ @<Construct a path from |pp| to |qq| of length zero@>=
21222
21223   if ( a>0 ) { mp_split_cubic(mp, q,a*010000); q=mp_link(q); };
21224   pp=mp_copy_knot(mp, q); qq=pp;
21225 }
21226
21227 @ @<Additional cases of binary operators@>=
21228 case point_of: case precontrol_of: case postcontrol_of: 
21229   if ( mp->cur_type==mp_pair_type )
21230      mp_pair_to_path(mp);
21231   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
21232     mp_find_point(mp, value(p),c);
21233   else 
21234     mp_bad_binary(mp, p,c);
21235   break;
21236 case pen_offset_of: 
21237   if ( (mp->cur_type==mp_pen_type)&& mp_nice_pair(mp, p,type(p)) )
21238     mp_set_up_offset(mp, value(p));
21239   else 
21240     mp_bad_binary(mp, p,pen_offset_of);
21241   break;
21242 case direction_time_of: 
21243   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21244   if ( (mp->cur_type==mp_path_type)&& mp_nice_pair(mp, p,type(p)) )
21245     mp_set_up_direction_time(mp, value(p));
21246   else 
21247     mp_bad_binary(mp, p,direction_time_of);
21248   break;
21249 case envelope_of:
21250   if ( (type(p) != mp_pen_type) || (mp->cur_type != mp_path_type) )
21251     mp_bad_binary(mp, p,envelope_of);
21252   else
21253     mp_set_up_envelope(mp, p);
21254   break;
21255
21256 @ @<Declare binary action...@>=
21257 static void mp_set_up_offset (MP mp,pointer p) { 
21258   mp_find_offset(mp, value(x_part_loc(p)),value(y_part_loc(p)),mp->cur_exp);
21259   mp_pair_value(mp, mp->cur_x,mp->cur_y);
21260 }
21261 static void mp_set_up_direction_time (MP mp,pointer p) { 
21262   mp_flush_cur_exp(mp, mp_find_direction_time(mp, value(x_part_loc(p)),
21263   value(y_part_loc(p)),mp->cur_exp));
21264 }
21265 static void mp_set_up_envelope (MP mp,pointer p) {
21266   quarterword ljoin, lcap;
21267   scaled miterlim;
21268   pointer q = mp_copy_path(mp, mp->cur_exp); /* the original path */
21269   /* TODO: accept elliptical pens for straight paths */
21270   if (pen_is_elliptical(value(p))) {
21271     mp_bad_envelope_pen(mp);
21272     mp->cur_exp = q;
21273     mp->cur_type = mp_path_type;
21274     return;
21275   }
21276   if ( mp->internal[mp_linejoin]>unity ) ljoin=2;
21277   else if ( mp->internal[mp_linejoin]>0 ) ljoin=1;
21278   else ljoin=0;
21279   if ( mp->internal[mp_linecap]>unity ) lcap=2;
21280   else if ( mp->internal[mp_linecap]>0 ) lcap=1;
21281   else lcap=0;
21282   if ( mp->internal[mp_miterlimit]<unity )
21283     miterlim=unity;
21284   else
21285     miterlim=mp->internal[mp_miterlimit];
21286   mp->cur_exp = mp_make_envelope(mp, q, value(p), ljoin,lcap,miterlim);
21287   mp->cur_type = mp_path_type;
21288 }
21289
21290 @ @<Declare binary action...@>=
21291 static void mp_find_point (MP mp,scaled v, quarterword c) {
21292   pointer p; /* the path */
21293   scaled n; /* its length */
21294   p=mp->cur_exp;
21295   if ( left_type(p)==mp_endpoint ) n=-unity; else n=0;
21296   do {  p=mp_link(p); n=n+unity; } while (p!=mp->cur_exp);
21297   if ( n==0 ) { 
21298     v=0; 
21299   } else if ( v<0 ) {
21300     if ( left_type(p)==mp_endpoint ) v=0;
21301     else v=n-1-((-v-1) % n);
21302   } else if ( v>n ) {
21303     if ( left_type(p)==mp_endpoint ) v=n;
21304     else v=v % n;
21305   }
21306   p=mp->cur_exp;
21307   while ( v>=unity ) { p=mp_link(p); v=v-unity;  };
21308   if ( v!=0 ) {
21309      @<Insert a fractional node by splitting the cubic@>;
21310   }
21311   @<Set the current expression to the desired path coordinates@>;
21312 }
21313
21314 @ @<Insert a fractional node...@>=
21315 { mp_split_cubic(mp, p,v*010000); p=mp_link(p); }
21316
21317 @ @<Set the current expression to the desired path coordinates...@>=
21318 switch (c) {
21319 case point_of: 
21320   mp_pair_value(mp, x_coord(p),y_coord(p));
21321   break;
21322 case precontrol_of: 
21323   if ( left_type(p)==mp_endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
21324   else mp_pair_value(mp, left_x(p),left_y(p));
21325   break;
21326 case postcontrol_of: 
21327   if ( right_type(p)==mp_endpoint ) mp_pair_value(mp, x_coord(p),y_coord(p));
21328   else mp_pair_value(mp, right_x(p),right_y(p));
21329   break;
21330 } /* there are no other cases */
21331
21332 @ @<Additional cases of binary operators@>=
21333 case arc_time_of: 
21334   if ( mp->cur_type==mp_pair_type )
21335      mp_pair_to_path(mp);
21336   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_known) )
21337     mp_flush_cur_exp(mp, mp_get_arc_time(mp, mp->cur_exp,value(p)));
21338   else 
21339     mp_bad_binary(mp, p,c);
21340   break;
21341
21342 @ @<Additional cases of bin...@>=
21343 case intersect: 
21344   if ( type(p)==mp_pair_type ) {
21345     q=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, p);
21346     mp_pair_to_path(mp); p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q);
21347   };
21348   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
21349   if ( (mp->cur_type==mp_path_type)&&(type(p)==mp_path_type) ) {
21350     mp_path_intersection(mp, value(p),mp->cur_exp);
21351     mp_pair_value(mp, mp->cur_t,mp->cur_tt);
21352   } else {
21353     mp_bad_binary(mp, p,intersect);
21354   }
21355   break;
21356
21357 @ @<Additional cases of bin...@>=
21358 case in_font:
21359   if ( (mp->cur_type!=mp_string_type)||(type(p)!=mp_string_type)) 
21360     mp_bad_binary(mp, p,in_font);
21361   else { mp_do_infont(mp, p); binary_return; }
21362   break;
21363
21364 @ Function |new_text_node| owns the reference count for its second argument
21365 (the text string) but not its first (the font name).
21366
21367 @<Declare binary action...@>=
21368 static void mp_do_infont (MP mp,pointer p) {
21369   pointer q;
21370   q=mp_get_node(mp, edge_header_size);
21371   mp_init_edges(mp, q);
21372   mp_link(obj_tail(q))=mp_new_text_node(mp,str(mp->cur_exp),value(p));
21373   obj_tail(q)=mp_link(obj_tail(q));
21374   mp_free_node(mp, p,value_node_size);
21375   mp_flush_cur_exp(mp, q);
21376   mp->cur_type=mp_picture_type;
21377 }
21378
21379 @* \[40] Statements and commands.
21380 The chief executive of \MP\ is the |do_statement| routine, which
21381 contains the master switch that causes all the various pieces of \MP\
21382 to do their things, in the right order.
21383
21384 In a sense, this is the grand climax of the program: It applies all the
21385 tools that we have worked so hard to construct. In another sense, this is
21386 the messiest part of the program: It necessarily refers to other pieces
21387 of code all over the place, so that a person can't fully understand what is
21388 going on without paging back and forth to be reminded of conventions that
21389 are defined elsewhere. We are now at the hub of the web.
21390
21391 The structure of |do_statement| itself is quite simple.  The first token
21392 of the statement is fetched using |get_x_next|.  If it can be the first
21393 token of an expression, we look for an equation, an assignment, or a
21394 title. Otherwise we use a \&{case} construction to branch at high speed to
21395 the appropriate routine for various and sundry other types of commands,
21396 each of which has an ``action procedure'' that does the necessary work.
21397
21398 The program uses the fact that
21399 $$\hbox{|min_primary_command=max_statement_command=type_name|}$$
21400 to interpret a statement that starts with, e.g., `\&{string}',
21401 as a type declaration rather than a boolean expression.
21402
21403 @c void mp_do_statement (MP mp) { /* governs \MP's activities */
21404   mp->cur_type=mp_vacuous; mp_get_x_next(mp);
21405   if ( mp->cur_cmd>max_primary_command ) {
21406     @<Worry about bad statement@>;
21407   } else if ( mp->cur_cmd>max_statement_command ) {
21408     @<Do an equation, assignment, title, or
21409      `$\langle\,$expression$\,\rangle\,$\&{endgroup}'@>;
21410   } else {
21411     @<Do a statement that doesn't begin with an expression@>;
21412   }
21413   if ( mp->cur_cmd<semicolon )
21414     @<Flush unparsable junk that was found after the statement@>;
21415   mp->error_count=0;
21416 }
21417
21418 @ @<Declarations@>=
21419 @<Declare action procedures for use by |do_statement|@>
21420
21421 @ The only command codes |>max_primary_command| that can be present
21422 at the beginning of a statement are |semicolon| and higher; these
21423 occur when the statement is null.
21424
21425 @<Worry about bad statement@>=
21426
21427   if ( mp->cur_cmd<semicolon ) {
21428     print_err("A statement can't begin with `");
21429 @.A statement can't begin with x@>
21430     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod); mp_print_char(mp, xord('\''));
21431     help5("I was looking for the beginning of a new statement.",
21432       "If you just proceed without changing anything, I'll ignore",
21433       "everything up to the next `;'. Please insert a semicolon",
21434       "now in front of anything that you don't want me to delete.",
21435       "(See Chapter 27 of The METAFONTbook for an example.)");
21436 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21437     mp_back_error(mp); mp_get_x_next(mp);
21438   }
21439 }
21440
21441 @ The help message printed here says that everything is flushed up to
21442 a semicolon, but actually the commands |end_group| and |stop| will
21443 also terminate a statement.
21444
21445 @<Flush unparsable junk that was found after the statement@>=
21446
21447   print_err("Extra tokens will be flushed");
21448 @.Extra tokens will be flushed@>
21449   help6("I've just read as much of that statement as I could fathom,",
21450         "so a semicolon should have been next. It's very puzzling...",
21451         "but I'll try to get myself back together, by ignoring",
21452         "everything up to the next `;'. Please insert a semicolon",
21453         "now in front of anything that you don't want me to delete.",
21454         "(See Chapter 27 of The METAFONTbook for an example.)");
21455 @:METAFONTbook}{\sl The {\logos METAFONT\/}book@>
21456   mp_back_error(mp); mp->scanner_status=flushing;
21457   do {  
21458     get_t_next;
21459     @<Decrease the string reference count...@>;
21460   } while (! end_of_statement); /* |cur_cmd=semicolon|, |end_group|, or |stop| */
21461   mp->scanner_status=normal;
21462 }
21463
21464 @ If |do_statement| ends with |cur_cmd=end_group|, we should have
21465 |cur_type=mp_vacuous| unless the statement was simply an expression;
21466 in the latter case, |cur_type| and |cur_exp| should represent that
21467 expression.
21468
21469 @<Do a statement that doesn't...@>=
21470
21471   if ( mp->internal[mp_tracing_commands]>0 ) 
21472     show_cur_cmd_mod;
21473   switch (mp->cur_cmd ) {
21474   case type_name:mp_do_type_declaration(mp); break;
21475   case macro_def:
21476     if ( mp->cur_mod>var_def ) mp_make_op_def(mp);
21477     else if ( mp->cur_mod>end_def ) mp_scan_def(mp);
21478      break;
21479   @<Cases of |do_statement| that invoke particular commands@>;
21480   } /* there are no other cases */
21481   mp->cur_type=mp_vacuous;
21482 }
21483
21484 @ The most important statements begin with expressions.
21485
21486 @<Do an equation, assignment, title, or...@>=
21487
21488   mp->var_flag=assignment; mp_scan_expression(mp);
21489   if ( mp->cur_cmd<end_group ) {
21490     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21491     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21492     else if ( mp->cur_type==mp_string_type ) {@<Do a title@> ; }
21493     else if ( mp->cur_type!=mp_vacuous ){ 
21494       exp_err("Isolated expression");
21495 @.Isolated expression@>
21496       help3("I couldn't find an `=' or `:=' after the",
21497         "expression that is shown above this error message,",
21498         "so I guess I'll just ignore it and carry on.");
21499       mp_put_get_error(mp);
21500     }
21501     mp_flush_cur_exp(mp, 0); mp->cur_type=mp_vacuous;
21502   }
21503 }
21504
21505 @ @<Do a title@>=
21506
21507   if ( mp->internal[mp_tracing_titles]>0 ) {
21508     mp_print_nl(mp, "");  mp_print_str(mp, mp->cur_exp); update_terminal;
21509   }
21510 }
21511
21512 @ Equations and assignments are performed by the pair of mutually recursive
21513 @^recursion@>
21514 routines |do_equation| and |do_assignment|. These routines are called when
21515 |cur_cmd=equals| and when |cur_cmd=assignment|, respectively; the left-hand
21516 side is in |cur_type| and |cur_exp|, while the right-hand side is yet
21517 to be scanned. After the routines are finished, |cur_type| and |cur_exp|
21518 will be equal to the right-hand side (which will normally be equal
21519 to the left-hand side).
21520
21521 @<Declarations@>=
21522 @<Declare the procedure called |make_eq|@>
21523 static void mp_do_equation (MP mp) ;
21524
21525 @ @c
21526 void mp_do_equation (MP mp) {
21527   pointer lhs; /* capsule for the left-hand side */
21528   pointer p; /* temporary register */
21529   lhs=mp_stash_cur_exp(mp); mp_get_x_next(mp); 
21530   mp->var_flag=assignment; mp_scan_expression(mp);
21531   if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21532   else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21533   if ( mp->internal[mp_tracing_commands]>two ) 
21534     @<Trace the current equation@>;
21535   if ( mp->cur_type==mp_unknown_path ) if ( type(lhs)==mp_pair_type ) {
21536     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, lhs); lhs=p;
21537   }; /* in this case |make_eq| will change the pair to a path */
21538   mp_make_eq(mp, lhs); /* equate |lhs| to |(cur_type,cur_exp)| */
21539 }
21540
21541 @ And |do_assignment| is similar to |do_equation|:
21542
21543 @<Declarations@>=
21544 static void mp_do_assignment (MP mp);
21545
21546 @ @c
21547 void mp_do_assignment (MP mp) {
21548   pointer lhs; /* token list for the left-hand side */
21549   pointer p; /* where the left-hand value is stored */
21550   pointer q; /* temporary capsule for the right-hand value */
21551   if ( mp->cur_type!=mp_token_list ) { 
21552     exp_err("Improper `:=' will be changed to `='");
21553 @.Improper `:='@>
21554     help2("I didn't find a variable name at the left of the `:=',",
21555           "so I'm going to pretend that you said `=' instead.");
21556     mp_error(mp); mp_do_equation(mp);
21557   } else { 
21558     lhs=mp->cur_exp; mp->cur_type=mp_vacuous;
21559     mp_get_x_next(mp); mp->var_flag=assignment; mp_scan_expression(mp);
21560     if ( mp->cur_cmd==equals ) mp_do_equation(mp);
21561     else if ( mp->cur_cmd==assignment ) mp_do_assignment(mp);
21562     if ( mp->internal[mp_tracing_commands]>two ) 
21563       @<Trace the current assignment@>;
21564     if ( info(lhs)>hash_end ) {
21565       @<Assign the current expression to an internal variable@>;
21566     } else  {
21567       @<Assign the current expression to the variable |lhs|@>;
21568     }
21569     mp_flush_node_list(mp, lhs);
21570   }
21571 }
21572
21573 @ @<Trace the current equation@>=
21574
21575   mp_begin_diagnostic(mp); mp_print_nl(mp, "{("); mp_print_exp(mp,lhs,0);
21576   mp_print(mp,")=("); mp_print_exp(mp,null,0); 
21577   mp_print(mp,")}"); mp_end_diagnostic(mp, false);
21578 }
21579
21580 @ @<Trace the current assignment@>=
21581
21582   mp_begin_diagnostic(mp); mp_print_nl(mp, "{");
21583   if ( info(lhs)>hash_end ) 
21584      mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21585   else 
21586      mp_show_token_list(mp, lhs,null,1000,0);
21587   mp_print(mp, ":="); mp_print_exp(mp, null,0); 
21588   mp_print_char(mp, xord('}')); mp_end_diagnostic(mp, false);
21589 }
21590
21591 @ @<Assign the current expression to an internal variable@>=
21592 if ( mp->cur_type==mp_known )  {
21593   mp->internal[info(lhs)-(hash_end)]=mp->cur_exp;
21594 } else { 
21595   exp_err("Internal quantity `");
21596 @.Internal quantity...@>
21597   mp_print(mp, mp->int_name[info(lhs)-(hash_end)]);
21598   mp_print(mp, "' must receive a known value");
21599   help2("I can\'t set an internal quantity to anything but a known",
21600         "numeric value, so I'll have to ignore this assignment.");
21601   mp_put_get_error(mp);
21602 }
21603
21604 @ @<Assign the current expression to the variable |lhs|@>=
21605
21606   p=mp_find_variable(mp, lhs);
21607   if ( p!=null ) {
21608     q=mp_stash_cur_exp(mp); mp->cur_type=mp_und_type(mp, p); 
21609     mp_recycle_value(mp, p);
21610     type(p)=mp->cur_type; value(p)=null; mp_make_exp_copy(mp, p);
21611     p=mp_stash_cur_exp(mp); mp_unstash_cur_exp(mp, q); mp_make_eq(mp, p);
21612   } else  { 
21613     mp_obliterated(mp, lhs); mp_put_get_error(mp);
21614   }
21615 }
21616
21617
21618 @ And now we get to the nitty-gritty. The |make_eq| procedure is given
21619 a pointer to a capsule that is to be equated to the current expression.
21620
21621 @<Declare the procedure called |make_eq|@>=
21622 static void mp_make_eq (MP mp,pointer lhs) ;
21623
21624
21625
21626 @c void mp_make_eq (MP mp,pointer lhs) {
21627   quarterword t; /* type of the left-hand side */
21628   pointer p,q; /* pointers inside of big nodes */
21629   integer v=0; /* value of the left-hand side */
21630 RESTART: 
21631   t=type(lhs);
21632   if ( t<=mp_pair_type ) v=value(lhs);
21633   switch (t) {
21634   @<For each type |t|, make an equation and |goto done| unless |cur_type|
21635     is incompatible with~|t|@>;
21636   } /* all cases have been listed */
21637   @<Announce that the equation cannot be performed@>;
21638 DONE:
21639   check_arith; mp_recycle_value(mp, lhs); 
21640   mp_free_node(mp, lhs,value_node_size);
21641 }
21642
21643 @ @<Announce that the equation cannot be performed@>=
21644 mp_disp_err(mp, lhs,""); 
21645 exp_err("Equation cannot be performed (");
21646 @.Equation cannot be performed@>
21647 if ( type(lhs)<=mp_pair_type ) mp_print_type(mp, type(lhs));
21648 else mp_print(mp, "numeric");
21649 mp_print_char(mp, xord('='));
21650 if ( mp->cur_type<=mp_pair_type ) mp_print_type(mp, mp->cur_type);
21651 else mp_print(mp, "numeric");
21652 mp_print_char(mp, xord(')'));
21653 help2("I'm sorry, but I don't know how to make such things equal.",
21654       "(See the two expressions just above the error message.)");
21655 mp_put_get_error(mp)
21656
21657 @ @<For each type |t|, make an equation and |goto done| unless...@>=
21658 case mp_boolean_type: case mp_string_type: case mp_pen_type:
21659 case mp_path_type: case mp_picture_type:
21660   if ( mp->cur_type==t+unknown_tag ) { 
21661     mp_nonlinear_eq(mp, v,mp->cur_exp,false); 
21662     mp_unstash_cur_exp(mp, mp->cur_exp); goto DONE;
21663   } else if ( mp->cur_type==t ) {
21664     @<Report redundant or inconsistent equation and |goto done|@>;
21665   }
21666   break;
21667 case unknown_types:
21668   if ( mp->cur_type==t-unknown_tag ) { 
21669     mp_nonlinear_eq(mp, mp->cur_exp,lhs,true); goto DONE;
21670   } else if ( mp->cur_type==t ) { 
21671     mp_ring_merge(mp, lhs,mp->cur_exp); goto DONE;
21672   } else if ( mp->cur_type==mp_pair_type ) {
21673     if ( t==mp_unknown_path ) { 
21674      mp_pair_to_path(mp); goto RESTART;
21675     };
21676   }
21677   break;
21678 case mp_transform_type: case mp_color_type:
21679 case mp_cmykcolor_type: case mp_pair_type:
21680   if ( mp->cur_type==t ) {
21681     @<Do multiple equations and |goto done|@>;
21682   }
21683   break;
21684 case mp_known: case mp_dependent:
21685 case mp_proto_dependent: case mp_independent:
21686   if ( mp->cur_type>=mp_known ) { 
21687     mp_try_eq(mp, lhs,null); goto DONE;
21688   };
21689   break;
21690 case mp_vacuous:
21691   break;
21692
21693 @ @<Report redundant or inconsistent equation and |goto done|@>=
21694
21695   if ( mp->cur_type<=mp_string_type ) {
21696     if ( mp->cur_type==mp_string_type ) {
21697       if ( mp_str_vs_str(mp, v,mp->cur_exp)!=0 ) {
21698         goto NOT_FOUND;
21699       }
21700     } else if ( v!=mp->cur_exp ) {
21701       goto NOT_FOUND;
21702     }
21703     @<Exclaim about a redundant equation@>; goto DONE;
21704   }
21705   print_err("Redundant or inconsistent equation");
21706 @.Redundant or inconsistent equation@>
21707   help2("An equation between already-known quantities can't help.",
21708         "But don't worry; continue and I'll just ignore it.");
21709   mp_put_get_error(mp); goto DONE;
21710 NOT_FOUND: 
21711   print_err("Inconsistent equation");
21712 @.Inconsistent equation@>
21713   help2("The equation I just read contradicts what was said before.",
21714         "But don't worry; continue and I'll just ignore it.");
21715   mp_put_get_error(mp); goto DONE;
21716 }
21717
21718 @ @<Do multiple equations and |goto done|@>=
21719
21720   p=v+mp->big_node_size[t]; 
21721   q=value(mp->cur_exp)+mp->big_node_size[t];
21722   do {  
21723     p=p-2; q=q-2; mp_try_eq(mp, p,q);
21724   } while (p!=v);
21725   goto DONE;
21726 }
21727
21728 @ The first argument to |try_eq| is the location of a value node
21729 in a capsule that will soon be recycled. The second argument is
21730 either a location within a pair or transform node pointed to by
21731 |cur_exp|, or it is |null| (which means that |cur_exp| itself
21732 serves as the second argument). The idea is to leave |cur_exp| unchanged,
21733 but to equate the two operands.
21734
21735 @<Declarations@>=
21736 static void mp_try_eq (MP mp,pointer l, pointer r) ;
21737
21738
21739 @c void mp_try_eq (MP mp,pointer l, pointer r) {
21740   pointer p; /* dependency list for right operand minus left operand */
21741   int t; /* the type of list |p| */
21742   pointer q; /* the constant term of |p| is here */
21743   pointer pp; /* dependency list for right operand */
21744   int tt; /* the type of list |pp| */
21745   boolean copied; /* have we copied a list that ought to be recycled? */
21746   @<Remove the left operand from its container, negate it, and
21747     put it into dependency list~|p| with constant term~|q|@>;
21748   @<Add the right operand to list |p|@>;
21749   if ( info(p)==null ) {
21750     @<Deal with redundant or inconsistent equation@>;
21751   } else { 
21752     mp_linear_eq(mp, p,t);
21753     if ( r==null ) if ( mp->cur_type!=mp_known ) {
21754       if ( type(mp->cur_exp)==mp_known ) {
21755         pp=mp->cur_exp; mp->cur_exp=value(mp->cur_exp); mp->cur_type=mp_known;
21756         mp_free_node(mp, pp,value_node_size);
21757       }
21758     }
21759   }
21760 }
21761
21762 @ @<Remove the left operand from its container, negate it, and...@>=
21763 t=type(l);
21764 if ( t==mp_known ) { 
21765   t=mp_dependent; p=mp_const_dependency(mp, -value(l)); q=p;
21766 } else if ( t==mp_independent ) {
21767   t=mp_dependent; p=mp_single_dependency(mp, l); negate(value(p));
21768   q=mp->dep_final;
21769 } else { 
21770   p=dep_list(l); q=p;
21771   while (1) { 
21772     negate(value(q));
21773     if ( info(q)==null ) break;
21774     q=mp_link(q);
21775   }
21776   mp_link(prev_dep(l))=mp_link(q); prev_dep(mp_link(q))=prev_dep(l);
21777   type(l)=mp_known;
21778 }
21779
21780 @ @<Deal with redundant or inconsistent equation@>=
21781
21782   if ( abs(value(p))>64 ) { /* off by .001 or more */
21783     print_err("Inconsistent equation");
21784 @.Inconsistent equation@>
21785     mp_print(mp, " (off by "); mp_print_scaled(mp, value(p)); 
21786     mp_print_char(mp, xord(')'));
21787     help2("The equation I just read contradicts what was said before.",
21788           "But don't worry; continue and I'll just ignore it.");
21789     mp_put_get_error(mp);
21790   } else if ( r==null ) {
21791     @<Exclaim about a redundant equation@>;
21792   }
21793   mp_free_node(mp, p,dep_node_size);
21794 }
21795
21796 @ @<Add the right operand to list |p|@>=
21797 if ( r==null ) {
21798   if ( mp->cur_type==mp_known ) {
21799     value(q)=value(q)+mp->cur_exp; goto DONE1;
21800   } else { 
21801     tt=mp->cur_type;
21802     if ( tt==mp_independent ) pp=mp_single_dependency(mp, mp->cur_exp);
21803     else pp=dep_list(mp->cur_exp);
21804   } 
21805 } else {
21806   if ( type(r)==mp_known ) {
21807     value(q)=value(q)+value(r); goto DONE1;
21808   } else { 
21809     tt=type(r);
21810     if ( tt==mp_independent ) pp=mp_single_dependency(mp, r);
21811     else pp=dep_list(r);
21812   }
21813 }
21814 if ( tt!=mp_independent ) copied=false;
21815 else  { copied=true; tt=mp_dependent; };
21816 @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>;
21817 if ( copied ) mp_flush_node_list(mp, pp);
21818 DONE1:
21819
21820 @ @<Add dependency list |pp| of type |tt| to dependency list~|p| of type~|t|@>=
21821 mp->watch_coefs=false;
21822 if ( t==tt ) {
21823   p=mp_p_plus_q(mp, p,pp,t);
21824 } else if ( t==mp_proto_dependent ) {
21825   p=mp_p_plus_fq(mp, p,unity,pp,mp_proto_dependent,mp_dependent);
21826 } else { 
21827   q=p;
21828   while ( info(q)!=null ) {
21829     value(q)=mp_round_fraction(mp, value(q)); q=mp_link(q);
21830   }
21831   t=mp_proto_dependent; p=mp_p_plus_q(mp, p,pp,t);
21832 }
21833 mp->watch_coefs=true;
21834
21835 @ Our next goal is to process type declarations. For this purpose it's
21836 convenient to have a procedure that scans a $\langle\,$declared
21837 variable$\,\rangle$ and returns the corresponding token list. After the
21838 following procedure has acted, the token after the declared variable
21839 will have been scanned, so it will appear in |cur_cmd|, |cur_mod|,
21840 and~|cur_sym|.
21841
21842 @<Declarations@>=
21843 static pointer mp_scan_declared_variable (MP mp) ;
21844
21845 @ @c
21846 pointer mp_scan_declared_variable (MP mp) {
21847   pointer x; /* hash address of the variable's root */
21848   pointer h,t; /* head and tail of the token list to be returned */
21849   pointer l; /* hash address of left bracket */
21850   mp_get_symbol(mp); x=mp->cur_sym;
21851   if ( mp->cur_cmd!=tag_token ) mp_clear_symbol(mp, x,false);
21852   h=mp_get_avail(mp); info(h)=x; t=h;
21853   while (1) { 
21854     mp_get_x_next(mp);
21855     if ( mp->cur_sym==0 ) break;
21856     if ( mp->cur_cmd!=tag_token ) if ( mp->cur_cmd!=internal_quantity)  {
21857       if ( mp->cur_cmd==left_bracket ) {
21858         @<Descend past a collective subscript@>;
21859       } else {
21860         break;
21861       }
21862     }
21863     mp_link(t)=mp_get_avail(mp); t=mp_link(t); info(t)=mp->cur_sym;
21864   }
21865   if ( (eq_type(x)%outer_tag)!=tag_token ) mp_clear_symbol(mp, x,false);
21866   if ( equiv(x)==null ) mp_new_root(mp, x);
21867   return h;
21868 }
21869
21870 @ If the subscript isn't collective, we don't accept it as part of the
21871 declared variable.
21872
21873 @<Descend past a collective subscript@>=
21874
21875   l=mp->cur_sym; mp_get_x_next(mp);
21876   if ( mp->cur_cmd!=right_bracket ) {
21877     mp_back_input(mp); mp->cur_sym=l; mp->cur_cmd=left_bracket; break;
21878   } else {
21879     mp->cur_sym=collective_subscript;
21880   }
21881 }
21882
21883 @ Type declarations are introduced by the following primitive operations.
21884
21885 @<Put each...@>=
21886 mp_primitive(mp, "numeric",type_name,mp_numeric_type);
21887 @:numeric_}{\&{numeric} primitive@>
21888 mp_primitive(mp, "string",type_name,mp_string_type);
21889 @:string_}{\&{string} primitive@>
21890 mp_primitive(mp, "boolean",type_name,mp_boolean_type);
21891 @:boolean_}{\&{boolean} primitive@>
21892 mp_primitive(mp, "path",type_name,mp_path_type);
21893 @:path_}{\&{path} primitive@>
21894 mp_primitive(mp, "pen",type_name,mp_pen_type);
21895 @:pen_}{\&{pen} primitive@>
21896 mp_primitive(mp, "picture",type_name,mp_picture_type);
21897 @:picture_}{\&{picture} primitive@>
21898 mp_primitive(mp, "transform",type_name,mp_transform_type);
21899 @:transform_}{\&{transform} primitive@>
21900 mp_primitive(mp, "color",type_name,mp_color_type);
21901 @:color_}{\&{color} primitive@>
21902 mp_primitive(mp, "rgbcolor",type_name,mp_color_type);
21903 @:color_}{\&{rgbcolor} primitive@>
21904 mp_primitive(mp, "cmykcolor",type_name,mp_cmykcolor_type);
21905 @:color_}{\&{cmykcolor} primitive@>
21906 mp_primitive(mp, "pair",type_name,mp_pair_type);
21907 @:pair_}{\&{pair} primitive@>
21908
21909 @ @<Cases of |print_cmd...@>=
21910 case type_name: mp_print_type(mp, m); break;
21911
21912 @ Now we are ready to handle type declarations, assuming that a
21913 |type_name| has just been scanned.
21914
21915 @<Declare action procedures for use by |do_statement|@>=
21916 static void mp_do_type_declaration (MP mp) ;
21917
21918 @ @c
21919 void mp_do_type_declaration (MP mp) {
21920   quarterword t; /* the type being declared */
21921   pointer p; /* token list for a declared variable */
21922   pointer q; /* value node for the variable */
21923   if ( mp->cur_mod>=mp_transform_type ) 
21924     t=mp->cur_mod;
21925   else 
21926     t=mp->cur_mod+unknown_tag;
21927   do {  
21928     p=mp_scan_declared_variable(mp);
21929     mp_flush_variable(mp, equiv(info(p)),mp_link(p),false);
21930     q=mp_find_variable(mp, p);
21931     if ( q!=null ) { 
21932       type(q)=t; value(q)=null; 
21933     } else  { 
21934       print_err("Declared variable conflicts with previous vardef");
21935 @.Declared variable conflicts...@>
21936       help2("You can't use, e.g., `numeric foo[]' after `vardef foo'.",
21937             "Proceed, and I'll ignore the illegal redeclaration.");
21938       mp_put_get_error(mp);
21939     }
21940     mp_flush_list(mp, p);
21941     if ( mp->cur_cmd<comma ) {
21942       @<Flush spurious symbols after the declared variable@>;
21943     }
21944   } while (! end_of_statement);
21945 }
21946
21947 @ @<Flush spurious symbols after the declared variable@>=
21948
21949   print_err("Illegal suffix of declared variable will be flushed");
21950 @.Illegal suffix...flushed@>
21951   help5("Variables in declarations must consist entirely of",
21952     "names and collective subscripts, e.g., `x[]a'.",
21953     "Are you trying to use a reserved word in a variable name?",
21954     "I'm going to discard the junk I found here,",
21955     "up to the next comma or the end of the declaration.");
21956   if ( mp->cur_cmd==numeric_token )
21957     mp->help_line[2]="Explicit subscripts like `x15a' aren't permitted.";
21958   mp_put_get_error(mp); mp->scanner_status=flushing;
21959   do {  
21960     get_t_next;
21961     @<Decrease the string reference count...@>;
21962   } while (mp->cur_cmd<comma); /* either |end_of_statement| or |cur_cmd=comma| */
21963   mp->scanner_status=normal;
21964 }
21965
21966 @ \MP's |main_control| procedure just calls |do_statement| repeatedly
21967 until coming to the end of the user's program.
21968 Each execution of |do_statement| concludes with
21969 |cur_cmd=semicolon|, |end_group|, or |stop|.
21970
21971 @c 
21972 static void mp_main_control (MP mp) { 
21973   do {  
21974     mp_do_statement(mp);
21975     if ( mp->cur_cmd==end_group ) {
21976       print_err("Extra `endgroup'");
21977 @.Extra `endgroup'@>
21978       help2("I'm not currently working on a `begingroup',",
21979             "so I had better not try to end anything.");
21980       mp_flush_error(mp, 0);
21981     }
21982   } while (mp->cur_cmd!=stop);
21983 }
21984 int mp_run (MP mp) {
21985   if (mp->history < mp_fatal_error_stop ) {
21986     mp->jump_buf = malloc(sizeof(jmp_buf));
21987     if (mp->jump_buf == NULL || setjmp(*(mp->jump_buf)) != 0) 
21988       return mp->history;
21989     mp_main_control(mp); /* come to life */
21990     mp_final_cleanup(mp); /* prepare for death */
21991     mp_close_files_and_terminate(mp);
21992   }
21993   return mp->history;
21994 }
21995
21996 @ For |mp_execute|, we need to define a structure to store the
21997 redirected input and output. This structure holds the five relevant
21998 streams: the three informational output streams, the PostScript
21999 generation stream, and the input stream. These streams have many
22000 things in common, so it makes sense to give them their own structure
22001 definition. 
22002
22003 \item{fptr} is a virtual file pointer
22004 \item{data} is the data this stream holds
22005 \item{cur}  is a cursor pointing into |data| 
22006 \item{size} is the allocated length of the data stream
22007 \item{used} is the actual length of the data stream
22008
22009 There are small differences between input and output: |term_in| never
22010 uses |used|, whereas the other four never use |cur|.
22011
22012 @<Exported types@>= 
22013 typedef struct {
22014    void * fptr;
22015    char * data;
22016    char * cur;
22017    size_t size;
22018    size_t used;
22019 } mp_stream;
22020
22021 typedef struct {
22022     mp_stream term_out;
22023     mp_stream error_out;
22024     mp_stream log_out;
22025     mp_stream ps_out;
22026     mp_stream term_in;
22027     struct mp_edge_object *edges;
22028 } mp_run_data;
22029
22030 @ We need a function to clear an output stream, this is called at the
22031 beginning of |mp_execute|. We also need one for destroying an output
22032 stream, this is called just before a stream is (re)opened.
22033
22034 @c
22035 static void mp_reset_stream(mp_stream *str) {
22036    xfree(str->data); 
22037    str->cur = NULL;
22038    str->size = 0; 
22039    str->used = 0;
22040 }
22041 static void mp_free_stream(mp_stream *str) {
22042    xfree(str->fptr); 
22043    mp_reset_stream(str);
22044 }
22045
22046 @ @<Declarations@>=
22047 static void mp_reset_stream(mp_stream *str);
22048 static void mp_free_stream(mp_stream *str);
22049
22050 @ The global instance contains a pointer instead of the actual structure
22051 even though it is essentially static, because that makes it is easier to move 
22052 the object around.
22053
22054 @<Global ...@>=
22055 mp_run_data run_data;
22056
22057 @ Another type is needed: the indirection will overload some of the
22058 file pointer objects in the instance (but not all). For clarity, an
22059 indirect object is used that wraps a |FILE *|.
22060
22061 @<Types ... @>=
22062 typedef struct File {
22063     FILE *f;
22064 } File;
22065
22066 @ Here are all of the functions that need to be overloaded for |mp_execute|.
22067
22068 @<Declarations@>=
22069 static void *mplib_open_file(MP mp, const char *fname, const char *fmode, int ftype);
22070 static int mplib_get_char(void *f, mp_run_data * mplib_data);
22071 static void mplib_unget_char(void *f, mp_run_data * mplib_data, int c);
22072 static char *mplib_read_ascii_file(MP mp, void *ff, size_t * size);
22073 static void mplib_write_ascii_file(MP mp, void *ff, const char *s);
22074 static void mplib_read_binary_file(MP mp, void *ff, void **data, size_t * size);
22075 static void mplib_write_binary_file(MP mp, void *ff, void *s, size_t size);
22076 static void mplib_close_file(MP mp, void *ff);
22077 static int mplib_eof_file(MP mp, void *ff);
22078 static void mplib_flush_file(MP mp, void *ff);
22079 static void mplib_shipout_backend(MP mp, int h);
22080
22081 @ The |xmalloc(1,1)| calls make sure the stored indirection values are unique.
22082
22083 @d reset_stream(a)  do { 
22084         mp_reset_stream(&(a));
22085         if (!ff->f) {
22086           ff->f = xmalloc(1,1);
22087           (a).fptr = ff->f;
22088         } } while (0)
22089
22090 @c
22091
22092 static void *mplib_open_file(MP mp, const char *fname, const char *fmode, int ftype)
22093 {
22094     File *ff = xmalloc(1, sizeof(File));
22095     mp_run_data *run = mp_rundata(mp);
22096     ff->f = NULL;
22097     if (ftype == mp_filetype_terminal) {
22098         if (fmode[0] == 'r') {
22099             if (!ff->f) {
22100               ff->f = xmalloc(1,1);
22101               run->term_in.fptr = ff->f;
22102             }
22103         } else {
22104             reset_stream(run->term_out);
22105         }
22106     } else if (ftype == mp_filetype_error) {
22107         reset_stream(run->error_out);
22108     } else if (ftype == mp_filetype_log) {
22109         reset_stream(run->log_out);
22110     } else if (ftype == mp_filetype_postscript) {
22111         mp_free_stream(&(run->ps_out));
22112         ff->f = xmalloc(1,1);
22113         run->ps_out.fptr = ff->f;
22114     } else {
22115         char realmode[3];
22116         char *f = (mp->find_file)(mp, fname, fmode, ftype);
22117         if (f == NULL)
22118             return NULL;
22119         realmode[0] = *fmode;
22120         realmode[1] = 'b';
22121         realmode[2] = 0;
22122         ff->f = fopen(f, realmode);
22123         free(f);
22124         if ((fmode[0] == 'r') && (ff->f == NULL)) {
22125             free(ff);
22126             return NULL;
22127         }
22128     }
22129     return ff;
22130 }
22131
22132 static int mplib_get_char(void *f, mp_run_data * run)
22133 {
22134     int c;
22135     if (f == run->term_in.fptr && run->term_in.data != NULL) {
22136         if (run->term_in.size == 0) {
22137             if (run->term_in.cur  != NULL) {
22138                 run->term_in.cur = NULL;
22139             } else {
22140                 xfree(run->term_in.data);
22141             }
22142             c = EOF;
22143         } else {
22144             run->term_in.size--;
22145             c = *(run->term_in.cur)++;
22146         }
22147     } else {
22148         c = fgetc(f);
22149     }
22150     return c;
22151 }
22152
22153 static void mplib_unget_char(void *f, mp_run_data * run, int c)
22154 {
22155     if (f == run->term_in.fptr && run->term_in.cur != NULL) {
22156         run->term_in.size++;
22157         run->term_in.cur--;
22158     } else {
22159         ungetc(c, f);
22160     }
22161 }
22162
22163
22164 static char *mplib_read_ascii_file(MP mp, void *ff, size_t * size)
22165 {
22166     char *s = NULL;
22167     if (ff != NULL) {
22168         int c;
22169         size_t len = 0, lim = 128;
22170         mp_run_data *run = mp_rundata(mp);
22171         FILE *f = ((File *) ff)->f;
22172         if (f == NULL)
22173             return NULL;
22174         *size = 0;
22175         c = mplib_get_char(f, run);
22176         if (c == EOF)
22177             return NULL;
22178         s = malloc(lim);
22179         if (s == NULL)
22180             return NULL;
22181         while (c != EOF && c != '\n' && c != '\r') {
22182             if (len == lim) {
22183                 s = xrealloc(s, (lim + (lim >> 2)),1);
22184                 if (s == NULL)
22185                     return NULL;
22186                 lim += (lim >> 2);
22187             }
22188             s[len++] = c;
22189             c = mplib_get_char(f, run);
22190         }
22191         if (c == '\r') {
22192             c = mplib_get_char(f, run);
22193             if (c != EOF && c != '\n')
22194                 mplib_unget_char(f, run, c);
22195         }
22196         s[len] = 0;
22197         *size = len;
22198     }
22199     return s;
22200 }
22201
22202 static void mp_append_string (MP mp, mp_stream *a,const char *b) {
22203     size_t l = strlen(b);
22204     if ((a->used+l)>=a->size) {
22205         a->size += 256+(a->size)/5+l;
22206         a->data = xrealloc(a->data,a->size,1);
22207     }
22208     (void)strcpy(a->data+a->used,b);
22209     a->used += l;
22210 }
22211
22212
22213 static void mplib_write_ascii_file(MP mp, void *ff, const char *s)
22214 {
22215     if (ff != NULL) {
22216         void *f = ((File *) ff)->f;
22217         mp_run_data *run = mp_rundata(mp);
22218         if (f != NULL) {
22219             if (f == run->term_out.fptr) {
22220                 mp_append_string(mp,&(run->term_out), s);
22221             } else if (f == run->error_out.fptr) {
22222                 mp_append_string(mp,&(run->error_out), s);
22223             } else if (f == run->log_out.fptr) {
22224                 mp_append_string(mp,&(run->log_out), s);
22225             } else if (f == run->ps_out.fptr) {
22226                 mp_append_string(mp,&(run->ps_out), s);
22227             } else {
22228                 fprintf((FILE *) f, "%s", s);
22229             }
22230         }
22231     }
22232 }
22233
22234 static void mplib_read_binary_file(MP mp, void *ff, void **data, size_t * size)
22235 {
22236     (void) mp;
22237     if (ff != NULL) {
22238         size_t len = 0;
22239         FILE *f = ((File *) ff)->f;
22240         if (f != NULL)
22241             len = fread(*data, 1, *size, f);
22242         *size = len;
22243     }
22244 }
22245
22246 static void mplib_write_binary_file(MP mp, void *ff, void *s, size_t size)
22247 {
22248     (void) mp;
22249     if (ff != NULL) {
22250         FILE *f = ((File *) ff)->f;
22251         if (f != NULL)
22252             (void)fwrite(s, size, 1, f);
22253     }
22254 }
22255
22256 static void mplib_close_file(MP mp, void *ff)
22257 {
22258     if (ff != NULL) {
22259         mp_run_data *run = mp_rundata(mp);
22260         void *f = ((File *) ff)->f;
22261         if (f != NULL) {
22262           if (f != run->term_out.fptr
22263             && f != run->error_out.fptr
22264             && f != run->log_out.fptr
22265             && f != run->ps_out.fptr
22266             && f != run->term_in.fptr) {
22267             fclose(f);
22268           }
22269         }
22270         free(ff);
22271     }
22272 }
22273
22274 static int mplib_eof_file(MP mp, void *ff)
22275 {
22276     if (ff != NULL) {
22277         mp_run_data *run = mp_rundata(mp);
22278         FILE *f = ((File *) ff)->f;
22279         if (f == NULL)
22280             return 1;
22281         if (f == run->term_in.fptr && run->term_in.data != NULL) {
22282             return (run->term_in.size == 0);
22283         }
22284         return feof(f);
22285     }
22286     return 1;
22287 }
22288
22289 static void mplib_flush_file(MP mp, void *ff)
22290 {
22291     (void) mp;
22292     (void) ff;
22293     return;
22294 }
22295
22296 static void mplib_shipout_backend(MP mp, int h)
22297 {
22298     mp_edge_object *hh = mp_gr_export(mp, h);
22299     if (hh) {
22300         mp_run_data *run = mp_rundata(mp);
22301         if (run->edges==NULL) {
22302            run->edges = hh;
22303         } else {
22304            mp_edge_object *p = run->edges; 
22305            while (p->_next!=NULL) { p = p->_next; }
22306             p->_next = hh;
22307         } 
22308     }
22309 }
22310
22311
22312 @ This is where we fill them all in.
22313 @<Prepare function pointers for non-interactive use@>=
22314 {
22315     mp->open_file         = mplib_open_file;
22316     mp->close_file        = mplib_close_file;
22317     mp->eof_file          = mplib_eof_file;
22318     mp->flush_file        = mplib_flush_file;
22319     mp->write_ascii_file  = mplib_write_ascii_file;
22320     mp->read_ascii_file   = mplib_read_ascii_file;
22321     mp->write_binary_file = mplib_write_binary_file;
22322     mp->read_binary_file  = mplib_read_binary_file;
22323     mp->shipout_backend   = mplib_shipout_backend;
22324 }
22325
22326 @ Perhaps this is the most important API function in the library.
22327
22328 @<Exported function ...@>=
22329 extern mp_run_data *mp_rundata (MP mp) ;
22330
22331 @ @c
22332 mp_run_data *mp_rundata (MP mp)  {
22333   return &(mp->run_data);
22334 }
22335
22336 @ @<Dealloc ...@>=
22337 mp_free_stream(&(mp->run_data.term_in));
22338 mp_free_stream(&(mp->run_data.term_out));
22339 mp_free_stream(&(mp->run_data.log_out));
22340 mp_free_stream(&(mp->run_data.error_out));
22341 mp_free_stream(&(mp->run_data.ps_out));
22342
22343 @ @<Finish non-interactive use@>=
22344 xfree(mp->term_out);
22345 xfree(mp->term_in);
22346 xfree(mp->err_out);
22347
22348 @ @<Start non-interactive work@>=
22349 @<Initialize the output routines@>;
22350 mp->input_ptr=0; mp->max_in_stack=0;
22351 mp->in_open=0; mp->open_parens=0; mp->max_buf_stack=0;
22352 mp->param_ptr=0; mp->max_param_stack=0;
22353 start = loc = iindex = 0; mp->first = 0;
22354 line=0; name=is_term;
22355 mp->mpx_name[0]=absent;
22356 mp->force_eof=false;
22357 t_open_in; 
22358 mp->scanner_status=normal;
22359 if (mp->mem_ident==NULL) {
22360   if ( ! mp_load_mem_file(mp) ) {
22361     (mp->close_file)(mp, mp->mem_file); 
22362      mp->history  = mp_fatal_error_stop;
22363      return mp->history;
22364   }
22365   (mp->close_file)(mp, mp->mem_file);
22366 }
22367 mp_fix_date_and_time(mp);
22368 if (mp->random_seed==0)
22369   mp->random_seed = (mp->internal[mp_time] / unity)+mp->internal[mp_day];
22370 mp_init_randoms(mp, mp->random_seed);
22371 @<Initialize the print |selector|...@>;
22372 mp_open_log_file(mp);
22373 mp_set_job_id(mp);
22374 mp_init_map_file(mp, mp->troff_mode);
22375 mp->history=mp_spotless; /* ready to go! */
22376 if (mp->troff_mode) {
22377   mp->internal[mp_gtroffmode]=unity; 
22378   mp->internal[mp_prologues]=unity; 
22379 }
22380 if ( mp->start_sym>0 ) { /* insert the `\&{everyjob}' symbol */
22381   mp->cur_sym=mp->start_sym; mp_back_input(mp);
22382 }
22383
22384 @ @c
22385 int mp_execute (MP mp, char *s, size_t l) {
22386   mp_reset_stream(&(mp->run_data.term_out));
22387   mp_reset_stream(&(mp->run_data.log_out));
22388   mp_reset_stream(&(mp->run_data.error_out));
22389   mp_reset_stream(&(mp->run_data.ps_out));
22390   if (mp->finished) {
22391       return mp->history;
22392   } else if (!mp->noninteractive) {
22393       mp->history = mp_fatal_error_stop ;
22394       return mp->history;
22395   }
22396   if (mp->history < mp_fatal_error_stop ) {
22397     mp->jump_buf = malloc(sizeof(jmp_buf));
22398     if (mp->jump_buf == NULL || setjmp(*(mp->jump_buf)) != 0) {   
22399        return mp->history; 
22400     }
22401     if (s==NULL) { /* this signals EOF */
22402       mp_final_cleanup(mp); /* prepare for death */
22403       mp_close_files_and_terminate(mp);
22404       return mp->history;
22405     } 
22406     mp->tally=0; 
22407     mp->term_offset=0; mp->file_offset=0; 
22408     /* Perhaps some sort of warning here when |data| is not 
22409      * yet exhausted would be nice ...  this happens after errors
22410      */
22411     if (mp->run_data.term_in.data)
22412       xfree(mp->run_data.term_in.data);
22413     mp->run_data.term_in.data = xstrdup(s);
22414     mp->run_data.term_in.cur = mp->run_data.term_in.data;
22415     mp->run_data.term_in.size = l;
22416     if (mp->run_state == 0) {
22417       mp->selector=term_only; 
22418       @<Start non-interactive work@>; 
22419     }
22420     mp->run_state =1;    
22421     (void)mp_input_ln(mp,mp->term_in);
22422     mp_firm_up_the_line(mp);    
22423     mp->buffer[limit]=xord('%');
22424     mp->first=(size_t)(limit+1); 
22425     loc=start;
22426         do {  
22427       mp_do_statement(mp);
22428     } while (mp->cur_cmd!=stop);
22429     mp_final_cleanup(mp); 
22430     mp_close_files_and_terminate(mp);
22431   }
22432   return mp->history;
22433 }
22434
22435 @ This function cleans up
22436 @c
22437 int mp_finish (MP mp) {
22438   int history = 0;
22439   if (mp->finished || mp->history >= mp_fatal_error_stop) {
22440     history = mp->history;
22441     mp_free(mp);
22442     return history;
22443   }
22444   mp->jump_buf = malloc(sizeof(jmp_buf));
22445   if (mp->jump_buf == NULL || setjmp(*(mp->jump_buf)) != 0) { 
22446     history = mp->history;
22447   } else {
22448     history = mp->history;
22449     mp_final_cleanup(mp); /* prepare for death */
22450   }
22451   mp_close_files_and_terminate(mp);
22452   mp_free(mp);
22453   return history;
22454 }
22455
22456 @ People may want to know the library version
22457 @c 
22458 const char * mp_metapost_version (void) {
22459   return metapost_version;
22460 }
22461
22462 @ @<Exported function headers@>=
22463 int mp_run (MP mp);
22464 int mp_execute (MP mp, char *s, size_t l);
22465 int mp_finish (MP mp);
22466 const char * mp_metapost_version (void);
22467
22468 @ @<Put each...@>=
22469 mp_primitive(mp, "end",stop,0);
22470 @:end_}{\&{end} primitive@>
22471 mp_primitive(mp, "dump",stop,1);
22472 @:dump_}{\&{dump} primitive@>
22473
22474 @ @<Cases of |print_cmd...@>=
22475 case stop:
22476   if ( m==0 ) mp_print(mp, "end");
22477   else mp_print(mp, "dump");
22478   break;
22479
22480 @* \[41] Commands.
22481 Let's turn now to statements that are classified as ``commands'' because
22482 of their imperative nature. We'll begin with simple ones, so that it
22483 will be clear how to hook command processing into the |do_statement| routine;
22484 then we'll tackle the tougher commands.
22485
22486 Here's one of the simplest:
22487
22488 @<Cases of |do_statement|...@>=
22489 case mp_random_seed: mp_do_random_seed(mp);  break;
22490
22491 @ @<Declare action procedures for use by |do_statement|@>=
22492 static void mp_do_random_seed (MP mp) ;
22493
22494 @ @c void mp_do_random_seed (MP mp) { 
22495   mp_get_x_next(mp);
22496   if ( mp->cur_cmd!=assignment ) {
22497     mp_missing_err(mp, ":=");
22498 @.Missing `:='@>
22499     help1("Always say `randomseed:=<numeric expression>'.");
22500     mp_back_error(mp);
22501   };
22502   mp_get_x_next(mp); mp_scan_expression(mp);
22503   if ( mp->cur_type!=mp_known ) {
22504     exp_err("Unknown value will be ignored");
22505 @.Unknown value...ignored@>
22506     help2("Your expression was too random for me to handle,",
22507           "so I won't change the random seed just now.");
22508     mp_put_get_flush_error(mp, 0);
22509   } else {
22510    @<Initialize the random seed to |cur_exp|@>;
22511   }
22512 }
22513
22514 @ @<Initialize the random seed to |cur_exp|@>=
22515
22516   mp_init_randoms(mp, mp->cur_exp);
22517   if ( mp->selector>=log_only && mp->selector<write_file) {
22518     mp->old_setting=mp->selector; mp->selector=log_only;
22519     mp_print_nl(mp, "{randomseed:="); 
22520     mp_print_scaled(mp, mp->cur_exp); 
22521     mp_print_char(mp, xord('}'));
22522     mp_print_nl(mp, ""); mp->selector=mp->old_setting;
22523   }
22524 }
22525
22526 @ And here's another simple one (somewhat different in flavor):
22527
22528 @<Cases of |do_statement|...@>=
22529 case mode_command: 
22530   mp_print_ln(mp); mp->interaction=mp->cur_mod;
22531   @<Initialize the print |selector| based on |interaction|@>;
22532   if ( mp->log_opened ) mp->selector=mp->selector+2;
22533   mp_get_x_next(mp);
22534   break;
22535
22536 @ @<Put each...@>=
22537 mp_primitive(mp, "batchmode",mode_command,mp_batch_mode);
22538 @:mp_batch_mode_}{\&{batchmode} primitive@>
22539 mp_primitive(mp, "nonstopmode",mode_command,mp_nonstop_mode);
22540 @:mp_nonstop_mode_}{\&{nonstopmode} primitive@>
22541 mp_primitive(mp, "scrollmode",mode_command,mp_scroll_mode);
22542 @:mp_scroll_mode_}{\&{scrollmode} primitive@>
22543 mp_primitive(mp, "errorstopmode",mode_command,mp_error_stop_mode);
22544 @:mp_error_stop_mode_}{\&{errorstopmode} primitive@>
22545
22546 @ @<Cases of |print_cmd_mod|...@>=
22547 case mode_command: 
22548   switch (m) {
22549   case mp_batch_mode: mp_print(mp, "batchmode"); break;
22550   case mp_nonstop_mode: mp_print(mp, "nonstopmode"); break;
22551   case mp_scroll_mode: mp_print(mp, "scrollmode"); break;
22552   default: mp_print(mp, "errorstopmode"); break;
22553   }
22554   break;
22555
22556 @ The `\&{inner}' and `\&{outer}' commands are only slightly harder.
22557
22558 @<Cases of |do_statement|...@>=
22559 case protection_command: mp_do_protection(mp); break;
22560
22561 @ @<Put each...@>=
22562 mp_primitive(mp, "inner",protection_command,0);
22563 @:inner_}{\&{inner} primitive@>
22564 mp_primitive(mp, "outer",protection_command,1);
22565 @:outer_}{\&{outer} primitive@>
22566
22567 @ @<Cases of |print_cmd...@>=
22568 case protection_command: 
22569   if ( m==0 ) mp_print(mp, "inner");
22570   else mp_print(mp, "outer");
22571   break;
22572
22573 @ @<Declare action procedures for use by |do_statement|@>=
22574 static void mp_do_protection (MP mp) ;
22575
22576 @ @c void mp_do_protection (MP mp) {
22577   int m; /* 0 to unprotect, 1 to protect */
22578   halfword t; /* the |eq_type| before we change it */
22579   m=mp->cur_mod;
22580   do {  
22581     mp_get_symbol(mp); t=eq_type(mp->cur_sym);
22582     if ( m==0 ) { 
22583       if ( t>=outer_tag ) 
22584         eq_type(mp->cur_sym)=t-outer_tag;
22585     } else if ( t<outer_tag ) {
22586       eq_type(mp->cur_sym)=t+outer_tag;
22587     }
22588     mp_get_x_next(mp);
22589   } while (mp->cur_cmd==comma);
22590 }
22591
22592 @ \MP\ never defines the tokens `\.(' and `\.)' to be primitives, but
22593 plain \MP\ begins with the declaration `\&{delimiters} \.{()}'. Such a
22594 declaration assigns the command code |left_delimiter| to `\.{(}' and
22595 |right_delimiter| to `\.{)}'; the |equiv| of each delimiter is the
22596 hash address of its mate.
22597
22598 @<Cases of |do_statement|...@>=
22599 case delimiters: mp_def_delims(mp); break;
22600
22601 @ @<Declare action procedures for use by |do_statement|@>=
22602 static void mp_def_delims (MP mp) ;
22603
22604 @ @c void mp_def_delims (MP mp) {
22605   pointer l_delim,r_delim; /* the new delimiter pair */
22606   mp_get_clear_symbol(mp); l_delim=mp->cur_sym;
22607   mp_get_clear_symbol(mp); r_delim=mp->cur_sym;
22608   eq_type(l_delim)=left_delimiter; equiv(l_delim)=r_delim;
22609   eq_type(r_delim)=right_delimiter; equiv(r_delim)=l_delim;
22610   mp_get_x_next(mp);
22611 }
22612
22613 @ Here is a procedure that is called when \MP\ has reached a point
22614 where some right delimiter is mandatory.
22615
22616 @<Declarations@>=
22617 static void mp_check_delimiter (MP mp,pointer l_delim, pointer r_delim);
22618
22619 @ @c
22620 void mp_check_delimiter (MP mp,pointer l_delim, pointer r_delim) {
22621   if ( mp->cur_cmd==right_delimiter ) 
22622     if ( mp->cur_mod==l_delim ) 
22623       return;
22624   if ( mp->cur_sym!=r_delim ) {
22625      mp_missing_err(mp, str(text(r_delim)));
22626 @.Missing `)'@>
22627     help2("I found no right delimiter to match a left one. So I've",
22628           "put one in, behind the scenes; this may fix the problem.");
22629     mp_back_error(mp);
22630   } else { 
22631     print_err("The token `"); mp_print_text(r_delim);
22632 @.The token...delimiter@>
22633     mp_print(mp, "' is no longer a right delimiter");
22634     help3("Strange: This token has lost its former meaning!",
22635       "I'll read it as a right delimiter this time;",
22636       "but watch out, I'll probably miss it later.");
22637     mp_error(mp);
22638   }
22639 }
22640
22641 @ The next four commands save or change the values associated with tokens.
22642
22643 @<Cases of |do_statement|...@>=
22644 case save_command: 
22645   do {  
22646     mp_get_symbol(mp); mp_save_variable(mp, mp->cur_sym); mp_get_x_next(mp);
22647   } while (mp->cur_cmd==comma);
22648   break;
22649 case interim_command: mp_do_interim(mp); break;
22650 case let_command: mp_do_let(mp); break;
22651 case new_internal: mp_do_new_internal(mp); break;
22652
22653 @ @<Declare action procedures for use by |do_statement|@>=
22654 static void mp_do_statement (MP mp);
22655 static void mp_do_interim (MP mp);
22656
22657 @ @c void mp_do_interim (MP mp) { 
22658   mp_get_x_next(mp);
22659   if ( mp->cur_cmd!=internal_quantity ) {
22660      print_err("The token `");
22661 @.The token...quantity@>
22662     if ( mp->cur_sym==0 ) mp_print(mp, "(%CAPSULE)");
22663     else mp_print_text(mp->cur_sym);
22664     mp_print(mp, "' isn't an internal quantity");
22665     help1("Something like `tracingonline' should follow `interim'.");
22666     mp_back_error(mp);
22667   } else { 
22668     mp_save_internal(mp, mp->cur_mod); mp_back_input(mp);
22669   }
22670   mp_do_statement(mp);
22671 }
22672
22673 @ The following procedure is careful not to undefine the left-hand symbol
22674 too soon, lest commands like `{\tt let x=x}' have a surprising effect.
22675
22676 @<Declare action procedures for use by |do_statement|@>=
22677 static void mp_do_let (MP mp) ;
22678
22679 @ @c void mp_do_let (MP mp) {
22680   pointer l; /* hash location of the left-hand symbol */
22681   mp_get_symbol(mp); l=mp->cur_sym; mp_get_x_next(mp);
22682   if ( mp->cur_cmd!=equals ) if ( mp->cur_cmd!=assignment ) {
22683      mp_missing_err(mp, "=");
22684 @.Missing `='@>
22685     help3("You should have said `let symbol = something'.",
22686       "But don't worry; I'll pretend that an equals sign",
22687       "was present. The next token I read will be `something'.");
22688     mp_back_error(mp);
22689   }
22690   mp_get_symbol(mp);
22691   switch (mp->cur_cmd) {
22692   case defined_macro: case secondary_primary_macro:
22693   case tertiary_secondary_macro: case expression_tertiary_macro: 
22694     add_mac_ref(mp->cur_mod);
22695     break;
22696   default: 
22697     break;
22698   }
22699   mp_clear_symbol(mp, l,false); eq_type(l)=mp->cur_cmd;
22700   if ( mp->cur_cmd==tag_token ) equiv(l)=null;
22701   else equiv(l)=mp->cur_mod;
22702   mp_get_x_next(mp);
22703 }
22704
22705 @ @<Declarations@>=
22706 static void mp_grow_internals (MP mp, int l);
22707 static void mp_do_new_internal (MP mp) ;
22708
22709 @ @c
22710 void mp_grow_internals (MP mp, int l) {
22711   scaled *internal;
22712   char * *int_name; 
22713   int k;
22714   if ( hash_end+l>max_halfword ) {
22715     mp_confusion(mp, "out of memory space"); /* can't be reached */
22716   }
22717   int_name = xmalloc ((l+1),sizeof(char *));
22718   internal = xmalloc ((l+1),sizeof(scaled));
22719   for (k=0;k<=l; k++ ) { 
22720     if (k<=mp->max_internal) {
22721       internal[k]=mp->internal[k]; 
22722       int_name[k]=mp->int_name[k]; 
22723     } else {
22724       internal[k]=0; 
22725       int_name[k]=NULL; 
22726     }
22727   }
22728   xfree(mp->internal); xfree(mp->int_name);
22729   mp->int_name = int_name;
22730   mp->internal = internal;
22731   mp->max_internal = l;
22732 }
22733
22734 void mp_do_new_internal (MP mp) { 
22735   do {  
22736     if ( mp->int_ptr==mp->max_internal ) {
22737       mp_grow_internals(mp, (mp->max_internal + (mp->max_internal/4)));
22738     }
22739     mp_get_clear_symbol(mp); incr(mp->int_ptr);
22740     eq_type(mp->cur_sym)=internal_quantity; 
22741     equiv(mp->cur_sym)=mp->int_ptr;
22742     if(mp->int_name[mp->int_ptr]!=NULL)
22743       xfree(mp->int_name[mp->int_ptr]);
22744     mp->int_name[mp->int_ptr]=str(text(mp->cur_sym)); 
22745     mp->internal[mp->int_ptr]=0;
22746     mp_get_x_next(mp);
22747   } while (mp->cur_cmd==comma);
22748 }
22749
22750 @ @<Dealloc variables@>=
22751 for (k=0;k<=mp->max_internal;k++) {
22752    xfree(mp->int_name[k]);
22753 }
22754 xfree(mp->internal); 
22755 xfree(mp->int_name); 
22756
22757
22758 @ The various `\&{show}' commands are distinguished by modifier fields
22759 in the usual way.
22760
22761 @d show_token_code 0 /* show the meaning of a single token */
22762 @d show_stats_code 1 /* show current memory and string usage */
22763 @d show_code 2 /* show a list of expressions */
22764 @d show_var_code 3 /* show a variable and its descendents */
22765 @d show_dependencies_code 4 /* show dependent variables in terms of independents */
22766
22767 @<Put each...@>=
22768 mp_primitive(mp, "showtoken",show_command,show_token_code);
22769 @:show_token_}{\&{showtoken} primitive@>
22770 mp_primitive(mp, "showstats",show_command,show_stats_code);
22771 @:show_stats_}{\&{showstats} primitive@>
22772 mp_primitive(mp, "show",show_command,show_code);
22773 @:show_}{\&{show} primitive@>
22774 mp_primitive(mp, "showvariable",show_command,show_var_code);
22775 @:show_var_}{\&{showvariable} primitive@>
22776 mp_primitive(mp, "showdependencies",show_command,show_dependencies_code);
22777 @:show_dependencies_}{\&{showdependencies} primitive@>
22778
22779 @ @<Cases of |print_cmd...@>=
22780 case show_command: 
22781   switch (m) {
22782   case show_token_code:mp_print(mp, "showtoken"); break;
22783   case show_stats_code:mp_print(mp, "showstats"); break;
22784   case show_code:mp_print(mp, "show"); break;
22785   case show_var_code:mp_print(mp, "showvariable"); break;
22786   default: mp_print(mp, "showdependencies"); break;
22787   }
22788   break;
22789
22790 @ @<Cases of |do_statement|...@>=
22791 case show_command:mp_do_show_whatever(mp); break;
22792
22793 @ The value of |cur_mod| controls the |verbosity| in the |print_exp| routine:
22794 if it's |show_code|, complicated structures are abbreviated, otherwise
22795 they aren't.
22796
22797 @<Declare action procedures for use by |do_statement|@>=
22798 static void mp_do_show (MP mp) ;
22799
22800 @ @c void mp_do_show (MP mp) { 
22801   do {  
22802     mp_get_x_next(mp); mp_scan_expression(mp);
22803     mp_print_nl(mp, ">> ");
22804 @.>>@>
22805     mp_print_exp(mp, null,2); mp_flush_cur_exp(mp, 0);
22806   } while (mp->cur_cmd==comma);
22807 }
22808
22809 @ @<Declare action procedures for use by |do_statement|@>=
22810 static void mp_disp_token (MP mp) ;
22811
22812 @ @c void mp_disp_token (MP mp) { 
22813   mp_print_nl(mp, "> ");
22814 @.>\relax@>
22815   if ( mp->cur_sym==0 ) {
22816     @<Show a numeric or string or capsule token@>;
22817   } else { 
22818     mp_print_text(mp->cur_sym); mp_print_char(mp, xord('='));
22819     if ( eq_type(mp->cur_sym)>=outer_tag ) mp_print(mp, "(outer) ");
22820     mp_print_cmd_mod(mp, mp->cur_cmd,mp->cur_mod);
22821     if ( mp->cur_cmd==defined_macro ) {
22822       mp_print_ln(mp); mp_show_macro(mp, mp->cur_mod,null,100000);
22823     } /* this avoids recursion between |show_macro| and |print_cmd_mod| */
22824 @^recursion@>
22825   }
22826 }
22827
22828 @ @<Show a numeric or string or capsule token@>=
22829
22830   if ( mp->cur_cmd==numeric_token ) {
22831     mp_print_scaled(mp, mp->cur_mod);
22832   } else if ( mp->cur_cmd==capsule_token ) {
22833     mp_print_capsule(mp,mp->cur_mod);
22834   } else  { 
22835     mp_print_char(mp, xord('"')); 
22836     mp_print_str(mp, mp->cur_mod); mp_print_char(mp, xord('"'));
22837     delete_str_ref(mp->cur_mod);
22838   }
22839 }
22840
22841 @ The following cases of |print_cmd_mod| might arise in connection
22842 with |disp_token|, although they don't necessarily correspond to
22843 primitive tokens.
22844
22845 @<Cases of |print_cmd_...@>=
22846 case left_delimiter:
22847 case right_delimiter: 
22848   if ( c==left_delimiter ) mp_print(mp, "left");
22849   else mp_print(mp, "right");
22850   mp_print(mp, " delimiter that matches "); 
22851   mp_print_text(m);
22852   break;
22853 case tag_token:
22854   if ( m==null ) mp_print(mp, "tag");
22855    else mp_print(mp, "variable");
22856    break;
22857 case defined_macro: 
22858    mp_print(mp, "macro:");
22859    break;
22860 case secondary_primary_macro:
22861 case tertiary_secondary_macro:
22862 case expression_tertiary_macro:
22863   mp_print_cmd_mod(mp, macro_def,c); 
22864   mp_print(mp, "'d macro:");
22865   mp_print_ln(mp); mp_show_token_list(mp, mp_link(mp_link(m)),null,1000,0);
22866   break;
22867 case repeat_loop:
22868   mp_print(mp, "[repeat the loop]");
22869   break;
22870 case internal_quantity:
22871   mp_print(mp, mp->int_name[m]);
22872   break;
22873
22874 @ @<Declare action procedures for use by |do_statement|@>=
22875 static void mp_do_show_token (MP mp) ;
22876
22877 @ @c void mp_do_show_token (MP mp) { 
22878   do {  
22879     get_t_next; mp_disp_token(mp);
22880     mp_get_x_next(mp);
22881   } while (mp->cur_cmd==comma);
22882 }
22883
22884 @ @<Declare action procedures for use by |do_statement|@>=
22885 static void mp_do_show_stats (MP mp) ;
22886
22887 @ @c void mp_do_show_stats (MP mp) { 
22888   mp_print_nl(mp, "Memory usage ");
22889 @.Memory usage...@>
22890   mp_print_int(mp, mp->var_used); mp_print_char(mp, xord('&')); mp_print_int(mp, mp->dyn_used);
22891   mp_print(mp, " ("); mp_print_int(mp, mp->hi_mem_min-mp->lo_mem_max-1);
22892   mp_print(mp, " still untouched)"); mp_print_ln(mp);
22893   mp_print_nl(mp, "String usage ");
22894   mp_print_int(mp, mp->strs_in_use-mp->init_str_use);
22895   mp_print_char(mp, xord('&')); mp_print_int(mp, mp->pool_in_use-mp->init_pool_ptr);
22896   mp_print(mp, " (");
22897   mp_print_int(mp, mp->max_strings-1-mp->strs_used_up); mp_print_char(mp, xord('&'));
22898   mp_print_int(mp, mp->pool_size-mp->pool_ptr); 
22899   mp_print(mp, " now untouched)"); mp_print_ln(mp);
22900   mp_get_x_next(mp);
22901 }
22902
22903 @ Here's a recursive procedure that gives an abbreviated account
22904 of a variable, for use by |do_show_var|.
22905
22906 @<Declare action procedures for use by |do_statement|@>=
22907 static void mp_disp_var (MP mp,pointer p) ;
22908
22909 @ @c void mp_disp_var (MP mp,pointer p) {
22910   pointer q; /* traverses attributes and subscripts */
22911   int n; /* amount of macro text to show */
22912   if ( type(p)==mp_structured )  {
22913     @<Descend the structure@>;
22914   } else if ( type(p)>=mp_unsuffixed_macro ) {
22915     @<Display a variable macro@>;
22916   } else if ( type(p)!=undefined ){ 
22917     mp_print_nl(mp, ""); mp_print_variable_name(mp, p); 
22918     mp_print_char(mp, xord('='));
22919     mp_print_exp(mp, p,0);
22920   }
22921 }
22922
22923 @ @<Descend the structure@>=
22924
22925   q=attr_head(p);
22926   do {  mp_disp_var(mp, q); q=mp_link(q); } while (q!=end_attr);
22927   q=subscr_head(p);
22928   while ( name_type(q)==mp_subscr ) { 
22929     mp_disp_var(mp, q); q=mp_link(q);
22930   }
22931 }
22932
22933 @ @<Display a variable macro@>=
22934
22935   mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22936   if ( type(p)>mp_unsuffixed_macro ) 
22937     mp_print(mp, "@@#"); /* |suffixed_macro| */
22938   mp_print(mp, "=macro:");
22939   if ( (int)mp->file_offset>=mp->max_print_line-20 ) n=5;
22940   else n=mp->max_print_line-mp->file_offset-15;
22941   mp_show_macro(mp, value(p),null,n);
22942 }
22943
22944 @ @<Declare action procedures for use by |do_statement|@>=
22945 static void mp_do_show_var (MP mp) ;
22946
22947 @ @c void mp_do_show_var (MP mp) { 
22948   do {  
22949     get_t_next;
22950     if ( mp->cur_sym>0 ) if ( mp->cur_sym<=hash_end )
22951       if ( mp->cur_cmd==tag_token ) if ( mp->cur_mod!=null ) {
22952       mp_disp_var(mp, mp->cur_mod); goto DONE;
22953     }
22954    mp_disp_token(mp);
22955   DONE:
22956    mp_get_x_next(mp);
22957   } while (mp->cur_cmd==comma);
22958 }
22959
22960 @ @<Declare action procedures for use by |do_statement|@>=
22961 static void mp_do_show_dependencies (MP mp) ;
22962
22963 @ @c void mp_do_show_dependencies (MP mp) {
22964   pointer p; /* link that runs through all dependencies */
22965   p=mp_link(dep_head);
22966   while ( p!=dep_head ) {
22967     if ( mp_interesting(mp, p) ) {
22968       mp_print_nl(mp, ""); mp_print_variable_name(mp, p);
22969       if ( type(p)==mp_dependent ) mp_print_char(mp, xord('='));
22970       else mp_print(mp, " = "); /* extra spaces imply proto-dependency */
22971       mp_print_dependency(mp, dep_list(p),type(p));
22972     }
22973     p=dep_list(p);
22974     while ( info(p)!=null ) p=mp_link(p);
22975     p=mp_link(p);
22976   }
22977   mp_get_x_next(mp);
22978 }
22979
22980 @ Finally we are ready for the procedure that governs all of the
22981 show commands.
22982
22983 @<Declare action procedures for use by |do_statement|@>=
22984 static void mp_do_show_whatever (MP mp) ;
22985
22986 @ @c void mp_do_show_whatever (MP mp) { 
22987   if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
22988   switch (mp->cur_mod) {
22989   case show_token_code:mp_do_show_token(mp); break;
22990   case show_stats_code:mp_do_show_stats(mp); break;
22991   case show_code:mp_do_show(mp); break;
22992   case show_var_code:mp_do_show_var(mp); break;
22993   case show_dependencies_code:mp_do_show_dependencies(mp); break;
22994   } /* there are no other cases */
22995   if ( mp->internal[mp_showstopping]>0 ){ 
22996     print_err("OK");
22997 @.OK@>
22998     if ( mp->interaction<mp_error_stop_mode ) { 
22999       help0; decr(mp->error_count);
23000     } else {
23001       help1("This isn't an error message; I'm just showing something.");
23002     }
23003     if ( mp->cur_cmd==semicolon ) mp_error(mp);
23004      else mp_put_get_error(mp);
23005   }
23006 }
23007
23008 @ The `\&{addto}' command needs the following additional primitives:
23009
23010 @d double_path_code 0 /* command modifier for `\&{doublepath}' */
23011 @d contour_code 1 /* command modifier for `\&{contour}' */
23012 @d also_code 2 /* command modifier for `\&{also}' */
23013
23014 @ Pre and postscripts need two new identifiers:
23015
23016 @d with_pre_script 11
23017 @d with_post_script 13
23018
23019 @<Put each...@>=
23020 mp_primitive(mp, "doublepath",thing_to_add,double_path_code);
23021 @:double_path_}{\&{doublepath} primitive@>
23022 mp_primitive(mp, "contour",thing_to_add,contour_code);
23023 @:contour_}{\&{contour} primitive@>
23024 mp_primitive(mp, "also",thing_to_add,also_code);
23025 @:also_}{\&{also} primitive@>
23026 mp_primitive(mp, "withpen",with_option,mp_pen_type);
23027 @:with_pen_}{\&{withpen} primitive@>
23028 mp_primitive(mp, "dashed",with_option,mp_picture_type);
23029 @:dashed_}{\&{dashed} primitive@>
23030 mp_primitive(mp, "withprescript",with_option,with_pre_script);
23031 @:with_pre_script_}{\&{withprescript} primitive@>
23032 mp_primitive(mp, "withpostscript",with_option,with_post_script);
23033 @:with_post_script_}{\&{withpostscript} primitive@>
23034 mp_primitive(mp, "withoutcolor",with_option,mp_no_model);
23035 @:with_color_}{\&{withoutcolor} primitive@>
23036 mp_primitive(mp, "withgreyscale",with_option,mp_grey_model);
23037 @:with_color_}{\&{withgreyscale} primitive@>
23038 mp_primitive(mp, "withcolor",with_option,mp_uninitialized_model);
23039 @:with_color_}{\&{withcolor} primitive@>
23040 /*  \&{withrgbcolor} is an alias for \&{withcolor} */
23041 mp_primitive(mp, "withrgbcolor",with_option,mp_rgb_model);
23042 @:with_color_}{\&{withrgbcolor} primitive@>
23043 mp_primitive(mp, "withcmykcolor",with_option,mp_cmyk_model);
23044 @:with_color_}{\&{withcmykcolor} primitive@>
23045
23046 @ @<Cases of |print_cmd...@>=
23047 case thing_to_add:
23048   if ( m==contour_code ) mp_print(mp, "contour");
23049   else if ( m==double_path_code ) mp_print(mp, "doublepath");
23050   else mp_print(mp, "also");
23051   break;
23052 case with_option:
23053   if ( m==mp_pen_type ) mp_print(mp, "withpen");
23054   else if ( m==with_pre_script ) mp_print(mp, "withprescript");
23055   else if ( m==with_post_script ) mp_print(mp, "withpostscript");
23056   else if ( m==mp_no_model ) mp_print(mp, "withoutcolor");
23057   else if ( m==mp_rgb_model ) mp_print(mp, "withrgbcolor");
23058   else if ( m==mp_uninitialized_model ) mp_print(mp, "withcolor");
23059   else if ( m==mp_cmyk_model ) mp_print(mp, "withcmykcolor");
23060   else if ( m==mp_grey_model ) mp_print(mp, "withgreyscale");
23061   else mp_print(mp, "dashed");
23062   break;
23063
23064 @ The |scan_with_list| procedure parses a $\langle$with list$\rangle$ and
23065 updates the list of graphical objects starting at |p|.  Each $\langle$with
23066 clause$\rangle$ updates all graphical objects whose |type| is compatible.
23067 Other objects are ignored.
23068
23069 @<Declare action procedures for use by |do_statement|@>=
23070 static void mp_scan_with_list (MP mp,pointer p) ;
23071
23072 @ @c void mp_scan_with_list (MP mp,pointer p) {
23073   quarterword t; /* |cur_mod| of the |with_option| (should match |cur_type|) */
23074   pointer q; /* for list manipulation */
23075   unsigned old_setting; /* saved |selector| setting */
23076   pointer k; /* for finding the near-last item in a list  */
23077   str_number s; /* for string cleanup after combining  */
23078   pointer cp,pp,dp,ap,bp;
23079     /* objects being updated; |void| initially; |null| to suppress update */
23080   cp=mp_void; pp=mp_void; dp=mp_void; ap=mp_void; bp=mp_void;
23081   k=0;
23082   while ( mp->cur_cmd==with_option ){ 
23083     t=mp->cur_mod;
23084     mp_get_x_next(mp);
23085     if ( t!=mp_no_model ) mp_scan_expression(mp);
23086     if (((t==with_pre_script)&&(mp->cur_type!=mp_string_type))||
23087      ((t==with_post_script)&&(mp->cur_type!=mp_string_type))||
23088      ((t==mp_uninitialized_model)&&
23089         ((mp->cur_type!=mp_cmykcolor_type)&&(mp->cur_type!=mp_color_type)
23090           &&(mp->cur_type!=mp_known)&&(mp->cur_type!=mp_boolean_type)))||
23091      ((t==mp_cmyk_model)&&(mp->cur_type!=mp_cmykcolor_type))||
23092      ((t==mp_rgb_model)&&(mp->cur_type!=mp_color_type))||
23093      ((t==mp_grey_model)&&(mp->cur_type!=mp_known))||
23094      ((t==mp_pen_type)&&(mp->cur_type!=t))||
23095      ((t==mp_picture_type)&&(mp->cur_type!=t)) ) {
23096       @<Complain about improper type@>;
23097     } else if ( t==mp_uninitialized_model ) {
23098       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
23099       if ( cp!=null )
23100         @<Transfer a color from the current expression to object~|cp|@>;
23101       mp_flush_cur_exp(mp, 0);
23102     } else if ( t==mp_rgb_model ) {
23103       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
23104       if ( cp!=null )
23105         @<Transfer a rgbcolor from the current expression to object~|cp|@>;
23106       mp_flush_cur_exp(mp, 0);
23107     } else if ( t==mp_cmyk_model ) {
23108       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
23109       if ( cp!=null )
23110         @<Transfer a cmykcolor from the current expression to object~|cp|@>;
23111       mp_flush_cur_exp(mp, 0);
23112     } else if ( t==mp_grey_model ) {
23113       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
23114       if ( cp!=null )
23115         @<Transfer a greyscale from the current expression to object~|cp|@>;
23116       mp_flush_cur_exp(mp, 0);
23117     } else if ( t==mp_no_model ) {
23118       if ( cp==mp_void ) @<Make |cp| a colored object in object list~|p|@>;
23119       if ( cp!=null )
23120         @<Transfer a noncolor from the current expression to object~|cp|@>;
23121     } else if ( t==mp_pen_type ) {
23122       if ( pp==mp_void ) @<Make |pp| an object in list~|p| that needs a pen@>;
23123       if ( pp!=null ) {
23124         if ( pen_p(pp)!=null ) mp_toss_knot_list(mp, pen_p(pp));
23125         pen_p(pp)=mp->cur_exp; mp->cur_type=mp_vacuous;
23126       }
23127     } else if ( t==with_pre_script ) {
23128       if ( ap==mp_void )
23129         ap=p;
23130       while ( (ap!=null)&&(! has_color(ap)) )
23131          ap=mp_link(ap);
23132       if ( ap!=null ) {
23133         if ( pre_script(ap)!=null ) { /*  build a new,combined string  */
23134           s=pre_script(ap);
23135           old_setting=mp->selector;
23136               mp->selector=new_string;
23137           str_room(length(pre_script(ap))+length(mp->cur_exp)+2);
23138               mp_print_str(mp, mp->cur_exp);
23139           append_char(13);  /* a forced \ps\ newline  */
23140           mp_print_str(mp, pre_script(ap));
23141           pre_script(ap)=mp_make_string(mp);
23142           delete_str_ref(s);
23143           mp->selector=old_setting;
23144         } else {
23145           pre_script(ap)=mp->cur_exp;
23146         }
23147         mp->cur_type=mp_vacuous;
23148       }
23149     } else if ( t==with_post_script ) {
23150       if ( bp==mp_void )
23151         k=p; 
23152       bp=k;
23153       while ( mp_link(k)!=null ) {
23154         k=mp_link(k);
23155         if ( has_color(k) ) bp=k;
23156       }
23157       if ( bp!=null ) {
23158          if ( post_script(bp)!=null ) {
23159            s=post_script(bp);
23160            old_setting=mp->selector;
23161                mp->selector=new_string;
23162            str_room(length(post_script(bp))+length(mp->cur_exp)+2);
23163            mp_print_str(mp, post_script(bp));
23164            append_char(13); /* a forced \ps\ newline  */
23165            mp_print_str(mp, mp->cur_exp);
23166            post_script(bp)=mp_make_string(mp);
23167            delete_str_ref(s);
23168            mp->selector=old_setting;
23169          } else {
23170            post_script(bp)=mp->cur_exp;
23171          }
23172          mp->cur_type=mp_vacuous;
23173        }
23174     } else { 
23175       if ( dp==mp_void ) {
23176         @<Make |dp| a stroked node in list~|p|@>;
23177       }
23178       if ( dp!=null ) {
23179         if ( dash_p(dp)!=null ) delete_edge_ref(dash_p(dp));
23180         dash_p(dp)=mp_make_dashes(mp, mp->cur_exp);
23181         dash_scale(dp)=unity;
23182         mp->cur_type=mp_vacuous;
23183       }
23184     }
23185   }
23186   @<Copy the information from objects |cp|, |pp|, and |dp| into the rest
23187     of the list@>;
23188 }
23189
23190 @ @<Complain about improper type@>=
23191 { exp_err("Improper type");
23192 @.Improper type@>
23193 help2("Next time say `withpen <known pen expression>';",
23194       "I'll ignore the bad `with' clause and look for another.");
23195 if ( t==with_pre_script )
23196   mp->help_line[1]="Next time say `withprescript <known string expression>';";
23197 else if ( t==with_post_script )
23198   mp->help_line[1]="Next time say `withpostscript <known string expression>';";
23199 else if ( t==mp_picture_type )
23200   mp->help_line[1]="Next time say `dashed <known picture expression>';";
23201 else if ( t==mp_uninitialized_model )
23202   mp->help_line[1]="Next time say `withcolor <known color expression>';";
23203 else if ( t==mp_rgb_model )
23204   mp->help_line[1]="Next time say `withrgbcolor <known color expression>';";
23205 else if ( t==mp_cmyk_model )
23206   mp->help_line[1]="Next time say `withcmykcolor <known cmykcolor expression>';";
23207 else if ( t==mp_grey_model )
23208   mp->help_line[1]="Next time say `withgreyscale <known numeric expression>';";;
23209 mp_put_get_flush_error(mp, 0);
23210 }
23211
23212 @ Forcing the color to be between |0| and |unity| here guarantees that no
23213 picture will ever contain a color outside the legal range for \ps\ graphics.
23214
23215 @<Transfer a color from the current expression to object~|cp|@>=
23216 { if ( mp->cur_type==mp_color_type )
23217    @<Transfer a rgbcolor from the current expression to object~|cp|@>
23218 else if ( mp->cur_type==mp_cmykcolor_type )
23219    @<Transfer a cmykcolor from the current expression to object~|cp|@>
23220 else if ( mp->cur_type==mp_known )
23221    @<Transfer a greyscale from the current expression to object~|cp|@>
23222 else if ( mp->cur_exp==false_code )
23223    @<Transfer a noncolor from the current expression to object~|cp|@>;
23224 }
23225
23226 @ @<Transfer a rgbcolor from the current expression to object~|cp|@>=
23227 { q=value(mp->cur_exp);
23228 cyan_val(cp)=0;
23229 magenta_val(cp)=0;
23230 yellow_val(cp)=0;
23231 black_val(cp)=0;
23232 red_val(cp)=value(red_part_loc(q));
23233 green_val(cp)=value(green_part_loc(q));
23234 blue_val(cp)=value(blue_part_loc(q));
23235 color_model(cp)=mp_rgb_model;
23236 if ( red_val(cp)<0 ) red_val(cp)=0;
23237 if ( green_val(cp)<0 ) green_val(cp)=0;
23238 if ( blue_val(cp)<0 ) blue_val(cp)=0;
23239 if ( red_val(cp)>unity ) red_val(cp)=unity;
23240 if ( green_val(cp)>unity ) green_val(cp)=unity;
23241 if ( blue_val(cp)>unity ) blue_val(cp)=unity;
23242 }
23243
23244 @ @<Transfer a cmykcolor from the current expression to object~|cp|@>=
23245 { q=value(mp->cur_exp);
23246 cyan_val(cp)=value(cyan_part_loc(q));
23247 magenta_val(cp)=value(magenta_part_loc(q));
23248 yellow_val(cp)=value(yellow_part_loc(q));
23249 black_val(cp)=value(black_part_loc(q));
23250 color_model(cp)=mp_cmyk_model;
23251 if ( cyan_val(cp)<0 ) cyan_val(cp)=0;
23252 if ( magenta_val(cp)<0 ) magenta_val(cp)=0;
23253 if ( yellow_val(cp)<0 ) yellow_val(cp)=0;
23254 if ( black_val(cp)<0 ) black_val(cp)=0;
23255 if ( cyan_val(cp)>unity ) cyan_val(cp)=unity;
23256 if ( magenta_val(cp)>unity ) magenta_val(cp)=unity;
23257 if ( yellow_val(cp)>unity ) yellow_val(cp)=unity;
23258 if ( black_val(cp)>unity ) black_val(cp)=unity;
23259 }
23260
23261 @ @<Transfer a greyscale from the current expression to object~|cp|@>=
23262 { q=mp->cur_exp;
23263 cyan_val(cp)=0;
23264 magenta_val(cp)=0;
23265 yellow_val(cp)=0;
23266 black_val(cp)=0;
23267 grey_val(cp)=q;
23268 color_model(cp)=mp_grey_model;
23269 if ( grey_val(cp)<0 ) grey_val(cp)=0;
23270 if ( grey_val(cp)>unity ) grey_val(cp)=unity;
23271 }
23272
23273 @ @<Transfer a noncolor from the current expression to object~|cp|@>=
23274 {
23275 cyan_val(cp)=0;
23276 magenta_val(cp)=0;
23277 yellow_val(cp)=0;
23278 black_val(cp)=0;
23279 grey_val(cp)=0;
23280 color_model(cp)=mp_no_model;
23281 }
23282
23283 @ @<Make |cp| a colored object in object list~|p|@>=
23284 { cp=p;
23285   while ( cp!=null ){ 
23286     if ( has_color(cp) ) break;
23287     cp=mp_link(cp);
23288   }
23289 }
23290
23291 @ @<Make |pp| an object in list~|p| that needs a pen@>=
23292 { pp=p;
23293   while ( pp!=null ) {
23294     if ( has_pen(pp) ) break;
23295     pp=mp_link(pp);
23296   }
23297 }
23298
23299 @ @<Make |dp| a stroked node in list~|p|@>=
23300 { dp=p;
23301   while ( dp!=null ) {
23302     if ( type(dp)==mp_stroked_code ) break;
23303     dp=mp_link(dp);
23304   }
23305 }
23306
23307 @ @<Copy the information from objects |cp|, |pp|, and |dp| into...@>=
23308 @<Copy |cp|'s color into the colored objects linked to~|cp|@>;
23309 if ( pp>mp_void ) {
23310   @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>;
23311 }
23312 if ( dp>mp_void ) {
23313   @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>;
23314 }
23315
23316
23317 @ @<Copy |cp|'s color into the colored objects linked to~|cp|@>=
23318 { q=mp_link(cp);
23319   while ( q!=null ) { 
23320     if ( has_color(q) ) {
23321       red_val(q)=red_val(cp);
23322       green_val(q)=green_val(cp);
23323       blue_val(q)=blue_val(cp);
23324       black_val(q)=black_val(cp);
23325       color_model(q)=color_model(cp);
23326     }
23327     q=mp_link(q);
23328   }
23329 }
23330
23331 @ @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>=
23332 { q=mp_link(pp);
23333   while ( q!=null ) {
23334     if ( has_pen(q) ) {
23335       if ( pen_p(q)!=null ) mp_toss_knot_list(mp, pen_p(q));
23336       pen_p(q)=copy_pen(pen_p(pp));
23337     }
23338     q=mp_link(q);
23339   }
23340 }
23341
23342 @ @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@>=
23343 { q=mp_link(dp);
23344   while ( q!=null ) {
23345     if ( type(q)==mp_stroked_code ) {
23346       if ( dash_p(q)!=null ) delete_edge_ref(dash_p(q));
23347       dash_p(q)=dash_p(dp);
23348       dash_scale(q)=unity;
23349       if ( dash_p(q)!=null ) add_edge_ref(dash_p(q));
23350     }
23351     q=mp_link(q);
23352   }
23353 }
23354
23355 @ One of the things we need to do when we've parsed an \&{addto} or
23356 similar command is find the header of a supposed \&{picture} variable, given
23357 a token list for that variable.  Since the edge structure is about to be
23358 updated, we use |private_edges| to make sure that this is possible.
23359
23360 @<Declare action procedures for use by |do_statement|@>=
23361 static pointer mp_find_edges_var (MP mp, pointer t) ;
23362
23363 @ @c pointer mp_find_edges_var (MP mp, pointer t) {
23364   pointer p;
23365   pointer cur_edges; /* the return value */
23366   p=mp_find_variable(mp, t); cur_edges=null;
23367   if ( p==null ) { 
23368     mp_obliterated(mp, t); mp_put_get_error(mp);
23369   } else if ( type(p)!=mp_picture_type )  { 
23370     print_err("Variable "); mp_show_token_list(mp, t,null,1000,0);
23371 @.Variable x is the wrong type@>
23372     mp_print(mp, " is the wrong type ("); 
23373     mp_print_type(mp, type(p)); mp_print_char(mp, xord(')'));
23374     help2("I was looking for a \"known\" picture variable.",
23375           "So I'll not change anything just now."); 
23376     mp_put_get_error(mp);
23377   } else { 
23378     value(p)=mp_private_edges(mp, value(p));
23379     cur_edges=value(p);
23380   }
23381   mp_flush_node_list(mp, t);
23382   return cur_edges;
23383 }
23384
23385 @ @<Cases of |do_statement|...@>=
23386 case add_to_command: mp_do_add_to(mp); break;
23387 case bounds_command:mp_do_bounds(mp); break;
23388
23389 @ @<Put each...@>=
23390 mp_primitive(mp, "clip",bounds_command,mp_start_clip_code);
23391 @:clip_}{\&{clip} primitive@>
23392 mp_primitive(mp, "setbounds",bounds_command,mp_start_bounds_code);
23393 @:set_bounds_}{\&{setbounds} primitive@>
23394
23395 @ @<Cases of |print_cmd...@>=
23396 case bounds_command: 
23397   if ( m==mp_start_clip_code ) mp_print(mp, "clip");
23398   else mp_print(mp, "setbounds");
23399   break;
23400
23401 @ The following function parses the beginning of an \&{addto} or \&{clip}
23402 command: it expects a variable name followed by a token with |cur_cmd=sep|
23403 and then an expression.  The function returns the token list for the variable
23404 and stores the command modifier for the separator token in the global variable
23405 |last_add_type|.  We must be careful because this variable might get overwritten
23406 any time we call |get_x_next|.
23407
23408 @<Glob...@>=
23409 quarterword last_add_type;
23410   /* command modifier that identifies the last \&{addto} command */
23411
23412 @ @<Declare action procedures for use by |do_statement|@>=
23413 static pointer mp_start_draw_cmd (MP mp,quarterword sep) ;
23414
23415 @ @c pointer mp_start_draw_cmd (MP mp,quarterword sep) {
23416   pointer lhv; /* variable to add to left */
23417   quarterword add_type=0; /* value to be returned in |last_add_type| */
23418   lhv=null;
23419   mp_get_x_next(mp); mp->var_flag=sep; mp_scan_primary(mp);
23420   if ( mp->cur_type!=mp_token_list ) {
23421     @<Abandon edges command because there's no variable@>;
23422   } else  { 
23423     lhv=mp->cur_exp; add_type=mp->cur_mod;
23424     mp->cur_type=mp_vacuous; mp_get_x_next(mp); mp_scan_expression(mp);
23425   }
23426   mp->last_add_type=add_type;
23427   return lhv;
23428 }
23429
23430 @ @<Abandon edges command because there's no variable@>=
23431 { exp_err("Not a suitable variable");
23432 @.Not a suitable variable@>
23433   help4("At this point I needed to see the name of a picture variable.",
23434     "(Or perhaps you have indeed presented me with one; I might",
23435     "have missed it, if it wasn't followed by the proper token.)",
23436     "So I'll not change anything just now.");
23437   mp_put_get_flush_error(mp, 0);
23438 }
23439
23440 @ Here is an example of how to use |start_draw_cmd|.
23441
23442 @<Declare action procedures for use by |do_statement|@>=
23443 static void mp_do_bounds (MP mp) ;
23444
23445 @ @c void mp_do_bounds (MP mp) {
23446   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
23447   pointer p; /* for list manipulation */
23448   integer m; /* initial value of |cur_mod| */
23449   m=mp->cur_mod;
23450   lhv=mp_start_draw_cmd(mp, to_token);
23451   if ( lhv!=null ) {
23452     lhe=mp_find_edges_var(mp, lhv);
23453     if ( lhe==null ) {
23454       mp_flush_cur_exp(mp, 0);
23455     } else if ( mp->cur_type!=mp_path_type ) {
23456       exp_err("Improper `clip'");
23457 @.Improper `addto'@>
23458       help2("This expression should have specified a known path.",
23459             "So I'll not change anything just now."); 
23460       mp_put_get_flush_error(mp, 0);
23461     } else if ( left_type(mp->cur_exp)==mp_endpoint ) {
23462       @<Complain about a non-cycle@>;
23463     } else {
23464       @<Make |cur_exp| into a \&{setbounds} or clipping path and add it to |lhe|@>;
23465     }
23466   }
23467 }
23468
23469 @ @<Complain about a non-cycle@>=
23470 { print_err("Not a cycle");
23471 @.Not a cycle@>
23472   help2("That contour should have ended with `..cycle' or `&cycle'.",
23473         "So I'll not change anything just now."); mp_put_get_error(mp);
23474 }
23475
23476 @ @<Make |cur_exp| into a \&{setbounds} or clipping path and add...@>=
23477 { p=mp_new_bounds_node(mp, mp->cur_exp,m);
23478   mp_link(p)=mp_link(dummy_loc(lhe));
23479   mp_link(dummy_loc(lhe))=p;
23480   if ( obj_tail(lhe)==dummy_loc(lhe) ) obj_tail(lhe)=p;
23481   p=mp_get_node(mp, mp->gr_object_size[stop_type(m)]);
23482   type(p)=stop_type(m);
23483   mp_link(obj_tail(lhe))=p;
23484   obj_tail(lhe)=p;
23485   mp_init_bbox(mp, lhe);
23486 }
23487
23488 @ The |do_add_to| procedure is a little like |do_clip| but there are a lot more
23489 cases to deal with.
23490
23491 @<Declare action procedures for use by |do_statement|@>=
23492 static void mp_do_add_to (MP mp) ;
23493
23494 @ @c void mp_do_add_to (MP mp) {
23495   pointer lhv,lhe; /* variable on left, the corresponding edge structure */
23496   pointer p; /* the graphical object or list for |scan_with_list| to update */
23497   pointer e; /* an edge structure to be merged */
23498   quarterword add_type; /* |also_code|, |contour_code|, or |double_path_code| */
23499   lhv=mp_start_draw_cmd(mp, thing_to_add); add_type=mp->last_add_type;
23500   if ( lhv!=null ) {
23501     if ( add_type==also_code ) {
23502       @<Make sure the current expression is a suitable picture and set |e| and |p|
23503        appropriately@>;
23504     } else {
23505       @<Create a graphical object |p| based on |add_type| and the current
23506         expression@>;
23507     }
23508     mp_scan_with_list(mp, p);
23509     @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>;
23510   }
23511 }
23512
23513 @ Setting |p:=null| causes the $\langle$with list$\rangle$ to be ignored;
23514 setting |e:=null| prevents anything from being added to |lhe|.
23515
23516 @ @<Make sure the current expression is a suitable picture and set |e|...@>=
23517
23518   p=null; e=null;
23519   if ( mp->cur_type!=mp_picture_type ) {
23520     exp_err("Improper `addto'");
23521 @.Improper `addto'@>
23522     help2("This expression should have specified a known picture.",
23523           "So I'll not change anything just now."); 
23524     mp_put_get_flush_error(mp, 0);
23525   } else { 
23526     e=mp_private_edges(mp, mp->cur_exp); mp->cur_type=mp_vacuous;
23527     p=mp_link(dummy_loc(e));
23528   }
23529 }
23530
23531 @ In this case |add_type<>also_code| so setting |p:=null| suppresses future
23532 attempts to add to the edge structure.
23533
23534 @<Create a graphical object |p| based on |add_type| and the current...@>=
23535 { e=null; p=null;
23536   if ( mp->cur_type==mp_pair_type ) mp_pair_to_path(mp);
23537   if ( mp->cur_type!=mp_path_type ) {
23538     exp_err("Improper `addto'");
23539 @.Improper `addto'@>
23540     help2("This expression should have specified a known path.",
23541           "So I'll not change anything just now."); 
23542     mp_put_get_flush_error(mp, 0);
23543   } else if ( add_type==contour_code ) {
23544     if ( left_type(mp->cur_exp)==mp_endpoint ) {
23545       @<Complain about a non-cycle@>;
23546     } else { 
23547       p=mp_new_fill_node(mp, mp->cur_exp);
23548       mp->cur_type=mp_vacuous;
23549     }
23550   } else { 
23551     p=mp_new_stroked_node(mp, mp->cur_exp);
23552     mp->cur_type=mp_vacuous;
23553   }
23554 }
23555
23556 @ @<Use |p|, |e|, and |add_type| to augment |lhv| as requested@>=
23557 lhe=mp_find_edges_var(mp, lhv);
23558 if ( lhe==null ) {
23559   if ( (e==null)&&(p!=null) ) e=mp_toss_gr_object(mp, p);
23560   if ( e!=null ) delete_edge_ref(e);
23561 } else if ( add_type==also_code ) {
23562   if ( e!=null ) {
23563     @<Merge |e| into |lhe| and delete |e|@>;
23564   } else { 
23565     do_nothing;
23566   }
23567 } else if ( p!=null ) {
23568   mp_link(obj_tail(lhe))=p;
23569   obj_tail(lhe)=p;
23570   if ( add_type==double_path_code )
23571     if ( pen_p(p)==null ) 
23572       pen_p(p)=mp_get_pen_circle(mp, 0);
23573 }
23574
23575 @ @<Merge |e| into |lhe| and delete |e|@>=
23576 { if ( mp_link(dummy_loc(e))!=null ) {
23577     mp_link(obj_tail(lhe))=mp_link(dummy_loc(e));
23578     obj_tail(lhe)=obj_tail(e);
23579     obj_tail(e)=dummy_loc(e);
23580     mp_link(dummy_loc(e))=null;
23581     mp_flush_dash_list(mp, lhe);
23582   }
23583   mp_toss_edges(mp, e);
23584 }
23585
23586 @ @<Cases of |do_statement|...@>=
23587 case ship_out_command: mp_do_ship_out(mp); break;
23588
23589 @ @<Declare action procedures for use by |do_statement|@>=
23590 @<Declare the \ps\ output procedures@>
23591 static void mp_do_ship_out (MP mp) ;
23592
23593 @ @c void mp_do_ship_out (MP mp) {
23594   integer c; /* the character code */
23595   mp_get_x_next(mp); mp_scan_expression(mp);
23596   if ( mp->cur_type!=mp_picture_type ) {
23597     @<Complain that it's not a known picture@>;
23598   } else { 
23599     c=mp_round_unscaled(mp, mp->internal[mp_char_code]) % 256;
23600     if ( c<0 ) c=c+256;
23601     @<Store the width information for character code~|c|@>;
23602     mp_ship_out(mp, mp->cur_exp);
23603     mp_flush_cur_exp(mp, 0);
23604   }
23605 }
23606
23607 @ @<Complain that it's not a known picture@>=
23608
23609   exp_err("Not a known picture");
23610   help1("I can only output known pictures.");
23611   mp_put_get_flush_error(mp, 0);
23612 }
23613
23614 @ The \&{everyjob} command simply assigns a nonzero value to the global variable
23615 |start_sym|.
23616
23617 @<Cases of |do_statement|...@>=
23618 case every_job_command: 
23619   mp_get_symbol(mp); mp->start_sym=mp->cur_sym; mp_get_x_next(mp);
23620   break;
23621
23622 @ @<Glob...@>=
23623 halfword start_sym; /* a symbolic token to insert at beginning of job */
23624
23625 @ @<Set init...@>=
23626 mp->start_sym=0;
23627
23628 @ Finally, we have only the ``message'' commands remaining.
23629
23630 @d message_code 0
23631 @d err_message_code 1
23632 @d err_help_code 2
23633 @d filename_template_code 3
23634 @d print_with_leading_zeroes(A)  g = mp->pool_ptr;
23635               mp_print_int(mp, (A)); g = mp->pool_ptr-g;
23636               if ( f>g ) {
23637                 mp->pool_ptr = mp->pool_ptr - g;
23638                 while ( f>g ) {
23639                   mp_print_char(mp, xord('0'));
23640                   decr(f);
23641                   };
23642                 mp_print_int(mp, (A));
23643               };
23644               f = 0
23645
23646 @<Put each...@>=
23647 mp_primitive(mp, "message",message_command,message_code);
23648 @:message_}{\&{message} primitive@>
23649 mp_primitive(mp, "errmessage",message_command,err_message_code);
23650 @:err_message_}{\&{errmessage} primitive@>
23651 mp_primitive(mp, "errhelp",message_command,err_help_code);
23652 @:err_help_}{\&{errhelp} primitive@>
23653 mp_primitive(mp, "filenametemplate",message_command,filename_template_code);
23654 @:filename_template_}{\&{filenametemplate} primitive@>
23655
23656 @ @<Cases of |print_cmd...@>=
23657 case message_command: 
23658   if ( m<err_message_code ) mp_print(mp, "message");
23659   else if ( m==err_message_code ) mp_print(mp, "errmessage");
23660   else if ( m==filename_template_code ) mp_print(mp, "filenametemplate");
23661   else mp_print(mp, "errhelp");
23662   break;
23663
23664 @ @<Cases of |do_statement|...@>=
23665 case message_command: mp_do_message(mp); break;
23666
23667 @ @<Declare action procedures for use by |do_statement|@>=
23668 @<Declare a procedure called |no_string_err|@>
23669 static void mp_do_message (MP mp) ;
23670
23671
23672 @c void mp_do_message (MP mp) {
23673   int m; /* the type of message */
23674   m=mp->cur_mod; mp_get_x_next(mp); mp_scan_expression(mp);
23675   if ( mp->cur_type!=mp_string_type )
23676     mp_no_string_err(mp, "A message should be a known string expression.");
23677   else {
23678     switch (m) {
23679     case message_code: 
23680       mp_print_nl(mp, ""); mp_print_str(mp, mp->cur_exp);
23681       break;
23682     case err_message_code:
23683       @<Print string |cur_exp| as an error message@>;
23684       break;
23685     case err_help_code:
23686       @<Save string |cur_exp| as the |err_help|@>;
23687       break;
23688     case filename_template_code:
23689       @<Save the filename template@>;
23690       break;
23691     } /* there are no other cases */
23692   }
23693   mp_flush_cur_exp(mp, 0);
23694 }
23695
23696 @ @<Declare a procedure called |no_string_err|@>=
23697 static void mp_no_string_err (MP mp, const char *s) { 
23698    exp_err("Not a string");
23699 @.Not a string@>
23700   help1(s);
23701   mp_put_get_error(mp);
23702 }
23703
23704 @ The global variable |err_help| is zero when the user has most recently
23705 given an empty help string, or if none has ever been given.
23706
23707 @<Save string |cur_exp| as the |err_help|@>=
23708
23709   if ( mp->err_help!=0 ) delete_str_ref(mp->err_help);
23710   if ( length(mp->cur_exp)==0 ) mp->err_help=0;
23711   else  { mp->err_help=mp->cur_exp; add_str_ref(mp->err_help); }
23712 }
23713
23714 @ If \&{errmessage} occurs often in |mp_scroll_mode|, without user-defined
23715 \&{errhelp}, we don't want to give a long help message each time. So we
23716 give a verbose explanation only once.
23717
23718 @<Glob...@>=
23719 boolean long_help_seen; /* has the long \.{\\errmessage} help been used? */
23720
23721 @ @<Set init...@>=mp->long_help_seen=false;
23722
23723 @ @<Print string |cur_exp| as an error message@>=
23724
23725   print_err(""); mp_print_str(mp, mp->cur_exp);
23726   if ( mp->err_help!=0 ) {
23727     mp->use_err_help=true;
23728   } else if ( mp->long_help_seen ) { 
23729     help1("(That was another `errmessage'.)") ; 
23730   } else  { 
23731    if ( mp->interaction<mp_error_stop_mode ) mp->long_help_seen=true;
23732     help4("This error message was generated by an `errmessage'",
23733      "command, so I can\'t give any explicit help.",
23734      "Pretend that you're Miss Marple: Examine all clues,",
23735 @^Marple, Jane@>
23736      "and deduce the truth by inspired guesses.");
23737   }
23738   mp_put_get_error(mp); mp->use_err_help=false;
23739 }
23740
23741 @ @<Cases of |do_statement|...@>=
23742 case write_command: mp_do_write(mp); break;
23743
23744 @ @<Declare action procedures for use by |do_statement|@>=
23745 static void mp_do_write (MP mp) ;
23746
23747 @ @c void mp_do_write (MP mp) {
23748   str_number t; /* the line of text to be written */
23749   write_index n,n0; /* for searching |wr_fname| and |wr_file| arrays */
23750   unsigned old_setting; /* for saving |selector| during output */
23751   mp_get_x_next(mp);
23752   mp_scan_expression(mp);
23753   if ( mp->cur_type!=mp_string_type ) {
23754     mp_no_string_err(mp, "The text to be written should be a known string expression");
23755   } else if ( mp->cur_cmd!=to_token ) { 
23756     print_err("Missing `to' clause");
23757     help1("A write command should end with `to <filename>'");
23758     mp_put_get_error(mp);
23759   } else { 
23760     t=mp->cur_exp; mp->cur_type=mp_vacuous;
23761     mp_get_x_next(mp);
23762     mp_scan_expression(mp);
23763     if ( mp->cur_type!=mp_string_type )
23764       mp_no_string_err(mp, "I can\'t write to that file name.  It isn't a known string");
23765     else {
23766       @<Write |t| to the file named by |cur_exp|@>;
23767     }
23768     delete_str_ref(t);
23769   }
23770   mp_flush_cur_exp(mp, 0);
23771 }
23772
23773 @ @<Write |t| to the file named by |cur_exp|@>=
23774
23775   @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if
23776     |cur_exp| must be inserted@>;
23777   if ( mp_str_vs_str(mp, t,mp->eof_line)==0 ) {
23778     @<Record the end of file on |wr_file[n]|@>;
23779   } else { 
23780     old_setting=mp->selector;
23781     mp->selector=n+write_file;
23782     mp_print_str(mp, t); mp_print_ln(mp);
23783     mp->selector = old_setting;
23784   }
23785 }
23786
23787 @ @<Find |n| where |wr_fname[n]=cur_exp| and call |open_write_file| if...@>=
23788 {
23789   char *fn = str(mp->cur_exp);
23790   n=mp->write_files;
23791   n0=mp->write_files;
23792   while (mp_xstrcmp(fn,mp->wr_fname[n])!=0) { 
23793     if ( n==0 ) { /* bottom reached */
23794           if ( n0==mp->write_files ) {
23795         if ( mp->write_files<mp->max_write_files ) {
23796           incr(mp->write_files);
23797         } else {
23798           void **wr_file;
23799           char **wr_fname;
23800               write_index l,k;
23801           l = mp->max_write_files + (mp->max_write_files/4);
23802           wr_file = xmalloc((l+1),sizeof(void *));
23803           wr_fname = xmalloc((l+1),sizeof(char *));
23804               for (k=0;k<=l;k++) {
23805             if (k<=mp->max_write_files) {
23806                   wr_file[k]=mp->wr_file[k]; 
23807               wr_fname[k]=mp->wr_fname[k];
23808             } else {
23809                   wr_file[k]=0; 
23810               wr_fname[k]=NULL;
23811             }
23812           }
23813               xfree(mp->wr_file); xfree(mp->wr_fname);
23814           mp->max_write_files = l;
23815           mp->wr_file = wr_file;
23816           mp->wr_fname = wr_fname;
23817         }
23818       }
23819       n=n0;
23820       mp_open_write_file(mp, fn ,n);
23821     } else { 
23822       decr(n);
23823           if ( mp->wr_fname[n]==NULL )  n0=n; 
23824     }
23825   }
23826 }
23827
23828 @ @<Record the end of file on |wr_file[n]|@>=
23829 { (mp->close_file)(mp,mp->wr_file[n]);
23830   xfree(mp->wr_fname[n]);
23831   if ( n==mp->write_files-1 ) mp->write_files=n;
23832 }
23833
23834
23835 @* \[42] Writing font metric data.
23836 \TeX\ gets its knowledge about fonts from font metric files, also called
23837 \.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX,
23838 but other programs know about them too. One of \MP's duties is to
23839 write \.{TFM} files so that the user's fonts can readily be
23840 applied to typesetting.
23841 @:TFM files}{\.{TFM} files@>
23842 @^font metric files@>
23843
23844 The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
23845 Since the number of bytes is always a multiple of~4, we could
23846 also regard the file as a sequence of 32-bit words, but \MP\ uses the
23847 byte interpretation. The format of \.{TFM} files was designed by
23848 Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
23849 @^Ramshaw, Lyle Harold@>
23850 of information in a compact but useful form.
23851
23852 @<Glob...@>=
23853 void * tfm_file; /* the font metric output goes here */
23854 char * metric_file_name; /* full name of the font metric file */
23855
23856 @ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
23857 integers that give the lengths of the various subsequent portions
23858 of the file. These twelve integers are, in order:
23859 $$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
23860 |lf|&length of the entire file, in words;\cr
23861 |lh|&length of the header data, in words;\cr
23862 |bc|&smallest character code in the font;\cr
23863 |ec|&largest character code in the font;\cr
23864 |nw|&number of words in the width table;\cr
23865 |nh|&number of words in the height table;\cr
23866 |nd|&number of words in the depth table;\cr
23867 |ni|&number of words in the italic correction table;\cr
23868 |nl|&number of words in the lig/kern table;\cr
23869 |nk|&number of words in the kern table;\cr
23870 |ne|&number of words in the extensible character table;\cr
23871 |np|&number of font parameter words.\cr}}$$
23872 They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
23873 |ne<=256|, and
23874 $$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
23875 Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
23876 and as few as 0 characters (if |bc=ec+1|).
23877
23878 Incidentally, when two or more 8-bit bytes are combined to form an integer of
23879 16 or more bits, the most significant bytes appear first in the file.
23880 This is called BigEndian order.
23881 @^BigEndian order@>
23882
23883 @ The rest of the \.{TFM} file may be regarded as a sequence of ten data
23884 arrays.
23885
23886 The most important data type used here is a |fix_word|, which is
23887 a 32-bit representation of a binary fraction. A |fix_word| is a signed
23888 quantity, with the two's complement of the entire word used to represent
23889 negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
23890 binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
23891 the smallest is $-2048$. We will see below, however, that all but two of
23892 the |fix_word| values must lie between $-16$ and $+16$.
23893
23894 @ The first data array is a block of header information, which contains
23895 general facts about the font. The header must contain at least two words,
23896 |header[0]| and |header[1]|, whose meaning is explained below.  Additional
23897 header information of use to other software routines might also be
23898 included, and \MP\ will generate it if the \.{headerbyte} command occurs.
23899 For example, 16 more words of header information are in use at the Xerox
23900 Palo Alto Research Center; the first ten specify the character coding
23901 scheme used (e.g., `\.{XEROX TEXT}' or `\.{TEX MATHSY}'), the next five
23902 give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
23903 last gives the ``face byte.''
23904
23905 \yskip\hang|header[0]| is a 32-bit check sum that \MP\ will copy into
23906 the \.{GF} output file. This helps ensure consistency between files,
23907 since \TeX\ records the check sums from the \.{TFM}'s it reads, and these
23908 should match the check sums on actual fonts that are used.  The actual
23909 relation between this check sum and the rest of the \.{TFM} file is not
23910 important; the check sum is simply an identification number with the
23911 property that incompatible fonts almost always have distinct check sums.
23912 @^check sum@>
23913
23914 \yskip\hang|header[1]| is a |fix_word| containing the design size of the
23915 font, in units of \TeX\ points. This number must be at least 1.0; it is
23916 fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
23917 font, i.e., a font that was designed to look best at a 10-point size,
23918 whatever that really means. When a \TeX\ user asks for a font `\.{at}
23919 $\delta$ \.{pt}', the effect is to override the design size and replace it
23920 by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in
23921 the font image by a factor of $\delta$ divided by the design size.  {\sl
23922 All other dimensions in the\/ \.{TFM} file are |fix_word|\kern-1pt\
23923 numbers in design-size units.} Thus, for example, the value of |param[6]|,
23924 which defines the \.{em} unit, is often the |fix_word| value $2^{20}=1.0$,
23925 since many fonts have a design size equal to one em.  The other dimensions
23926 must be less than 16 design-size units in absolute value; thus,
23927 |header[1]| and |param[1]| are the only |fix_word| entries in the whole
23928 \.{TFM} file whose first byte might be something besides 0 or 255.
23929 @^design size@>
23930
23931 @ Next comes the |char_info| array, which contains one |char_info_word|
23932 per character. Each word in this part of the file contains six fields
23933 packed into four bytes as follows.
23934
23935 \yskip\hang first byte: |width_index| (8 bits)\par
23936 \hang second byte: |height_index| (4 bits) times 16, plus |depth_index|
23937   (4~bits)\par
23938 \hang third byte: |italic_index| (6 bits) times 4, plus |tag|
23939   (2~bits)\par
23940 \hang fourth byte: |remainder| (8 bits)\par
23941 \yskip\noindent
23942 The actual width of a character is \\{width}|[width_index]|, in design-size
23943 units; this is a device for compressing information, since many characters
23944 have the same width. Since it is quite common for many characters
23945 to have the same height, depth, or italic correction, the \.{TFM} format
23946 imposes a limit of 16 different heights, 16 different depths, and
23947 64 different italic corrections.
23948
23949 Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
23950 \\{italic}[0]=0$ should always hold, so that an index of zero implies a
23951 value of zero.  The |width_index| should never be zero unless the
23952 character does not exist in the font, since a character is valid if and
23953 only if it lies between |bc| and |ec| and has a nonzero |width_index|.
23954
23955 @ The |tag| field in a |char_info_word| has four values that explain how to
23956 interpret the |remainder| field.
23957
23958 \yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
23959 \hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
23960 program starting at location |remainder| in the |lig_kern| array.\par
23961 \hang|tag=2| (|list_tag|) means that this character is part of a chain of
23962 characters of ascending sizes, and not the largest in the chain.  The
23963 |remainder| field gives the character code of the next larger character.\par
23964 \hang|tag=3| (|ext_tag|) means that this character code represents an
23965 extensible character, i.e., a character that is built up of smaller pieces
23966 so that it can be made arbitrarily large. The pieces are specified in
23967 |exten[remainder]|.\par
23968 \yskip\noindent
23969 Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
23970 unless they are used in special circumstances in math formulas. For example,
23971 \TeX's \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
23972 operation looks for both |list_tag| and |ext_tag|.
23973
23974 @d no_tag 0 /* vanilla character */
23975 @d lig_tag 1 /* character has a ligature/kerning program */
23976 @d list_tag 2 /* character has a successor in a charlist */
23977 @d ext_tag 3 /* character is extensible */
23978
23979 @ The |lig_kern| array contains instructions in a simple programming language
23980 that explains what to do for special letter pairs. Each word in this array is a
23981 |lig_kern_command| of four bytes.
23982
23983 \yskip\hang first byte: |skip_byte|, indicates that this is the final program
23984   step if the byte is 128 or more, otherwise the next step is obtained by
23985   skipping this number of intervening steps.\par
23986 \hang second byte: |next_char|, ``if |next_char| follows the current character,
23987   then perform the operation and stop, otherwise continue.''\par
23988 \hang third byte: |op_byte|, indicates a ligature step if less than~128,
23989   a kern step otherwise.\par
23990 \hang fourth byte: |remainder|.\par
23991 \yskip\noindent
23992 In a kern step, an
23993 additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
23994 between the current character and |next_char|. This amount is
23995 often negative, so that the characters are brought closer together
23996 by kerning; but it might be positive.
23997
23998 There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
23999 $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
24000 |remainder| is inserted between the current character and |next_char|;
24001 then the current character is deleted if $b=0$, and |next_char| is
24002 deleted if $c=0$; then we pass over $a$~characters to reach the next
24003 current character (which may have a ligature/kerning program of its own).
24004
24005 If the very first instruction of the |lig_kern| array has |skip_byte=255|,
24006 the |next_char| byte is the so-called right boundary character of this font;
24007 the value of |next_char| need not lie between |bc| and~|ec|.
24008 If the very last instruction of the |lig_kern| array has |skip_byte=255|,
24009 there is a special ligature/kerning program for a left boundary character,
24010 beginning at location |256*op_byte+remainder|.
24011 The interpretation is that \TeX\ puts implicit boundary characters
24012 before and after each consecutive string of characters from the same font.
24013 These implicit characters do not appear in the output, but they can affect
24014 ligatures and kerning.
24015
24016 If the very first instruction of a character's |lig_kern| program has
24017 |skip_byte>128|, the program actually begins in location
24018 |256*op_byte+remainder|. This feature allows access to large |lig_kern|
24019 arrays, because the first instruction must otherwise
24020 appear in a location |<=255|.
24021
24022 Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
24023 the condition
24024 $$\hbox{|256*op_byte+remainder<nl|.}$$
24025 If such an instruction is encountered during
24026 normal program execution, it denotes an unconditional halt; no ligature
24027 command is performed.
24028
24029 @d stop_flag (128)
24030   /* value indicating `\.{STOP}' in a lig/kern program */
24031 @d kern_flag (128) /* op code for a kern step */
24032 @d skip_byte(A) mp->lig_kern[(A)].b0
24033 @d next_char(A) mp->lig_kern[(A)].b1
24034 @d op_byte(A) mp->lig_kern[(A)].b2
24035 @d rem_byte(A) mp->lig_kern[(A)].b3
24036
24037 @ Extensible characters are specified by an |extensible_recipe|, which
24038 consists of four bytes called |top|, |mid|, |bot|, and |rep| (in this
24039 order). These bytes are the character codes of individual pieces used to
24040 build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
24041 present in the built-up result. For example, an extensible vertical line is
24042 like an extensible bracket, except that the top and bottom pieces are missing.
24043
24044 Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
24045 if the piece isn't present. Then the extensible characters have the form
24046 $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
24047 in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
24048 The width of the extensible character is the width of $R$; and the
24049 height-plus-depth is the sum of the individual height-plus-depths of the
24050 components used, since the pieces are butted together in a vertical list.
24051
24052 @d ext_top(A) mp->exten[(A)].b0 /* |top| piece in a recipe */
24053 @d ext_mid(A) mp->exten[(A)].b1 /* |mid| piece in a recipe */
24054 @d ext_bot(A) mp->exten[(A)].b2 /* |bot| piece in a recipe */
24055 @d ext_rep(A) mp->exten[(A)].b3 /* |rep| piece in a recipe */
24056
24057 @ The final portion of a \.{TFM} file is the |param| array, which is another
24058 sequence of |fix_word| values.
24059
24060 \yskip\hang|param[1]=slant| is the amount of italic slant, which is used
24061 to help position accents. For example, |slant=.25| means that when you go
24062 up one unit, you also go .25 units to the right. The |slant| is a pure
24063 number; it is the only |fix_word| other than the design size itself that is
24064 not scaled by the design size.
24065 @^design size@>
24066
24067 \hang|param[2]=space| is the normal spacing between words in text.
24068 Note that character 040 in the font need not have anything to do with
24069 blank spaces.
24070
24071 \hang|param[3]=space_stretch| is the amount of glue stretching between words.
24072
24073 \hang|param[4]=space_shrink| is the amount of glue shrinking between words.
24074
24075 \hang|param[5]=x_height| is the size of one ex in the font; it is also
24076 the height of letters for which accents don't have to be raised or lowered.
24077
24078 \hang|param[6]=quad| is the size of one em in the font.
24079
24080 \hang|param[7]=extra_space| is the amount added to |param[2]| at the
24081 ends of sentences.
24082
24083 \yskip\noindent
24084 If fewer than seven parameters are present, \TeX\ sets the missing parameters
24085 to zero.
24086
24087 @d slant_code 1
24088 @d space_code 2
24089 @d space_stretch_code 3
24090 @d space_shrink_code 4
24091 @d x_height_code 5
24092 @d quad_code 6
24093 @d extra_space_code 7
24094
24095 @ So that is what \.{TFM} files hold. One of \MP's duties is to output such
24096 information, and it does this all at once at the end of a job.
24097 In order to prepare for such frenetic activity, it squirrels away the
24098 necessary facts in various arrays as information becomes available.
24099
24100 Character dimensions (\&{charwd}, \&{charht}, \&{chardp}, and \&{charic})
24101 are stored respectively in |tfm_width|, |tfm_height|, |tfm_depth|, and
24102 |tfm_ital_corr|. Other information about a character (e.g., about
24103 its ligatures or successors) is accessible via the |char_tag| and
24104 |char_remainder| arrays. Other information about the font as a whole
24105 is kept in additional arrays called |header_byte|, |lig_kern|,
24106 |kern|, |exten|, and |param|.
24107
24108 @d max_tfm_int 32510
24109 @d undefined_label max_tfm_int /* an undefined local label */
24110
24111 @<Glob...@>=
24112 #define TFM_ITEMS 257
24113 eight_bits bc;
24114 eight_bits ec; /* smallest and largest character codes shipped out */
24115 scaled tfm_width[TFM_ITEMS]; /* \&{charwd} values */
24116 scaled tfm_height[TFM_ITEMS]; /* \&{charht} values */
24117 scaled tfm_depth[TFM_ITEMS]; /* \&{chardp} values */
24118 scaled tfm_ital_corr[TFM_ITEMS]; /* \&{charic} values */
24119 boolean char_exists[TFM_ITEMS]; /* has this code been shipped out? */
24120 int char_tag[TFM_ITEMS]; /* |remainder| category */
24121 int char_remainder[TFM_ITEMS]; /* the |remainder| byte */
24122 char *header_byte; /* bytes of the \.{TFM} header */
24123 int header_last; /* last initialized \.{TFM} header byte */
24124 int header_size; /* size of the \.{TFM} header */
24125 four_quarters *lig_kern; /* the ligature/kern table */
24126 short nl; /* the number of ligature/kern steps so far */
24127 scaled *kern; /* distinct kerning amounts */
24128 short nk; /* the number of distinct kerns so far */
24129 four_quarters exten[TFM_ITEMS]; /* extensible character recipes */
24130 short ne; /* the number of extensible characters so far */
24131 scaled *param; /* \&{fontinfo} parameters */
24132 short np; /* the largest \&{fontinfo} parameter specified so far */
24133 short nw;short nh;short nd;short ni; /* sizes of \.{TFM} subtables */
24134 short skip_table[TFM_ITEMS]; /* local label status */
24135 boolean lk_started; /* has there been a lig/kern step in this command yet? */
24136 integer bchar; /* right boundary character */
24137 short bch_label; /* left boundary starting location */
24138 short ll;short lll; /* registers used for lig/kern processing */
24139 short label_loc[257]; /* lig/kern starting addresses */
24140 eight_bits label_char[257]; /* characters for |label_loc| */
24141 short label_ptr; /* highest position occupied in |label_loc| */
24142
24143 @ @<Allocate or initialize ...@>=
24144 mp->header_size = 128; /* just for init */
24145 mp->header_byte = xmalloc(mp->header_size, sizeof(char));
24146
24147 @ @<Dealloc variables@>=
24148 xfree(mp->header_byte);
24149 xfree(mp->lig_kern);
24150 xfree(mp->kern);
24151 xfree(mp->param);
24152
24153 @ @<Set init...@>=
24154 for (k=0;k<= 255;k++ ) {
24155   mp->tfm_width[k]=0; mp->tfm_height[k]=0; mp->tfm_depth[k]=0; mp->tfm_ital_corr[k]=0;
24156   mp->char_exists[k]=false; mp->char_tag[k]=no_tag; mp->char_remainder[k]=0;
24157   mp->skip_table[k]=undefined_label;
24158 }
24159 memset(mp->header_byte,0,(size_t)mp->header_size);
24160 mp->bc=255; mp->ec=0; mp->nl=0; mp->nk=0; mp->ne=0; mp->np=0;
24161 mp->internal[mp_boundary_char]=-unity;
24162 mp->bch_label=undefined_label;
24163 mp->label_loc[0]=-1; mp->label_ptr=0;
24164
24165 @ @<Declarations@>=
24166 static scaled mp_tfm_check (MP mp,quarterword m) ;
24167
24168 @ @c
24169 static scaled mp_tfm_check (MP mp,quarterword m) {
24170   if ( abs(mp->internal[m])>=fraction_half ) {
24171     print_err("Enormous "); mp_print(mp, mp->int_name[m]);
24172 @.Enormous charwd...@>
24173 @.Enormous chardp...@>
24174 @.Enormous charht...@>
24175 @.Enormous charic...@>
24176 @.Enormous designsize...@>
24177     mp_print(mp, " has been reduced");
24178     help1("Font metric dimensions must be less than 2048pt.");
24179     mp_put_get_error(mp);
24180     if ( mp->internal[m]>0 ) return (fraction_half-1);
24181     else return (1-fraction_half);
24182   } else {
24183     return mp->internal[m];
24184   }
24185 }
24186
24187 @ @<Store the width information for character code~|c|@>=
24188 if ( c<mp->bc ) mp->bc=(eight_bits)c;
24189 if ( c>mp->ec ) mp->ec=(eight_bits)c;
24190 mp->char_exists[c]=true;
24191 mp->tfm_width[c]=mp_tfm_check(mp,mp_char_wd);
24192 mp->tfm_height[c]=mp_tfm_check(mp, mp_char_ht);
24193 mp->tfm_depth[c]=mp_tfm_check(mp, mp_char_dp);
24194 mp->tfm_ital_corr[c]=mp_tfm_check(mp, mp_char_ic)
24195
24196 @ Now let's consider \MP's special \.{TFM}-oriented commands.
24197
24198 @<Cases of |do_statement|...@>=
24199 case tfm_command: mp_do_tfm_command(mp); break;
24200
24201 @ @d char_list_code 0
24202 @d lig_table_code 1
24203 @d extensible_code 2
24204 @d header_byte_code 3
24205 @d font_dimen_code 4
24206
24207 @<Put each...@>=
24208 mp_primitive(mp, "charlist",tfm_command,char_list_code);
24209 @:char_list_}{\&{charlist} primitive@>
24210 mp_primitive(mp, "ligtable",tfm_command,lig_table_code);
24211 @:lig_table_}{\&{ligtable} primitive@>
24212 mp_primitive(mp, "extensible",tfm_command,extensible_code);
24213 @:extensible_}{\&{extensible} primitive@>
24214 mp_primitive(mp, "headerbyte",tfm_command,header_byte_code);
24215 @:header_byte_}{\&{headerbyte} primitive@>
24216 mp_primitive(mp, "fontdimen",tfm_command,font_dimen_code);
24217 @:font_dimen_}{\&{fontdimen} primitive@>
24218
24219 @ @<Cases of |print_cmd...@>=
24220 case tfm_command: 
24221   switch (m) {
24222   case char_list_code:mp_print(mp, "charlist"); break;
24223   case lig_table_code:mp_print(mp, "ligtable"); break;
24224   case extensible_code:mp_print(mp, "extensible"); break;
24225   case header_byte_code:mp_print(mp, "headerbyte"); break;
24226   default: mp_print(mp, "fontdimen"); break;
24227   }
24228   break;
24229
24230 @ @<Declare action procedures for use by |do_statement|@>=
24231 static eight_bits mp_get_code (MP mp) ;
24232
24233 @ @c eight_bits mp_get_code (MP mp) { /* scans a character code value */
24234   integer c; /* the code value found */
24235   mp_get_x_next(mp); mp_scan_expression(mp);
24236   if ( mp->cur_type==mp_known ) { 
24237     c=mp_round_unscaled(mp, mp->cur_exp);
24238     if ( c>=0 ) if ( c<256 ) return (eight_bits)c;
24239   } else if ( mp->cur_type==mp_string_type ) {
24240     if ( length(mp->cur_exp)==1 )  { 
24241       c=mp->str_pool[mp->str_start[mp->cur_exp]];
24242       return (eight_bits)c;
24243     }
24244   }
24245   exp_err("Invalid code has been replaced by 0");
24246 @.Invalid code...@>
24247   help2("I was looking for a number between 0 and 255, or for a",
24248         "string of length 1. Didn't find it; will use 0 instead.");
24249   mp_put_get_flush_error(mp, 0); c=0;
24250   return (eight_bits)c;
24251 }
24252
24253 @ @<Declare action procedures for use by |do_statement|@>=
24254 static void mp_set_tag (MP mp,halfword c, quarterword t, halfword r) ;
24255
24256 @ @c void mp_set_tag (MP mp,halfword c, quarterword t, halfword r) { 
24257   if ( mp->char_tag[c]==no_tag ) {
24258     mp->char_tag[c]=t; mp->char_remainder[c]=r;
24259     if ( t==lig_tag ){ 
24260       incr(mp->label_ptr); mp->label_loc[mp->label_ptr]=r; 
24261       mp->label_char[mp->label_ptr]=(eight_bits)c;
24262     }
24263   } else {
24264     @<Complain about a character tag conflict@>;
24265   }
24266 }
24267
24268 @ @<Complain about a character tag conflict@>=
24269
24270   print_err("Character ");
24271   if ( (c>' ')&&(c<127) ) mp_print_char(mp,xord(c));
24272   else if ( c==256 ) mp_print(mp, "||");
24273   else  { mp_print(mp, "code "); mp_print_int(mp, c); };
24274   mp_print(mp, " is already ");
24275 @.Character c is already...@>
24276   switch (mp->char_tag[c]) {
24277   case lig_tag: mp_print(mp, "in a ligtable"); break;
24278   case list_tag: mp_print(mp, "in a charlist"); break;
24279   case ext_tag: mp_print(mp, "extensible"); break;
24280   } /* there are no other cases */
24281   help2("It's not legal to label a character more than once.",
24282         "So I'll not change anything just now.");
24283   mp_put_get_error(mp); 
24284 }
24285
24286 @ @<Declare action procedures for use by |do_statement|@>=
24287 static void mp_do_tfm_command (MP mp) ;
24288
24289 @ @c void mp_do_tfm_command (MP mp) {
24290   int c,cc; /* character codes */
24291   int k; /* index into the |kern| array */
24292   int j; /* index into |header_byte| or |param| */
24293   switch (mp->cur_mod) {
24294   case char_list_code: 
24295     c=mp_get_code(mp);
24296      /* we will store a list of character successors */
24297     while ( mp->cur_cmd==colon )   { 
24298       cc=mp_get_code(mp); mp_set_tag(mp, c,list_tag,cc); c=cc;
24299     };
24300     break;
24301   case lig_table_code: 
24302     if (mp->lig_kern==NULL) 
24303        mp->lig_kern = xmalloc((max_tfm_int+1),sizeof(four_quarters));
24304     if (mp->kern==NULL) 
24305        mp->kern = xmalloc((max_tfm_int+1),sizeof(scaled));
24306     @<Store a list of ligature/kern steps@>;
24307     break;
24308   case extensible_code: 
24309     @<Define an extensible recipe@>;
24310     break;
24311   case header_byte_code: 
24312   case font_dimen_code: 
24313     c=mp->cur_mod; mp_get_x_next(mp);
24314     mp_scan_expression(mp);
24315     if ( (mp->cur_type!=mp_known)||(mp->cur_exp<half_unit) ) {
24316       exp_err("Improper location");
24317 @.Improper location@>
24318       help2("I was looking for a known, positive number.",
24319             "For safety's sake I'll ignore the present command.");
24320       mp_put_get_error(mp);
24321     } else  { 
24322       j=mp_round_unscaled(mp, mp->cur_exp);
24323       if ( mp->cur_cmd!=colon ) {
24324         mp_missing_err(mp, ":");
24325 @.Missing `:'@>
24326         help1("A colon should follow a headerbyte or fontinfo location.");
24327         mp_back_error(mp);
24328       }
24329       if ( c==header_byte_code ) { 
24330         @<Store a list of header bytes@>;
24331       } else {     
24332         if (mp->param==NULL) 
24333           mp->param = xmalloc((max_tfm_int+1),sizeof(scaled));
24334         @<Store a list of font dimensions@>;
24335       }
24336     }
24337     break;
24338   } /* there are no other cases */
24339 }
24340
24341 @ @<Store a list of ligature/kern steps@>=
24342
24343   mp->lk_started=false;
24344 CONTINUE: 
24345   mp_get_x_next(mp);
24346   if ((mp->cur_cmd==skip_to)&& mp->lk_started )
24347     @<Process a |skip_to| command and |goto done|@>;
24348   if ( mp->cur_cmd==bchar_label ) { c=256; mp->cur_cmd=colon; }
24349   else { mp_back_input(mp); c=mp_get_code(mp); };
24350   if ((mp->cur_cmd==colon)||(mp->cur_cmd==double_colon)) {
24351     @<Record a label in a lig/kern subprogram and |goto continue|@>;
24352   }
24353   if ( mp->cur_cmd==lig_kern_token ) { 
24354     @<Compile a ligature/kern command@>; 
24355   } else  { 
24356     print_err("Illegal ligtable step");
24357 @.Illegal ligtable step@>
24358     help1("I was looking for `=:' or `kern' here.");
24359     mp_back_error(mp); next_char(mp->nl)=qi(0); 
24360     op_byte(mp->nl)=qi(0); rem_byte(mp->nl)=qi(0);
24361     skip_byte(mp->nl)=stop_flag+1; /* this specifies an unconditional stop */
24362   }
24363   if ( mp->nl==max_tfm_int) mp_fatal_error(mp, "ligtable too large");
24364   incr(mp->nl);
24365   if ( mp->cur_cmd==comma ) goto CONTINUE;
24366   if ( skip_byte(mp->nl-1)<stop_flag ) skip_byte(mp->nl-1)=stop_flag;
24367 }
24368 DONE:
24369
24370 @ @<Put each...@>=
24371 mp_primitive(mp, "=:",lig_kern_token,0);
24372 @:=:_}{\.{=:} primitive@>
24373 mp_primitive(mp, "=:|",lig_kern_token,1);
24374 @:=:/_}{\.{=:\char'174} primitive@>
24375 mp_primitive(mp, "=:|>",lig_kern_token,5);
24376 @:=:/>_}{\.{=:\char'174>} primitive@>
24377 mp_primitive(mp, "|=:",lig_kern_token,2);
24378 @:=:/_}{\.{\char'174=:} primitive@>
24379 mp_primitive(mp, "|=:>",lig_kern_token,6);
24380 @:=:/>_}{\.{\char'174=:>} primitive@>
24381 mp_primitive(mp, "|=:|",lig_kern_token,3);
24382 @:=:/_}{\.{\char'174=:\char'174} primitive@>
24383 mp_primitive(mp, "|=:|>",lig_kern_token,7);
24384 @:=:/>_}{\.{\char'174=:\char'174>} primitive@>
24385 mp_primitive(mp, "|=:|>>",lig_kern_token,11);
24386 @:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
24387 mp_primitive(mp, "kern",lig_kern_token,128);
24388 @:kern_}{\&{kern} primitive@>
24389
24390 @ @<Cases of |print_cmd...@>=
24391 case lig_kern_token: 
24392   switch (m) {
24393   case 0:mp_print(mp, "=:"); break;
24394   case 1:mp_print(mp, "=:|"); break;
24395   case 2:mp_print(mp, "|=:"); break;
24396   case 3:mp_print(mp, "|=:|"); break;
24397   case 5:mp_print(mp, "=:|>"); break;
24398   case 6:mp_print(mp, "|=:>"); break;
24399   case 7:mp_print(mp, "|=:|>"); break;
24400   case 11:mp_print(mp, "|=:|>>"); break;
24401   default: mp_print(mp, "kern"); break;
24402   }
24403   break;
24404
24405 @ Local labels are implemented by maintaining the |skip_table| array,
24406 where |skip_table[c]| is either |undefined_label| or the address of the
24407 most recent lig/kern instruction that skips to local label~|c|. In the
24408 latter case, the |skip_byte| in that instruction will (temporarily)
24409 be zero if there were no prior skips to this label, or it will be the
24410 distance to the prior skip.
24411
24412 We may need to cancel skips that span more than 127 lig/kern steps.
24413
24414 @d cancel_skips(A) mp->ll=(A);
24415   do {  
24416     mp->lll=qo(skip_byte(mp->ll)); 
24417     skip_byte(mp->ll)=stop_flag; mp->ll=mp->ll-mp->lll;
24418   } while (mp->lll!=0)
24419 @d skip_error(A) { print_err("Too far to skip");
24420 @.Too far to skip@>
24421   help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
24422   mp_error(mp); cancel_skips((A));
24423   }
24424
24425 @<Process a |skip_to| command and |goto done|@>=
24426
24427   c=mp_get_code(mp);
24428   if ( mp->nl-mp->skip_table[c]>128 ) {
24429     skip_error(mp->skip_table[c]); mp->skip_table[c]=undefined_label;
24430   }
24431   if ( mp->skip_table[c]==undefined_label ) skip_byte(mp->nl-1)=qi(0);
24432   else skip_byte(mp->nl-1)=qi(mp->nl-mp->skip_table[c]-1);
24433   mp->skip_table[c]=mp->nl-1; goto DONE;
24434 }
24435
24436 @ @<Record a label in a lig/kern subprogram and |goto continue|@>=
24437
24438   if ( mp->cur_cmd==colon ) {
24439     if ( c==256 ) mp->bch_label=mp->nl;
24440     else mp_set_tag(mp, c,lig_tag,mp->nl);
24441   } else if ( mp->skip_table[c]<undefined_label ) {
24442     mp->ll=mp->skip_table[c]; mp->skip_table[c]=undefined_label;
24443     do {  
24444       mp->lll=qo(skip_byte(mp->ll));
24445       if ( mp->nl-mp->ll>128 ) {
24446         skip_error(mp->ll); goto CONTINUE;
24447       }
24448       skip_byte(mp->ll)=qi(mp->nl-mp->ll-1); mp->ll=mp->ll-mp->lll;
24449     } while (mp->lll!=0);
24450   }
24451   goto CONTINUE;
24452 }
24453
24454 @ @<Compile a ligature/kern...@>=
24455
24456   next_char(mp->nl)=qi(c); skip_byte(mp->nl)=qi(0);
24457   if ( mp->cur_mod<128 ) { /* ligature op */
24458     op_byte(mp->nl)=qi(mp->cur_mod); rem_byte(mp->nl)=qi(mp_get_code(mp));
24459   } else { 
24460     mp_get_x_next(mp); mp_scan_expression(mp);
24461     if ( mp->cur_type!=mp_known ) {
24462       exp_err("Improper kern");
24463 @.Improper kern@>
24464       help2("The amount of kern should be a known numeric value.",
24465             "I'm zeroing this one. Proceed, with fingers crossed.");
24466       mp_put_get_flush_error(mp, 0);
24467     }
24468     mp->kern[mp->nk]=mp->cur_exp;
24469     k=0; 
24470     while ( mp->kern[k]!=mp->cur_exp ) incr(k);
24471     if ( k==mp->nk ) {
24472       if ( mp->nk==max_tfm_int ) mp_fatal_error(mp, "too many TFM kerns");
24473       incr(mp->nk);
24474     }
24475     op_byte(mp->nl)=kern_flag+(k / 256);
24476     rem_byte(mp->nl)=qi((k % 256));
24477   }
24478   mp->lk_started=true;
24479 }
24480
24481 @ @d missing_extensible_punctuation(A) 
24482   { mp_missing_err(mp, (A));
24483 @.Missing `\char`\#'@>
24484   help1("I'm processing `extensible c: t,m,b,r'."); mp_back_error(mp);
24485   }
24486
24487 @<Define an extensible recipe@>=
24488
24489   if ( mp->ne==256 ) mp_fatal_error(mp, "too many extensible recipies");
24490   c=mp_get_code(mp); mp_set_tag(mp, c,ext_tag,mp->ne);
24491   if ( mp->cur_cmd!=colon ) missing_extensible_punctuation(":");
24492   ext_top(mp->ne)=qi(mp_get_code(mp));
24493   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
24494   ext_mid(mp->ne)=qi(mp_get_code(mp));
24495   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
24496   ext_bot(mp->ne)=qi(mp_get_code(mp));
24497   if ( mp->cur_cmd!=comma ) missing_extensible_punctuation(",");
24498   ext_rep(mp->ne)=qi(mp_get_code(mp));
24499   incr(mp->ne);
24500 }
24501
24502 @ The header could contain ASCII zeroes, so can't use |strdup|.
24503
24504 @<Store a list of header bytes@>=
24505 do {  
24506   if ( j>=mp->header_size ) {
24507     size_t l = (size_t)(mp->header_size + (mp->header_size/4));
24508     char *t = xmalloc(l,1);
24509     memset(t,0,l); 
24510     memcpy(t,mp->header_byte,(size_t)mp->header_size);
24511     xfree (mp->header_byte);
24512     mp->header_byte = t;
24513     mp->header_size = (int)l;
24514   }
24515   mp->header_byte[j]=(char)mp_get_code(mp); 
24516   incr(j); incr(mp->header_last);
24517 } while (mp->cur_cmd==comma)
24518
24519 @ @<Store a list of font dimensions@>=
24520 do {  
24521   if ( j>max_tfm_int ) mp_fatal_error(mp, "too many fontdimens");
24522   while ( j>mp->np ) { incr(mp->np); mp->param[mp->np]=0; };
24523   mp_get_x_next(mp); mp_scan_expression(mp);
24524   if ( mp->cur_type!=mp_known ){ 
24525     exp_err("Improper font parameter");
24526 @.Improper font parameter@>
24527     help1("I'm zeroing this one. Proceed, with fingers crossed.");
24528     mp_put_get_flush_error(mp, 0);
24529   }
24530   mp->param[j]=mp->cur_exp; incr(j);
24531 } while (mp->cur_cmd==comma)
24532
24533 @ OK: We've stored all the data that is needed for the \.{TFM} file.
24534 All that remains is to output it in the correct format.
24535
24536 An interesting problem needs to be solved in this connection, because
24537 the \.{TFM} format allows at most 256~widths, 16~heights, 16~depths,
24538 and 64~italic corrections. If the data has more distinct values than
24539 this, we want to meet the necessary restrictions by perturbing the
24540 given values as little as possible.
24541
24542 \MP\ solves this problem in two steps. First the values of a given
24543 kind (widths, heights, depths, or italic corrections) are sorted;
24544 then the list of sorted values is perturbed, if necessary.
24545
24546 The sorting operation is facilitated by having a special node of
24547 essentially infinite |value| at the end of the current list.
24548
24549 @<Initialize table entries...@>=
24550 value(inf_val)=fraction_four;
24551
24552 @ Straight linear insertion is good enough for sorting, since the lists
24553 are usually not terribly long. As we work on the data, the current list
24554 will start at |mp_link(temp_head)| and end at |inf_val|; the nodes in this
24555 list will be in increasing order of their |value| fields.
24556
24557 Given such a list, the |sort_in| function takes a value and returns a pointer
24558 to where that value can be found in the list. The value is inserted in
24559 the proper place, if necessary.
24560
24561 At the time we need to do these operations, most of \MP's work has been
24562 completed, so we will have plenty of memory to play with. The value nodes
24563 that are allocated for sorting will never be returned to free storage.
24564
24565 @d clear_the_list mp_link(temp_head)=inf_val
24566
24567 @c 
24568 static pointer mp_sort_in (MP mp,scaled v) {
24569   pointer p,q,r; /* list manipulation registers */
24570   p=temp_head;
24571   while (1) { 
24572     q=mp_link(p);
24573     if ( v<=value(q) ) break;
24574     p=q;
24575   }
24576   if ( v<value(q) ) {
24577     r=mp_get_node(mp, value_node_size); value(r)=v; mp_link(r)=q; mp_link(p)=r;
24578   }
24579   return mp_link(p);
24580 }
24581
24582 @ Now we come to the interesting part, where we reduce the list if necessary
24583 until it has the required size. The |min_cover| routine is basic to this
24584 process; it computes the minimum number~|m| such that the values of the
24585 current sorted list can be covered by |m|~intervals of width~|d|. It
24586 also sets the global value |perturbation| to the smallest value $d'>d$
24587 such that the covering found by this algorithm would be different.
24588
24589 In particular, |min_cover(0)| returns the number of distinct values in the
24590 current list and sets |perturbation| to the minimum distance between
24591 adjacent values.
24592
24593 @c 
24594 static integer mp_min_cover (MP mp,scaled d) {
24595   pointer p; /* runs through the current list */
24596   scaled l; /* the least element covered by the current interval */
24597   integer m; /* lower bound on the size of the minimum cover */
24598   m=0; p=mp_link(temp_head); mp->perturbation=el_gordo;
24599   while ( p!=inf_val ){ 
24600     incr(m); l=value(p);
24601     do {  p=mp_link(p); } while (value(p)<=l+d);
24602     if ( value(p)-l<mp->perturbation ) 
24603       mp->perturbation=value(p)-l;
24604   }
24605   return m;
24606 }
24607
24608 @ @<Glob...@>=
24609 scaled perturbation; /* quantity related to \.{TFM} rounding */
24610 integer excess; /* the list is this much too long */
24611
24612 @ The smallest |d| such that a given list can be covered with |m| intervals
24613 is determined by the |threshold| routine, which is sort of an inverse
24614 to |min_cover|. The idea is to increase the interval size rapidly until
24615 finding the range, then to go sequentially until the exact borderline has
24616 been discovered.
24617
24618 @c 
24619 static scaled mp_threshold (MP mp,integer m) {
24620   scaled d; /* lower bound on the smallest interval size */
24621   mp->excess=mp_min_cover(mp, 0)-m;
24622   if ( mp->excess<=0 ) {
24623     return 0;
24624   } else  { 
24625     do {  
24626       d=mp->perturbation;
24627     } while (mp_min_cover(mp, d+d)>m);
24628     while ( mp_min_cover(mp, d)>m ) 
24629       d=mp->perturbation;
24630     return d;
24631   }
24632 }
24633
24634 @ The |skimp| procedure reduces the current list to at most |m| entries,
24635 by changing values if necessary. It also sets |info(p):=k| if |value(p)|
24636 is the |k|th distinct value on the resulting list, and it sets
24637 |perturbation| to the maximum amount by which a |value| field has
24638 been changed. The size of the resulting list is returned as the
24639 value of |skimp|.
24640
24641 @c 
24642 static integer mp_skimp (MP mp,integer m) {
24643   scaled d; /* the size of intervals being coalesced */
24644   pointer p,q,r; /* list manipulation registers */
24645   scaled l; /* the least value in the current interval */
24646   scaled v; /* a compromise value */
24647   d=mp_threshold(mp, m); mp->perturbation=0;
24648   q=temp_head; m=0; p=mp_link(temp_head);
24649   while ( p!=inf_val ) {
24650     incr(m); l=value(p); info(p)=m;
24651     if ( value(mp_link(p))<=l+d ) {
24652       @<Replace an interval of values by its midpoint@>;
24653     }
24654     q=p; p=mp_link(p);
24655   }
24656   return m;
24657 }
24658
24659 @ @<Replace an interval...@>=
24660
24661   do {  
24662     p=mp_link(p); info(p)=m;
24663     decr(mp->excess); if ( mp->excess==0 ) d=0;
24664   } while (value(mp_link(p))<=l+d);
24665   v=l+halfp(value(p)-l);
24666   if ( value(p)-v>mp->perturbation ) 
24667     mp->perturbation=value(p)-v;
24668   r=q;
24669   do {  
24670     r=mp_link(r); value(r)=v;
24671   } while (r!=p);
24672   mp_link(q)=p; /* remove duplicate values from the current list */
24673 }
24674
24675 @ A warning message is issued whenever something is perturbed by
24676 more than 1/16\thinspace pt.
24677
24678 @c 
24679 static void mp_tfm_warning (MP mp,quarterword m) { 
24680   mp_print_nl(mp, "(some "); 
24681   mp_print(mp, mp->int_name[m]);
24682 @.some charwds...@>
24683 @.some chardps...@>
24684 @.some charhts...@>
24685 @.some charics...@>
24686   mp_print(mp, " values had to be adjusted by as much as ");
24687   mp_print_scaled(mp, mp->perturbation); mp_print(mp, "pt)");
24688 }
24689
24690 @ Here's an example of how we use these routines.
24691 The width data needs to be perturbed only if there are 256 distinct
24692 widths, but \MP\ must check for this case even though it is
24693 highly unusual.
24694
24695 An integer variable |k| will be defined when we use this code.
24696 The |dimen_head| array will contain pointers to the sorted
24697 lists of dimensions.
24698
24699 @<Massage the \.{TFM} widths@>=
24700 clear_the_list;
24701 for (k=mp->bc;k<=mp->ec;k++)  {
24702   if ( mp->char_exists[k] )
24703     mp->tfm_width[k]=mp_sort_in(mp, mp->tfm_width[k]);
24704 }
24705 mp->nw=mp_skimp(mp, 255)+1; mp->dimen_head[1]=mp_link(temp_head);
24706 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_wd)
24707
24708 @ @<Glob...@>=
24709 pointer dimen_head[5]; /* lists of \.{TFM} dimensions */
24710
24711 @ Heights, depths, and italic corrections are different from widths
24712 not only because their list length is more severely restricted, but
24713 also because zero values do not need to be put into the lists.
24714
24715 @<Massage the \.{TFM} heights, depths, and italic corrections@>=
24716 clear_the_list;
24717 for (k=mp->bc;k<=mp->ec;k++) {
24718   if ( mp->char_exists[k] ) {
24719     if ( mp->tfm_height[k]==0 ) mp->tfm_height[k]=zero_val;
24720     else mp->tfm_height[k]=mp_sort_in(mp, mp->tfm_height[k]);
24721   }
24722 }
24723 mp->nh=mp_skimp(mp, 15)+1; mp->dimen_head[2]=mp_link(temp_head);
24724 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_ht);
24725 clear_the_list;
24726 for (k=mp->bc;k<=mp->ec;k++) {
24727   if ( mp->char_exists[k] ) {
24728     if ( mp->tfm_depth[k]==0 ) mp->tfm_depth[k]=zero_val;
24729     else mp->tfm_depth[k]=mp_sort_in(mp, mp->tfm_depth[k]);
24730   }
24731 }
24732 mp->nd=mp_skimp(mp, 15)+1; mp->dimen_head[3]=mp_link(temp_head);
24733 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_dp);
24734 clear_the_list;
24735 for (k=mp->bc;k<=mp->ec;k++) {
24736   if ( mp->char_exists[k] ) {
24737     if ( mp->tfm_ital_corr[k]==0 ) mp->tfm_ital_corr[k]=zero_val;
24738     else mp->tfm_ital_corr[k]=mp_sort_in(mp, mp->tfm_ital_corr[k]);
24739   }
24740 }
24741 mp->ni=mp_skimp(mp, 63)+1; mp->dimen_head[4]=mp_link(temp_head);
24742 if ( mp->perturbation>=010000 ) mp_tfm_warning(mp, mp_char_ic)
24743
24744 @ @<Initialize table entries...@>=
24745 value(zero_val)=0; info(zero_val)=0;
24746
24747 @ Bytes 5--8 of the header are set to the design size, unless the user has
24748 some crazy reason for specifying them differently.
24749 @^design size@>
24750
24751 Error messages are not allowed at the time this procedure is called,
24752 so a warning is printed instead.
24753
24754 The value of |max_tfm_dimen| is calculated so that
24755 $$\hbox{|make_scaled(16*max_tfm_dimen,internal[mp_design_size])|}
24756  < \\{three\_bytes}.$$
24757
24758 @d three_bytes 0100000000 /* $2^{24}$ */
24759
24760 @c 
24761 static void mp_fix_design_size (MP mp) {
24762   scaled d; /* the design size */
24763   d=mp->internal[mp_design_size];
24764   if ( (d<unity)||(d>=fraction_half) ) {
24765     if ( d!=0 )
24766       mp_print_nl(mp, "(illegal design size has been changed to 128pt)");
24767 @.illegal design size...@>
24768     d=040000000; mp->internal[mp_design_size]=d;
24769   }
24770   if ( mp->header_byte[4]<0 ) if ( mp->header_byte[5]<0 )
24771     if ( mp->header_byte[6]<0 ) if ( mp->header_byte[7]<0 ) {
24772      mp->header_byte[4]=d / 04000000;
24773      mp->header_byte[5]=(d / 4096) % 256;
24774      mp->header_byte[6]=(d / 16) % 256;
24775      mp->header_byte[7]=(d % 16)*16;
24776   };
24777   mp->max_tfm_dimen=16*mp->internal[mp_design_size]-1-mp->internal[mp_design_size] / 010000000;
24778   if ( mp->max_tfm_dimen>=fraction_half ) mp->max_tfm_dimen=fraction_half-1;
24779 }
24780
24781 @ The |dimen_out| procedure computes a |fix_word| relative to the
24782 design size. If the data was out of range, it is corrected and the
24783 global variable |tfm_changed| is increased by~one.
24784
24785 @c 
24786 static integer mp_dimen_out (MP mp,scaled x) { 
24787   if ( abs(x)>mp->max_tfm_dimen ) {
24788     incr(mp->tfm_changed);
24789     if ( x>0 ) x=mp->max_tfm_dimen; else x=-mp->max_tfm_dimen;
24790   }
24791   x=mp_make_scaled(mp, x*16,mp->internal[mp_design_size]);
24792   return x;
24793 }
24794
24795 @ @<Glob...@>=
24796 scaled max_tfm_dimen; /* bound on widths, heights, kerns, etc. */
24797 integer tfm_changed; /* the number of data entries that were out of bounds */
24798
24799 @ If the user has not specified any of the first four header bytes,
24800 the |fix_check_sum| procedure replaces them by a ``check sum'' computed
24801 from the |tfm_width| data relative to the design size.
24802 @^check sum@>
24803
24804 @c 
24805 static void mp_fix_check_sum (MP mp) {
24806   eight_bits k; /* runs through character codes */
24807   eight_bits B1,B2,B3,B4; /* bytes of the check sum */
24808   integer x;  /* hash value used in check sum computation */
24809   if ( mp->header_byte[0]==0 && mp->header_byte[1]==0 &&
24810        mp->header_byte[2]==0 && mp->header_byte[3]==0 ) {
24811     @<Compute a check sum in |(b1,b2,b3,b4)|@>;
24812     mp->header_byte[0]=(char)B1; mp->header_byte[1]=(char)B2;
24813     mp->header_byte[2]=(char)B3; mp->header_byte[3]=(char)B4; 
24814     return;
24815   }
24816 }
24817
24818 @ @<Compute a check sum in |(b1,b2,b3,b4)|@>=
24819 B1=mp->bc; B2=mp->ec; B3=mp->bc; B4=mp->ec; mp->tfm_changed=0;
24820 for (k=mp->bc;k<=mp->ec;k++) { 
24821   if ( mp->char_exists[k] ) {
24822     x=mp_dimen_out(mp, value(mp->tfm_width[k]))+(k+4)*020000000; /* this is positive */
24823     B1=(eight_bits)((B1+B1+x) % 255);
24824     B2=(eight_bits)((B2+B2+x) % 253);
24825     B3=(eight_bits)((B3+B3+x) % 251);
24826     B4=(eight_bits)((B4+B4+x) % 247);
24827   }
24828 }
24829
24830 @ Finally we're ready to actually write the \.{TFM} information.
24831 Here are some utility routines for this purpose.
24832
24833 @d tfm_out(A) do { /* output one byte to |tfm_file| */
24834   unsigned char s=(unsigned char)(A); 
24835   (mp->write_binary_file)(mp,mp->tfm_file,(void *)&s,1); 
24836   } while (0)
24837
24838 @c 
24839 static void mp_tfm_two (MP mp,integer x) { /* output two bytes to |tfm_file| */
24840   tfm_out(x / 256); tfm_out(x % 256);
24841 }
24842 static void mp_tfm_four (MP mp,integer x) { /* output four bytes to |tfm_file| */
24843   if ( x>=0 ) tfm_out(x / three_bytes);
24844   else { 
24845     x=x+010000000000; /* use two's complement for negative values */
24846     x=x+010000000000;
24847     tfm_out((x / three_bytes) + 128);
24848   };
24849   x=x % three_bytes; tfm_out(x / unity);
24850   x=x % unity; tfm_out(x / 0400);
24851   tfm_out(x % 0400);
24852 }
24853 static void mp_tfm_qqqq (MP mp,four_quarters x) { /* output four quarterwords to |tfm_file| */
24854   tfm_out(qo(x.b0)); tfm_out(qo(x.b1)); 
24855   tfm_out(qo(x.b2)); tfm_out(qo(x.b3));
24856 }
24857
24858 @ @<Finish the \.{TFM} file@>=
24859 if ( mp->job_name==NULL ) mp_open_log_file(mp);
24860 mp_pack_job_name(mp, ".tfm");
24861 while ( ! mp_b_open_out(mp, &mp->tfm_file, mp_filetype_metrics) )
24862   mp_prompt_file_name(mp, "file name for font metrics",".tfm");
24863 mp->metric_file_name=xstrdup(mp->name_of_file);
24864 @<Output the subfile sizes and header bytes@>;
24865 @<Output the character information bytes, then
24866   output the dimensions themselves@>;
24867 @<Output the ligature/kern program@>;
24868 @<Output the extensible character recipes and the font metric parameters@>;
24869   if ( mp->internal[mp_tracing_stats]>0 )
24870   @<Log the subfile sizes of the \.{TFM} file@>;
24871 mp_print_nl(mp, "Font metrics written on "); 
24872 mp_print(mp, mp->metric_file_name); mp_print_char(mp, xord('.'));
24873 @.Font metrics written...@>
24874 (mp->close_file)(mp,mp->tfm_file)
24875
24876 @ Integer variables |lh|, |k|, and |lk_offset| will be defined when we use
24877 this code.
24878
24879 @<Output the subfile sizes and header bytes@>=
24880 k=mp->header_last;
24881 LH=(k+3) / 4; /* this is the number of header words */
24882 if ( mp->bc>mp->ec ) mp->bc=1; /* if there are no characters, |ec=0| and |bc=1| */
24883 @<Compute the ligature/kern program offset and implant the
24884   left boundary label@>;
24885 mp_tfm_two(mp,6+LH+(mp->ec-mp->bc+1)+mp->nw+mp->nh+mp->nd+mp->ni+mp->nl
24886      +lk_offset+mp->nk+mp->ne+mp->np);
24887   /* this is the total number of file words that will be output */
24888 mp_tfm_two(mp, LH); mp_tfm_two(mp, mp->bc); mp_tfm_two(mp, mp->ec); 
24889 mp_tfm_two(mp, mp->nw); mp_tfm_two(mp, mp->nh);
24890 mp_tfm_two(mp, mp->nd); mp_tfm_two(mp, mp->ni); mp_tfm_two(mp, mp->nl+lk_offset); 
24891 mp_tfm_two(mp, mp->nk); mp_tfm_two(mp, mp->ne);
24892 mp_tfm_two(mp, mp->np);
24893 for (k=0;k< 4*LH;k++)   { 
24894   tfm_out(mp->header_byte[k]);
24895 }
24896
24897 @ @<Output the character information bytes...@>=
24898 for (k=mp->bc;k<=mp->ec;k++) {
24899   if ( ! mp->char_exists[k] ) {
24900     mp_tfm_four(mp, 0);
24901   } else { 
24902     tfm_out(info(mp->tfm_width[k])); /* the width index */
24903     tfm_out((info(mp->tfm_height[k]))*16+info(mp->tfm_depth[k]));
24904     tfm_out((info(mp->tfm_ital_corr[k]))*4+mp->char_tag[k]);
24905     tfm_out(mp->char_remainder[k]);
24906   };
24907 }
24908 mp->tfm_changed=0;
24909 for (k=1;k<=4;k++) { 
24910   mp_tfm_four(mp, 0); p=mp->dimen_head[k];
24911   while ( p!=inf_val ) {
24912     mp_tfm_four(mp, mp_dimen_out(mp, value(p))); p=mp_link(p);
24913   }
24914 }
24915
24916
24917 @ We need to output special instructions at the beginning of the
24918 |lig_kern| array in order to specify the right boundary character
24919 and/or to handle starting addresses that exceed 255. The |label_loc|
24920 and |label_char| arrays have been set up to record all the
24921 starting addresses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
24922 \le|label_loc|[|label_ptr]|$.
24923
24924 @<Compute the ligature/kern program offset...@>=
24925 mp->bchar=mp_round_unscaled(mp, mp->internal[mp_boundary_char]);
24926 if ((mp->bchar<0)||(mp->bchar>255))
24927   { mp->bchar=-1; mp->lk_started=false; lk_offset=0; }
24928 else { mp->lk_started=true; lk_offset=1; };
24929 @<Find the minimum |lk_offset| and adjust all remainders@>;
24930 if ( mp->bch_label<undefined_label )
24931   { skip_byte(mp->nl)=qi(255); next_char(mp->nl)=qi(0);
24932   op_byte(mp->nl)=qi(((mp->bch_label+lk_offset)/ 256));
24933   rem_byte(mp->nl)=qi(((mp->bch_label+lk_offset)% 256));
24934   incr(mp->nl); /* possibly |nl=lig_table_size+1| */
24935   }
24936
24937 @ @<Find the minimum |lk_offset|...@>=
24938 k=mp->label_ptr; /* pointer to the largest unallocated label */
24939 if ( mp->label_loc[k]+lk_offset>255 ) {
24940   lk_offset=0; mp->lk_started=false; /* location 0 can do double duty */
24941   do {  
24942     mp->char_remainder[mp->label_char[k]]=lk_offset;
24943     while ( mp->label_loc[k-1]==mp->label_loc[k] ) {
24944        decr(k); mp->char_remainder[mp->label_char[k]]=lk_offset;
24945     }
24946     incr(lk_offset); decr(k);
24947   } while (! (lk_offset+mp->label_loc[k]<256));
24948     /* N.B.: |lk_offset=256| satisfies this when |k=0| */
24949 }
24950 if ( lk_offset>0 ) {
24951   while ( k>0 ) {
24952     mp->char_remainder[mp->label_char[k]]
24953      =mp->char_remainder[mp->label_char[k]]+lk_offset;
24954     decr(k);
24955   }
24956 }
24957
24958 @ @<Output the ligature/kern program@>=
24959 for (k=0;k<= 255;k++ ) {
24960   if ( mp->skip_table[k]<undefined_label ) {
24961      mp_print_nl(mp, "(local label "); mp_print_int(mp, k); mp_print(mp, ":: was missing)");
24962 @.local label l:: was missing@>
24963     cancel_skips(mp->skip_table[k]);
24964   }
24965 }
24966 if ( mp->lk_started ) { /* |lk_offset=1| for the special |bchar| */
24967   tfm_out(255); tfm_out(mp->bchar); mp_tfm_two(mp, 0);
24968 } else {
24969   for (k=1;k<=lk_offset;k++) {/* output the redirection specs */
24970     mp->ll=mp->label_loc[mp->label_ptr];
24971     if ( mp->bchar<0 ) { tfm_out(254); tfm_out(0);   }
24972     else { tfm_out(255); tfm_out(mp->bchar);   };
24973     mp_tfm_two(mp, mp->ll+lk_offset);
24974     do {  
24975       decr(mp->label_ptr);
24976     } while (! (mp->label_loc[mp->label_ptr]<mp->ll));
24977   }
24978 }
24979 for (k=0;k<=mp->nl-1;k++) mp_tfm_qqqq(mp, mp->lig_kern[k]);
24980 for (k=0;k<=mp->nk-1;k++) mp_tfm_four(mp, mp_dimen_out(mp, mp->kern[k]))
24981
24982 @ @<Output the extensible character recipes...@>=
24983 for (k=0;k<=mp->ne-1;k++) 
24984   mp_tfm_qqqq(mp, mp->exten[k]);
24985 for (k=1;k<=mp->np;k++) {
24986   if ( k==1 ) {
24987     if ( abs(mp->param[1])<fraction_half ) {
24988       mp_tfm_four(mp, mp->param[1]*16);
24989     } else  { 
24990       incr(mp->tfm_changed);
24991       if ( mp->param[1]>0 ) mp_tfm_four(mp, el_gordo);
24992       else mp_tfm_four(mp, -el_gordo);
24993     }
24994   } else {
24995     mp_tfm_four(mp, mp_dimen_out(mp, mp->param[k]));
24996   }
24997 }
24998 if ( mp->tfm_changed>0 )  { 
24999   if ( mp->tfm_changed==1 ) mp_print_nl(mp, "(a font metric dimension");
25000 @.a font metric dimension...@>
25001   else  { 
25002     mp_print_nl(mp, "("); mp_print_int(mp, mp->tfm_changed);
25003 @.font metric dimensions...@>
25004     mp_print(mp, " font metric dimensions");
25005   }
25006   mp_print(mp, " had to be decreased)");
25007 }
25008
25009 @ @<Log the subfile sizes of the \.{TFM} file@>=
25010
25011   char s[200];
25012   wlog_ln(" ");
25013   if ( mp->bch_label<undefined_label ) decr(mp->nl);
25014   mp_snprintf(s,128,"(You used %iw,%ih,%id,%ii,%il,%ik,%ie,%ip metric file positions)",
25015                  mp->nw, mp->nh, mp->nd, mp->ni, mp->nl, mp->nk, mp->ne,mp->np);
25016   wlog_ln(s);
25017 }
25018
25019 @* \[43] Reading font metric data.
25020
25021 \MP\ isn't a typesetting program but it does need to find the bounding box
25022 of a sequence of typeset characters.  Thus it needs to read \.{TFM} files as
25023 well as write them.
25024
25025 @<Glob...@>=
25026 void * tfm_infile;
25027
25028 @ All the width, height, and depth information is stored in an array called
25029 |font_info|.  This array is allocated sequentially and each font is stored
25030 as a series of |char_info| words followed by the width, height, and depth
25031 tables.  Since |font_name| entries are permanent, their |str_ref| values are
25032 set to |max_str_ref|.
25033
25034 @<Types...@>=
25035 typedef unsigned int font_number; /* |0..font_max| */
25036
25037 @ The |font_info| array is indexed via a group directory arrays.
25038 For example, the |char_info| data for character~|c| in font~|f| will be
25039 in |font_info[char_base[f]+c].qqqq|.
25040
25041 @<Glob...@>=
25042 font_number font_max; /* maximum font number for included text fonts */
25043 size_t      font_mem_size; /* number of words for \.{TFM} information for text fonts */
25044 memory_word *font_info; /* height, width, and depth data */
25045 char        **font_enc_name; /* encoding names, if any */
25046 boolean     *font_ps_name_fixed; /* are the postscript names fixed already?  */
25047 size_t      next_fmem; /* next unused entry in |font_info| */
25048 font_number last_fnum; /* last font number used so far */
25049 scaled      *font_dsize;  /* 16 times the ``design'' size in \ps\ points */
25050 char        **font_name;  /* name as specified in the \&{infont} command */
25051 char        **font_ps_name;  /* PostScript name for use when |internal[mp_prologues]>0| */
25052 font_number last_ps_fnum; /* last valid |font_ps_name| index */
25053 eight_bits  *font_bc;
25054 eight_bits  *font_ec;  /* first and last character code */
25055 int         *char_base;  /* base address for |char_info| */
25056 int         *width_base; /* index for zeroth character width */
25057 int         *height_base; /* index for zeroth character height */
25058 int         *depth_base; /* index for zeroth character depth */
25059 pointer     *font_sizes;
25060
25061 @ @<Allocate or initialize ...@>=
25062 mp->font_mem_size = 10000; 
25063 mp->font_info = xmalloc ((mp->font_mem_size+1),sizeof(memory_word));
25064 memset (mp->font_info,0,sizeof(memory_word)*(mp->font_mem_size+1));
25065 mp->last_fnum = null_font;
25066
25067 @ @<Dealloc variables@>=
25068 for (k=1;k<=(int)mp->last_fnum;k++) {
25069   xfree(mp->font_enc_name[k]);
25070   xfree(mp->font_name[k]);
25071   xfree(mp->font_ps_name[k]);
25072 }
25073 xfree(mp->font_info);
25074 xfree(mp->font_enc_name);
25075 xfree(mp->font_ps_name_fixed);
25076 xfree(mp->font_dsize);
25077 xfree(mp->font_name);
25078 xfree(mp->font_ps_name);
25079 xfree(mp->font_bc);
25080 xfree(mp->font_ec);
25081 xfree(mp->char_base);
25082 xfree(mp->width_base);
25083 xfree(mp->height_base);
25084 xfree(mp->depth_base);
25085 xfree(mp->font_sizes);
25086
25087
25088 @c 
25089 void mp_reallocate_fonts (MP mp, font_number l) {
25090   font_number f;
25091   XREALLOC(mp->font_enc_name,      l, char *);
25092   XREALLOC(mp->font_ps_name_fixed, l, boolean);
25093   XREALLOC(mp->font_dsize,         l, scaled);
25094   XREALLOC(mp->font_name,          l, char *);
25095   XREALLOC(mp->font_ps_name,       l, char *);
25096   XREALLOC(mp->font_bc,            l, eight_bits);
25097   XREALLOC(mp->font_ec,            l, eight_bits);
25098   XREALLOC(mp->char_base,          l, int);
25099   XREALLOC(mp->width_base,         l, int);
25100   XREALLOC(mp->height_base,        l, int);
25101   XREALLOC(mp->depth_base,         l, int);
25102   XREALLOC(mp->font_sizes,         l, pointer);
25103   for (f=(mp->last_fnum+1);f<=l;f++) {
25104     mp->font_enc_name[f]=NULL;
25105     mp->font_ps_name_fixed[f] = false;
25106     mp->font_name[f]=NULL;
25107     mp->font_ps_name[f]=NULL;
25108     mp->font_sizes[f]=null;
25109   }
25110   mp->font_max = l;
25111 }
25112
25113 @ @<Internal library declarations@>=
25114 void mp_reallocate_fonts (MP mp, font_number l);
25115
25116
25117 @ A |null_font| containing no characters is useful for error recovery.  Its
25118 |font_name| entry starts out empty but is reset each time an erroneous font is
25119 found.  This helps to cut down on the number of duplicate error messages without
25120 wasting a lot of space.
25121
25122 @d null_font 0 /* the |font_number| for an empty font */
25123
25124 @<Set initial...@>=
25125 mp->font_dsize[null_font]=0;
25126 mp->font_bc[null_font]=1;
25127 mp->font_ec[null_font]=0;
25128 mp->char_base[null_font]=0;
25129 mp->width_base[null_font]=0;
25130 mp->height_base[null_font]=0;
25131 mp->depth_base[null_font]=0;
25132 mp->next_fmem=0;
25133 mp->last_fnum=null_font;
25134 mp->last_ps_fnum=null_font;
25135 mp->font_name[null_font]=(char *)"nullfont";
25136 mp->font_ps_name[null_font]=(char *)"";
25137 mp->font_ps_name_fixed[null_font] = false;
25138 mp->font_enc_name[null_font]=NULL;
25139 mp->font_sizes[null_font]=null;
25140
25141 @ Each |char_info| word is of type |four_quarters|.  The |b0| field contains
25142 the |width index|; the |b1| field contains the height
25143 index; the |b2| fields contains the depth index, and the |b3| field used only
25144 for temporary storage. (It is used to keep track of which characters occur in
25145 an edge structure that is being shipped out.)
25146 The corresponding words in the width, height, and depth tables are stored as
25147 |scaled| values in units of \ps\ points.
25148
25149 With the macros below, the |char_info| word for character~|c| in font~|f| is
25150 |char_info(f,c)| and the width is
25151 $$\hbox{|char_width(f,char_info(f,c)).sc|.}$$
25152
25153 @d char_info(A,B) mp->font_info[mp->char_base[(A)]+(B)].qqqq
25154 @d char_width(A,B) mp->font_info[mp->width_base[(A)]+(B).b0].sc
25155 @d char_height(A,B) mp->font_info[mp->height_base[(A)]+(B).b1].sc
25156 @d char_depth(A,B) mp->font_info[mp->depth_base[(A)]+(B).b2].sc
25157 @d ichar_exists(A) ((A).b0>0)
25158
25159 @ When we have a font name and we don't know whether it has been loaded yet,
25160 we scan the |font_name| array before calling |read_font_info|.
25161
25162 @<Declarations@>=
25163 static font_number mp_find_font (MP mp, char *f) ;
25164
25165 @ @c
25166 font_number mp_find_font (MP mp, char *f) {
25167   font_number n;
25168   for (n=0;n<=mp->last_fnum;n++) {
25169     if (mp_xstrcmp(f,mp->font_name[n])==0 ) {
25170       mp_xfree(f);
25171       return n;
25172     }
25173   }
25174   n = mp_read_font_info(mp, f);
25175   mp_xfree(f);
25176   return n;
25177 }
25178
25179 @ This is an interface function for getting the width of character,
25180 as a double in ps units
25181
25182 @c double mp_get_char_dimension (MP mp, char *fname, int c, int t) {
25183   unsigned n;
25184   four_quarters cc;
25185   font_number f = 0;
25186   double w = -1.0;
25187   for (n=0;n<=mp->last_fnum;n++) {
25188     if (mp_xstrcmp(fname,mp->font_name[n])==0 ) {
25189       f = n;
25190       break;
25191     }
25192   }
25193   if (f==0)
25194     return 0.0;
25195   cc = char_info(f,c);
25196   if (! ichar_exists(cc) )
25197     return 0.0;
25198   if (t=='w')
25199     w = (double)char_width(f,cc);
25200   else if (t=='h')
25201     w = (double)char_height(f,cc);
25202   else if (t=='d')
25203     w = (double)char_depth(f,cc);
25204   return w/655.35*(72.27/72);
25205 }
25206
25207 @ @<Exported function ...@>=
25208 double mp_get_char_dimension (MP mp, char *fname, int n, int t);
25209
25210
25211 @ One simple application of |find_font| is the implementation of the |font_size|
25212 operator that gets the design size for a given font name.
25213
25214 @<Find the design size of the font whose name is |cur_exp|@>=
25215 mp_flush_cur_exp(mp, (mp->font_dsize[mp_find_font(mp, str(mp->cur_exp))]+8) / 16)
25216
25217 @ If we discover that the font doesn't have a requested character, we omit it
25218 from the bounding box computation and expect the \ps\ interpreter to drop it.
25219 This routine issues a warning message if the user has asked for it.
25220
25221 @<Declarations@>=
25222 static void mp_lost_warning (MP mp,font_number f, pool_pointer k);
25223
25224 @ @c 
25225 void mp_lost_warning (MP mp,font_number f, pool_pointer k) { 
25226   if ( mp->internal[mp_tracing_lost_chars]>0 ) { 
25227     mp_begin_diagnostic(mp);
25228     if ( mp->selector==log_only ) incr(mp->selector);
25229     mp_print_nl(mp, "Missing character: There is no ");
25230 @.Missing character@>
25231     mp_print_str(mp, mp->str_pool[k]); 
25232     mp_print(mp, " in font ");
25233     mp_print(mp, mp->font_name[f]); mp_print_char(mp, xord('!')); 
25234     mp_end_diagnostic(mp, false);
25235   }
25236 }
25237
25238 @ The whole purpose of saving the height, width, and depth information is to be
25239 able to find the bounding box of an item of text in an edge structure.  The
25240 |set_text_box| procedure takes a text node and adds this information.
25241
25242 @<Declarations@>=
25243 static void mp_set_text_box (MP mp,pointer p); 
25244
25245 @ @c 
25246 void mp_set_text_box (MP mp,pointer p) {
25247   font_number f; /* |font_n(p)| */
25248   ASCII_code bc,ec; /* range of valid characters for font |f| */
25249   pool_pointer k,kk; /* current character and character to stop at */
25250   four_quarters cc; /* the |char_info| for the current character */
25251   scaled h,d; /* dimensions of the current character */
25252   width_val(p)=0;
25253   height_val(p)=-el_gordo;
25254   depth_val(p)=-el_gordo;
25255   f=(font_number)font_n(p);
25256   bc=mp->font_bc[f];
25257   ec=mp->font_ec[f];
25258   kk=str_stop(text_p(p));
25259   k=mp->str_start[text_p(p)];
25260   while ( k<kk ) {
25261     @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>;
25262   }
25263   @<Set the height and depth to zero if the bounding box is empty@>;
25264 }
25265
25266 @ @<Adjust |p|'s bounding box to contain |str_pool[k]|; advance |k|@>=
25267
25268   if ( (mp->str_pool[k]<bc)||(mp->str_pool[k]>ec) ) {
25269     mp_lost_warning(mp, f,k);
25270   } else { 
25271     cc=char_info(f,mp->str_pool[k]);
25272     if ( ! ichar_exists(cc) ) {
25273       mp_lost_warning(mp, f,k);
25274     } else { 
25275       width_val(p)=width_val(p)+char_width(f,cc);
25276       h=char_height(f,cc);
25277       d=char_depth(f,cc);
25278       if ( h>height_val(p) ) height_val(p)=h;
25279       if ( d>depth_val(p) ) depth_val(p)=d;
25280     }
25281   }
25282   incr(k);
25283 }
25284
25285 @ Let's hope modern compilers do comparisons correctly when the difference would
25286 overflow.
25287
25288 @<Set the height and depth to zero if the bounding box is empty@>=
25289 if ( height_val(p)<-depth_val(p) ) { 
25290   height_val(p)=0;
25291   depth_val(p)=0;
25292 }
25293
25294 @ The new primitives fontmapfile and fontmapline.
25295
25296 @<Declare action procedures for use by |do_statement|@>=
25297 static void mp_do_mapfile (MP mp) ;
25298 static void mp_do_mapline (MP mp) ;
25299
25300 @ @c 
25301 static void mp_do_mapfile (MP mp) { 
25302   mp_get_x_next(mp); mp_scan_expression(mp);
25303   if ( mp->cur_type!=mp_string_type ) {
25304     @<Complain about improper map operation@>;
25305   } else {
25306     mp_map_file(mp,mp->cur_exp);
25307   }
25308 }
25309 static void mp_do_mapline (MP mp) { 
25310   mp_get_x_next(mp); mp_scan_expression(mp);
25311   if ( mp->cur_type!=mp_string_type ) {
25312      @<Complain about improper map operation@>;
25313   } else { 
25314      mp_map_line(mp,mp->cur_exp);
25315   }
25316 }
25317
25318 @ @<Complain about improper map operation@>=
25319
25320   exp_err("Unsuitable expression");
25321   help1("Only known strings can be map files or map lines.");
25322   mp_put_get_error(mp);
25323 }
25324
25325 @ To print |scaled| value to PDF output we need some subroutines to ensure
25326 accurary.
25327
25328 @d max_integer   0x7FFFFFFF /* $2^{31}-1$ */
25329
25330 @<Glob...@>=
25331 scaled one_bp; /* scaled value corresponds to 1bp */
25332 scaled one_hundred_bp; /* scaled value corresponds to 100bp */
25333 scaled one_hundred_inch; /* scaled value corresponds to 100in */
25334 integer ten_pow[10]; /* $10^0..10^9$ */
25335 integer scaled_out; /* amount of |scaled| that was taken out in |divide_scaled| */
25336
25337 @ @<Set init...@>=
25338 mp->one_bp = 65782; /* 65781.76 */
25339 mp->one_hundred_bp = 6578176;
25340 mp->one_hundred_inch = 473628672;
25341 mp->ten_pow[0] = 1;
25342 for (i = 1;i<= 9; i++ ) {
25343   mp->ten_pow[i] = 10*mp->ten_pow[i - 1];
25344 }
25345
25346 @ The following function divides |s| by |m|. |dd| is number of decimal digits.
25347
25348 @c scaled mp_divide_scaled (MP mp,scaled s, scaled m, integer  dd) {
25349   scaled q,r;
25350   integer sign,i;
25351   sign = 1;
25352   if ( s < 0 ) { sign = -sign; s = -s; }
25353   if ( m < 0 ) { sign = -sign; m = -m; }
25354   if ( m == 0 )
25355     mp_confusion(mp, "arithmetic: divided by zero");
25356   else if ( m >= (max_integer / 10) )
25357     mp_confusion(mp, "arithmetic: number too big");
25358   q = s / m;
25359   r = s % m;
25360   for (i = 1;i<=dd;i++) {
25361     q = 10*q + (10*r) / m;
25362     r = (10*r) % m;
25363   }
25364   if ( 2*r >= m ) { incr(q); r = r - m; }
25365   mp->scaled_out = sign*(s - (r / mp->ten_pow[dd]));
25366   return (sign*q);
25367 }
25368
25369 @* \[44] Shipping pictures out.
25370 The |ship_out| procedure, to be described below, is given a pointer to
25371 an edge structure. Its mission is to output a file containing the \ps\
25372 description of an edge structure.
25373
25374 @ Each time an edge structure is shipped out we write a new \ps\ output
25375 file named according to the current \&{charcode}.
25376 @:char_code_}{\&{charcode} primitive@>
25377
25378 This is the only backend function that remains in the main |mpost.w| file. 
25379 There are just too many variable accesses needed for status reporting 
25380 etcetera to make it worthwile to move the code to |psout.w|.
25381
25382 @<Internal library declarations@>=
25383 void mp_open_output_file (MP mp) ;
25384
25385 @ @c 
25386 static char *mp_set_output_file_name (MP mp, integer c) {
25387   char *ss = NULL; /* filename extension proposal */  
25388   char *nn = NULL; /* temp string  for str() */
25389   unsigned old_setting; /* previous |selector| setting */
25390   pool_pointer i; /*  indexes into |filename_template|  */
25391   integer cc; /* a temporary integer for template building  */
25392   integer f,g=0; /* field widths */
25393   if ( mp->job_name==NULL ) mp_open_log_file(mp);
25394   if ( mp->filename_template==0 ) {
25395     char *s; /* a file extension derived from |c| */
25396     if ( c<0 ) 
25397       s=xstrdup(".ps");
25398     else 
25399       @<Use |c| to compute the file extension |s|@>;
25400     mp_pack_job_name(mp, s);
25401     free(s);
25402     ss = xstrdup(mp->name_of_file);
25403   } else { /* initializations */
25404     str_number s, n; /* a file extension derived from |c| */
25405     old_setting=mp->selector; 
25406     mp->selector=new_string;
25407     f = 0;
25408     i = mp->str_start[mp->filename_template];
25409     n = null_str; /* initialize */
25410     while ( i<str_stop(mp->filename_template) ) {
25411        if ( mp->str_pool[i]=='%' ) {
25412       CONTINUE:
25413         incr(i);
25414         if ( i<str_stop(mp->filename_template) ) {
25415           if ( mp->str_pool[i]=='j' ) {
25416             mp_print(mp, mp->job_name);
25417           } else if ( mp->str_pool[i]=='d' ) {
25418              cc= mp_round_unscaled(mp, mp->internal[mp_day]);
25419              print_with_leading_zeroes(cc);
25420           } else if ( mp->str_pool[i]=='m' ) {
25421              cc= mp_round_unscaled(mp, mp->internal[mp_month]);
25422              print_with_leading_zeroes(cc);
25423           } else if ( mp->str_pool[i]=='y' ) {
25424              cc= mp_round_unscaled(mp, mp->internal[mp_year]);
25425              print_with_leading_zeroes(cc);
25426           } else if ( mp->str_pool[i]=='H' ) {
25427              cc= mp_round_unscaled(mp, mp->internal[mp_time]) / 60;
25428              print_with_leading_zeroes(cc);
25429           }  else if ( mp->str_pool[i]=='M' ) {
25430              cc= mp_round_unscaled(mp, mp->internal[mp_time]) % 60;
25431              print_with_leading_zeroes(cc);
25432           } else if ( mp->str_pool[i]=='c' ) {
25433             if ( c<0 ) mp_print(mp, "ps");
25434             else print_with_leading_zeroes(c);
25435           } else if ( (mp->str_pool[i]>='0') && 
25436                       (mp->str_pool[i]<='9') ) {
25437             if ( (f<10)  )
25438               f = (f*10) + mp->str_pool[i]-'0';
25439             goto CONTINUE;
25440           } else {
25441             mp_print_str(mp, mp->str_pool[i]);
25442           }
25443         }
25444       } else {
25445         if ( mp->str_pool[i]=='.' )
25446           if (length(n)==0)
25447             n = mp_make_string(mp);
25448         mp_print_str(mp, mp->str_pool[i]);
25449       };
25450       incr(i);
25451     }
25452     s = mp_make_string(mp);
25453     mp->selector= old_setting;
25454     if (length(n)==0) {
25455        n=s;
25456        s=null_str;
25457     }
25458     ss = str(s);
25459     nn = str(n);
25460     mp_pack_file_name(mp, nn,"",ss);
25461     free(nn);
25462     delete_str_ref(n);
25463     delete_str_ref(s);
25464   }
25465   return ss;
25466 }
25467
25468 static char * mp_get_output_file_name (MP mp) {
25469   char *f;
25470   char *saved_name;  /* saved |name_of_file| */
25471   saved_name = xstrdup(mp->name_of_file);
25472   f = xstrdup(mp_set_output_file_name(mp, mp_round_unscaled(mp, mp->internal[mp_char_code])));
25473   mp_pack_file_name(mp, saved_name,NULL,NULL);
25474   free(saved_name);
25475   return f;
25476 }
25477
25478 void mp_open_output_file (MP mp) {
25479   char *ss; /* filename extension proposal */
25480   integer c; /* \&{charcode} rounded to the nearest integer */
25481   c=mp_round_unscaled(mp, mp->internal[mp_char_code]);
25482   ss = mp_set_output_file_name(mp, c);
25483   while ( ! mp_a_open_out(mp, (void *)&mp->ps_file, mp_filetype_postscript) )
25484     mp_prompt_file_name(mp, "file name for output",ss);
25485   xfree(ss);
25486   @<Store the true output file name if appropriate@>;
25487 }
25488
25489 @ The file extension created here could be up to five characters long in
25490 extreme cases so it may have to be shortened on some systems.
25491 @^system dependencies@>
25492
25493 @<Use |c| to compute the file extension |s|@>=
25494
25495   s = xmalloc(7,1);
25496   mp_snprintf(s,7,".%i",(int)c);
25497 }
25498
25499 @ The user won't want to see all the output file names so we only save the
25500 first and last ones and a count of how many there were.  For this purpose
25501 files are ordered primarily by \&{charcode} and secondarily by order of
25502 creation.
25503 @:char_code_}{\&{charcode} primitive@>
25504
25505 @<Store the true output file name if appropriate@>=
25506 if ((c<mp->first_output_code)&&(mp->first_output_code>=0)) {
25507   mp->first_output_code=c;
25508   xfree(mp->first_file_name);
25509   mp->first_file_name=xstrdup(mp->name_of_file);
25510 }
25511 if ( c>=mp->last_output_code ) {
25512   mp->last_output_code=c;
25513   xfree(mp->last_file_name);
25514   mp->last_file_name=xstrdup(mp->name_of_file);
25515 }
25516
25517 @ @<Glob...@>=
25518 char * first_file_name;
25519 char * last_file_name; /* full file names */
25520 integer first_output_code;integer last_output_code; /* rounded \&{charcode} values */
25521 @:char_code_}{\&{charcode} primitive@>
25522 integer total_shipped; /* total number of |ship_out| operations completed */
25523
25524 @ @<Set init...@>=
25525 mp->first_file_name=xstrdup("");
25526 mp->last_file_name=xstrdup("");
25527 mp->first_output_code=32768;
25528 mp->last_output_code=-32768;
25529 mp->total_shipped=0;
25530
25531 @ @<Dealloc variables@>=
25532 xfree(mp->first_file_name);
25533 xfree(mp->last_file_name);
25534
25535 @ @<Begin the progress report for the output of picture~|c|@>=
25536 if ( (int)mp->term_offset>mp->max_print_line-6 ) mp_print_ln(mp);
25537 else if ( (mp->term_offset>0)||(mp->file_offset>0) ) mp_print_char(mp, xord(' '));
25538 mp_print_char(mp, xord('['));
25539 if ( c>=0 ) mp_print_int(mp, c)
25540
25541 @ @<End progress report@>=
25542 mp_print_char(mp, xord(']'));
25543 update_terminal;
25544 incr(mp->total_shipped)
25545
25546 @ @<Explain what output files were written@>=
25547 if ( mp->total_shipped>0 ) { 
25548   mp_print_nl(mp, "");
25549   mp_print_int(mp, mp->total_shipped);
25550   if (mp->noninteractive) {
25551     mp_print(mp, " figure");
25552     if ( mp->total_shipped>1 ) mp_print_char(mp, xord('s'));
25553     mp_print(mp, " created.");
25554   } else {
25555     mp_print(mp, " output file");
25556     if ( mp->total_shipped>1 ) mp_print_char(mp, xord('s'));
25557     mp_print(mp, " written: ");
25558     mp_print(mp, mp->first_file_name);
25559     if ( mp->total_shipped>1 ) {
25560       if ( 31+strlen(mp->first_file_name)+
25561          strlen(mp->last_file_name)> (unsigned)mp->max_print_line) 
25562         mp_print_ln(mp);
25563       mp_print(mp, " .. ");
25564       mp_print(mp, mp->last_file_name);
25565     }
25566   }
25567 }
25568
25569 @ @<Internal library declarations@>=
25570 boolean mp_has_font_size(MP mp, font_number f );
25571
25572 @ @c 
25573 boolean mp_has_font_size(MP mp, font_number f ) {
25574   return (mp->font_sizes[f]!=null);
25575 }
25576
25577 @ The \&{special} command saves up lines of text to be printed during the next
25578 |ship_out| operation.  The saved items are stored as a list of capsule tokens.
25579
25580 @<Glob...@>=
25581 pointer last_pending; /* the last token in a list of pending specials */
25582
25583 @ @<Set init...@>=
25584 mp->last_pending=spec_head;
25585
25586 @ @<Cases of |do_statement|...@>=
25587 case special_command: 
25588   if ( mp->cur_mod==0 ) mp_do_special(mp); else 
25589   if ( mp->cur_mod==1 ) mp_do_mapfile(mp); else 
25590   mp_do_mapline(mp);
25591   break;
25592
25593 @ @<Declare action procedures for use by |do_statement|@>=
25594 static void mp_do_special (MP mp) ;
25595
25596 @ @c void mp_do_special (MP mp) { 
25597   mp_get_x_next(mp); mp_scan_expression(mp);
25598   if ( mp->cur_type!=mp_string_type ) {
25599     @<Complain about improper special operation@>;
25600   } else { 
25601     mp_link(mp->last_pending)=mp_stash_cur_exp(mp);
25602     mp->last_pending=mp_link(mp->last_pending);
25603     mp_link(mp->last_pending)=null;
25604   }
25605 }
25606
25607 @ @<Complain about improper special operation@>=
25608
25609   exp_err("Unsuitable expression");
25610   help1("Only known strings are allowed for output as specials.");
25611   mp_put_get_error(mp);
25612 }
25613
25614 @ On the export side, we need an extra object type for special strings.
25615
25616 @<Graphical object codes@>=
25617 mp_special_code=8, 
25618
25619 @ @<Export pending specials@>=
25620 p=mp_link(spec_head);
25621 while ( p!=null ) {
25622   mp_special_object *tp;
25623   tp = (mp_special_object *)mp_new_graphic_object(mp,mp_special_code);  
25624   gr_pre_script(tp)  = str(value(p));
25625   if (hh->body==NULL) hh->body = (mp_graphic_object *)tp; 
25626   else gr_link(hp) = (mp_graphic_object *)tp;
25627   hp = (mp_graphic_object *)tp;
25628   p=mp_link(p);
25629 }
25630 mp_flush_token_list(mp, mp_link(spec_head));
25631 mp_link(spec_head)=null;
25632 mp->last_pending=spec_head
25633
25634 @ We are now ready for the main output procedure.  Note that the |selector|
25635 setting is saved in a global variable so that |begin_diagnostic| can access it.
25636
25637 @<Declare the \ps\ output procedures@>=
25638 static void mp_ship_out (MP mp, pointer h) ;
25639
25640 @ Once again, the |gr_XXXX| macros are defined in |mppsout.h|
25641
25642 @d export_color(q,p) 
25643   if ( color_model(p)==mp_uninitialized_model ) {
25644     gr_color_model(q)  = (unsigned char)(mp->internal[mp_default_color_model]/65536);
25645     gr_cyan_val(q)     = 0;
25646         gr_magenta_val(q)  = 0;
25647         gr_yellow_val(q)   = 0;
25648         gr_black_val(q)    = (gr_color_model(q)==mp_cmyk_model ? unity : 0);
25649   } else {
25650     gr_color_model(q)  = (unsigned char)color_model(p);
25651     gr_cyan_val(q)     = cyan_val(p);
25652     gr_magenta_val(q)  = magenta_val(p);
25653     gr_yellow_val(q)   = yellow_val(p);
25654     gr_black_val(q)    = black_val(p);
25655   }
25656
25657 @d export_scripts(q,p)
25658   if (pre_script(p)!=null)  gr_pre_script(q)   = str(pre_script(p));
25659   if (post_script(p)!=null) gr_post_script(q)  = str(post_script(p));
25660
25661 @c
25662 struct mp_edge_object *mp_gr_export(MP mp, pointer h) {
25663   pointer p; /* the current graphical object */
25664   integer t; /* a temporary value */
25665   integer c; /* a rounded charcode */
25666   scaled d_width; /* the current pen width */
25667   mp_edge_object *hh; /* the first graphical object */
25668   mp_graphic_object *hq; /* something |hp| points to  */
25669   mp_text_object    *tt;
25670   mp_fill_object    *tf;
25671   mp_stroked_object *ts;
25672   mp_clip_object    *tc;
25673   mp_bounds_object  *tb;
25674   mp_graphic_object *hp = NULL; /* the current graphical object */
25675   mp_set_bbox(mp, h, true);
25676   hh = xmalloc(1,sizeof(mp_edge_object));
25677   hh->body = NULL;
25678   hh->_next = NULL;
25679   hh->_parent = mp;
25680   hh->_minx = minx_val(h);
25681   hh->_miny = miny_val(h);
25682   hh->_maxx = maxx_val(h);
25683   hh->_maxy = maxy_val(h);
25684   hh->_filename = mp_get_output_file_name(mp);
25685   c = mp_round_unscaled(mp,mp->internal[mp_char_code]);
25686   hh->_charcode = c;
25687   hh->_width = mp->internal[mp_char_wd];
25688   hh->_height = mp->internal[mp_char_ht];
25689   hh->_depth = mp->internal[mp_char_dp];
25690   hh->_ital_corr = mp->internal[mp_char_ic];
25691   @<Export pending specials@>;
25692   p=mp_link(dummy_loc(h));
25693   while ( p!=null ) { 
25694     hq = mp_new_graphic_object(mp,type(p));
25695     switch (type(p)) {
25696     case mp_fill_code:
25697       tf = (mp_fill_object *)hq;
25698       gr_pen_p(tf)        = mp_export_knot_list(mp,pen_p(p));
25699       d_width = mp_get_pen_scale(mp, pen_p(p));
25700       if ((pen_p(p)==null) || pen_is_elliptical(pen_p(p)))  {
25701             gr_path_p(tf)       = mp_export_knot_list(mp,path_p(p));
25702       } else {
25703         pointer pc, pp;
25704         pc = mp_copy_path(mp, path_p(p));
25705         pp = mp_make_envelope(mp, pc, pen_p(p),ljoin_val(p),0,miterlim_val(p));
25706         gr_path_p(tf)       = mp_export_knot_list(mp,pp);
25707         mp_toss_knot_list(mp, pp);
25708         pc = mp_htap_ypoc(mp, path_p(p));
25709         pp = mp_make_envelope(mp, pc, pen_p(p),ljoin_val(p),0,miterlim_val(p));
25710         gr_htap_p(tf)       = mp_export_knot_list(mp,pp);
25711         mp_toss_knot_list(mp, pp);
25712       }
25713       export_color(tf,p) ;
25714       export_scripts(tf,p);
25715       gr_ljoin_val(tf)    = (unsigned char)ljoin_val(p);
25716       gr_miterlim_val(tf) = miterlim_val(p);
25717       break;
25718     case mp_stroked_code:
25719       ts = (mp_stroked_object *)hq;
25720       gr_pen_p(ts)        = mp_export_knot_list(mp,pen_p(p));
25721       d_width = mp_get_pen_scale(mp, pen_p(p));
25722       if (pen_is_elliptical(pen_p(p)))  {
25723               gr_path_p(ts)       = mp_export_knot_list(mp,path_p(p));
25724       } else {
25725         pointer pc;
25726         pc=mp_copy_path(mp, path_p(p));
25727         t=lcap_val(p);
25728         if ( left_type(pc)!=mp_endpoint ) { 
25729           left_type(mp_insert_knot(mp, pc,x_coord(pc),y_coord(pc)))=mp_endpoint;
25730           right_type(pc)=mp_endpoint;
25731           pc=mp_link(pc);
25732           t=1;
25733         }
25734         pc=mp_make_envelope(mp,pc,pen_p(p),ljoin_val(p),t,miterlim_val(p));
25735         gr_path_p(ts)       = mp_export_knot_list(mp,pc);
25736         mp_toss_knot_list(mp, pc);
25737       }
25738       export_color(ts,p) ;
25739       export_scripts(ts,p);
25740       gr_ljoin_val(ts)    = (unsigned char)ljoin_val(p);
25741       gr_miterlim_val(ts) = miterlim_val(p);
25742       gr_lcap_val(ts)     = (unsigned char)lcap_val(p);
25743       gr_dash_p(ts)       = mp_export_dashes(mp,p,&d_width);
25744       break;
25745     case mp_text_code:
25746       tt = (mp_text_object *)hq;
25747       gr_text_p(tt)       = str(text_p(p));
25748       gr_font_n(tt)       = (unsigned int)font_n(p);
25749       gr_font_name(tt)    = mp_xstrdup(mp,mp->font_name[font_n(p)]);
25750       gr_font_dsize(tt)   = (unsigned int)mp->font_dsize[font_n(p)];
25751       export_color(tt,p) ;
25752       export_scripts(tt,p);
25753       gr_width_val(tt)    = width_val(p);
25754       gr_height_val(tt)   = height_val(p);
25755       gr_depth_val(tt)    = depth_val(p);
25756       gr_tx_val(tt)       = tx_val(p);
25757       gr_ty_val(tt)       = ty_val(p);
25758       gr_txx_val(tt)      = txx_val(p);
25759       gr_txy_val(tt)      = txy_val(p);
25760       gr_tyx_val(tt)      = tyx_val(p);
25761       gr_tyy_val(tt)      = tyy_val(p);
25762       break;
25763     case mp_start_clip_code: 
25764       tc = (mp_clip_object *)hq;
25765       gr_path_p(tc) = mp_export_knot_list(mp,path_p(p));
25766       break;
25767     case mp_start_bounds_code:
25768       tb = (mp_bounds_object *)hq;
25769       gr_path_p(tb) = mp_export_knot_list(mp,path_p(p));
25770       break;
25771     case mp_stop_clip_code: 
25772     case mp_stop_bounds_code:
25773       /* nothing to do here */
25774       break;
25775     } 
25776     if (hh->body==NULL) hh->body=hq; else  gr_link(hp) = hq;
25777     hp = hq;
25778     p=mp_link(p);
25779   }
25780   return hh;
25781 }
25782
25783 @ @<Declarations@>=
25784 static struct mp_edge_object *mp_gr_export(MP mp, int h);
25785
25786 @ This function is now nearly trivial.
25787
25788 @c
25789 void mp_ship_out (MP mp, pointer h) { /* output edge structure |h| */
25790   integer c; /* \&{charcode} rounded to the nearest integer */
25791   c=mp_round_unscaled(mp, mp->internal[mp_char_code]);
25792   @<Begin the progress report for the output of picture~|c|@>;
25793   (mp->shipout_backend) (mp, h);
25794   @<End progress report@>;
25795   if ( mp->internal[mp_tracing_output]>0 ) 
25796    mp_print_edges(mp, h," (just shipped out)",true);
25797 }
25798
25799 @ @<Declarations@>=
25800 static void mp_shipout_backend (MP mp, pointer h);
25801
25802 @ @c
25803 void mp_shipout_backend (MP mp, pointer h) {
25804   mp_edge_object *hh; /* the first graphical object */
25805   hh = mp_gr_export(mp,h);
25806   (void)mp_gr_ship_out (hh,
25807                  (mp->internal[mp_prologues]/65536),
25808                  (mp->internal[mp_procset]/65536), 
25809                  false);
25810   mp_gr_toss_objects(hh);
25811 }
25812
25813 @ @<Exported types@>=
25814 typedef void (*mp_backend_writer)(MP, int);
25815
25816 @ @<Option variables@>=
25817 mp_backend_writer shipout_backend;
25818
25819 @ Now that we've finished |ship_out|, let's look at the other commands
25820 by which a user can send things to the \.{GF} file.
25821
25822 @ @<Determine if a character has been shipped out@>=
25823
25824   mp->cur_exp=mp_round_unscaled(mp, mp->cur_exp) % 256;
25825   if ( mp->cur_exp<0 ) mp->cur_exp=mp->cur_exp+256;
25826   boolean_reset(mp->char_exists[mp->cur_exp]);
25827   mp->cur_type=mp_boolean_type;
25828 }
25829
25830 @ @<Glob...@>=
25831 psout_data ps;
25832
25833 @ @<Allocate or initialize ...@>=
25834 mp_backend_initialize(mp);
25835
25836 @ @<Dealloc...@>=
25837 mp_backend_free(mp);
25838
25839
25840 @* \[45] Dumping and undumping the tables.
25841 After \.{INIMP} has seen a collection of macros, it
25842 can write all the necessary information on an auxiliary file so
25843 that production versions of \MP\ are able to initialize their
25844 memory at high speed. The present section of the program takes
25845 care of such output and input. We shall consider simultaneously
25846 the processes of storing and restoring,
25847 so that the inverse relation between them is clear.
25848 @.INIMP@>
25849
25850 The global variable |mem_ident| is a string that is printed right
25851 after the |banner| line when \MP\ is ready to start. For \.{INIMP} this
25852 string says simply `\.{(INIMP)}'; for other versions of \MP\ it says,
25853 for example, `\.{(mem=plain 1990.4.14)}', showing the year,
25854 month, and day that the mem file was created. We have |mem_ident=0|
25855 before \MP's tables are loaded.
25856
25857 @<Glob...@>=
25858 char * mem_ident;
25859
25860 @ @<Set init...@>=
25861 mp->mem_ident=NULL;
25862
25863 @ @<Initialize table entries...@>=
25864 mp->mem_ident=xstrdup(" (INIMP)");
25865
25866 @ @<Declare act...@>=
25867 static void mp_store_mem_file (MP mp) ;
25868
25869 @ @c void mp_store_mem_file (MP mp) {
25870   integer k;  /* all-purpose index */
25871   pointer p,q; /* all-purpose pointers */
25872   integer x; /* something to dump */
25873   four_quarters w; /* four ASCII codes */
25874   memory_word WW;
25875   @<Create the |mem_ident|, open the mem file,
25876     and inform the user that dumping has begun@>;
25877   @<Dump constants for consistency check@>;
25878   @<Dump the string pool@>;
25879   @<Dump the dynamic memory@>;
25880   @<Dump the table of equivalents and the hash table@>;
25881   @<Dump a few more things and the closing check word@>;
25882   @<Close the mem file@>;
25883 }
25884
25885 @ Corresponding to the procedure that dumps a mem file, we also have a function
25886 that reads~one~in. The function returns |false| if the dumped mem is
25887 incompatible with the present \MP\ table sizes, etc.
25888
25889 @d too_small(A) { wake_up_terminal;
25890   wterm_ln("---! Must increase the "); wterm((A));
25891 @.Must increase the x@>
25892   goto OFF_BASE;
25893   }
25894
25895 @c 
25896 boolean mp_load_mem_file (MP mp) {
25897   integer k; /* all-purpose index */
25898   pointer p,q; /* all-purpose pointers */
25899   integer x; /* something undumped */
25900   str_number s; /* some temporary string */
25901   four_quarters w; /* four ASCII codes */
25902   memory_word WW;
25903   /* |@<Undump constants for consistency check@>;|  read earlier */
25904   @<Undump the string pool@>;
25905   @<Undump the dynamic memory@>;
25906   @<Undump the table of equivalents and the hash table@>;
25907   @<Undump a few more things and the closing check word@>;
25908   return true; /* it worked! */
25909 OFF_BASE: 
25910   wake_up_terminal;
25911   wterm_ln("(Fatal mem file error; I'm stymied)\n");
25912 @.Fatal mem file error@>
25913    return false;
25914 }
25915
25916 @ @<Declarations@>=
25917 static boolean mp_load_mem_file (MP mp) ;
25918
25919 @ Mem files consist of |memory_word| items, and we use the following
25920 macros to dump words of different types:
25921
25922 @d dump_wd(A)   { WW=(A);       (mp->write_binary_file)(mp,mp->mem_file,&WW,sizeof(WW)); }
25923 @d dump_int(A)  { int cint=(A); (mp->write_binary_file)(mp,mp->mem_file,&cint,sizeof(cint)); }
25924 @d dump_hh(A)   { WW.hh=(A);    (mp->write_binary_file)(mp,mp->mem_file,&WW,sizeof(WW)); }
25925 @d dump_qqqq(A) { WW.qqqq=(A);  (mp->write_binary_file)(mp,mp->mem_file,&WW,sizeof(WW)); }
25926 @d dump_string(A) { dump_int((int)(strlen(A)+1));
25927                     (mp->write_binary_file)(mp,mp->mem_file,A,strlen(A)+1); }
25928
25929 @<Glob...@>=
25930 void * mem_file; /* for input or output of mem information */
25931
25932 @ The inverse macros are slightly more complicated, since we need to check
25933 the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
25934 read an integer value |x| that is supposed to be in the range |a<=x<=b|.
25935
25936 @d mgeti(A) do {
25937   size_t wanted = sizeof(A);
25938   void *A_ptr = &A;
25939   (mp->read_binary_file)(mp, mp->mem_file,&A_ptr,&wanted);
25940   if (wanted!=sizeof(A)) goto OFF_BASE;
25941 } while (0)
25942
25943 @d mgetw(A) do {
25944   size_t wanted = sizeof(A);
25945   void *A_ptr = &A;
25946   (mp->read_binary_file)(mp, mp->mem_file,&A_ptr,&wanted);
25947   if (wanted!=sizeof(A)) goto OFF_BASE;
25948 } while (0)
25949
25950 @d undump_wd(A)   { mgetw(WW); A=WW; }
25951 @d undump_int(A)  { int cint; mgeti(cint); A=cint; }
25952 @d undump_hh(A)   { mgetw(WW); A=WW.hh; }
25953 @d undump_qqqq(A) { mgetw(WW); A=WW.qqqq; }
25954 @d undump_strings(A,B,C) { 
25955    undump_int(x); if ( (x<(A)) || (x>(B)) ) goto OFF_BASE; else C=str(x); }
25956 @d undump(A,B,C) { undump_int(x); 
25957                    if ( (x<(A)) || (x>(int)(B)) ) goto OFF_BASE; else C=x; }
25958 @d undump_size(A,B,C,D) { undump_int(x);
25959                           if (x<(A)) goto OFF_BASE; 
25960                           if (x>(B)) too_small((C)); else D=x; }
25961 @d undump_string(A) { 
25962   size_t the_wanted; 
25963   void *the_string;
25964   integer XX=0; 
25965   undump_int(XX);
25966   the_wanted = (size_t)XX;
25967   the_string = xmalloc(XX,1);
25968   (mp->read_binary_file)(mp,mp->mem_file,&the_string,&the_wanted);
25969   A = (char *)the_string;
25970   if (the_wanted!=(size_t)XX) goto OFF_BASE;
25971 }
25972
25973 @ The next few sections of the program should make it clear how we use the
25974 dump/undump macros.
25975
25976 @<Dump constants for consistency check@>=
25977 dump_int(mp->mem_top);
25978 dump_int((integer)mp->hash_size);
25979 dump_int(mp->hash_prime)
25980 dump_int(mp->param_size);
25981 dump_int(mp->max_in_open);
25982
25983 @ Sections of a \.{WEB} program that are ``commented out'' still contribute
25984 strings to the string pool; therefore \.{INIMP} and \MP\ will have
25985 the same strings. (And it is, of course, a good thing that they do.)
25986 @.WEB@>
25987 @^string pool@>
25988
25989 @<Undump constants for consistency check@>=
25990 undump_int(x); mp->mem_top = x;
25991 undump_int(x); mp->hash_size = (unsigned)x;
25992 undump_int(x); mp->hash_prime = x;
25993 undump_int(x); mp->param_size = x;
25994 undump_int(x); mp->max_in_open = x;
25995
25996 @ We do string pool compaction to avoid dumping unused strings.
25997
25998 @d dump_four_ASCII 
25999   w.b0=qi(mp->str_pool[k]); w.b1=qi(mp->str_pool[k+1]);
26000   w.b2=qi(mp->str_pool[k+2]); w.b3=qi(mp->str_pool[k+3]);
26001   dump_qqqq(w)
26002
26003 @<Dump the string pool@>=
26004 mp_do_compaction(mp, mp->pool_size);
26005 dump_int(mp->pool_ptr);
26006 dump_int(mp->max_str_ptr);
26007 dump_int(mp->str_ptr);
26008 k=0;
26009 while ( (mp->next_str[k]==k+1) && (k<=mp->max_str_ptr) ) 
26010   k++;
26011 dump_int(k);
26012 while ( k<=mp->max_str_ptr ) { 
26013   dump_int(mp->next_str[k]); incr(k);
26014 }
26015 k=0;
26016 while (1)  { 
26017   dump_int(mp->str_start[k]); /* TODO: valgrind warning here */
26018   if ( k==mp->str_ptr ) {
26019     break;
26020   } else { 
26021     k=mp->next_str[k]; 
26022   }
26023 }
26024 k=0;
26025 while (k+4<mp->pool_ptr ) { 
26026   dump_four_ASCII; k=k+4; 
26027 }
26028 k=mp->pool_ptr-4; dump_four_ASCII;
26029 mp_print_ln(mp); mp_print(mp, "at most "); mp_print_int(mp, mp->max_str_ptr);
26030 mp_print(mp, " strings of total length ");
26031 mp_print_int(mp, mp->pool_ptr)
26032
26033 @ @d undump_four_ASCII 
26034   undump_qqqq(w);
26035   mp->str_pool[k]=(ASCII_code)qo(w.b0); mp->str_pool[k+1]=(ASCII_code)qo(w.b1);
26036   mp->str_pool[k+2]=(ASCII_code)qo(w.b2); mp->str_pool[k+3]=(ASCII_code)qo(w.b3)
26037
26038 @<Undump the string pool@>=
26039 undump_int(mp->pool_ptr);
26040 mp_reallocate_pool(mp, mp->pool_ptr) ;
26041 undump_int(mp->max_str_ptr);
26042 mp_reallocate_strings (mp,mp->max_str_ptr) ;
26043 undump(0,mp->max_str_ptr,mp->str_ptr);
26044 undump(0,mp->max_str_ptr+1,s);
26045 for (k=0;k<=s-1;k++) 
26046   mp->next_str[k]=k+1;
26047 for (k=s;k<=mp->max_str_ptr;k++) 
26048   undump(s+1,mp->max_str_ptr+1,mp->next_str[k]);
26049 mp->fixed_str_use=0;
26050 k=0;
26051 while (1) { 
26052   undump(0,mp->pool_ptr,mp->str_start[k]);
26053   if ( k==mp->str_ptr ) break;
26054   mp->str_ref[k]=max_str_ref;
26055   incr(mp->fixed_str_use);
26056   mp->last_fixed_str=k; k=mp->next_str[k];
26057 }
26058 k=0;
26059 while ( k+4<mp->pool_ptr ) { 
26060   undump_four_ASCII; k=k+4;
26061 }
26062 k=mp->pool_ptr-4; undump_four_ASCII;
26063 mp->init_str_use=mp->fixed_str_use; mp->init_pool_ptr=mp->pool_ptr;
26064 mp->max_pool_ptr=mp->pool_ptr;
26065 mp->strs_used_up=mp->fixed_str_use;
26066 mp->pool_in_use=mp->str_start[mp->str_ptr]; mp->strs_in_use=mp->fixed_str_use;
26067 mp->max_pl_used=mp->pool_in_use; mp->max_strs_used=mp->strs_in_use;
26068 mp->pact_count=0; mp->pact_chars=0; mp->pact_strs=0;
26069
26070 @ By sorting the list of available spaces in the variable-size portion of
26071 |mem|, we are usually able to get by without having to dump very much
26072 of the dynamic memory.
26073
26074 We recompute |var_used| and |dyn_used|, so that \.{INIMP} dumps valid
26075 information even when it has not been gathering statistics.
26076
26077 @<Dump the dynamic memory@>=
26078 mp_sort_avail(mp); mp->var_used=0;
26079 dump_int(mp->lo_mem_max); dump_int(mp->rover);
26080 p=0; q=mp->rover; x=0;
26081 do {  
26082   for (k=p;k<= q+1;k++) 
26083     dump_wd(mp->mem[k]);
26084   x=x+q+2-p; mp->var_used=mp->var_used+q-p;
26085   p=q+node_size(q); q=rmp_link(q);
26086 } while (q!=mp->rover);
26087 mp->var_used=mp->var_used+mp->lo_mem_max-p; 
26088 mp->dyn_used=mp->mem_end+1-mp->hi_mem_min;
26089 for (k=p;k<= mp->lo_mem_max;k++ ) 
26090   dump_wd(mp->mem[k]);
26091 x=x+mp->lo_mem_max+1-p;
26092 dump_int(mp->hi_mem_min); dump_int(mp->avail);
26093 for (k=mp->hi_mem_min;k<=mp->mem_end;k++ ) 
26094   dump_wd(mp->mem[k]);
26095 x=x+mp->mem_end+1-mp->hi_mem_min;
26096 p=mp->avail;
26097 while ( p!=null ) { 
26098   decr(mp->dyn_used); p=mp_link(p);
26099 }
26100 dump_int(mp->var_used); dump_int(mp->dyn_used);
26101 mp_print_ln(mp); mp_print_int(mp, x);
26102 mp_print(mp, " memory locations dumped; current usage is ");
26103 mp_print_int(mp, mp->var_used); mp_print_char(mp, xord('&')); mp_print_int(mp, mp->dyn_used)
26104
26105 @ @<Undump the dynamic memory@>=
26106 undump(lo_mem_stat_max+1000,hi_mem_stat_min-1,mp->lo_mem_max);
26107 undump(lo_mem_stat_max+1,mp->lo_mem_max,mp->rover);
26108 p=0; q=mp->rover;
26109 do {  
26110   for (k=p;k<= q+1; k++) 
26111     undump_wd(mp->mem[k]);
26112   p=q+node_size(q);
26113   if ( (p>mp->lo_mem_max)||((q>=rmp_link(q))&&(rmp_link(q)!=mp->rover)) ) 
26114     goto OFF_BASE;
26115   q=rmp_link(q);
26116 } while (q!=mp->rover);
26117 for (k=p;k<=mp->lo_mem_max;k++ ) 
26118   undump_wd(mp->mem[k]);
26119 undump(mp->lo_mem_max+1,hi_mem_stat_min,mp->hi_mem_min);
26120 undump(null,mp->mem_top,mp->avail); mp->mem_end=mp->mem_top;
26121 mp->last_pending=spec_head;
26122 for (k=mp->hi_mem_min;k<= mp->mem_end;k++) 
26123   undump_wd(mp->mem[k]);
26124 undump_int(mp->var_used); undump_int(mp->dyn_used)
26125
26126 @ A different scheme is used to compress the hash table, since its lower region
26127 is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output three
26128 words: |p|, |hash[p]|, and |eqtb[p]|. The hash table is, of course, densely
26129 packed for |p>=hash_used|, so the remaining entries are output in~a~block.
26130
26131 @<Dump the table of equivalents and the hash table@>=
26132 dump_int(mp->hash_used); 
26133 mp->st_count=frozen_inaccessible-1-mp->hash_used;
26134 for (p=1;p<=mp->hash_used;p++) {
26135   if ( text(p)!=0 ) {
26136      dump_int(p); dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]); incr(mp->st_count);
26137   }
26138 }
26139 for (p=mp->hash_used+1;p<=(int)hash_end;p++) {
26140   dump_hh(mp->hash[p]); dump_hh(mp->eqtb[p]);
26141 }
26142 dump_int(mp->st_count);
26143 mp_print_ln(mp); mp_print_int(mp, mp->st_count); mp_print(mp, " symbolic tokens")
26144
26145 @ @<Undump the table of equivalents and the hash table@>=
26146 undump(1,frozen_inaccessible,mp->hash_used); 
26147 p=0;
26148 do {  
26149   undump(p+1,mp->hash_used,p); 
26150   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
26151 } while (p!=mp->hash_used);
26152 for (p=mp->hash_used+1;p<=(int)hash_end;p++ )  { 
26153   undump_hh(mp->hash[p]); undump_hh(mp->eqtb[p]);
26154 }
26155 undump_int(mp->st_count)
26156
26157 @ We have already printed a lot of statistics, so we set |mp_tracing_stats:=0|
26158 to prevent them appearing again.
26159
26160 @<Dump a few more things and the closing check word@>=
26161 dump_int(mp->max_internal);
26162 dump_int(mp->int_ptr);
26163 for (k=1;k<= mp->int_ptr;k++ ) { 
26164   dump_int(mp->internal[k]); 
26165   dump_string(mp->int_name[k]);
26166 }
26167 dump_int(mp->start_sym); 
26168 dump_int(mp->interaction); 
26169 dump_string(mp->mem_ident);
26170 dump_int(mp->bg_loc); dump_int(mp->eg_loc); dump_int(mp->serial_no); dump_int(69073);
26171 mp->internal[mp_tracing_stats]=0
26172
26173 @ @<Undump a few more things and the closing check word@>=
26174 undump_int(x);
26175 if (x>mp->max_internal) mp_grow_internals(mp,x);
26176 undump_int(mp->int_ptr);
26177 for (k=1;k<= mp->int_ptr;k++) { 
26178   undump_int(mp->internal[k]);
26179   undump_string(mp->int_name[k]);
26180 }
26181 undump(0,frozen_inaccessible,mp->start_sym);
26182 if (mp->interaction==mp_unspecified_mode) {
26183   undump(mp_unspecified_mode,mp_error_stop_mode,mp->interaction);
26184 } else {
26185   undump(mp_unspecified_mode,mp_error_stop_mode,x);
26186 }
26187 undump_string(mp->mem_ident);
26188 undump(1,hash_end,mp->bg_loc);
26189 undump(1,hash_end,mp->eg_loc);
26190 undump_int(mp->serial_no);
26191 undump_int(x); 
26192 if (x!=69073) goto OFF_BASE
26193
26194 @ @<Create the |mem_ident|...@>=
26195
26196   char *tmp = xmalloc(11,1);
26197   xfree(mp->mem_ident);
26198   mp->mem_ident = xmalloc(256,1);
26199   mp_snprintf(tmp,11,"%04d.%02d.%02d",
26200           (int)mp_round_unscaled(mp, mp->internal[mp_year]),
26201           (int)mp_round_unscaled(mp, mp->internal[mp_month]),
26202           (int)mp_round_unscaled(mp, mp->internal[mp_day]));
26203   mp_snprintf(mp->mem_ident,256," (mem=%s %s)",mp->job_name, tmp);
26204   xfree(tmp);
26205   mp_pack_job_name(mp, ".mem");
26206   while (! mp_w_open_out(mp, &mp->mem_file) )
26207     mp_prompt_file_name(mp, "mem file name", ".mem");
26208   mp_print_nl(mp, "Beginning to dump on file ");
26209 @.Beginning to dump...@>
26210   mp_print(mp, mp->name_of_file); 
26211   mp_print_nl(mp, mp->mem_ident);
26212 }
26213
26214 @ @<Dealloc variables@>=
26215 xfree(mp->mem_ident);
26216
26217 @ @<Close the mem file@>=
26218 (mp->close_file)(mp,mp->mem_file)
26219
26220 @* \[46] The main program.
26221 This is it: the part of \MP\ that executes all those procedures we have
26222 written.
26223
26224 Well---almost. We haven't put the parsing subroutines into the
26225 program yet; and we'd better leave space for a few more routines that may
26226 have been forgotten.
26227
26228 @c @<Declare the basic parsing subroutines@>
26229 @<Declare miscellaneous procedures that were declared |forward|@>
26230
26231 @ We've noted that there are two versions of \MP. One, called \.{INIMP},
26232 @.INIMP@>
26233 has to be run first; it initializes everything from scratch, without
26234 reading a mem file, and it has the capability of dumping a mem file.
26235 The other one is called `\.{VIRMP}'; it is a ``virgin'' program that needs
26236 @.VIRMP@>
26237 to input a mem file in order to get started. \.{VIRMP} typically has
26238 a bit more memory capacity than \.{INIMP}, because it does not need the
26239 space consumed by the dumping/undumping routines and the numerous calls on
26240 |primitive|, etc.
26241
26242 The \.{VIRMP} program cannot read a mem file instantaneously, of course;
26243 the best implementations therefore allow for production versions of \MP\ that
26244 not only avoid the loading routine for object code, they also have
26245 a mem file pre-loaded. 
26246
26247 @ @<Option variables@>=
26248 int ini_version; /* are we iniMP? */
26249
26250 @ @<Set |ini_version|@>=
26251 mp->ini_version = (opt->ini_version ? true : false);
26252
26253 @ The code below make the final chosen hash size the next larger
26254 multiple of 2 from the requested size, and this array is a list of
26255 suitable prime numbers to go with such values. 
26256
26257 The top limit is chosen such that it is definately lower than
26258 |max_halfword-3*param_size|, because |param_size| cannot be larger
26259 than |max_halfword/sizeof(pointer)|.
26260
26261 @<Declarations@>=
26262 static int mp_prime_choices[] = 
26263   { 12289,        24593,    49157,    98317,
26264     196613,      393241,   786433,  1572869,
26265     3145739,    6291469, 12582917, 25165843,
26266     50331653, 100663319  };
26267
26268 @ @<Find constant sizes@>=
26269 if (mp->ini_version) {
26270   unsigned i = 14;
26271   set_value(mp->mem_top,opt->main_memory,5000);
26272   mp->mem_max = mp->mem_top;
26273   set_value(mp->param_size,opt->param_size,150);
26274   set_value(mp->max_in_open,opt->max_in_open,10);
26275   if (opt->hash_size>0x8000000) 
26276     opt->hash_size=0x8000000;
26277   set_value(mp->hash_size,(2*opt->hash_size-1),16384);
26278   mp->hash_size = mp->hash_size>>i;
26279   while (mp->hash_size>=2) {
26280     mp->hash_size /= 2;
26281     i++;
26282   }
26283   mp->hash_size = mp->hash_size << i;
26284   if (mp->hash_size>0x8000000) 
26285     mp->hash_size=0x8000000;
26286   mp->hash_prime=mp_prime_choices[(i-14)];
26287 } else {
26288   int x;
26289   if (mp->command_line != NULL && *(mp->command_line) == '&') {
26290     char *s = NULL;
26291     char *cmd = mp->command_line+1;
26292     xfree(mp->mem_name); /* just in case */
26293     mp->mem_name = mp_xstrdup(mp,cmd);
26294     while (*cmd && *cmd!=' ')  cmd++;
26295     if (*cmd==' ') *cmd++ = '\0';
26296     if (*cmd) {
26297       s = mp_xstrdup(mp,cmd);
26298     }
26299     xfree(mp->command_line);
26300     mp->command_line = s;
26301   }
26302   if (mp->mem_name == NULL) {
26303     mp->mem_name = mp_xstrdup(mp,"plain");
26304   }
26305   if (mp_open_mem_file(mp)) {
26306     @<Undump constants for consistency check@>;
26307     set_value(mp->mem_max,opt->main_memory,mp->mem_top);
26308     goto DONE;
26309   } 
26310 OFF_BASE:
26311   wterm_ln("(Fatal mem file error; I'm stymied)\n");
26312   mp->history = mp_fatal_error_stop;
26313   mp_jump_out(mp);
26314 }
26315 DONE:
26316
26317
26318 @ Here we do whatever is needed to complete \MP's job gracefully on the
26319 local operating system. The code here might come into play after a fatal
26320 error; it must therefore consist entirely of ``safe'' operations that
26321 cannot produce error messages. For example, it would be a mistake to call
26322 |str_room| or |make_string| at this time, because a call on |overflow|
26323 might lead to an infinite loop.
26324 @^system dependencies@>
26325
26326 This program doesn't bother to close the input files that may still be open.
26327
26328 @ @c
26329 void mp_close_files_and_terminate (MP mp) {
26330   integer k; /* all-purpose index */
26331   integer LH; /* the length of the \.{TFM} header, in words */
26332   int lk_offset; /* extra words inserted at beginning of |lig_kern| array */
26333   pointer p; /* runs through a list of \.{TFM} dimensions */
26334   @<Close all open files in the |rd_file| and |wr_file| arrays@>;
26335   if ( mp->internal[mp_tracing_stats]>0 )
26336     @<Output statistics about this job@>;
26337   wake_up_terminal; 
26338   @<Do all the finishing work on the \.{TFM} file@>;
26339   @<Explain what output files were written@>;
26340   if ( mp->log_opened  && ! mp->noninteractive ){ 
26341     wlog_cr;
26342     (mp->close_file)(mp,mp->log_file); 
26343     mp->selector=mp->selector-2;
26344     if ( mp->selector==term_only ) {
26345       mp_print_nl(mp, "Transcript written on ");
26346 @.Transcript written...@>
26347       mp_print(mp, mp->log_name); mp_print_char(mp, xord('.'));
26348     }
26349   }
26350   mp_print_ln(mp);
26351   mp->finished = true;
26352 }
26353
26354 @ @<Declarations@>=
26355 static void mp_close_files_and_terminate (MP mp) ;
26356
26357 @ @<Close all open files in the |rd_file| and |wr_file| arrays@>=
26358 if (mp->rd_fname!=NULL) {
26359   for (k=0;k<=(int)mp->read_files-1;k++ ) {
26360     if ( mp->rd_fname[k]!=NULL ) {
26361       (mp->close_file)(mp,mp->rd_file[k]);
26362       xfree(mp->rd_fname[k]);      
26363    }
26364  }
26365 }
26366 if (mp->wr_fname!=NULL) {
26367   for (k=0;k<=(int)mp->write_files-1;k++) {
26368     if ( mp->wr_fname[k]!=NULL ) {
26369      (mp->close_file)(mp,mp->wr_file[k]);
26370       xfree(mp->wr_fname[k]); 
26371     }
26372   }
26373 }
26374
26375 @ @<Dealloc ...@>=
26376 for (k=0;k<(int)mp->max_read_files;k++ ) {
26377   if ( mp->rd_fname[k]!=NULL ) {
26378     (mp->close_file)(mp,mp->rd_file[k]);
26379     xfree(mp->rd_fname[k]); 
26380   }
26381 }
26382 xfree(mp->rd_file);
26383 xfree(mp->rd_fname);
26384 for (k=0;k<(int)mp->max_write_files;k++) {
26385   if ( mp->wr_fname[k]!=NULL ) {
26386     (mp->close_file)(mp,mp->wr_file[k]);
26387     xfree(mp->wr_fname[k]); 
26388   }
26389 }
26390 xfree(mp->wr_file);
26391 xfree(mp->wr_fname);
26392
26393
26394 @ We want to produce a \.{TFM} file if and only if |mp_fontmaking| is positive.
26395
26396 We reclaim all of the variable-size memory at this point, so that
26397 there is no chance of another memory overflow after the memory capacity
26398 has already been exceeded.
26399
26400 @<Do all the finishing work on the \.{TFM} file@>=
26401 if ( mp->internal[mp_fontmaking]>0 ) {
26402   @<Make the dynamic memory into one big available node@>;
26403   @<Massage the \.{TFM} widths@>;
26404   mp_fix_design_size(mp); mp_fix_check_sum(mp);
26405   @<Massage the \.{TFM} heights, depths, and italic corrections@>;
26406   mp->internal[mp_fontmaking]=0; /* avoid loop in case of fatal error */
26407   @<Finish the \.{TFM} file@>;
26408 }
26409
26410 @ @<Make the dynamic memory into one big available node@>=
26411 mp->rover=lo_mem_stat_max+1; mp_link(mp->rover)=empty_flag; mp->lo_mem_max=mp->hi_mem_min-1;
26412 if ( mp->lo_mem_max-mp->rover>max_halfword ) mp->lo_mem_max=max_halfword+mp->rover;
26413 node_size(mp->rover)=mp->lo_mem_max-mp->rover; 
26414 lmp_link(mp->rover)=mp->rover; rmp_link(mp->rover)=mp->rover;
26415 mp_link(mp->lo_mem_max)=null; info(mp->lo_mem_max)=null
26416
26417 @ The present section goes directly to the log file instead of using
26418 |print| commands, because there's no need for these strings to take
26419 up |str_pool| memory when a non-{\bf stat} version of \MP\ is being used.
26420
26421 @<Output statistics...@>=
26422 if ( mp->log_opened ) { 
26423   char s[128];
26424   wlog_ln(" ");
26425   wlog_ln("Here is how much of MetaPost's memory you used:");
26426 @.Here is how much...@>
26427   mp_snprintf(s,128," %i string%s out of %i",(int)mp->max_strs_used-mp->init_str_use,
26428           (mp->max_strs_used!=mp->init_str_use+1 ? "s" : ""),
26429           (int)(mp->max_strings-1-mp->init_str_use));
26430   wlog_ln(s);
26431   mp_snprintf(s,128," %i string characters out of %i",
26432            (int)mp->max_pl_used-mp->init_pool_ptr,
26433            (int)mp->pool_size-mp->init_pool_ptr);
26434   wlog_ln(s);
26435   mp_snprintf(s,128," %i words of memory out of %i",
26436            (int)mp->lo_mem_max+mp->mem_end-mp->hi_mem_min+2,
26437            (int)mp->mem_end);
26438   wlog_ln(s);
26439   mp_snprintf(s,128," %i symbolic tokens out of %i", (int)mp->st_count, (int)mp->hash_size);
26440   wlog_ln(s);
26441   mp_snprintf(s,128," %ii,%in,%ip,%ib stack positions out of %ii,%in,%ip,%ib",
26442            (int)mp->max_in_stack,(int)mp->int_ptr,
26443            (int)mp->max_param_stack,(int)mp->max_buf_stack+1,
26444            (int)mp->stack_size,(int)mp->max_internal,(int)mp->param_size,(int)mp->buf_size);
26445   wlog_ln(s);
26446   mp_snprintf(s,128," %i string compactions (moved %i characters, %i strings)",
26447           (int)mp->pact_count,(int)mp->pact_chars,(int)mp->pact_strs);
26448   wlog_ln(s);
26449 }
26450
26451 @ It is nice to have have some of the stats available from the API.
26452
26453 @<Exported function ...@>=
26454 int mp_memory_usage (MP mp );
26455 int mp_hash_usage (MP mp );
26456 int mp_param_usage (MP mp );
26457 int mp_open_usage (MP mp );
26458
26459 @ @c
26460 int mp_memory_usage (MP mp ) {
26461         return (int)mp->lo_mem_max+mp->mem_end-mp->hi_mem_min+2;
26462 }
26463 int mp_hash_usage (MP mp ) {
26464   return (int)mp->st_count;
26465 }
26466 int mp_param_usage (MP mp ) {
26467         return (int)mp->max_param_stack;
26468 }
26469 int mp_open_usage (MP mp ) {
26470         return (int)mp->max_in_stack;
26471 }
26472
26473 @ We get to the |final_cleanup| routine when \&{end} or \&{dump} has
26474 been scanned.
26475
26476 @c
26477 void mp_final_cleanup (MP mp) {
26478   quarterword c; /* 0 for \&{end}, 1 for \&{dump} */
26479   c=mp->cur_mod;
26480   if ( mp->job_name==NULL ) mp_open_log_file(mp);
26481   while ( mp->input_ptr>0 ) {
26482     if ( token_state ) mp_end_token_list(mp);
26483     else  mp_end_file_reading(mp);
26484   }
26485   while ( mp->loop_ptr!=null ) mp_stop_iteration(mp);
26486   while ( mp->open_parens>0 ) { 
26487     mp_print(mp, " )"); decr(mp->open_parens);
26488   };
26489   while ( mp->cond_ptr!=null ) {
26490     mp_print_nl(mp, "(end occurred when ");
26491 @.end occurred...@>
26492     mp_print_cmd_mod(mp, fi_or_else,mp->cur_if);
26493     /* `\.{if}' or `\.{elseif}' or `\.{else}' */
26494     if ( mp->if_line!=0 ) {
26495       mp_print(mp, " on line "); mp_print_int(mp, mp->if_line);
26496     }
26497     mp_print(mp, " was incomplete)");
26498     mp->if_line=if_line_field(mp->cond_ptr);
26499     mp->cur_if=name_type(mp->cond_ptr); mp->cond_ptr=mp_link(mp->cond_ptr);
26500   }
26501   if ( mp->history!=mp_spotless )
26502     if ( ((mp->history==mp_warning_issued)||(mp->interaction<mp_error_stop_mode)) )
26503       if ( mp->selector==term_and_log ) {
26504     mp->selector=term_only;
26505     mp_print_nl(mp, "(see the transcript file for additional information)");
26506 @.see the transcript file...@>
26507     mp->selector=term_and_log;
26508   }
26509   if ( c==1 ) {
26510     if (mp->ini_version) {
26511       mp_store_mem_file(mp); return;
26512     }
26513     mp_print_nl(mp, "(dump is performed only by INIMP)"); return;
26514 @.dump...only by INIMP@>
26515   }
26516 }
26517
26518 @ @<Declarations@>=
26519 static void mp_final_cleanup (MP mp) ;
26520 static void mp_init_prim (MP mp) ;
26521 static void mp_init_tab (MP mp) ;
26522
26523 @ @c
26524 void mp_init_prim (MP mp) { /* initialize all the primitives */
26525   @<Put each...@>;
26526 }
26527 @#
26528 void mp_init_tab (MP mp) { /* initialize other tables */
26529   integer k; /* all-purpose index */
26530   @<Initialize table entries (done by \.{INIMP} only)@>;
26531 }
26532
26533
26534 @ When we begin the following code, \MP's tables may still contain garbage;
26535 thus we must proceed cautiously to get bootstrapped in.
26536
26537 But when we finish this part of the program, \MP\ is ready to call on the
26538 |main_control| routine to do its work.
26539
26540 @<Get the first line...@>=
26541
26542   @<Initialize the input routines@>;
26543   if (mp->mem_ident==NULL) {
26544     if ( ! mp_load_mem_file(mp) ) {
26545       (mp->close_file)(mp, mp->mem_file); 
26546        mp->history = mp_fatal_error_stop;
26547        return mp;
26548     }
26549     (mp->close_file)(mp, mp->mem_file);
26550   }
26551   @<Initializations following first line@>;
26552 }
26553
26554 @ @<Initializations following first line@>=
26555   mp->buffer[limit]=(ASCII_code)'%';
26556   mp_fix_date_and_time(mp);
26557   if (mp->random_seed==0)
26558     mp->random_seed = (mp->internal[mp_time] / unity)+mp->internal[mp_day];
26559   mp_init_randoms(mp, mp->random_seed);
26560   @<Initialize the print |selector|...@>;
26561   if ( loc<limit ) if ( mp->buffer[loc]!='\\' ) 
26562     mp_start_input(mp); /* \&{input} assumed */
26563
26564 @ @<Run inimpost commands@>=
26565 {
26566   mp_get_strings_started(mp);
26567   mp_init_tab(mp); /* initialize the tables */
26568   mp_init_prim(mp); /* call |primitive| for each primitive */
26569   mp->init_str_use=mp->max_str_ptr=mp->str_ptr;
26570   mp->init_pool_ptr=mp->max_pool_ptr=mp->pool_ptr;
26571   mp_fix_date_and_time(mp);
26572 }
26573
26574 @ Saving the filename template
26575
26576 @<Save the filename template@>=
26577
26578   if ( mp->filename_template!=0 ) delete_str_ref(mp->filename_template);
26579   if ( length(mp->cur_exp)==0 ) mp->filename_template=0;
26580   else { 
26581     mp->filename_template=mp->cur_exp; add_str_ref(mp->filename_template);
26582   }
26583 }
26584
26585 @* \[47] Debugging.
26586
26587
26588 @* \[48] System-dependent changes.
26589 This section should be replaced, if necessary, by any special
26590 modification of the program
26591 that are necessary to make \MP\ work at a particular installation.
26592 It is usually best to design your change file so that all changes to
26593 previous sections preserve the section numbering; then everybody's version
26594 will be consistent with the published program. More extensive changes,
26595 which introduce new sections, can be inserted here; then only the index
26596 itself will get a new section number.
26597 @^system dependencies@>
26598
26599 @* \[49] Index.
26600 Here is where you can find all uses of each identifier in the program,
26601 with underlined entries pointing to where the identifier was defined.
26602 If the identifier is only one letter long, however, you get to see only
26603 the underlined entries. {\sl All references are to section numbers instead of
26604 page numbers.}
26605
26606 This index also lists error messages and other aspects of the program
26607 that you might want to look up some day. For example, the entry
26608 for ``system dependencies'' lists all sections that should receive
26609 special attention from people who are installing \MP\ in a new
26610 operating environment. A list of various things that can't happen appears
26611 under ``this can't happen''.
26612 Approximately 25 sections are listed under ``inner loop''; these account
26613 for more than 60\pct! of \MP's running time, exclusive of input and output.