Gamma and other image manipulation commands
[TeXnicard.git] / texnicard.w
blob5cac22599de58992adf7812ce87688c9eb38653d
1 % TeXnicard
2 % version 0.1
4 % Licensed by GNU GPL v3 or later version.
6 \def\contentspagenumber{1}\pageno=3
7 \def\title{\TeX nicard}
8 \def\covernote{{\fiverm Batteries not included. Do not use this book as a
9 flotation device. This is free software; see source file for details.}}
11 % Prevent \outer from getting in the way, stupid!
12 \def\+{\tabalign}
14 @mp@-
15 ``u{YJ"@<Predeclaration of procedures@>=
16 qJA";
17 J"@
18 "@<Procedure codes@>=
19 B" {
22 \long\def\IndexCharacter#1':{`\.{\char`#1}'}
23 @mcase@-
24 ``u "case
25 qAqA/@!@^\IndexCharacter\
26 Bqu'B"@>
27 YJ"@<Nothing~@>
30 \iffalse
31 @s _decl_head_ =09
32 @s FILE int
33 @s dvi_measure int
34 \fi
36 \newcount\bibliocount \bibliocount=0
37 \def\biblio#1{%
38 \advance\bibliocount by 1 %
39 $^{[\the\bibliocount]}$%
40 \expandafter\def\csname biblio \the\bibliocount\endcsname{#1}%
43 \emergencystretch=\hsize
45 \def\strike#1{%
46 \setbox0=\hbox{#1}%
47 \rlap{\vrule height 3.2pt depth -2.5pt width \wd0}{\box0}%
50 \def\sectionnumber\PB#1{\sectionnumbernext#1}
51 \def\sectionnumbernext$\X#1:#2\X${#1}
53 @*Introduction. This is \TeX nicard, a program designed for similar
54 purposes of Magic Set Editor, but in a different (and better) way. It
55 should be able to produce higher quality cards than Wizards of the Coast,
56 and then they ought to use this program, too!
58 @^Magic Set Editor@>
59 @^Wizards of the Coast@>
60 @^commercial viability@>
63 @<Memory usage logging@>@;
64 @<Interpreted C codes@>@;
65 @<Include files@>@;
67 @<Typedefs@>@;
68 @<Late Typedefs@>@;
69 @<The include file for memory managed types@>@;
70 @<Global variables@>@;
71 @<Predeclaration of procedures@>@;
72 @<Procedure codes@>@;
74 @ This line below should be changed with the current version number,
75 whenever a new version is released. (If you fork this program, you should
76 also include some indication of forking in the \\{version\_string}.)
77 % (it doesn't work if I use vertical bars here)
79 @^forking@>
81 @d version_string "0.1"
82 @d version_number 1 // one major is worth ten minors
84 @ @<Typedefs@>=
85 typedef unsigned char boolean;
87 @ You might be wondering what this section is for (especially since it
88 appears to be unused). The reason is that some metamacros use it in order
89 to force the compiler to know the correct line numbers (in case some lines
90 have been added by metamacros).
92 @^nothing@>
93 @^metamacro@>
95 @<Nothing~@>= /* ... */
97 @ There is also memory usage logging. If it is not being compiled for
98 memory usage logging, it should just ignore these kind of commands.
100 @<Memory usage logging@>=
101 #ifndef @!memusage_log
102 #define @[memusage_log(_text,_arg1)@]
103 #endif
105 @*Memory Management. This program uses a lot of similar memory management,
106 so they will be defined in this chapter.
108 @^memory management@>
110 @d none -1 // indication that a |data_index| means nothing
112 @<Typedefs@>=
113 typedef struct {
114 char*data; // pointer to array of blocks (|char*| for use with |sizeof|)
115 int used; // number of blocks used
116 int allocated; // number of blocks allocated
117 } managed_memory;
118 @#typedef int data_index;
120 @ We will use an interpreted C code here, which will send output to a
121 header file |"memory_management.h"|.
123 @<The include file for memory managed types@>=
124 #include "memory_management.h"
126 @ We will need some variables now just to keep track of which kinds of
127 memory managed areas are needed.
129 @<Interpreted C codes@>= @{
130 char**memory_managed_types;
131 int num_memory_managed_types;
132 memory_managed_types=malloc(128*sizeof(char*));
133 num_memory_managed_types=0;
136 @ From this code, the structure will be created in the header file for
137 each type that we need a |memory_of|. This section, however, is just a
138 ``wrapper'' code for the template.
140 @f @!memory_of _decl_head_ // category 9
142 @<Interpreted C codes@>= @{
143 void memory_of$() {
144 should_output=0;
145 set_goal("bp","",@+{
146 sendc(0200|'{'); // begin interpret mode
147 send("send_memory_of(\"");
148 set_goal("e","",@+{
149 send("\");");
150 sendc(0200|'}'); // end interpret mode
151 should_output=0;
152 }@+);
153 }@+);
157 @ Here is what it does in order to keep a list of the memory managed
158 types. Note the type name was enclosed in quotation marks, so now it will
159 be received as a string.
161 @<Interpreted C codes@>= @{
162 void send_memory_of(char*s) {
163 int i;
164 s++;
165 @<Send the proper name of the memory managed type@>;
166 for(i=0;i<num_memory_managed_types;i++) {
167 if(!strcmp(s,memory_managed_types[i])) return;
169 memory_managed_types[num_memory_managed_types++]=s;
173 @ @<Send the proper name of the memory managed type@>= {
174 send(" x__");
175 send(s);
176 send(" ");
179 @ Now the code you get to in order to define the structures in the header
180 file. We are mostly just copying the form of our |managed_memory|
181 structure, but it will be customized to work with the specific type of the
182 |data| components.
184 @<Interpreted C codes@>= @{
185 void send_memory_managed_types() {
186 int i;
187 for(i=0;i<num_memory_managed_types;i++) {
188 send("typedef struct {");
189 send(memory_managed_types[i]);
190 send("*data; int used; int allocated; } x__");
191 send(memory_managed_types[i]);
192 send(";");
197 @ @(memory_management.h@>= @{
198 send_memory_managed_types();
201 @ These next two subroutines are used to allocate additional memory.
203 @d init_memory(_a,_size) init_memory_(&(_a),sizeof(*((_a).data)),(_size))
204 @d new_record(_area) new_record_(&(_area),sizeof(*((_area).data)))
206 @-p void*init_memory_(void*mem,int record_size,int num_records) {
207 managed_memory*m=mem;
208 m->data=malloc(record_size*num_records);
209 m->used=0;
210 m->allocated=num_records;
211 if(!m->data) @<Fatal error due to lack of memory@>;
212 return m->data;
215 @ @-p data_index new_record_(void*mem,int record_size) {
216 managed_memory*m=mem;
217 m->used++;
218 if(m->used>m->allocated) {
219 m->allocated*=2;
220 m->data=realloc(m->data,m->allocated*record_size);
222 if(!m->data) @<Fatal error due to lack of memory@>;
223 @<Zero the new record@>;
224 return m->used-1;
227 @ @<Fatal error due to lack of memory@>= {
228 fprintf(stderr,"Out of memory\n");
229 @.Out of memory@>
230 exit(1);
233 @ @<Zero the new record@>= {
234 memset(m->data+(record_size*(m->used-1)),0,record_size);
237 @ Now just one more thing. It is useful to have a |foreach| macro to
238 iterate the areas.
240 @d foreach(_var,_area) for(_var=0;_var<_area.used;_var++)@;
241 @f foreach while
243 @*Symbolic Names. There will be some names defined for the use of naming
244 subroutines, symbolic constants, patterns, card areas, etc. These names
245 are stored in a |managed_memory| called |names|.
247 It also stores references to other things (defined in later chapters). The
248 numeric value of a name in |names.data[x]| is |x+256|.
250 @<Late Typedefs@>=
251 typedef struct {
252 char*name;
253 @<More elements of |name_data|@>@;
254 } name_data;
256 @ @<Global variables@>=
257 memory_of(name_data) names;
259 @ @<Initialize memory@>= init_memory(names,16);
261 @ This subroutine finds a name, adding it if necessary. The number
262 corresponding to it (as described above) will be the return value.
264 @-p int find_name(char*name) {
265 @<Search for the |name| in |names|@>;
266 @<Add the new name (it was not found)@>;
269 @ @<Search for the |name| in |names|@>= {
270 int i;
271 foreach(i,names) {
272 if(!strcmp(names.data[i].name,name)) return i+256;
276 @ @<Add the new name (it was not found)@>= {
277 int n=new_record(names);
278 names.data[n].name=strdup(name);
279 return n+256;
282 @ A macro will be useful to access the data from a number.
284 @d name_info(_num) names.data[(_num)-0x0100]
286 @ This code lists the names. It is used for a diagnostic purpose.
288 @<Display the list of names@>= {
289 int n;
290 foreach(n,names) {
291 printf("%d \"%s\" ",n+256,names.data[n].name);
292 @<Display other fields of |names.data[n]|@>;
293 printf("\n");
297 @*Storage of Tokens. Tokens are stored as 16-bit numbers. Values |0x0020|
298 to |0x00FF| represent those ASCII characters, and |0x0000| to |0x001F| are
299 ASCII control codes. Higher numbers represent an index into the |names|
300 array (where |0x0101| represents |names.data[0x0001]|).
302 @<Typedefs@>=
303 @q[data type of tokens]@>
304 typedef unsigned short token;
306 @ This section lists the ASCII control codes which can be used. Some of
307 them have slightly different meaning from the ASCII standard.
309 @d null_char 0x00 // end of a |raw_data| string or similar things
310 @d pre_null_char 0x01 // becomes |null_char|
311 @d end_transmission 0x04 // marks the end of the last card in this area
312 @d tabulation 0x09 // represents a tab in a {\TeX} alignment
313 @d raw_data 0x10 // enter raw {\TeX} mode
314 @d whatsit 0x1A // a token for converting into a name token
315 @d escape_code 0x1B // represents a {\TeX} control sequence introducer
316 @d record_separator 0x1E // marks the end of a card
317 @d field_separator 0x1F // marks the end of a field of a card
318 @d start_name_code 0x0100
320 @ These tokens are used in card areas, which are defined (and described)
321 in the next chapter.
323 @*Cards. The data of the cards is stored in card areas. Each card area
324 is a list of tokens, terminated by |record_separator|. The final card in
325 the area is terminated by |end_transmission|.
327 @<Typedefs@>=
328 typedef struct {
329 token*tokens;
330 int allocated;
331 int used;
332 } card_area_data;
334 @ @<More elements of |name_data|@>=
335 boolean has_card_area;
336 data_index card_area;
338 @ @<Global variables@>=
339 memory_of(card_area_data) card_areas;
341 @ @<Initialize memory@>= init_memory(card_areas,1);
343 @ A new card area is created with this.
345 @-p data_index set_card_area(int num) {
346 name_data*m=&name_info(num);
347 @<Use the card area which is already set, if able@>;
348 @<Otherwise, create a new card area and use the new one@>;
351 @ @<Use the card area which is already set, if able@>= {
352 if(m->has_card_area) return m->card_area;
355 @ @<Otherwise, create a new card area and use the new one@>= {
356 data_index n=new_record(card_areas);
357 m->has_card_area=1;
358 card_areas.data[n].allocated=0x100;
359 card_areas.data[n].tokens=malloc(0x100*sizeof(token));
360 card_areas.data[n].used=0;
361 return n;
364 @ This subroutine sends a token to a card area.
366 @-p void send_token(data_index a,token x) {
367 if(card_areas.data[a].allocated<card_areas.data[a].used+4)
368 @<Double the allocation of card area tokens@>;
369 card_areas.data[a].tokens[card_areas.data[a].used++]=x;
372 @ @<Double the allocation of card area tokens@>= {
373 int n=(card_areas.data[a].allocated*=2)*sizeof(token);
374 card_areas.data[a].tokens=realloc(card_areas.data[a].tokens,n);
377 @ @<Display other fields of |names.data[n]|@>= {
378 if(names.data[n].has_card_area)
379 printf("C(%d) ",names.data[n].card_area);
382 @ The code in this section is used to ensure that each card area is
383 properly terminated with |end_transmission| marker, so that when it is
384 time to write the output files, it will know when to stop.
386 @<Send |end_transmission| to each card area@>= {
387 data_index a;
388 foreach(a,card_areas) send_token(a,end_transmission);
391 @*Patterns. For pattern matching, we store the patterns in one memory
392 managed area. The index of the beginning of each pattern area is stored
393 in the |names| list.
395 These constants are special codes which can occur in the |text| string
396 of a pattern.
398 @d begin_capture 1
399 @d end_capture 2
400 @d match_keyword 3 // match a keyword followed by a character in a table
401 @d match_table 4 // match a character using a table
402 @d optional_table 5 // match a character optional using a table
403 @d failed_match 6
404 @d jump_table 7 // use a table to jump to a marker
405 @d successful_match 8
406 @d back_one_space 9
407 @d forward_one_space 10
408 @d match_left_side 11 // match at beginning of line
409 @d match_right_side 12 // match at end of line
410 @d match_eight_bit 13 // match 8-bit encodings and control characters
412 @<Typedefs@>=
413 typedef struct {
414 char*text;
415 unsigned int category; // category for keywords
416 data_index subroutine;
417 data_index next;
418 } pattern_data;
420 @ @<More elements of |name_data|@>=
421 boolean has_pattern_area;
422 data_index pattern_area;
424 @ @<Global variables@>=
425 memory_of(pattern_data) pattern_areas;
427 @ @<Initialize memory@>= init_memory(pattern_areas,4);
429 @ @<Display other fields of |names.data[n]|@>= {
430 if(names.data[n].has_pattern_area)
431 printf("P(%d) ",names.data[n].pattern_area);
434 @ A new pattern area is created with this. The patterns in an area are
435 stored like a linked list. The last one with |next| pointing to nothing,
436 is the terminator entry.
438 @-p data_index set_pattern_area(int num) {
439 name_data*m=&name_info(num);
440 @<Use the pattern area which is already set, if able@>;
441 @<Otherwise, create a new pattern area and use the new one@>;
444 @ @<Use the pattern area which is already set, if able@>= {
445 if(m->has_pattern_area) return m->pattern_area;
448 @ @<Otherwise, create a new pattern area and use the new one@>= {
449 data_index n=new_record(pattern_areas);
450 m->has_pattern_area=1;
451 pattern_areas.data[n].subroutine=none;
452 pattern_areas.data[n].next=none;
453 return n;
456 @ @<Display the list of patterns@>= {
457 int i;
458 foreach(i,pattern_areas) {
459 if(pattern_areas.data[i].text) {
460 printf("%d:%08X:%d:%d\n",i,pattern_areas.data[i].category
461 ,pattern_areas.data[i].subroutine,pattern_areas.data[i].next
463 display_string(pattern_areas.data[i].text);
464 printf("\n");
469 @*Keywords. Keywords means words which can be placed on the card and which
470 can have special meanings, and possibly reminder text.
472 Keywords are stored in a large list in only one keyword area. A category
473 can be given a name, which will automatically be assigned for the next bit
474 of the keyword category when it is entered the first time.
476 @<Typedefs@>=
477 typedef struct {
478 char*match; // match text (can contain pattern codes)
479 unsigned int category; // bitfield of categories
480 int extra1;
481 int extra2;
482 char*replacement; // replacement text or reminder text
483 } keyword_data;
485 @ @<Global variables@>=
486 unsigned int next_keyword_category=1;
487 memory_of(keyword_data) keywords;
489 @ @<Initialize memory@>= init_memory(keywords,4);
491 @ A keyword category is found (and created, if it is not found) using the
492 following code.
494 @-p unsigned int find_category(char*name) {
495 int i=find_name(name);
496 if(name_info(i).value.number) {
497 return name_info(i).value.number;
498 } @+else if(!name_info(i).value.is_string) {
499 name_info(i).value.number=next_keyword_category;
500 next_keyword_category<<=1;
501 if(!next_keyword_category)
502 fprintf(stderr,"Too many keyword categories: %s\n",name);
503 @.Too many keyword categories@>
504 return name_info(i).value.number;
508 @ Some stack code commands are used when dealing with reading/writing
509 keyword info.
511 In order that you might be able to iterate them, it will exit out of the
512 current block when trying to read nonexisting keyword info instead of
513 displaying an error message.
515 @<Cases for system commands@>=
516 @-case 'k': {
517 // Read keyword info
518 if(registers['K'].number<0 || registers['K'].number>=keywords.used)
519 return 0;
520 push_num(keywords.data[registers['K'].number].extra1);
521 push_num(keywords.data[registers['K'].number].extra2);
522 push_string(keywords.data[registers['K'].number].replacement);
523 break;
525 @-case 'K': {
526 // Write keyword info
527 if(registers['K'].number<0 || registers['K'].number>=keywords.used)
528 program_error("Out of range");
529 free(keywords.data[registers['K'].number].replacement);
530 keywords.data[registers['K'].number].replacement=pop_string();
531 keywords.data[registers['K'].number].extra2=pop_num();
532 keywords.data[registers['K'].number].extra1=pop_num();
533 break;
536 @ @<Display the list of keywords@>= {
537 int i;
538 foreach(i,keywords) {
539 display_string(keywords.data[i].match);
540 printf(" [%d:%08X:%d:%d:%d]\n",i,keywords.data[i].category
541 ,keywords.data[i].extra1,keywords.data[i].extra2
542 ,strlen(keywords.data[i].replacement)
547 @*Card List. A sorted summary list of the cards is kept in one list,
548 having thirty-two general-purpose numeric fields, and a pointer to the
549 beginning of the record (usually the name in which it will be indexed by).
551 @<Typedefs@>=
552 typedef struct {
553 int token_ptr;
554 int field[32];
555 int amount_in_pack; // used in pack generation
556 } list_entry;
558 @ @<Global variables@>=
559 memory_of(list_entry) card_list;
561 @ @<Initialize memory@>= init_memory(card_list,16);
563 @*Deck Lists. Deck lists involve lists of cards or rules for cards that
564 belong to a deck or pack.
566 @^booster pack@>
568 There is one macro |lflag| here just to convert letters to bit flags. For
569 example |lflag('a')| is the least significant bit.
571 @d lflag(_ch) (1<<((_ch)-'a'))
573 @<Typedefs@>=
574 typedef struct {
575 int amount;
576 unsigned int flags;
577 char*name;
578 data_index next;
579 } deck_entry;
581 @ @<Global variables@>=
582 memory_of(deck_entry) deck_lists;
584 @ @<More elements of |name_data|@>=
585 boolean has_deck_list;
586 data_index deck_list;
588 @ @<Initialize memory@>= init_memory(deck_lists,4);
590 @ A new deck list is created with this. The deck entries are stored like a
591 linked list. The terminator has |next| pointing to |none|.
593 @-p data_index set_deck_list(int num) {
594 name_data*m=&name_info(num);
595 @<Use the deck list which is already set, if able@>;
596 @<Otherwise, create a new deck list and use the new one@>;
599 @ @<Use the deck list which is already set, if able@>= {
600 if(m->has_deck_list) return m->deck_list;
603 @ @<Otherwise, create a new deck list and use the new one@>= {
604 data_index n=new_record(deck_lists);
605 m->has_deck_list=1;
606 deck_lists.data[n].next=none;
607 return n;
610 @ @<Display the deck list@>= {
611 data_index i;
612 foreach(i,deck_lists) {
613 printf("%d ",i);
614 if(deck_lists.data[i].name) display_string(deck_lists.data[i].name);
615 else printf("-");
616 printf(" [%08X:%d:%d]\n",deck_lists.data[i].flags
617 ,deck_lists.data[i].amount,deck_lists.data[i].next);
621 @*Image Manipulators. Image manipulators are used to render the card
622 images from the typesetting and external PNG files and special effects.
623 Each line of code is one or more 16-bit unsigned numbers, where the first
624 number indicates what command is being used. These specify effects such as
625 convolution, blur, mask, etc.
627 @<Typedefs@>=
628 typedef struct {
629 unsigned char data_len;
630 unsigned short*data;
631 data_index next;
632 } image_manipulator;
634 @ @<Global variables@>=
635 memory_of(image_manipulator) image_manips;
637 @ @<More elements of |name_data|@>=
638 boolean has_image_manip;
639 data_index image_manip;
641 @ @<Initialize memory@>= init_memory(image_manips,1);
643 @ Creating a new image manipulation is similar to a new deck list and so
644 on. The program is a linked list of the program lines, with the terminator
645 |next| pointing to |none|.
647 @-p data_index set_image_manip(int num) {
648 name_data*m=&name_info(num);
649 @<Use the image manipulator which is already set, if able@>;
650 @<Otherwise, create a new image manipulator and use the new one@>;
653 @ @<Use the image manipulator which is already set, if able@>= {
654 if(m->has_image_manip) return m->deck_list;
657 @ @<Otherwise, create a new image manipulator and use the new one@>= {
658 data_index n=new_record(image_manips);
659 m->has_image_manip=1;
660 image_manips.data[n].next=none;
661 return n;
664 @*Word Forms. These structures are used to store word form rules, such as
665 plurals\biblio{Conway, Damian. ``An Algorithmic Approach to English
666 Pluralization''. \hskip 0pt plus 1in\hbox{}
667 \.{http://www.csse.monash.edu.au/\~damian/papers/HTML/Plurals.html}}. You
668 can store up to four different kinds, in case of languages other than
669 English.
671 @^Conway, Damian@>
672 @^plurals@>
674 @<Typedefs@>=
675 typedef struct {
676 int level;
677 data_index next;
678 unsigned char orig[32];
679 unsigned char dest[32];
680 boolean left_boundary;
681 boolean right_boundary;
682 } word_form_entry;
684 @ @<Global variables@>=
685 memory_of(word_form_entry) word_forms;
687 @ @<Initialize memory@>= {
688 int i;
689 init_memory(word_forms,16);
690 word_forms.used=8;
691 for(i=0;i<8;i+=2) {
692 word_forms.data[i].orig[0]=word_forms.data[i].dest[0]=0;
693 word_forms.data[i].next=i+1;
694 word_forms.data[i].level=0x7FFFFFFF;
695 word_forms.data[i+1].orig[0]=word_forms.data[i+1].dest[0]=0;
696 word_forms.data[i+1].next=none;
697 word_forms.data[i+1].level=0;
701 @ Word form rules are added and then inserted in the correct place in the
702 linked list using the |next| field. Entries with a higher numbered level
703 take higher priority, therefore will be placed before the ones with lower
704 numbered level. Next, longer |orig| strings come before shorter strings,
705 since they might be more specific forms of the others and will therefore
706 override them.
708 @-p data_index add_word_form(int kind,int level,char*orig,char*dest) {
709 data_index n=new_record(word_forms);
710 @<Set the fields of the new word form rule@>;
711 @<Insert the new word form rule into the linked list@>;
712 return n;
715 @ The |left_boundary| and |right_boundary| fields specify if they should
716 match only at the boundary. Characters are checked using the \.W table and
717 removed from the string to place in the list.
719 @d last_character(_str) ((_str)[strlen(_str)-1])
721 @<Set the fields of the new word form rule@>= {
722 word_forms.data[n].level=level;
723 strcpy(word_forms.data[n].orig,orig+(tables['W'][*orig]==2));
724 word_forms.data[n].left_boundary=(tables['W'][*orig]==2);
725 if((word_forms.data[n].right_boundary=
726 (tables['W'][last_character(word_forms.data[n].orig)]==3)))
727 last_character(word_forms.data[n].orig)=0;
728 strcpy(word_forms.data[n].dest,dest+(tables['W'][*dest]==2));
729 if(tables['W'][last_character(word_forms.data[n].dest)]==3)
730 last_character(word_forms.data[n].dest)=0;
733 @ @<Insert the new word form rule into the linked list@>= {
734 data_index y=(kind&3)<<1; // previous item to |x|
735 data_index x=word_forms.data[y].next; // current item
736 int s=strlen(orig);
737 for(;x!=none;y=x,x=word_forms.data[y].next) {
738 if(word_forms.data[x].next==none) break;
739 @#if(word_forms.data[x].level<level) break;
740 if(word_forms.data[x].level>level) continue;
741 @#if(strlen(word_forms.data[x].orig)<s) break;
743 word_forms.data[y].next=n;
744 word_forms.data[n].next=x;
747 @ Now to do computation of changing a word by word forms. This function
748 expects only one word from input, or multiple words where the last one
749 should be the word to be converted. Uppercase letters are converted to
750 lowercase for conversion (but not the other way around), but if the
751 letters are uppercase in the input, the output will also have uppercase
752 letters on those positions. The algorithm starts from the right side of
753 the input string.
755 The parameter |src| is the input, and |dest| should point to a buffer
756 which is large enough to store the output string.
758 @^plurals@>
760 @-p data_index reform_word(int kind,char*src,char*dest) {
761 char*l=src+strlen(src);
762 data_index n=word_forms.data[(kind&3)<<1].next;
763 strcpy(dest,src); // this is used later
764 @<Try each word form rule, following the |next| pointers@>;
765 return none; // in case there is nothing to do
768 @ @<Try each word form rule, following the |next| pointers@>= {
769 char*p;
770 int s;
771 while(n!=none && word_forms.data[n].next!=none) {
772 s=strlen(word_forms.data[n].orig); @+ p=l-s;
773 @<Check the characters matching from |p|, going backwards@>;
774 n=word_forms.data[n].next;
778 @ Look ahead for the definition of |wcasecmp| (true means it matches).
780 @<Check the characters matching from |p|, going backwards@>= {
781 for(;;) {
782 if((!word_forms.data[n].left_boundary || p==src
783 || tables['W'][p[-1]])
784 && wcasecmp(word_forms.data[n].orig,p))
785 @<A match to the word form rules has been found@>;
786 @<Go backwards, stop if we are not allowed to continue backwards@>;
790 @ @<A match to the word form rules has been found@>= {
791 char*o=dest+(p-src);
792 sprintf(o,"%s%s",word_forms.data[n].dest,p+s);
793 @<Change the capitalization to match the original@>;
794 return n;
797 @ Remember, that for example if ``cow'' becomes ``kine'', then ``Cow''
798 will become ``Kine''. So, it will retain capitalization.
800 @^cows@>
802 @<Change the capitalization to match the original@>= {
803 char*q=word_forms.data[n].orig;
804 for(;*p && *q;p++,o++,q++)
805 if(*p==tables['U'][*q] && *p!=tables['L'][*q]) *o=tables['U'][*o];
808 @ @<Go backwards, stop if we are not allowed to continue backwards@>= {
809 if(word_forms.data[n].right_boundary) break; // matches only on boundary
810 if(tables['W'][p[s]]) break; // only the last word(s) can be matched
811 if(p--==src) break; // stop at beginning
814 @ This function is defined to compare strings in the way needed for
815 matching word forms, including case conversion. The lowercase letters in
816 the |shorter| string are permitted to match lowercase and uppercase
817 letters in the |longer| string, and the |shorter| string is permitted to
818 be shorter and still match.
820 @-p boolean wcasecmp(char*shorter,char*longer) {
821 for(;;shorter++,longer++) {
822 if(!*shorter) return 1;
823 if(!*longer) return 0;
824 if(*shorter!=*longer && *shorter!=tables['L'][*longer]) return 0;
828 @ Of course it is now needed a command that can access these features from
829 within a \TeX nicard template. The |level| of the matched rule is also
830 returned, in case your program might use that information for something.
832 @<Cases for system commands@>=
833 @-case 'W': {
834 // Convert a word form
835 int k=pop_num();
836 char*o=pop_string();
837 char q[1500];
838 data_index n=reform_word(k,o,q);
839 push_string(q);
840 if(n==none) push_num(0);
841 else push_num(word_forms.data[n].level);
842 free(o);
843 break;
846 @ @<Display the list of word form rules@>= {
847 data_index i;
848 foreach(i,word_forms) {
849 printf("%d %c\"",i,word_forms.data[i].left_boundary?'[':' ');
850 display_string(word_forms.data[i].orig);
851 printf("\"%c -> \"",word_forms.data[i].right_boundary?']':' ');
852 display_string(word_forms.data[i].dest);
853 printf("\" %d >%d\n",word_forms.data[i].level
854 ,word_forms.data[i].next);
858 @*Random Number Generation. This program uses the Xorshift algorithm,
859 invented by George Marsaglia\biblio{Marsaglia (July 2003). ``Xorshift
860 RNGs''. Journal of Statistical Software Vol.~8 (Issue 14). {\tt
861 http://www.jstatsoft.org/v08/i14/paper}.}.
863 @^Marsaglia, George@>
864 @^random numbers@>
866 @<Global variables@>=
867 unsigned int rng_x;
868 unsigned int rng_y;
869 unsigned int rng_z;
870 unsigned int rng_w;
872 @ @<Initialize the random number generator@>= {
873 @q[initialize the random seed::]@>
874 rng_seed((unsigned int)time(0));
875 @q[::initialize the random seed]@>
878 @ The seed parameters for the random number generator will be seeded using
879 the linear congruential generator, which is a simpler generator which can
880 be used to seed it with.
882 The parameters |lcg_a| and |lcg_c| are parameters to the linear
883 congruential generator algorithm. The values used here are the same as
884 those used in GNU C. In this program they will be specified explicitly so
885 that you can get identical output on different computers.
887 @d lcg_a 1103515245
888 @d lcg_c 12345
890 @-p void rng_seed(unsigned int x) {
891 rng_x=x=lcg_a*x+lcg_c;
892 rng_y=x=lcg_a*x+lcg_c;
893 rng_z=x=lcg_a*x+lcg_c;
894 rng_w=x=lcg_a*x+lcg_c;
897 @ There is a command to reseed it using a constant (so that you can
898 generate the same numbers on different computers).
900 @<Cases for system commands@>=
901 @-case 'U': {
902 // Reseed the random number generator
903 if(stack_ptr->is_string) program_error("Type mismatch");
904 rng_seed(pop_num());
905 break;
908 @ And now follows the algorithm for generating random numbers. One change
909 has been made so that once it is modulo, all number will still be of equal
910 probability.
912 Numbers are generated in the range from 0 up to but not including |limit|.
914 @d max_uint ((unsigned int)(-1))
916 @-p unsigned int gen_random(unsigned int limit) {
917 unsigned int r=max_uint-(max_uint%limit); // range check
918 for(;;) {
919 @<Make the next number |rng_w|...@>;
920 @<Check the range, try again if out of range, else |return|@>;
924 @ @<Make the next number |rng_w| by Xorshift algorithm@>= {
925 unsigned int t = rng_x ^ (rng_x << 11);
926 rng_x = rng_y; @+ rng_y = rng_z; @+ rng_z = rng_w;
927 rng_w ^= (rng_w >> 19) ^ t ^ (t >> 8);
930 @ @<Check the range, try again if out of range, else |return|@>= {
931 if(rng_w<=r) return rng_w%limit;
934 @ @<Cases for system commands@>=
935 @-case 'u': {
936 // Generate a random number
937 if(stack_ptr->is_string) program_error("Type mismatch");
938 stack_ptr->number=gen_random(stack_ptr->number);
939 break;
942 @*Stack Programming Language. Now we get to the part where the user can
943 enter a program, in order to control the features of this program. The
944 programming language used is like \.{dc}, but different.
946 @.dc@>
948 Subroutines are simply stored as strings in the |names| area, since they
949 are the same as registers.
951 @ Now we have the storage of registers. Registers 0 to 255 are stored in
952 this separate list, while other register values are just stored in the
953 |names| list. There is also a stack, which has storage of the same values
954 as registers can contain.
956 @d max_stack 0x1000
958 @<Typedefs@>=
959 typedef struct {
960 boolean is_string;
961 union @+{
962 int number;
963 unsigned char*text;
964 }@+;
965 } register_value;
967 @ @<More elements of |name_data|@>=
968 register_value value;
970 @ @<Global variables@>=
971 register_value registers[256];
972 register_value stack[max_stack];
973 register_value*stack_ptr=stack-1; // current top of stack element
975 @ Here are some codes for pushing and popping the stack.
977 @d pop_num() ((stack_ptr--)->number)
979 @-p inline void push_string(char*s) {
980 ++stack_ptr;
981 stack_ptr->is_string=1;
982 stack_ptr->text=strdup(s);
985 @ @-p inline void push_num(int n) {
986 ++stack_ptr;
987 stack_ptr->is_string=0;
988 stack_ptr->number=n;
991 @ @-p inline void stack_dup(void) {
992 if((stack_ptr[1].is_string=stack_ptr->is_string)) {
993 stack_ptr[1].text=strdup(stack_ptr->text);
994 } @+else {
995 stack_ptr[1].number=stack_ptr->number;
997 stack_ptr++;
1000 @ @-p inline void stack_drop(void) {
1001 if(stack_ptr->is_string) free(stack_ptr->text);
1002 --stack_ptr;
1005 @ @-p inline char*pop_string(void) {
1006 char*p=stack_ptr->text;
1007 stack_ptr->is_string=0; stack_ptr->text=0;
1008 --stack_ptr;
1009 return p;
1012 @ Also, some subroutines are needed here in order to deal with registers.
1014 For |fetch_code|, the string |"0[]+"| is returned if it is not a string,
1015 generating a ``Type mismatch'' error when you try to run it.
1017 @-p inline char*fetch_code(int r) {
1018 if(!(r&~0xFF)) {
1019 if(!registers[r].is_string) return "0[]+";
1020 return registers[r].text;
1021 } @+else {
1022 if(!name_info(r).value.is_string) return "0[]+";
1023 return name_info(r).value.text;
1027 @ @-p inline void fetch(int r) {
1028 register_value*v;
1029 if(!(r&~0xFF)) v=&(registers[r]);
1030 else v=&(name_info(r).value);
1031 (++stack_ptr)->is_string=v->is_string;
1032 if(v->is_string) {
1033 stack_ptr->text=strdup(v->text);
1034 } @+else {
1035 stack_ptr->number=v->number;
1039 @ @-p inline void store(int r) {
1040 register_value*v;
1041 if(!(r&~0xFF)) v=&(registers[r]);
1042 else v=&(name_info(r).value);
1043 if(v->is_string) free(v->text);
1044 v->is_string=stack_ptr->is_string;
1045 if(v->is_string) {
1046 v->text=stack_ptr->text;
1047 } @+else {
1048 v->number=stack_ptr->number;
1050 --stack_ptr;
1053 @ There is also a save stack. This save stack stores the saved values of
1054 the registers |'0'| to |'9'|, so that you can have local variables in a
1055 subroutine.
1057 @<Global variables@>=
1058 register_value save_stack[520];
1059 register_value*save_stack_ptr=save_stack;
1061 @ These codes deal with the save stack. Strings will be copied when
1062 saving. When loading, strings that were previously in the registers will
1063 be freed.
1065 @<Save local registers to the save stack@>= {
1066 int i;
1067 for(i='0';i<='9';i++) {
1068 *save_stack_ptr=registers[i];
1069 if(registers[i].is_string)
1070 save_stack_ptr->text=strdup(save_stack_ptr->text);
1071 save_stack_ptr++;
1075 @ @<Load local registers from the save stack@>= {
1076 int i;
1077 for(i='9';i>='0';i--) {
1078 if(registers[i].is_string) free(registers[i].text);
1079 registers[i]=*--save_stack_ptr;
1083 @*Commands for Stack Programming Language. Finally, is the code where it
1084 can be executed. The return value of this function indicates how many
1085 levels should be exit when it is called.
1087 @-p int execute_program(unsigned char*prog) {
1088 unsigned char*ptr=prog;
1089 reset_execute_program:
1090 for(;*ptr;ptr++) {
1091 switch(*ptr) {
1092 @<Cases for literal data commands@>@;
1093 @<Cases for stack manipulation commands@>@;
1094 @<Cases for arithmetic commands@>@;
1095 @<Cases for flow-control commands@>@;
1096 @<Cases for register/table operation commands@>@;
1097 @<Cases for string commands@>@;
1098 @<Cases for condition/compare commands@>@;
1099 @<Cases for local registers commands@>@;
1100 @<Cases for system commands@>@;
1101 @-case '?': @<Do a diagnostics command@>@;@+break;
1102 @-case '=': @<Do a typesetting command@>@;@+break;
1103 default:
1104 if(*ptr>='0' && *ptr<='9') {
1105 @<Read a literal number and push to stack@>;
1106 } @+else if(0x80&*ptr) {
1107 @<Execute a subroutine code from the current character@>;
1109 break;
1111 if(stack_ptr<stack-1) program_error("Stack underflow");
1112 if(stack_ptr>stack+max_stack) program_error("Stack overflow");
1114 return 0;
1117 @ @<Cases for literal data commands@>=
1118 @-case '`': {
1119 // Literal ASCII character
1120 push_num(*++ptr);
1121 break;
1123 @-case '[': {
1124 // Literal string
1125 @<Read a literal string and push to stack@>;
1126 break;
1128 @-case '(': {
1129 // Literal name
1130 @<Read a literal name and push its number to the stack@>;
1131 break;
1134 @ @<Read a literal number and push to stack@>= {
1135 int n=0;
1136 while(*ptr>='0' && *ptr<='9') n=10*n+(*ptr++)-'0';
1137 --ptr;
1138 push_num(n);
1141 @ @<Read a literal string and push to stack@>= {
1142 char*p=++ptr;
1143 int n=1;
1144 while(n && *ptr) {
1145 if(*ptr=='[') ++n;
1146 if(*ptr==']') --n;
1147 if(n) ptr++;
1149 if(!*ptr) program_error("Unterminated string literal");
1150 *ptr=0;
1151 push_string(p);
1152 *ptr=']';
1155 @ @<Read a literal name and push its number to the stack@>= {
1156 char*p=++ptr;
1157 while(*ptr && *ptr!=')') ptr++;
1158 if(!*ptr) program_error("Unterminated string literal");
1159 *ptr=0;
1160 push_num(find_name(p));
1161 *ptr=')';
1164 @ @<Cases for stack manipulation commands@>=
1165 @-case 'D': {
1166 // Drop top item of stack
1167 stack_drop();
1168 break;
1170 @-case 'c': {
1171 // Clears the stack, rendering it empty
1172 while(stack_ptr>=stack) stack_drop();
1173 break;
1175 @-case 'd': {
1176 // Duplicates the value on top of the stack.
1177 stack_dup();
1178 break;
1180 @-case 'r': {
1181 // Swaps the top two values on the stack
1182 stack_ptr[1]=stack_ptr[0];
1183 stack_ptr[0]=stack_ptr[-1];
1184 stack_ptr[-1]=stack_ptr[1];
1185 break;
1188 @ @<Cases for arithmetic commands@>=
1189 @-case '+': {
1190 // Add two numbers, or concatenate two strings
1191 if(stack_ptr->is_string) {
1192 @<Concatenate strings on the stack@>;
1193 }@+ else {
1194 int n=pop_num();
1195 if(stack_ptr->is_string)
1196 program_error("Type mismatch");
1197 stack_ptr->number+=n;
1199 break;
1201 @-case '-': {
1202 // Subtract two numbers, or compare two strings
1203 if(stack_ptr->is_string) {
1204 @<Compare strings on the stack@>;
1205 }@+ else {
1206 int n=pop_num();
1207 if(stack_ptr->is_string)
1208 program_error("Type mismatch");
1209 stack_ptr->number-=n;
1211 break;
1213 @-case '*': {
1214 // Multiply two numbers
1215 int n=pop_num();
1216 if(stack_ptr[0].is_string || stack_ptr[1].is_string)
1217 program_error("Number expected");
1218 stack_ptr->number*=n;
1219 break;
1221 @-case '/': {
1222 // Divide two numbers
1223 int n=pop_num();
1224 if(stack_ptr[0].is_string || stack_ptr[1].is_string)
1225 program_error("Number expected");
1226 if(n==0) program_error("Division by zero");
1227 stack_ptr->number/=n;
1228 break;
1230 @-case '%': {
1231 // Modulo of two numbers
1232 int n=pop_num();
1233 if(stack_ptr[0].is_string || stack_ptr[1].is_string)
1234 program_error("Number expected");
1235 if(n==0) program_error("Division by zero");
1236 stack_ptr->number%=n;
1237 break;
1240 @ @<Concatenate strings on the stack@>= {
1241 char*s=pop_string();
1242 char*q;
1243 if(!stack_ptr->is_string) program_error("Type mismatch");
1244 q=malloc(strlen(s)+strlen(stack_ptr->text)+1);
1245 strcpy(q,stack_ptr->text);
1246 strcpy(q+strlen(q),s);
1247 stack_drop();
1248 push_string(q);
1249 free(q);
1250 free(s);
1253 @ @<Compare strings on the stack@>= {
1254 char*s=pop_string();
1255 char*q=pop_string();
1256 push_num(strcmp(q,s));
1257 free(q);
1258 free(s);
1261 @ @<Cases for flow-control commands@>=
1262 @-case 'Q': {
1263 // Exit from multiple levels
1264 int q=pop_num();
1265 if(q>0) return q-1;
1266 break;
1268 @-case 'Y': {
1269 // Go back to beginning
1270 ptr=prog-1;
1271 break;
1273 @-case 'q': {
1274 // Exit from two levels
1275 return 1;
1276 break;
1278 @-case 'x': {
1279 // Execute code from top of stack
1280 @<Execute a string or subroutine code from top of stack@>;
1281 break;
1284 @ Note here, it is a recursive function call.
1285 @^recursive@>
1287 @<Execute a string or subroutine code from top of stack@>= {
1288 if(stack_ptr->is_string) {
1289 char*p=pop_string();
1290 int q=execute_program(p);
1291 free(p);
1292 if(q) return q-1;
1293 } @+else {
1294 char*p=fetch_code(pop_num());
1295 int q=execute_program(p);
1296 if(q) return q-1;
1300 @ Since the extended characters (|0x80| to |0xFF|) do not correspond to
1301 any commands, here we can use them to execute a subroutine code, allowing
1302 many things related to self-modifying code (and other stuff) to be done
1303 that would be difficult otherwise.
1305 @<Execute a subroutine code from the current character@>= {
1306 char*p=fetch_code(*ptr);
1307 int q=execute_program(p);
1308 if(q) return q-1;
1311 @ @<Cases for register/table operation commands@>=
1312 @-case ':': {
1313 // Store value to table
1314 int n;
1315 if(stack_ptr->is_string) program_error("Number expected");
1316 n=pop_num();
1317 tables[0x7F&*++ptr][n]=pop_num();
1318 break;
1320 @-case ';': {
1321 // Load value from table
1322 stack_ptr->number=tables[0x7F&*++ptr][stack_ptr->number];
1323 break;
1325 @-case 'L': {
1326 // Load value from register named by stack
1327 if(stack_ptr->is_string) program_error("Number expected");
1328 fetch(pop_num());
1329 break;
1331 @-case 'S': {
1332 // Store value in register named by stack
1333 if(stack_ptr->is_string) program_error("Number expected");
1334 store(pop_num());
1335 break;
1337 @-case 'l': {
1338 // Load value from register
1339 fetch(*++ptr);
1340 break;
1342 @-case 's': {
1343 // Store value in register
1344 store(*++ptr);
1345 break;
1348 @ @<Cases for string commands@>=
1349 @-case 'B': {
1350 // Put brackets around a string, or convert number to text
1351 if(stack_ptr->is_string) {
1352 @<Put brackets around string at top of stack@>;
1353 } @+else {
1354 @<Convert top of stack to string representation of a number@>;
1356 break;
1358 @-case 'Z': {
1359 // Calculate number of characters in a string
1360 char*s=pop_string();
1361 push_num(strlen(s));
1362 free(s);
1363 break;
1365 @-case 'a': {
1366 // ``ASCIIfy'' a number
1367 if(stack_ptr->is_string) {
1368 if(stack_ptr->text[0]) stack_ptr->text[1]=0;
1369 } @+else {
1370 int n=stack_ptr->number;
1371 stack_ptr->is_string=1;
1372 stack_ptr->text=malloc(2);
1373 stack_ptr->text[0]=n;
1374 stack_ptr->text[1]=0;
1376 break;
1378 @-case 'A': {
1379 // Take the first character from the string
1380 char*s=stack_ptr->text;
1381 if(!stack_ptr->is_string || !*s) return 0;
1382 push_num(*s);
1383 stack_ptr[-1].text=strdup(s+1);
1384 free(s);
1385 break;
1387 @-case 'N': {
1388 // Convert a register number to its name
1389 int n=stack_ptr->number;
1390 if(stack_ptr->is_string) program_error("Type mismatch");
1391 if(n<256 || n>=names.used+256) program_error("Out of range");
1392 stack_drop();
1393 push_string(names.data[n-256].name);
1394 break;
1397 @ @<Put brackets around string at top of stack@>= {
1398 char*buf=malloc(strlen(stack_ptr->text)+3);
1399 sprintf(buf,"[%s]",stack_ptr->text);
1400 free(stack_ptr->text);
1401 stack_ptr->text=buf;
1404 @ @<Convert top of stack to string representation of a number@>= {
1405 char buf[32];
1406 sprintf(buf,"%d",stack_ptr->number);
1407 stack_drop();
1408 push_string(buf);
1411 @ Here is how the ``Arithmetic IF'' command works: On the stack you have
1412 any three values at the top, and a number underneath it. Those are all
1413 removed, except one of the three values which is selected based on the
1414 sign of the number (the condition value).
1416 @<Cases for condition/compare commands@>=
1417 @-case 'i': {
1418 // Arithmetic IF
1419 @<Do the ``Arithmetic IF''@>;
1420 break;
1422 @-case '&': {
1423 // Bitwise AND
1424 int n=pop_num();
1425 if(stack_ptr[0].is_string || stack_ptr[1].is_string)
1426 program_error("Number expected");
1427 stack_ptr->number&=n;
1428 break;
1431 @ Do you like this algorithm? Is this a real question?
1433 @^strange codes@>
1435 @<Do the ``Arithmetic IF''@>= {
1436 register_value v=stack_ptr[-3];
1437 int n=v.number;
1438 n=-(n<0?2:!n);
1439 stack_ptr[-3]=stack_ptr[n];
1440 stack_ptr[n]=v;
1441 stack_drop();@+stack_drop();@+stack_drop();
1444 @ @<Cases for local registers commands@>=
1445 @-case '<': {
1446 // Save locals
1447 @<Save local registers to the save stack@>;
1448 break;
1450 @-case '>': {
1451 // Restore locals
1452 @<Load local registers from the save stack@>;
1453 break;
1456 @ When there is a program error (such as stack underflow), the following
1457 subroutine is used to handle it.
1459 @d program_error(_text) program_error_(prog,ptr,_text)
1461 @-p void program_error_(char*prog,char*ptr,char*msg) {
1462 fprintf(stderr,"Error in %s on line %d",current_filename,current_line);
1463 fprintf(stderr,"\n! %s\ns%dS%dp%d near \"",msg,stack_ptr-stack,
1464 save_stack_ptr-save_stack,ptr-prog);
1465 @<Display the codes near the part that caused the error@>;
1466 fprintf(stderr,"\"\n");
1467 exit(1);
1470 @ @<Display the codes near the part that caused the error@>= {
1471 char buf[32];
1472 char*p=ptr-5;
1473 int i;
1474 if(p<prog || p>ptr) p=prog;
1475 for(i=0;p+i<=ptr && p[i];i++) buf[i]=p[i];
1476 buf[i]=0;
1477 fprintf(stderr,"%s",buf);
1480 @*Tables and Registers. The tables must be stored here. There are 128
1481 tables with 256 entries each, each of which can store one byte of data.
1482 These tables are used for converting uppercase/lowercase, for deciding
1483 which characters need to be escaped in \TeX, and so on.
1485 The purposes of the built-in registers are also described in this chapter.
1486 The tables and registers named by uppercase letters are for system use.
1487 The tables and registers named by lowercase can be used by the user.
1489 @<Global variables@>=
1490 unsigned char tables[128][256];
1492 @ Here are the uses of the built-in tables and registers:
1493 @^built-in registers@>
1494 @^built-in tables@>
1496 Register \.A: The current position in the current cards area.
1498 Register \.C: The current cards area.
1500 Register \.D: Dots per inch, multiplied by 100.
1502 Register \.E: The escape character for \TeX. If this is a string, the
1503 entire string is the prefix; otherwise, it is a ASCII number of the
1504 character to be used.
1506 Register \.K: Index number for last keyword entry added. Also used when
1507 dealing with keyword operation commands, and when a keyword is matched in
1508 a pattern.
1510 Register \.P: The current pattern area.
1512 Register \.Q: The parameters for the ImageMagick command-line, separated
1513 by spaces.
1515 Register \.T: Alignment tab character for \TeX. Same considerations apply
1516 as the \.E register.
1518 Register \.U: A code to execute for a deck specification enrty with \.x
1519 flag set.
1521 Register \.V: The version number of this program.
1523 Register \.W: A code which pushes the whatsit replacements onto the stack.
1524 It is initialized to a blank string before each line in a card area. It
1525 should push the replacements in the reverse order of the whatsits, so you
1526 could use a code like this, for example: \.{[(Abracadabra)]lW+sW}
1528 Register \.X: Horizontal coordinate across the page (in pixels).
1530 Register \.Y: Vertical coordinate across the page (in pixels).
1532 Register \.Z: Should be set to a code to execute after doing everything
1533 else (but before writing output files).
1535 Table \.E: Indicates which characters need escaped for \TeX. Also used for
1536 category codes in internal typesetting mode (a discussion of the category
1537 codes will be deferred to a later part of this book).
1539 Table \.F: Space factor codes for internal typesetting, where 40 is normal
1540 (multiplying these values by 25 results in the corresponding \.{\\sfcode}
1541 values in \TeX). Zero means no change.
1543 Table \.G: Table containing information for sorting and grouping.
1545 Table \.J: Left margin protrusions for internal typesetting. A value of
1546 128 is normal. Each one unit less or greater than 128 represents a
1547 distance of 0.005 em, where number less than 128 for negative kerns and
1548 greater than 128 for positive kerns. (Note that you will use {\sl negative
1549 negative} kerns to protrude into the margin, both for the left protrusions
1550 and for the right protrusions!)
1552 Table \.K: Right margin protrusions for internal typesetting.
1554 Table \.L: Conversion to lowercase.
1556 Table \.S: Information for natural sorting.
1558 Table \.U: Conversion to uppercase.
1560 Table \.W: Table for word form rules. Zero means a letter, one means a
1561 word separator, two means use to mark beginning of a word, three means use
1562 to mark the end of a word. In this program, it is advantageous to use the
1563 fact that zero means word characters (such as letters), and nonzero means
1564 nonword characters.
1566 @d init_register(_reg,_val) do@+{
1567 registers[_reg].is_string=0;
1568 registers[_reg].number=(_val);
1569 }@+while(0)@;
1571 @d init_register_str(_reg,_val) do@+{
1572 registers[_reg].is_string=1;
1573 registers[_reg].text=strdup(_val);
1574 }@+while(0)@;
1576 @<Initialize the tables and registers@>= {
1577 int i;
1578 for(i=0;i<256;i++) init_register(i,0);
1579 init_register('E','\\');
1580 init_register('V',version_number);
1581 @<Initialize table of alphabetical case conversion@>;
1582 @<Initialize tables for internal typesetting@>;
1585 @ @<Initialize table of alphabetical case conversion@>= {
1586 for(i=0;i<256;i++) tables['L'][i]=tables['U'][i]=i;
1587 for(i='A';i<='Z';i++) {
1588 tables['L'][i]=i+'a'-'A';
1589 tables['U'][i+'a'-'A']=i;
1593 @ @<Display the contents of table |*++ptr|@>= {
1594 int t=*++ptr;
1595 int i;
1596 for(i=0;i<256;i++) {
1597 printf("%c%c",tables[t][i]?'+':'.',@|
1598 (tables[t][i]<0x7F && tables[t][i]>=' ')?tables[t][i]:'.'
1600 if((i&0x0F)==0x0F) printf("\n");
1602 for(i=' ';i<0x7F;i++) if(tables[t][i]) printf("%c",i);
1605 @*Diagnostics. Here is diagnostics commands. These are used to display the
1606 internal information on standard output, so that you can check how these
1607 things are working. (You can also use \.{gdb} for debugging purposes.) A
1608 diagnostics command always starts with a question mark, and is then
1609 followed by one more character indicating the type of diagnostics
1610 requestsed. (Some are followed by an additional character after that.)
1612 @<Do a diagnostics command@>= {
1613 switch(*++ptr) {
1614 case 'c': @<Display the sorted card list@>; @+break;
1615 case 'd': @<Display the deck list@>; @+break;
1616 case 'f': @<Display font information@>; @+break;
1617 case 'k': @<Display the list of keywords@>; @+break;
1618 case 'n': @<Display the list of names@>; @+break;
1619 case 'p': @<Display the list of patterns@>; @+break;
1620 case 's': @<Display the contents of the stack@>; @+break;
1621 case 't': @<Display the contents of table |*++ptr|@>; @+break;
1622 case 'w': @<Display the list of word form rules@>; @+break;
1623 case 'x': @<Display the list of typeset nodes@>; @+break;
1624 case 'y': @<Display typesetting diagnostics@>; @+break;
1625 default: program_error("Unknown type of diagnostics");
1629 @ One subroutine is used here for displaying strings with escaped, so that
1630 it will display on a terminal without messing it up or omitting the
1631 display of some characters.
1633 @-p void display_string(char*s) {
1634 for(;*s;s++) {
1635 if(*s<' ' || *s==0x7F) {
1636 printf("^%c",0x40^*s);
1637 } @+else {
1638 printf("%c",*s);
1643 @ @<Display the contents of the stack@>= {
1644 register_value*p;
1645 for(p=stack;p<=stack_ptr;p++) {
1646 if(p->is_string) {
1647 printf("[");
1648 display_string(p->text);
1649 printf("]\n");
1650 } @+else {
1651 printf("%d\n",p->number);
1656 @ More of the diagnostics functions are included in the chapters for the
1657 data structures which it is displaying.
1659 @*Pattern Matching. Now, finally, after the chapter about patterns, and
1660 going through many other things in between, comes to the chapter in which
1661 patterns are actually being matched.
1663 One structure is used here for the information about how to match it, and
1664 what has been matched from it. The parameter |num_capture| is how many
1665 captured parts there are, and the |start| and |end| arrays store the index
1666 into the |src| string of where the matches are. The entire matched part is
1667 indicated by |start[0]| and |end[0]| (note always |start[0]==0|).
1669 @<Typedefs@>=
1670 typedef struct {
1671 char*src;
1672 char*truesrc; // used for checking true beginning of the line
1673 char*pattern;
1674 unsigned int category;
1675 int start[16];
1676 int end[16];
1677 int num_capture;
1678 } match_info;
1680 @ This first one just matches one pattern against a string to see if it
1681 matches. It returns true if it does match. (It is somewhat inefficient.)
1683 @-p boolean match_pattern(match_info*mat) {
1684 char*src; // current start of source string
1685 char*ptr; // pointer into source string |src|
1686 char*pptr; // pointer into pattern string
1687 src=mat->src; @+ mat->num_capture=0; @+ pptr=mat->pattern; @+ ptr=src;
1688 @<Execute the pattern on the string |src|@>;
1689 mismatch: return 0;
1692 @ This loop executes each command in the pattern in attempt to match each
1693 character. In case of mismatch, it will break out of this loop, and
1694 continue with the next iteration of the loop in the previous section.
1696 @d not_a_marker !(pptr[-1]&0x80)
1698 @<Execute the pattern on the string |src|@>= {
1699 while(*pptr) {
1700 switch(*pptr++) {
1701 case begin_capture:
1702 mat->start[++mat->num_capture]=ptr-mat->src; @+break;
1703 case end_capture: mat->end[mat->num_capture]=ptr-mat->src; @+break;
1704 case match_keyword: @<Do |match_keyword|@>; @+break;
1705 case match_table:
1706 if(!tables[*pptr++][*ptr++]) goto mismatch; @+break;
1707 case optional_table: ptr+=!!tables[*pptr++][*ptr]; @+break;
1708 case failed_match: goto mismatch;
1709 case jump_table:
1710 if(!(pptr=strchr(mat->pattern,0x80|tables[*pptr++][*ptr++])))
1711 goto mismatch;
1712 @+break;
1713 case successful_match: @<Do |successful_match|@>;
1714 case back_one_space: if(ptr--==mat->src) goto mismatch; @+break;
1715 case forward_one_space: if(!*ptr++) goto mismatch; @+break;
1716 case match_left_side: if(ptr!=mat->truesrc) goto mismatch; @+break;
1717 case match_right_side: if(*ptr>=' ') goto mismatch; @+break;
1718 default: if(not_a_marker && pptr[-1]!=*ptr++) goto mismatch;
1723 @ @<Do |successful_match|@>= {
1724 mat->start[0]=0;
1725 mat->end[0]=ptr-mat->src;
1726 return 1;
1729 @ And now, the next part matches from an area and changes the string in
1730 place, possibly by reallocating it. The |src| pointer passed to this
1731 function should be one that can be freed!
1733 @-p char*do_patterns(char*src,int area) {
1734 pattern_data*pat;
1735 match_info mat;
1736 int index=0; // index into |src| string
1737 @<Cancel if there isn't a pattern area@>;
1738 continue_matching:
1739 if(index>=strlen(src)) return src;
1740 pat=pattern_areas.data+name_info(area).pattern_area;
1741 for(;;) {
1742 @<Fill up the |mat| structure for testing the current pattern@>;
1743 if(mat.pattern && match_pattern(&mat)) {
1744 @<Push the captured strings to the stack@>;
1745 @<Call the subroutine associated with this pattern@>;
1746 if(stack_ptr->is_string) {
1747 @<Replace the matched part from the stack and fix the |index|@>;
1748 } @+else {
1749 index+=mat.end[0];
1751 stack_drop();
1752 goto continue_matching;
1754 @<Select the next pattern in this area or |break|@>;
1756 index++; @+ goto continue_matching;
1759 @ @<Cancel if there isn't a pattern area@>= {
1760 if(area<256) return src;
1761 if(!name_info(area).has_pattern_area) return src;
1764 @ @<Fill up the |mat| structure for testing the current pattern@>= {
1765 mat.src=src+index;
1766 mat.truesrc=src;
1767 mat.pattern=pat->text;
1768 mat.category=pat->category;
1771 @ @<Push the captured strings to the stack@>= {
1772 int i;
1773 for(i=mat.num_capture;i;i--) {
1774 push_string(src+index+mat.start[i]);
1775 stack_ptr->text[mat.end[i]-mat.start[i]]=0;
1779 @ @<Call the subroutine associated with this pattern@>= {
1780 execute_program(names.data[pat->subroutine].value.text);
1783 @ The memory allocated is probably more than is needed, but this way is
1784 simpler. It is always sufficient amount, though. Think about it.
1786 @^thought@>
1788 @<Replace the matched part from the stack and fix the |index|@>= {
1789 char*q=malloc(strlen(src)+strlen(stack_ptr->text)+1);
1790 strcpy(q,src);
1791 sprintf(q+index,"%s%s",stack_ptr->text,src+index+mat.end[0]);
1792 free(src);
1793 src=q;
1794 index+=strlen(stack_ptr->text);
1797 @ @<Select the next pattern in this area or |break|@>= {
1798 if(pat->next==none) break;
1799 pat=pattern_areas.data+pat->next;
1802 @ Finally, there is a command |'M'| to do a pattern matching and
1803 replacement with a string, inside of a stack subroutine code.
1805 @<Cases for system commands@>=
1806 @-case 'M': {
1807 // do pattern matching and replacement
1808 int n=pop_num();
1809 if(!stack_ptr->is_string) program_error("Type mismatch");
1810 stack_ptr->text=do_patterns(stack_ptr->text,n);
1811 break;
1814 @*Matching Keywords. Codes for matching keywords have been placed in
1815 another chapter, instead of making the previous chapter longer.
1817 So now we can see how it is matched keywords in a pattern code.
1819 @<Do |match_keyword|@>= {
1820 match_info m;
1821 char mstr[512];
1822 char t=*pptr++; // indicate which table to use
1823 data_index best=none;
1824 int best_length=-1;
1825 @<Try matching each keyword belonging to the category@>;
1826 if(best==none) goto mismatch;
1827 @<Adjust the \.K register for this keyword match@>;
1828 ptr+=m.end[0];
1831 @ @<Adjust the \.K register for this keyword match@>= {
1832 if(registers['K'].is_string) free(registers['K'].text);
1833 registers['K'].is_string=0;
1834 registers['K'].number=best;
1837 @ When matching keywords, all of them will be tried, in case there are
1838 better candidates for the search (bigger is better (so, for example,
1839 |"Power of One"| will override |"Power"|); failing that, later ones are
1840 better than earlier ones (so that user files can override keywords in
1841 template files)).
1843 @^Courtenay, Bryce@>
1844 @^Houghton, Israel@>
1845 @^Luce, Ron@>
1847 @<Try matching each keyword belonging to the category@>= {
1848 data_index i;
1849 foreach(i,keywords) {
1850 if(keywords.data[i].category&mat->category &&
1851 strlen(keywords.data[i].match)>=best_length) {
1852 @<Set up the |match_info| structure called |m|@>;
1853 @<Attempt applying this keyword match@>;
1858 @ @<Set up the |match_info| structure called |m|@>= {
1859 sprintf(mstr,"%s%c%c%c",
1860 keywords.data[i].match,match_table,t,successful_match);
1861 m.src=m.truesrc=ptr;
1862 m.pattern=mstr;
1865 @ @<Attempt applying this keyword match@>= {
1866 if(match_pattern(&m)) {
1867 best=i;
1868 best_length=strlen(keywords.data[i].match);
1872 @*Sorting and Grouping. The card lists can be sorted/grouped using these
1873 commands, which are generally used by macros that create the records for
1874 the cards in the card areas.
1876 @<Cases for system commands@>=
1877 @-case 'n': {
1878 // Add a new list entry
1879 data_index n=new_record(card_list);
1880 card_list.data[n].token_ptr=
1881 card_areas.data[set_card_area(registers['C'].number)].used
1883 break;
1885 @-case 'f': {
1886 // Set a field value of the list entry
1887 data_index n=card_list.used-1;
1888 int x=pop_num();
1889 int y=pop_num();
1890 if(n==none) program_error("No card list is available");
1891 card_list.data[n].field[x&31]=y;
1892 break;
1895 @ Other than the commands to make the list entries above, there must be,
1896 of course, the actual sorting and grouping being done!
1898 Sorting and grouping are controlled by the \.G table. Starting from a
1899 given offset (added), you use thirty-two entries for the thirty-two
1900 fields.
1902 @<Cases for system commands@>=
1903 @-case 'G': {
1904 // Sort the list
1905 sorting_table_offset=pop_num();
1906 qsort(card_list.data,card_list.used,sizeof(list_entry),list_compare);
1907 @<Mark positions in the sorted list@>;
1908 break;
1911 @ @<Global variables@>=
1912 int sorting_table_offset;
1914 @ This is the compare function for the list sorting. It is also worth to
1915 notice here what values belong in the \.G table. (There are also some
1916 other values, which are described a bit later.)
1918 @d no_sort 0
1919 @d primary_ascending 'A'
1920 @d primary_descending 'Z'
1921 @d primary_name 'N'
1922 @d secondary_ascending 'a'
1923 @d secondary_descending 'z'
1924 @d secondary_name 'n'
1925 @d record_sorted_position 'R'
1926 @d reset_high_bits 'q'
1928 @d G_table(_field) (tables['G'][((sorting_table_offset+(_field))&0xFF)])
1929 @d p1s ((list_entry*)p1)
1930 @d p2s ((list_entry*)p2)
1932 @-p int list_compare(const void*p1,const void*p2) {
1933 @<Compare using fields indicated by \.G table@>;
1934 @<Compare using the card's name and the \.S table@>;
1935 @<Compare using the order in which the cards are typed in@>;
1936 return 0; // This can't, but will, happen.
1939 @ @<Compare using fields indicated by \.G table@>= {
1940 int i;
1941 for(i=0;i<32;i++) if(p1s->field[i]!=p2s->field[i]) {
1942 if(G_table(i)==primary_ascending || (G_table(i)&0x80)) {
1943 return (p1s->field[i]>p2s->field[i])?1:-1;
1944 } @+else if(G_table(i)==primary_descending) {
1945 return (p1s->field[i]<p2s->field[i])?1:-1;
1946 } @+else if(G_table(i)==primary_name) {
1947 return name_compare(p1s->field[i],p2s->field[i]);
1950 for(i=0;i<32;i++) if(p1s->field[i]!=p2s->field[i]) {
1951 if(G_table(i)==secondary_ascending) {
1952 return (p1s->field[i]>p2s->field[i])?1:-1;
1953 } @+else if(G_table(i)==secondary_descending) {
1954 return (p1s->field[i]<p2s->field[i])?1:-1;
1955 } @+else if(G_table(i)==secondary_name) {
1956 return name_compare(p1s->field[i],p2s->field[i]);
1961 @ When all else fails, \strike{play dead} use the order in which the cards
1962 have been typed in. This is how it is made stable, and that you can get
1963 the same results on any computer.
1965 @^Smith, Steve@>
1967 @<Compare using the order in which the cards...@>= {
1968 if(p1s->token_ptr>p2s->token_ptr) return 1;
1969 if(p1s->token_ptr<p2s->token_ptr) return -1;
1972 @ The last thing to do after sorting, is mark positions in the list if it
1973 is requested to do so.
1975 In addition, it shall also optionally mark high bits (30 to 27) of some
1976 fields, based on when other fields change. This helps with doing multi-%
1977 dimensional statistics. The fields that it is based on will automatically
1978 be primary sorted since such sorting is required for the marking algorithm
1979 to work properly.
1981 @<Mark positions in the sorted list@>= {
1982 data_index i;
1983 int j;
1984 for(j=0;j<32;j++) {
1985 if(G_table(j)==record_sorted_position) {
1986 foreach(i,card_list) card_list.data[i].field[j]=i;
1987 } @+else if(G_table(j)&0x80) {
1988 @<Mark high bits of fields to prepare for...@>;
1989 } @+else if(G_table(j)==reset_high_bits) {
1990 foreach(i,card_list) card_list.data[i].field[j]&=0x0FFFFFFF;
1995 @ The rule is that whenever the current field's value changes, the bit in
1996 the corresponding grouping field will be flipped. Since the statistics
1997 grouping always treats consecutive equal values in the grouping field as
1998 belonging to the same group, this is a way to insert ``group breaks'' into
1999 the list.
2001 @<Mark high bits of fields to prepare for complex statistics@>= {
2002 int f=G_table(j)&0x1F; // other field number
2003 int v=card_list.data[0].field[j]; // previous value
2004 int k=1<<(27+((G_table(j)&0x60)>>5)); // bit flip value
2005 int b=0; // current bit value
2006 foreach(i,card_list) {
2007 if(v!=card_list.data[i].field[j]) b^=k;
2008 card_list.data[i].field[f]&=~k;
2009 card_list.data[i].field[f]|=b;
2010 v=card_list.data[i].field[j];
2014 @ @<Display the sorted card list@>= {
2015 data_index i;
2016 int j;
2017 foreach(i,card_list) {
2018 printf("%d=[ ",card_list.data[i].token_ptr);
2019 for(j=0;j<32;j++) printf("%d ",card_list.data[i].field[j]);
2020 printf("]\n");
2024 @*Natural Sorting. A natural compare algorithm is used here. It is a
2025 generalization of Martin Pool's algorithm\biblio{Pool, Martin. ``Natural
2026 Order String Comparison''. {\tt
2027 http://sourcefrog.net/projects/natsort/}.}.
2029 The \.S table maps from character tokens to the sorting specifications.
2030 Name tokens are converted to |whatsit| when looking up in this table.
2032 Tokens are grouped into digits, letters, and priority letters. There are
2033 also some extras, such as spaces and radix point. A string of consecutive
2034 digits is treated as numeric, so a number with more digits comes after a
2035 number with less digits.
2037 Priority letters are used mainly for sorting roman numerals. Two or more
2038 consecutive priority letters are considered as a group, otherwise they are
2039 treated in the same way as ordinary letters. A group is ranked with the
2040 letters latest in the alphabet, so for example, if |'I'| and |'X'| are
2041 priority, then |"IX"| is placed between |"W"| and |"X"|. This way, all
2042 roman numerals from I to XXXIX will be sorted correctly.
2044 @^natural compare@>
2045 @^Pool, Martin@>
2047 @d nat_end_low 0
2048 @d nat_end_high 1
2049 @d nat_space 2
2050 @d nat_ignore 3
2051 @d nat_radix_point 4
2053 @d nat_digit_zero 64 // digits go up to 127
2054 @d nat_first_letter 128 // letters go up to 191
2055 @d nat_first_priority_letter 192 // priority letters go up to 255
2056 @d nat_high_value 256
2058 @<Compare using the card's name and the \.S table@>= {
2059 token*pa=card_areas.data[set_card_area(registers['C'].number)].tokens
2060 +p1s->token_ptr;
2061 token*pb=card_areas.data[set_card_area(registers['C'].number)].tokens
2062 +p2s->token_ptr;
2063 boolean fractional=0; // Are we reading digits after a radix point?
2064 int a,b,c;
2065 for(;;pa++,pb++) {
2066 begin_natural_compare_loop: @/
2067 a=tables['S'][*pa>=256?whatsit:*pa];
2068 @+ b=tables['S'][*pb>=256?whatsit:*pb];
2069 @<Skip over leading spaces and/or zeros@>;
2070 @<Process a run of digits@>;
2071 @<Check if the end of either string is reached@>;
2072 @<Check for a radix point@>;
2073 @<Process priority letters@>;
2074 @<Check if the current positions of each string sufficiently differ@>;
2078 @ @<Skip over leading spaces and/or zeros@>= {
2079 while(a==nat_space||a==nat_ignore||(!fractional&&a==nat_digit_zero)) {
2080 int aa=tables['S'][pa[1]>=256?whatsit:pa[1]];
2081 if(a!=nat_ignore) fractional=0;
2082 if(!fractional && a==nat_digit_zero
2083 && aa>=nat_digit_zero && aa<nat_first_letter) break;
2084 pa++; @+ a=tables['S'][*pa>=256?whatsit:*pa];
2086 while(b==nat_space||b==nat_ignore||(!fractional&&b==nat_digit_zero)) {
2087 int bb=tables['S'][pa[1]>=256?whatsit:pa[1]];
2088 if(b!=nat_ignore) fractional=0;
2089 if(!fractional && b==nat_digit_zero
2090 && bb>=nat_digit_zero && bb<nat_first_letter) break;
2091 pb++; @+ b=tables['S'][*pb>=256?whatsit:*pb];
2095 @ @<Process a run of digits@>= {
2096 if(a>=nat_digit_zero&&a<nat_first_letter&&
2097 b>=nat_digit_zero&&b<nat_first_letter) {
2098 if((c=(fractional?compare_left:compare_right)(pa,pb))) return c;
2099 @<Skip the run of digits, since they are the same@>;
2100 fractional=0;
2103 @^strange codes@>
2105 @ Compare two left-aligned numbers: the first to have a different value
2106 wins. This function and |compare_right| are basically equivalent, there
2107 are only a few differences (this one is the simpler one).
2109 @-p int compare_left(token*pa,token*pb) {
2110 int a,b;
2111 for(;;pa++,pb++) {
2112 a=tables['S'][*pa>=256?whatsit:*pa];
2113 @+ b=tables['S'][*pb>=256?whatsit:*pb];
2114 @<Skip over ignored characters@>;
2115 @<If neither |a| nor |b| is digit, |break|@>;
2116 @<If one is a digit and the other isn't, the longest run wins@>;
2117 @<If both are different digits, the greater one wins@>;
2119 return 0;
2122 @ The longest run of digits wins. That aside, the greatest value wins, but
2123 we can't know that it will until we've scanned both numbers to know they
2124 have the same magnitude, so we remember it in |bias|.
2126 @-p int compare_right(token*pa,token*pb) {
2127 int a,b;
2128 int bias=0;
2129 for(;;pa++,pb++) {
2130 a=tables['S'][*pa>=256?whatsit:*pa];
2131 @+ b=tables['S'][*pb>=256?whatsit:*pb];
2132 @<Skip over ignored characters@>;
2133 @<If neither |a| nor |b| is digit, |break|@>;
2134 @<If one is a digit and the other isn't, the longest run wins@>;
2135 @<If both are digits, set the |bias|@>;
2137 return bias;
2140 @ Ignored characters might be commas for grouping digits into thousands.
2142 @<Skip over ignored characters@>= {
2143 while(a==nat_ignore) {
2144 pa++; @+ a=tables['S'][*pa>=256?whatsit:*pa];
2146 while(b==nat_ignore) {
2147 pb++; @+ b=tables['S'][*pb>=256?whatsit:*pb];
2151 @ @<If neither |a| nor |b| is digit, |break|@>= {
2152 if(!(a>=nat_digit_zero&&a<nat_first_letter)&&
2153 !(b>=nat_digit_zero&&b<nat_first_letter)) break;
2156 @ @<If one is a digit and the other isn't, the longest run wins@>= {
2157 if(!(a>=nat_digit_zero&&a<nat_first_letter)) return -1;
2158 if(!(b>=nat_digit_zero&&b<nat_first_letter)) return 1;
2161 @ @<If both are different digits, the greater one wins@>= {
2162 if(a!=b) return a-b;
2165 @ @<If both are digits, set the |bias|@>= {
2166 if(a!=b && !bias) bias=(a<b)?-1:1;
2169 @ @<Skip the run of digits, since they are the same@>= {
2170 while(a>=nat_digit_zero&&a<nat_first_letter) {
2171 pa++; @+ pb++; @+ a=tables['S'][*pa>=256?whatsit:*pa];
2173 b=tables['S'][*pb>=256?whatsit:*pb];
2176 @ @<Check if the end of either string is reached@>= {
2177 if(a==nat_end_low && b>nat_end_high) return -1;
2178 if(b==nat_end_low && a>nat_end_high) return 1;
2179 if(a==nat_end_high && b>nat_end_high) return 1;
2180 if(b==nat_end_high && a>nat_end_high) return -1;
2181 if(a<=nat_end_high && b<=nat_end_high) break; // tied
2184 @ A radix point must be followed by a digit, otherwise it is considered to
2185 be punctuation (and ignored). Radix points come before digits in the
2186 sorting order (|".5"| comes before |"5"|).
2188 @<Check for a radix point@>= {
2189 if(a==nat_radix_point && b==nat_radix_point) {
2190 int aa=tables['S'][pa[1]>=256?whatsit:pa[1]];
2191 int bb=tables['S'][pb[1]>=256?whatsit:pb[1]];
2192 if(aa>=nat_digit_zero&&aa<nat_first_letter
2193 &&bb>=nat_digit_zero&&bb<nat_first_letter) fractional=1;
2194 } @+else if(a==nat_radix_point) {
2195 int aa=tables['S'][pa[1]>=256?whatsit:pa[1]];
2196 if(!(aa>=nat_digit_zero&&aa<nat_first_letter)) {
2197 pa++; goto begin_natural_compare_loop;
2199 } @+else if(b==nat_radix_point) {
2200 int bb=tables['S'][pb[1]>=256?whatsit:pb[1]];
2201 if(!(bb>=nat_digit_zero&&bb<nat_first_letter)) {
2202 pb++; goto begin_natural_compare_loop;
2207 @ This is used so that |"IX"| can be sorted between |"VIII"| and |"X"|. In
2208 normal alphabetical order, |"IX"| sorts before |"V"|. This algorithm makes
2209 it so that doesn't happen. For example: |a| is |'I'| and |aa| (the
2210 character after |a| in the text) is |'X'| (the check |aa>a| ensures that
2211 it too is priority, in addition to checking that |a| represents a negative
2212 part of a roman number), and |b| is |'V'|. Now, since |'V'| comes between
2213 |'I'| and |'X'| in the alphabetical order, the condition is checked to be
2214 valid and it overrides the later check.
2216 @<Process priority letters@>= {
2217 if(a>=nat_first_priority_letter) {
2218 int aa=tables['S'][pa[1]>=256?whatsit:pa[1]];
2219 if(aa>a && b>=nat_first_letter && (b&63)>(a&63) && (b&63)<(aa&63))
2220 return 1;
2222 if(b>=nat_first_priority_letter) {
2223 int bb=tables['S'][pb[1]>=256?whatsit:pb[1]];
2224 if(bb>b && a>=nat_first_letter && (a&63)>(b&63) && (a&63)<(bb&63))
2225 return -1;
2229 @ At this point, |a| and |b| will both be |@[@]>=nat_radix_point|. Numbers
2230 always come after letters (this rule is designed so that when a radix
2231 point is found after a number, it will make a larger number; otherwise it
2232 will be followed by a letter and therefore the one followed by the letter
2233 is lesser since it has no fractional part to make it greater).
2235 @<Check if the current positions of each string suffic...@>= {
2236 if(a>=nat_first_priority_letter) a-=64;
2237 if(b>=nat_first_priority_letter) b-=64;
2238 if(a<nat_first_letter) a+=128;
2239 if(b<nat_first_letter) b+=128;
2240 if(a!=b) return (a<b)?-1:1;
2243 @*Name Sorting. This kind of sorting is used when items are grouped
2244 together by some extra field in the statistics, such as creature types in
2245 Magic: the Gathering.
2247 It works in a similar way to the natural sorting algorithm, but this time
2248 it is simpler and not as many things need to be checked. Digits and
2249 priority letters are treated as normal letters, and the types |nat_space|,
2250 |nat_ignore|, and |nat_radix_point| are all ignored. In addition, a null
2251 terminator is always treated as |nat_end_low|.
2253 If both names compare the same, their number is used instead, in order to
2254 force sorting stability.
2256 @-p int name_compare(int n1,int n2) {
2257 char*s1=name_info(n1).name;
2258 char*s2=name_info(n2).name;
2259 int a,b;
2260 for(;*s1 || *s2;s1++,s2++) {
2261 a=(*s1)?tables['S'][*s1]:nat_end_low;
2262 b=(*s2)?tables['S'][*s2]:nat_end_low;
2263 @<Skip over spaces and ignored characters@>;
2264 @<Check if the end of either string is reached@>;
2265 @<Check if the current positions of...@>;
2267 return (n1<n2)?-1:1;
2270 @ @<Skip over spaces and ignored characters@>= {
2271 while(a<nat_digit_zero) {
2272 s1++; @+ a=(*s1)?tables['S'][*s1]:nat_end_low;
2274 while(b<nat_digit_zero) {
2275 s2++; @+ b=(*s2)?tables['S'][*s2]:nat_end_low;
2279 @*Statistics. After the card lists are created and sorted and grouped, it
2280 can make statistics from them. It can be just a plain list, or it can be
2281 in summary of groups, measuring count, minimum, maximum, mean, median, and
2282 so on.
2284 First we do the simple iteration.
2286 @^mean@>
2287 @^median@>
2288 @^groups@>
2289 @^minimum@>
2290 @^maximum@>
2292 @<Cases for system commands@>=
2293 @-case 'V': {
2294 // Iterate the card list
2295 data_index i;
2296 char*q=pop_string();
2297 if(!stack_ptr[1].is_string) program_error("Type mismatch");
2298 foreach(i,card_list) {
2299 push_num(card_list.data[i].token_ptr);
2300 store('A');
2301 execute_program(q);
2303 free(q);
2304 break;
2306 @-case 'v': {
2307 // Read a field from the card list
2308 int x=pop_num()&31;
2309 int y=0;
2310 data_index i;
2311 foreach(i,card_list) {
2312 if(registers['A'].number==card_list.data[i].token_ptr)
2313 y=card_list.data[i].field[x];
2315 push_num(y);
2316 break;
2319 @ That was simple, see? Now to do gathering statistics of summary of
2320 groups, which is a bit more complicated. The list is expected to be sorted
2321 by the group field primary, and the statistics field ascending as
2322 secondary, in order to make the correct calculation of the fields.
2324 However, it will not do the sorting automatically, since there are some
2325 reasons why you might want it to work differently. One thing you can do is
2326 to sort the group field {\sl secondary} and some other more major group as
2327 primary, in order to do two-dimensional statistics, and this will work as
2328 long as you do not require the minimum, maximum, or median.
2330 @<Cases for system commands@>=
2331 @-case 'g': {
2332 // Gather statistics of groups
2333 data_index i,si=0;
2334 int x=pop_num()&31; // field for grouping
2335 int y=pop_num()&31; // field to measure statistics with
2336 int sum1,sum2; // running totals of $s_1$ and $s_2$
2337 sum1=sum2=0;
2338 char*q=pop_string(); // code to execute for each group
2339 if(!stack_ptr[1].is_string) program_error("Type mismatch");
2340 foreach(i,card_list) {
2341 if(card_list.data[i].field[x]!=card_list.data[si].field[x]) {
2342 @<Send the results of the current group@>;
2343 sum1=sum2=0; @+ si=i;
2345 @<Add to the running totals@>;
2347 @<Send the results of the current group@>;
2348 free(q);
2349 break;
2352 @ Running totals are kept for two quantities called $s_1$ and $s_2$. There
2353 is also $s_0$, but that can be calculated easily using subtraction, so
2354 there is no need to keep a running total. If the sample values are denoted
2355 $x_k$, the following equation represents the running totals:
2356 $$s_j=\sum_{k=1}^N{x_k^j}$$ (note that $s_0=N$.)
2358 @^mathematics@>
2360 @<Add to the running totals@>= {
2361 sum1+=card_list.data[i].field[y];
2362 sum2+=card_list.data[i].field[y]*card_list.data[i].field[y];
2365 @ Now we will send the results and call |q|. The results are sent to the
2366 stack in the following order: $s_0$, $s_1$, $s_2$, $Q_0$, $2Q_2$, $Q_4$
2367 (where $Q_0$ is the minimum, $Q_2$ the median, and $Q_4$ the maximum).
2369 From these results, it is then possible to calculate the standard
2370 deviation: $$\sigma={1\over s_0}\sqrt{s_0s_2-s_1^2}$$ and
2371 $$s=\sqrt{s_0s_2-s_1^2\over s_0(s_0-1)}.$$
2373 @^mathematics@>
2375 @<Send the results of the current group@>= {
2376 push_num(i-si); // $s_0$
2377 push_num(sum1); // $s_1$
2378 push_num(sum2); // $s_2$
2379 push_num(card_list.data[si].field[y]); // $Q_0$
2380 push_num(
2381 card_list.data[(si+i)/2].field[y]+card_list.data[(si+i+1)/2].field[y]
2382 ); // $2Q_2$
2383 push_num(card_list.data[i-1].field[y]); // $Q_4$
2384 @# push_num(card_list.data[si].token_ptr); @+ store('A');
2385 execute_program(q);
2388 @*Random Pack Generation. Now the codes so that it can create random packs
2389 (such as booster packs) by using the card lists and deck lists.
2391 A command |'P'| is used for evaluation of a deck list. It expects the deck
2392 list number and the code to execute for each card on the list.
2394 @^booster pack@>
2396 @<Cases for system commands@>=
2397 @-case 'P': {
2398 // Generate a random pack or deck
2399 data_index s=set_deck_list(pop_num());
2400 data_index n; // current deck list entry
2401 if(stack_ptr[1].is_string) program_error("Number expected");
2402 @<Figure out what cards belong in the pack@>;
2403 @<Execute the code on the stack for each card in the pack@>;
2404 break;
2407 @ @<Figure out what cards belong in the pack@>= {
2408 deck_entry*e;
2409 int tries=1000; // How many times can you retry if it fails?
2410 figure_out_again:
2411 if(!--tries) program_error("No cards matched the deck criteria");
2412 n=s;
2413 @<Reset |amount_in_pack| of each card to zero@>;
2414 while(n!=none && (n=(e=deck_lists.data+n)->next)!=none)
2415 @<Process this deck entry@>;
2418 @ @<Reset |amount_in_pack| of each card to zero@>= {
2419 data_index i;
2420 foreach(i,card_list) card_list.data[i].amount_in_pack=0;
2423 @ The deck entry must be processed according to the flags. Here is a list
2424 of flags:
2426 \.a: Use all cards that meet the criteria, instead of only one. If this is
2427 the case, it is possible to use negative weights to remove cards from the
2428 pack. Also, it cannot fail.
2429 [Combine with \.{x}]
2431 \.k: Select without replacement. It is fail if the total weight is not
2432 enough. There are two ways in which this differs from \.u (below). One is
2433 that the previous lines in the deck list are not used. The other one is
2434 that if the weight is more than one, there will be more than one ball for
2435 that card, therefore the same card can be picked up multiple times.
2436 [Combine with \.{sux}]
2438 \.n: Use the |amount| as a probability. If |amount<=100| then the
2439 probability is |amount/100| otherwise it is |100/amount|. This is a
2440 probability of using the |name| to select another deck list instead of
2441 this one.
2442 [Combine with nothing]
2444 \.s: Skip the next line if this line does not fail. (Normally, if one line
2445 fails, everything does, and you have to try again.)
2446 [Combine with \.{kux}]
2448 \.u: Require unique selection. It is fail if the card is already in this
2449 pack.
2450 [Combine with \.{ksx}]
2452 \.x: Pass the |name| as a string to the code in the \.U register, and then
2453 use the resulting code as the code to determine weights instead of using
2454 the code in the register named by |name| directly. Now you can type things
2455 such as |"12x Forest"| into your deck list.
2456 [Combine with \.{aksu}]
2458 @<Process this deck entry@>= {
2459 if(e->flags&lflag('n')) {
2460 @<Determine whether or not to skip to another deck list@>;
2461 } @+else {
2462 char*c; // code for weights of each card
2463 int total; // total weight of cards
2464 data_index*bag=malloc(sizeof(data_index));
2465 @<Get the code |c| for the weights of each card@>;
2466 @<Calculate the weights of each card@>;
2467 if(!(e->flags&lflag('a')))
2468 @<Select some of the cards at random and add them to the pack@>;
2469 if(e->flags&lflag('x')) free(c);
2470 free(bag);
2474 @ @<Determine whether or not to skip to another deck list@>= {
2475 boolean q;
2476 if(e->amount<=100) {
2477 q=(gen_random(100)<e->amount);
2478 } @+else {
2479 q=(100<gen_random(e->amount));
2481 if(q) n=set_deck_list(find_name(e->name));
2484 @ @<Get the code |c| for the weights of each card@>= {
2485 if(e->flags&lflag('x')) {
2486 execute_program(registers['U'].text);
2487 if(stack_ptr->is_string) {
2488 c=pop_string();
2489 } @+else {
2490 program_error("Type mismatch");
2492 } @+else {
2493 int n=find_name(e->name);
2494 if(name_info(n).value.is_string) {
2495 c=name_info(n).value.text;
2496 } @+else {
2497 program_error("Type mismatch");
2502 @ @<Calculate the weights of each card@>= {
2503 data_index i;
2504 foreach(i,card_list) {
2505 registers['A'].number=card_list.data[i].token_ptr;
2506 execute_program(c);
2507 if(stack_ptr->number) {
2508 if(e->flags&lflag('a')) {
2509 card_list.data[i].amount_in_pack+=e->amount*stack_ptr->number;
2510 } @+else if(stack_ptr->number>0) {
2511 @<Add the cards to the |bag|@>;
2514 stack_drop();
2518 @ The |bag| is like, you put the balls in the bag so that you can mix it
2519 and take one out, whatever number is on the ball is the card you put into
2520 the pack. Except, that there is no balls and no bag.
2522 There is one ball per point of weight.
2524 @^balls@>
2526 @<Add the cards to the |bag|@>= {
2527 int j=stack_ptr->number;
2528 bag=realloc(bag,(total+j)*sizeof(data_index));
2529 while(j--) bag[total+j]=i;
2530 total+=stack_ptr->number;
2533 @ If it is not a line which adds all possibilities at once, then the cards
2534 must be selected from the |bag| at random to bag them. In some cases it
2535 will fail.
2537 @<Select some of the cards at random and add them to the pack@>= {
2538 data_index r;
2539 int amount=e->amount;
2540 bag_next:
2541 if(!total) @<Deal with bag failure@>;
2542 r=gen_random(total);
2543 if((e->flags&lflag('u')) && card_list.data[bag[r]].amount_in_pack) {
2544 bag[r]=bag[--total];
2545 goto bag_next;
2547 card_list.data[bag[r]].amount_in_pack++;
2548 if(e->flags&lflag('k')) bag[r]=bag[--total];
2549 if(amount--) goto bag_next;
2550 @#if(e->flags&lflag('s')) n=deck_lists.data[n].next;
2551 bag_done: ;
2554 @ @<Deal with bag failure@>= {
2555 if(e->flags&lflag('s')) goto bag_done;
2556 else goto figure_out_again;
2559 @ Now it must do stuff using the list which is generated. The quantity for
2560 how many of that card is pushed on the stack, and this is done even for
2561 cards with negative quantity (but not for zero quantity).
2563 @<Execute the code on the stack for each card in the pack@>= {
2564 data_index i;
2565 char*q=pop_string();
2566 if(!stack_ptr[1].is_string) program_error("Type mismatch");
2567 foreach(i,card_list) {
2568 if(card_list.data[i].amount_in_pack) {
2569 push_num(card_list.data[i].amount_in_pack);
2570 execute_program(q);
2573 free(q);
2576 @*Reading Input Files. Now it is time for the part of the program where
2577 input files are read and processed. The areas of the file (and other
2578 special commands) are indicated using \.@@ signs.
2580 At first we have state information. Each state is labeled by uppercase
2581 letters, or by digits 1 to 9. The high bit is set for the heading state,
2582 meaning the first line that contains the name and/or other heading
2583 information.
2585 @d null_state 0
2586 @d card_state 'C'
2587 @d deck_state 'D'
2588 @d execute_state 'E'
2589 @d file_state 'F'
2590 @d include_state 'I'
2591 @d keyword_state 'K'
2592 @d image_state 'M'
2593 @d pattern_state 'P'
2594 @d subroutine_state 'S'
2595 @d font_state 'T'
2596 @d encoding_state 'U'
2597 @d wordforms_state 'W'
2598 @d heading 0x80
2600 @<Global variables@>=
2601 int cur_state;
2602 data_index cur_name;
2603 data_index cur_data;
2604 boolean omit_line_break;
2606 @ The next thing that must be kept track of for input files is the stack
2607 of open input files.
2609 @d max_pathname_length 128
2610 @d max_filename_length 128
2611 @d max_input_stack 128
2612 @d max_line_length 256
2614 @<Typedefs@>=
2615 typedef struct {
2616 FILE*fp; // zero for terminal input
2617 char name[max_filename_length+1];
2618 int line;
2619 } input_file_data;
2621 @ @<Global variables@>=
2622 input_file_data input_files[max_input_stack];
2623 input_file_data*current_input_file=input_files;
2624 char input_buffer[max_line_length];
2626 @ Some macros are useful to access the current file data.
2628 @d current_line (current_input_file->line)
2629 @d current_filename (current_input_file->name)
2630 @d current_fp (current_input_file->fp)
2632 @d parsing_error(_text) fprintf(stderr,"%s on line %d in %s\n",
2633 _text,current_line,current_filename)@;
2635 @ There is also conditional processing directives, which uses a single
2636 variable to keep track of the level. If it is greater than zero, the
2637 condition is false, and it is increased for nesting conditions (the
2638 nested conditions have no truth to them).
2640 @<Global variables@>=
2641 int condition_level=0;
2643 @ This subroutine inputs the next line. True is returned if there is a
2644 line, or false if it is finished.
2646 It is necessary to check for end of file and if so, close that file and
2647 try the one it was included from; and if it is terminal input, display the
2648 current state when prompting input from the user.
2650 @-p boolean input_line(void) {
2651 input_line_again: if(current_fp) {
2652 @<Get a line of input from the file@>;
2653 } @+else {
2654 @<Get a line of terminal input@>;
2656 @<Remove trailing |'\n'|, |'\r'|, and spaces@>;
2657 ++current_line;
2658 return 1;
2661 @ @<Get a line of input from the file@>= {
2662 if(!fgets(input_buffer,max_line_length,current_fp)) {
2663 memusage_log("Closing input file",current_input_file-input_files)@;
2664 fclose(current_fp);
2665 if(current_input_file>input_files) {
2666 --current_input_file;
2667 goto input_line_again;
2668 } @+else {
2669 return 0;
2674 @ @<Get a line of terminal input@>= {
2675 printf("\n%c> ",cur_state?cur_state:'>');
2676 fflush(stdout);
2677 if(!fgets(input_buffer,max_line_length,stdin)) return 0;
2680 @ This function is used to open the main input file.
2682 @-p void open_input(char*name) {
2683 if(++current_input_file>input_files+max_input_stack) {
2684 fprintf(stderr,"Too many simultaneous input files\n");
2685 @.Too many simultaneous...@>
2686 exit(1);
2688 memusage_log("Opening input file",current_input_file-input_files)@;
2689 strcpy(current_filename,name);
2690 current_line=0;
2691 current_fp=fopen(name,"r");
2692 if(!current_fp) {
2693 fprintf(stderr,"Cannot open input file: %s\n",name);
2694 @.Cannot open input file@>
2695 exit(1);
2699 @ Trailing newlines and spaces are removed. On some computers, there will
2700 be a carriage return before the line feed, it should be removed, so that
2701 the same file will work on other computers, too.
2703 @d last_character_input input_buffer[strlen(input_buffer)-1]
2705 @<Remove trailing |'\n'|, |'\r'|, and spaces@>= {
2706 if(last_character_input=='\n') last_character_input=0;
2707 if(last_character_input=='\r') last_character_input=0;
2708 while(last_character_input==' ') last_character_input=0;
2711 @ The input states start at these values.
2713 @<Initialize the input states@>= {
2714 cur_state=execute_state;
2715 cur_name=cur_data=0;
2718 @ Now it is the time to do the actual processing according to the contents
2719 of the lines of the file. A line starting with \.@@ sign will indicate a
2720 special command (to operate in all modes) or a mode switch command.
2722 @d delete_chars(_buf,_c) memmove((_buf),(_buf)+(_c),strlen((_buf)+(_c))+1)
2724 @<Process the input files@>= {
2725 char*buf;
2726 while(input_line()) {
2727 buf=input_buffer;
2728 if(condition_level) {
2729 buf+=strspn(buf," ");
2730 condition_level+=!strcmp(buf,"@@<");
2731 condition_level-=!strcmp(buf,"@@>");
2732 } @+else {
2733 omit_line_break=1;
2734 @<Convert \.@@ commands in the |input_buffer|@>;
2735 omit_line_break=0;
2736 process_line(buf);
2741 @ @<Convert \.@@ commands in the |input_buffer|@>= {
2742 char*ptr=input_buffer;
2743 while(*ptr) {
2744 if(*ptr=='@@') {
2745 @<Convert the current \.@@ command@>;
2746 } @+else {
2747 ptr++;
2752 @ @<Convert the current \.@@ command@>= {
2753 switch(*++ptr) {
2754 case '@@': @/
2755 delete_chars(ptr,1);
2756 break;
2757 case '.': @<Process \.{@@.} command@>;@+break;
2758 case '&': @<Process \.{@@\&} command@>;@+break;
2759 case '^': @<Process \.{@@\^} command@>;@+break;
2760 case '(': @<Process \.{@@(} command@>;@+break;
2761 case '<': @<Process \.{@@<} command@>;@+break;
2762 case '>': @<Remove this command from the input@>;@+break;
2763 default: @/
2764 if((*ptr>='A' && *ptr<='Z') || (*ptr>='0' && *ptr<='9')) {
2765 @<Enter a |heading| state@>;
2766 } @+else {
2767 parsing_error("Unknown @@ command");
2772 @ @<Remove this command from the input@>= {
2773 ptr--;
2774 delete_chars(ptr,2);
2777 @ Heading states are used for the first line of a section in the file.
2778 After that line is processed, it becomes the corresponding non-heading
2779 state |(cur_state&~heading)|.
2781 Note: The state |'0'| is deliberately unused; you might use it for
2782 documentation areas, for example.
2784 @^documentation areas@>
2786 @<Enter a |heading| state@>= {
2787 cur_state=heading|*ptr--;
2788 delete_chars(ptr,2);
2789 while(*ptr==' ' || *ptr=='\t') delete_chars(ptr,1);
2792 @ @-p void process_line(char*buf) {
2793 int q=cur_state;
2794 cur_state&=~heading;
2795 switch(q) {
2796 case card_state: @<Process card state@>;@+break;
2797 case deck_state: @<Process deck state@>;@+break;
2798 case execute_state: @<Process execute state@>;@+break;
2799 case file_state: @<Process file state@>;@+break;
2800 case keyword_state: @<Process keyword state@>;@+break;
2801 case keyword_state: @<Process image state@>;@+break;
2802 case pattern_state: @<Process pattern state@>;@+break;
2803 case subroutine_state: @<Process subroutine state@>;@+break;
2804 case wordforms_state: @<Process word forms state@>;@+break;
2805 case card_state|heading: @<Process card heading@>;@+break;
2806 case deck_state|heading: @<Process deck heading@>;@+break;
2807 case file_state|heading: @<Process file heading@>;@+break;
2808 case include_state|heading: @<Process include heading@>;@+break;
2809 case keyword_state|heading: @<Process keyword heading@>;@+break;
2810 case image_state|heading: @<Process image heading@>;@+break;
2811 case pattern_state|heading: @<Process pattern heading@>;@+break;
2812 case subroutine_state|heading: @<Process subroutine heading@>;@+break;
2813 default: ; // nothing happens
2817 @ Sometimes you might want a macro which can send a line programmatically.
2818 So, here is the way that it is done.
2820 @<Cases for system commands@>=
2821 @-case 'X': {
2822 // Process a line by programming
2823 int n;
2824 if(stack_ptr->is_string) program_error("Type mismatch");
2825 n=pop_num();
2826 if(n) cur_state=n|heading;
2827 if(!stack_ptr->is_string) program_error("Type mismatch");
2828 omit_line_break=1;
2829 process_line(stack_ptr->text);
2830 stack_drop();
2831 break;
2834 @*Inner Commands. These are commands other than the section headings.
2836 @ The first command to deal with is simple--it is a comment. The rest of
2837 the current line is simply discarded.
2839 @<Process \.{@@.} command@>= {
2840 ptr[-1]=0;
2843 @ This command is a pattern split. It means it will process the part of
2844 the line before this command and then process the stuff after it. The
2845 variable |omit_line_break| is 1 if this command is used; because it means
2846 there will not be a line break. (Otherwise, patterns and so on are split
2847 at line breaks.)
2849 @<Process \.{@@\&} command@>= {
2850 ptr[-1]=0;
2851 process_line(buf);
2852 buf=++ptr;
2855 @ This allows control characters to be inserted into the input. This code
2856 takes advantage of the way the ASCII code works, in which stripping all
2857 but the five low bits can convert a letter (uppercase or lowercase) to its
2858 corresponding control character.
2860 @^control character@>
2862 @<Process \.{@@\^} command@>= {
2863 ptr[1]&=0x1F;
2864 --ptr;
2865 delete_chars(ptr,2);
2868 @ The following command is used to execute a code in a different state and
2869 then include the results in this area.
2871 @<Process \.{@@(} command@>= {
2872 char*p;
2873 char*q;
2874 @<Skip over the name and save the rest of the line@>;
2875 @<Execute the code for the named subroutine@>;
2876 @<Insert the returned string and fix the line buffer@>;
2879 @ @<Skip over the name and save the rest of the line@>= {
2880 p=ptr+1;
2881 while(*ptr && *ptr!=')') ptr++;
2882 q=strdup(ptr+!!*ptr);
2883 *ptr=0;
2886 @ @<Execute the code for the named subroutine@>= {
2887 int n=find_name(p);
2888 execute_program(fetch_code(n));
2891 @ @<Insert the returned string and fix the line buffer@>= {
2892 char*s=pop_string();
2893 sprintf(p-2,"%s%s",s,q);
2894 ptr=p+strlen(s)-2;
2895 free(s);
2896 free(q);
2899 @ This command is used for conditional processing. The condition value
2900 comes from the stack. Zero is false, everything else is true.
2902 @<Process \.{@@<} command@>= {
2903 --ptr;
2904 delete_chars(ptr,2);
2905 condition_level=!stack_ptr->number;
2906 stack_drop();
2909 @*Card State. Cards are added to the card areas by using the card state.
2910 The \.C register tells which is the current card area, and \.P register is
2911 used to select the current pattern area. The pattern area is used to match
2912 patterns after reading a line. Please note that it won't work to change
2913 the value of the \.C register during the card state.
2915 @<Process card heading@>= {
2916 int n=find_name(buf);
2917 cur_data=set_card_area(n);
2918 cur_name=n-256;
2919 push_num(n);@+store('C');
2922 @ @<Process card state@>= {
2923 char*b;
2924 if(!omit_line_break) strcpy(buf+strlen(buf),"\n");
2925 @<Initialize the \.W register@>;
2926 b=do_patterns(strdup(buf),registers['P'].number);
2927 if(registers['W'].is_string) execute_program(registers['W'].text);
2928 @<Send the tokens of |b| and replace whatsits@>;
2929 free(b);
2932 @ @<Initialize the \.W register@>= {
2933 if(registers['W'].is_string) free(registers['W'].text);
2934 registers['W'].is_string=1;
2935 registers['W'].text=strdup("");
2938 @ @<Send the tokens of |b| and replace whatsits@>= {
2939 char*p;
2940 for(p=b;*p;p++) {
2941 if(*p==whatsit) {
2942 send_token(cur_data,pop_num());
2943 } @+else {
2944 send_token(cur_data,(*p==1)?0:*p);
2949 @ There is one command you might want to send tokens in any other time.
2951 @<Cases for system commands@>=
2952 @-case 'T': {
2953 // Add tokens to the card area
2954 if(stack_ptr->is_string) {
2955 @<Send tokens from the string on the stack@>;
2956 } @+else {
2957 send_token(set_card_area(registers['C'].number),stack_ptr->number);
2959 stack_drop();
2960 break;
2963 @ @<Send tokens from the string on the stack@>= {
2964 char*p;
2965 data_index q=set_card_area(registers['C'].number);
2966 for(p=stack_ptr->text;*p;p++) send_token(q,*p);
2969 @*Deck State. Deck state is used for creating deck lists and random packs.
2971 @<Process deck heading@>= {
2972 cur_name=find_name(buf)-256;
2973 cur_data=set_deck_list(cur_name+256);
2974 @<Skip to the end of the deck list@>;
2977 @ @<Skip to the end of the deck list@>= {
2978 while(deck_lists.data[cur_data].next!=none)
2979 cur_data=deck_lists.data[cur_data].next;
2982 @ Now to parse each line in turn. Each line consists of a number, the
2983 flags, and a text.
2985 @<Process deck state@>= {
2986 int n=strtol(buf,&buf,10);
2987 unsigned int f=0;
2988 if(n) {
2989 buf+=strspn(buf,"\x20\t");
2990 @<Read the flags for the deck list@>;
2991 buf+=strspn(buf,"\x20\t"); // Now we are at the point of the text
2992 @<Send this line to the deck list@>;
2993 @<Create and advance to the new terminator of the deck list@>;
2997 @ @<Read the flags for the deck list@>= {
2998 while(*buf>='a' && *buf<='z') f |=lflag(*buf++);
2999 buf++; // Skip terminator of flags
3002 @ If the \.x flag is set, it will be determined what to do with the text
3003 by the user-defined code. Otherwise, it is always a name, so we can save
3004 memory by pointing to the name buffer (since name buffers never vary).
3006 @<Send this line to the deck list@>= {
3007 if(f&lflag('x')) {
3008 deck_lists.data[cur_data].name=strdup(buf);
3009 } @+else {
3010 deck_lists.data[cur_data].name=name_info(find_name(buf)).name;
3014 @ @<Create and advance to the new terminator of the deck list@>= {
3015 data_index i=new_record(deck_lists);
3016 deck_lists.data[cur_data].next=i;
3017 deck_lists.data[cur_data=i].next=none;
3020 @*Execute State. This state is simple, just execute stack codes. It is the
3021 initial state; you can use it with terminal input, too.
3023 @<Process execute state@>= {
3024 execute_program(buf);
3027 @*File State. This state is used to make list of output files. Each one is
3028 stored as a string, like subroutine state. The difference is that newlines
3029 will not be discarded. The other difference is that there is a flag in the
3030 |name_data| record for it that tells it that it is a file that should be
3031 sent to output.
3033 @<More elements of |name_data|@>=
3034 boolean is_output_file;
3036 @ @<Process file heading@>= {
3037 cur_name=find_name(buf)-256;
3038 if(!names.data[cur_name].value.is_string) {
3039 names.data[cur_name].value.is_string=1;
3040 names.data[cur_name].value.text=strdup("");
3041 names.data[cur_name].is_output_file=1;
3045 @ @<Process file state@>= {
3046 int z=strlen(names.data[cur_name].value.text);
3047 if(!omit_line_break) strcpy(buf+strlen(buf),"\n");
3048 names.data[cur_name].value.text=realloc(names.data[cur_name].value.text,
3049 z+strlen(buf)+1);
3050 strcpy(names.data[cur_name].value.text+z,buf);
3053 @*Include State. The include state causes inclusion of another source file
3054 from this one.
3056 @<Process include heading@>= {
3057 cur_state=execute_state;
3058 @<Push the include file onto the input stack@>;
3059 @<Attempt to open the include file...@>;
3062 @ @<Push the include file onto the input stack@>= {
3063 ++current_input_file;
3064 memusage_log("Opening input file",current_input_file-input_files)@;
3065 strcpy(current_filename,buf);
3066 current_line=0;
3067 current_fp=0;
3070 @ Include files are searched using the search path specified in the
3071 environment variable called \.{TEXNICARDPATH}, which is a list of paths
3072 delimited by colons on UNIX systems (including Cygwin), but semicolons on
3073 Windows (colons are used in Windows for drive letters). A forward slash is
3074 the path separator. Please note that if you want to use include files in
3075 the current directory, you must include |"."| as the first entry in the
3076 search path!!
3078 @^search path@>
3079 @.TEXNICARDPATH@>
3080 @^Windows@>
3082 @<Set |includepath_separator| depending on operating system@>=
3083 #ifdef WIN32
3084 #define @!includepath_separator ';'
3085 #else
3086 #define includepath_separator ':'
3087 #endif
3089 @ @<Attempt to open the include file by finding it in the search path@>= {
3090 current_fp=open_file(current_filename,"r");
3091 @<It is a fatal error if no such file was found@>;
3094 @ Since this part of the code is activated in many parts of the program,
3095 we will make it a subroutine that can open files in different modes.
3097 @-p FILE*open_file(char*filename,char*mode) {
3098 char searchpath[max_pathname_length+max_filename_length+1];
3099 char*cpath;
3100 char*npath=getenv("TEXNICARDPATH");
3101 FILE*fp=0;
3102 strcpy(searchpath,npath?npath:".");
3103 npath=cpath=searchpath;
3104 @<Set |includepath_separator| depending on operating system@>;
3105 @<Attempt to open the file from each each directory in the search path@>;
3106 return fp;
3109 @ @<Attempt to open the file from each each directory...@>= {
3110 while(!fp) {
3111 char f[max_pathname_length+max_filename_length+1];
3112 @<Select the next path name into |cpath| and |npath|@>;
3113 sprintf(f,"%s/%s",cpath,filename);
3114 fp=fopen(f,mode);
3118 @ @<Select the next path name into |cpath| and |npath|@>= {
3119 if(!(cpath=npath)) break;
3120 if((npath=strchr(npath,includepath_separator))) *npath++=0;
3123 @ @<It is a fatal error if no such file was found@>= {
3124 if(!current_fp) {
3125 fprintf(stderr,"%s not found in search path.\n",current_filename);
3126 @.not found in search path@>
3127 exit(1);
3131 @*Keyword State. You can add keywords to the keyword area by using this.
3132 Each keyword heading is one entry in the list.
3134 @<Process keyword heading@>= {
3135 cur_data=new_record(keywords);
3136 keywords.data[cur_data].match=strdup(buf);
3137 keywords.data[cur_data].replacement=strdup("");
3140 @ @<Process keyword state@>= {
3141 keyword_data*k=&keywords.data[cur_data];
3142 if(*buf=='+') {
3143 k->category|=find_category(buf+1);
3144 } @+else {
3145 if(!omit_line_break) strcpy(buf+strlen(buf),"\n");
3146 @<Append buffer to keyword text@>;
3150 @ @<Append buffer to keyword text@>= {
3151 if(*buf) {
3152 int z=strlen(k->replacement);
3153 k->replacement=realloc(k->replacement,z+strlen(buf)+1);
3154 strcpy(k->replacement+z,buf);
3158 @*Image State. This state compiles image manipulator commands.
3160 @<Process image heading@>= {
3161 int n=find_name(buf);
3162 cur_data=set_image_manip(n);
3163 cur_name=n-256;
3166 @ Each line will be executed and then the numbers on the stack are used as
3167 the command codes. This means you can also use names and calculations and
3168 so on, instead of always entering the commands directly.
3170 @<Process image state@>= {
3171 register_value*p=stack_ptr;
3172 execute_program(buf);
3173 if(stack_ptr<p) {
3174 fprintf(stderr,"Stack underflow\n");
3175 exit(1);
3177 if(stack_ptr>p) {
3178 @<Get the numbers from the stack, store at image manipulation area@>;
3179 while(stack_ptr>p) stack_drop();
3183 @ @<Get the numbers from the stack, store at image manipulation area@>= {
3184 register_value*s=stack_ptr;
3185 int i=0;
3186 image_manipulator*im=image_manips.data+cur_data;
3187 while(im->next!=none) im=image_manips.data+im->next;
3188 im->data=malloc((im->data_len=s-p)*sizeof(unsigned short));
3189 for(;s<p;s++,i++) im->data[i]=s->number;
3192 @*Pattern State. This state compiles patterns into a pattern area. It
3193 uses its own syntax, and then is converted into the proper control codes
3194 for the |text| of a pattern.
3196 @<Process pattern heading@>= {
3197 cur_name=find_name(buf)-256;
3198 cur_data=set_pattern_area(cur_name+256);
3201 @ The stuff inside the pattern state has its own commands.
3203 @<Process pattern state@>= {
3204 char add_buf[1024]; // buffer of text to add to the current pattern
3205 pattern_data*pat=&pattern_areas.data[cur_data];
3206 *add_buf=0;
3207 switch(*buf) {
3208 case '<': @<Create a new pattern with top priority@>;@+break;
3209 case '>': @<Create a new pattern with bottom priority@>;@+break;
3210 case ':': @<Make a pattern text with a marker@>;@+break;
3211 case '+': @<Add a keyword category to this pattern@>;@+break;
3212 default: ; // do nothing
3214 @<Append contents of |add_buf| to the pattern, if needed@>;
3217 @ @<Create a new pattern with top priority@>= {
3218 cur_data=new_record(pattern_areas);
3219 pattern_areas.data[cur_data].text=strdup("");
3220 pattern_areas.data[cur_data].subroutine=find_name(buf+1)-256;
3221 pattern_areas.data[cur_data].next=names.data[cur_name].pattern_area;
3222 names.data[cur_name].pattern_area=cur_data;
3225 @ @<Create a new pattern with bottom priority@>= {
3226 data_index n;
3227 cur_data=new_record(pattern_areas);
3228 pattern_areas.data[cur_data].text=strdup("");
3229 pattern_areas.data[cur_data].subroutine=find_name(buf+1)-256;
3230 pattern_areas.data[cur_data].next=none;
3231 @<Find the bottom pattern and store its index in |n|@>;
3232 pattern_areas.data[n].next=cur_data;
3235 @ @<Find the bottom pattern and...@>= {
3236 n=names.data[cur_name].pattern_area;
3237 while(pattern_areas.data[n].next!=none && pattern_areas.data[n].text &&
3238 pattern_areas.data[pattern_areas.data[n].next].next!=none)
3239 n=pattern_areas.data[n].next;
3242 @ Actually, the name of this \strike{cake} chunk is a lie, because it does
3243 not always add a marker.
3245 @<Make a pattern text with a marker@>= {
3246 char*p;
3247 char*b=add_buf;
3248 @<Add the pattern marker if applicable@>;
3249 for(p=buf+2;p[-1] && *p;p++) {
3250 switch(*p) {
3251 case '\\': *b++=*++p; @+break;
3252 case '(': *b++=begin_capture; @+break;
3253 case ')': *b++=end_capture; @+break;
3254 case '%': *b++=match_keyword; @+*b++=*++p; @+break;
3255 case '!': *b++=match_table; @+*b++=*++p; @+break;
3256 case '?': *b++=optional_table; @+*b++=*++p; @+break;
3257 case '#': *b++=failed_match; @+break;
3258 case '&': *b++=jump_table; @+*b++=*++p; @+break;
3259 case ';': *b++=successful_match; @+break;
3260 case '<': *b++=back_one_space; @+break;
3261 case '>': *b++=forward_one_space; @+break;
3262 case '[': *b++=match_left_side; @+break;
3263 case ']': *b++=match_right_side; @+break;
3264 default: *b++=*p; @+break;
3267 *b=0;
3270 @ @<Add the pattern marker if applicable@>= {
3271 if(buf[1]>' ') *b++=buf[1]|0x80;
3274 @ @<Add a keyword category to this pattern@>= {
3275 pattern_areas.data[cur_data].category=find_category(buf+1);
3278 @ @<Append contents of |add_buf| to the pattern...@>= {
3279 if(*add_buf) {
3280 int z=strlen(pat->text);
3281 pat->text=realloc(pat->text,z+strlen(add_buf)+1);
3282 strcpy(pat->text+z,add_buf);
3286 @*Subroutine State. This state is used to add a named subroutine.
3288 @<Process subroutine heading@>= {
3289 cur_name=find_name(buf)-256;
3290 if(!names.data[cur_name].value.is_string) {
3291 names.data[cur_name].value.is_string=1;
3292 names.data[cur_name].value.text=strdup("");
3296 @ @<Process subroutine state@>= {
3297 int z=strlen(names.data[cur_name].value.text);
3298 names.data[cur_name].value.text=realloc(names.data[cur_name].value.text,
3299 z+strlen(buf)+1);
3300 strcpy(names.data[cur_name].value.text+z,buf);
3303 @*Word Forms State. You can use the word forms state to enter rules and
3304 exceptions for word forms, such as plurals.
3306 @<Global variables@>=
3307 char wordform_code[256]; // code to execute at \.= line
3308 char wordform_kind; // which kind of word forms is being made now?
3310 @ @<Process word forms state@>= {
3311 switch(*buf) {
3312 case '>': @<Process \.> line in word forms state@>; @+break;
3313 case '=': @<Process \.= line in word forms state@>; @+break;
3314 case '#': wordform_kind=buf[1]; @+break;
3315 default: if(*buf>='0' && *buf<='9')
3316 @<Process numeric line in word forms state@>;
3320 @ The commands are \.>, \.=, and numbers. The command \.> sets a code for
3321 processing \.= commands, and then add to the list.
3323 @<Process \.> line in word forms state@>= {
3324 strcpy(wordform_code,buf+1);
3327 @ @<Process \.= line in word forms state@>= {
3328 int level,kind;
3329 char*orig;
3330 char*dest;
3331 push_string(buf+1);
3332 execute_program(wordform_code);
3333 kind=pop_num(); @+ level=pop_num();
3334 dest=pop_string(); @+ orig=pop_string();
3335 add_word_form(kind,level,orig,dest);
3336 free(orig); @+ free(dest);
3339 @ Now the command for numeric forms. You put ``level\.:orig\.:dest'' in
3340 that order, please.
3342 @<Process numeric line in word forms state@>= {
3343 int level=strtol(buf,&buf,0);
3344 char*p;
3345 if(*buf==':') buf++;
3346 p=strchr(buf,':');
3347 if(p) *p=0;
3348 add_word_form(wordform_kind,level,buf,p+1);
3351 @*Writing Output Files. Finally, it will be time to send any output
3352 generated into the files (if there is any, which there usually is).
3354 @^output@>
3356 @d ctrl(_letter) (0x1F&(_letter))
3358 @d call_final_subroutine ctrl('C')
3359 @d copy_field ctrl('F')
3360 @d newline ctrl('J')
3361 @d loop_point ctrl('L')
3362 @d next_record ctrl('N')
3363 @d skip_one_character ctrl('S')
3365 @<Write the output files@>= {
3366 data_index n;
3367 foreach(n,names) {
3368 if(names.data[n].is_output_file && names.data[n].value.is_string)
3369 @<Write this output file@>;
3373 @ @<Write this output file@>= {
3374 FILE*fout=fopen(names.data[n].name,"w");
3375 char*ptr=names.data[n].value.text;
3376 char*loopptr=ptr; // loop point
3377 if(!fout) @<Error about unable to open output file@>;
3378 while(*ptr) @<Write the character and advance to the next one@>;
3379 fclose(fout);
3382 @ @<Error about unable to open output file@>= {
3383 fprintf(stderr,"Unable to open output file: %s\n",names.data[n].name);
3384 @.Unable to open output file@>
3385 exit(1);
3388 @ @<Write the character and advance to the next one@>= {
3389 switch(*ptr) {
3390 case call_final_subroutine: @<Do |call_final_subroutine|@>; @+break;
3391 case copy_field: @<Do |copy_field|@>; @+break;
3392 case loop_point: loopptr=++ptr; @+break;
3393 case next_record: @<Do |next_record|@>; @+break;
3394 case skip_one_character: ptr+=2; @+break;
3395 default: fputc(*ptr++,fout);
3397 done_writing_one_character: ;
3400 @ @<Do |call_final_subroutine|@>= {
3401 register_value*v;
3402 if(*++ptr=='(') {
3403 char*p=strchr(ptr,')');
3404 *p=0;
3405 v=&name_info(find_name(ptr+1)).value;
3406 *p=')';
3407 ptr=p+1;
3408 } @+else {
3409 v=&registers[*ptr++];
3411 if(v->is_string) {
3412 execute_program(v->text);
3413 @<Write or loop based on result of subroutine call@>;
3414 stack_drop();
3418 @ @<Write or loop based on result of subroutine call@>= {
3419 if(stack_ptr->is_string) {
3420 fprintf(fout,"%s",stack_ptr->text);
3421 } @+else if(stack_ptr->number) {
3422 ptr=loopptr;
3426 @ This command is used to copy the next field.
3428 Look at the definition for the |send_reg_char_or_text| macro. It is
3429 strange, but it should work wherever a statement is expected. Please note
3430 that a ternary condition operator should have both choices of the same
3431 type.
3433 @^strange codes@>
3435 @d tok_idx (registers['A'].number)
3436 @d tok_area
3437 (card_areas.data[name_info(registers['C'].number).value.number].tokens)
3439 @d send_reg_char_or_text(_reg)
3440 if(!registers[_reg].is_string || *registers[_reg].text)
3441 fprintf(fout, "%c%s",
3442 registers[_reg].is_string?
3443 *registers[_reg].text:registers[_reg].number,
3444 registers[_reg].is_string?
3445 registers[_reg].text+1:(unsigned char*)""
3448 @<Do |copy_field|@>= {
3449 ++ptr;
3450 for(;;) {
3451 switch(tok_area[tok_idx++]) {
3452 case null_char: @<Unexpected |null_char|@>;
3453 case end_transmission: tok_idx=0; @+goto done_writing_one_character;
3454 case tabulation: send_reg_char_or_text('T'); @+break;
3455 case raw_data: @<Do |raw_data|@>; @+break;
3456 case escape_code: send_reg_char_or_text('E'); @+break;
3457 case record_separator: tok_idx--; @+goto done_writing_one_character;
3458 case field_separator: @+goto done_writing_one_character;
3459 default: @/
3460 if(tok_area[--tok_idx]&~0xFF)
3461 @<Deal with name code@>@;
3462 else
3463 @<Deal with normal character@>;
3464 tok_idx++;
3469 @ @<Unexpected |null_char|@>= {
3470 fprintf(stderr,"Unexpected null character found in a card area\n");
3471 @.Unexpected null character...@>
3472 exit(1);
3475 @ @<Do |raw_data|@>= {
3476 while(tok_area[tok_idx]) fputc(tok_area[tok_idx++],fout);
3477 tok_idx++;
3480 @ A name code found here is a code to tell it to call the subroutine code
3481 when it is time to write it out to the file. It should return a string on
3482 the stack (if it is a number, it will be ignored).
3484 @<Deal with name code@>= {
3485 if(name_info(tok_area[tok_idx]).value.is_string)
3486 execute_program(name_info(tok_area[tok_idx]).value.text);
3487 if(stack_ptr->is_string) fprintf(fout,"%s",stack_ptr->text);
3488 stack_drop();
3491 @ In case of a normal character, normally just write it out. But some
3492 characters need escaped for \TeX.
3494 @<Deal with normal character@>= {
3495 if(tables['E'][tok_area[tok_idx]]) send_reg_char_or_text('E');
3496 fputc(tok_area[tok_idx],fout);
3499 @ This one moves to the next record, looping if a next record is in fact
3500 available. Otherwise, just continue. Note that a |record_separator|
3501 immediately followed by a |end_transmission| is assumed to mean there is
3502 no next record, and that there is allowed to be a optional
3503 |record_separator| just before the |end_transmission|.
3505 @<Do |next_record|@>= {
3506 ++ptr;
3507 while(tok_area[tok_idx]!=record_separator &&
3508 tok_area[tok_idx]!=end_transmission) tok_idx++;
3509 if(tok_area[tok_idx]!=end_transmission &&
3510 tok_area[tok_idx+1]!=end_transmission) ptr=loopptr;
3513 @*Functions Common to DVI and GF. Numbers for \.{GF} and \.{DVI} files use
3514 the |dvi_number| data type. (Change this in the change file if the current
3515 setting is inappropriate for your system.)
3517 There is also the |dvi_measure| type, which is twice as long and is used
3518 to compute numbers that can be fractional (with thirty-two fractional bits
3519 and thirty-two normal bits).
3521 @<Typedefs@>=
3522 @q[Type of DVI numbers::]@>
3523 typedef signed int dvi_number;
3524 typedef signed long long int dvi_measure;
3525 @q[::Type of DVI numbers]@>
3527 @ There is one subroutine here to read a |dvi_number| from a file. They
3528 come in different sizes and some are signed and some are unsigned.
3530 @^endianness@>
3531 @^byte order@>
3533 @-p dvi_number get_dvi_number(FILE*fp,boolean is_signed,int size) {
3534 dvi_number r=0;
3535 if(size) r=fgetc(fp);
3536 if((r&0x80) && is_signed) r|=0xFFFFFF00;
3537 while(--size) r=(r<<8)|fgetc(fp);
3538 return r;
3541 @ Some macros are defined here in order to deal with |dvi_measure| values.
3543 @^fractions@>
3545 @d to_measure(_value) (((dvi_measure)(_value))<<32)
3546 @d floor(_value) ((dvi_number)((_value)>>32))
3547 @d round(_value) ((dvi_number)(((_value)+0x8000)>>32))
3548 @d ceiling(_value) ((dvi_number)(((_value)+0xFFFF)>>32))
3550 @ Here division must be done in a careful way, to ensure that none of the
3551 intermediate results exceed sixty-four bits.
3553 @d fraction_one to_measure(1)
3555 @-p dvi_measure make_fraction(dvi_measure p,dvi_measure q) {
3556 dvi_measure f,n;
3557 boolean negative=(p<0)^(q<0);
3558 if(p<0) p=-p;
3559 if(q<0) q=-q;
3560 n=p/q; @+ p=p%q;
3561 n=(n-1)*fraction_one;
3562 @<Compute $f=\lfloor2^{32}(1+p/q)+{1\over2}\rfloor$@>;
3563 return (f+n)*(negative?-1:1);
3566 @ Notice that the computation specifies $(p-q)+p$ instead of $(p+p)-q$,
3567 because the latter could overflow.
3569 @<Compute $f=...@>= {
3570 register dvi_measure b;
3571 f=1;
3572 while(f<fraction_one) {
3573 b=p-q; @+ p+=b;
3574 if(p>=0) {
3575 f+=f+1;
3576 } @+else {
3577 f<<=1;
3578 p+=q;
3583 @ And a few miscellaneous macros.
3585 @d upto4(_var,_cmd) (_var>=_cmd && _var<_cmd+4)
3587 @*DVI Reading. The device-independent file format is a format invented by
3588 David R.~Fuchs in 1979. The file format need not be explained here, since
3589 there are other books which explain it\biblio{Knuth, Donald. ``\TeX: The
3590 Program''. Computers {\char`\&} Typesetting. ISBN 0-201-13437-3.}\biblio{%
3591 Knuth, Donald. ``\TeX ware''. Stanford Computer Science Report 1097.}.
3593 \edef\TeXwareBiblio{\the\bibliocount}
3594 @^Fuchs, David@>
3595 @.DVI@>
3596 @^device independent@>
3598 At first, names will be given for the commands in a \.{DVI} file.
3600 @d set_char_0 0 // Set a character and move [up to 127]
3601 @d set1 128 // Take one parameter to set character [up to 131]
3602 @d set_rule 132 // Set a rule and move down, two parameters
3603 @d put1 133 // As |set1| but no move [up to 136]
3604 @d put_rule 137 // As |set_rule| but no move
3605 @d nop 138 // No operation
3606 @d bop 139 // Beginning of a page
3607 @d eop 140 // End of a page
3608 @d push 141 // Push $(h,v,w,x,y,z)$ to the stack
3609 @d pop 142 // Pop $(h,v,w,x,y,z)$ from the stack
3610 @d right1 143 // Take one parameter, move right [up to 146]
3611 @d w0 147 // Move right $w$ units
3612 @d w1 148 // Set $w$ and move right [up to 151]
3613 @d x0 152 // Move right $x$ units
3614 @d x1 153 // Set $x$ and move right [up to 156]
3615 @d down1 157 // Take one parameter, move down [up to 160]
3616 @d y0 161 // Move down $y$ units
3617 @d y1 162 // Set $y$ and move down [up to 165]
3618 @d z0 166 // Move down $z$ units
3619 @d z1 167 // Set $z$ and move down [up to 170]
3620 @d fnt_num_0 171 // Select font 0 [up to 234]
3621 @d fnt1 235 // Take parameter to select font [up to 238]
3622 @d xxx1 239 // Specials [up to 242]
3623 @d fnt_def1 243 // Font definitions [up to 246]
3624 @d pre 247 // Preamble
3625 @d post 248 // Postamble
3626 @d post_post 249 // Postpostamble
3628 @ We should now start reading the \.{DVI} file. Filenames of fonts being
3629 used will be sent to standard output.
3631 @-p boolean read_dvi_file(char*filename) {
3632 boolean fonts_okay=1;
3633 FILE*fp=fopen(filename,"rb");
3634 if(!fp) dvi_error(fp,"Unable to open file");
3635 @#@<Skip the preamble of the \.{DVI} file@>;
3636 @<Skip to the next page@>;
3637 @<Read the metapage heading@>;
3638 @<Compute the conversion factor@>;
3639 read_dvi_page(fp);
3640 @<Skip to and read the postamble@>;
3641 @<Read the font definitions and load the fonts@>;
3642 if(fonts_okay) @<Read the pages for each card@>;
3643 @#fclose(fp);
3644 return fonts_okay;
3647 @ @-p void dvi_error(FILE*fp,char*text) {
3648 fprintf(stderr,"DVI error");
3649 @.DVI error@>
3650 if(fp) fprintf(stderr," at %08X",ftell(fp));
3651 fprintf(stderr,": %s\n",text);
3652 exit(1);
3655 @ Please note the version number of the \.{DVI} file must be 2.
3657 @<Skip the preamble of the \.{DVI} file@>= {
3658 if(fgetc(fp)!=pre) dvi_error(fp,"Bad preamble");
3659 if(fgetc(fp)!=2) dvi_error(fp,"Wrong DVI version");
3660 @<Read the measurement parameters@>;
3661 @<Skip the DVI comment@>;
3664 @ @<Read the measurement parameters@>= {
3665 unit_num=get_dvi_number(fp,0,4);
3666 unit_den=get_dvi_number(fp,0,4);
3667 unit_mag=get_dvi_number(fp,0,4);
3670 @ @<Skip the DVI comment@>= {
3671 int n=fgetc(fp);
3672 fseek(fp,n,SEEK_CUR);
3675 @ From the postamble we can read the pointer for the last page.
3677 @<Global variables@>=
3678 dvi_number last_page_ptr;
3680 @ @<Skip to and read the postamble@>= {
3681 fseek(fp,-4,SEEK_END);
3682 while(fgetc(fp)==223) fseek(fp,-2,SEEK_CUR);
3683 fseek(fp,-5,SEEK_CUR);
3684 fseek(fp,get_dvi_number(fp,0,4)+1,SEEK_SET);
3685 last_page_ptr=get_dvi_number(fp,0,4);
3686 fseek(fp,20,SEEK_CUR); // Skipped parameters of |post|
3687 dvi_stack=malloc(get_dvi_number(fp,0,2)*sizeof(dvi_stack_entry));
3688 fseek(fp,2,SEEK_CUR);
3691 @ Between the preamble and the first page can be |nop| commands and font
3692 definitions, so these will be skipped. The same things can occur between
3693 the end of one page and the beginning of the next page.
3695 @<Skip to the next page@>= {
3696 int c;
3697 for(;;) {
3698 c=fgetc(fp);
3699 if(c==bop) break;
3700 if(c>=fnt_def1 && c<fnt_def1+4) {
3701 @<Skip a font definition@>;
3702 } @+else if(c!=nop) {
3703 dvi_error(fp,"Bad command between pages");
3708 @ @<Skip a font definition@>= {
3709 int a,l;
3710 fseek(fp,c+13-fnt_def1,SEEK_CUR);
3711 a=fgetc(fp);
3712 l=fgetc(fp);
3713 fseek(fp,a+l,SEEK_CUR);
3716 @ The metapage includes the resolution and other things which must be set,
3717 such as subroutine codes. The resolution must be read before fonts can be
3718 read. Please note that no characters can be typeset on the metapage, since
3719 fonts have not been loaded yet. You can still place empty boxes. The DPI
3720 setting (resolution) is read from the \.{\\count1} register.
3722 @<Read the metapage heading@>= {
3723 dvi_number n=get_dvi_number(fp,0,4);
3724 if(n) {
3725 fprintf(stderr,"Metapage must be numbered zero (found %d).\n",n);
3726 @.Metapage must be...@>
3727 exit(1);
3729 push_num(get_dvi_number(fp,0,4)); @+ store('D');
3730 fseek(fp,9*4,SEEK_CUR); // Skip other parameters
3731 layer_width=layer_height=0;
3734 @ A stack is kept of the page registers, for use with the |push| and |pop|
3735 commands of a \.{DVI} file. This stack is used by the |read_dvi_page|
3736 subroutine and stores the |quan| registers (described in the next
3737 chapter).
3739 @<Typedefs@>=
3740 typedef struct {
3741 dvi_number h;
3742 dvi_number v;
3743 dvi_number w;
3744 dvi_number x;
3745 dvi_number y;
3746 dvi_number z;
3747 dvi_number hh;
3748 dvi_number vv;
3749 } dvi_stack_entry;
3751 @ @<Global variables@>=
3752 dvi_stack_entry*dvi_stack;
3753 dvi_stack_entry*dvi_stack_ptr;
3755 @ Here is the subroutine to read commands from a DVI page. The file
3756 position should be at the beginning of the page after the |bop| command.
3758 @^pages@>
3760 @-p void read_dvi_page(FILE*fp) {
3761 memusage_log("Beginning of page",fseek(fp));
3762 @<Reset the page registers and stack@>;
3763 typeset_new_page();
3764 @<Read the commands of this page@>;
3765 if(layer_width && layer_height) @<Render this page@>;
3768 @ @<Reset the page registers and stack@>= {
3769 quan('A')=quan('B')=quan('H')=quan('I')=quan('J')=quan('L')=quan('V')=
3770 quan('W')=quan('X')=quan('Y')=quan('Z')=0;
3771 dvi_stack_ptr=dvi_stack;
3774 @ @<Read the commands of this page@>= {
3775 int c,a;
3776 boolean moveaftertyping;
3777 for(;;) {
3778 c=fgetc(fp);
3779 if(c<set1) {
3780 moveaftertyping=1;
3781 @<Typeset character |c| on the current layer@>;
3782 } @+else if(upto4(c,set1)) {
3783 moveaftertyping=1;
3784 c=get_dvi_number(fp,0,c+1-set1);
3785 @<Typeset character |c| on the current layer@>;
3786 } @+else if(c==set_rule || c==put_rule) {
3787 moveaftertyping=(c==set_rule);
3788 c=get_dvi_number(fp,1,4);
3789 a=get_dvi_number(fp,1,4);
3790 @<Typeset |a| by |c| rule on the current layer@>;
3791 } @+else if(upto4(c,put1)) {
3792 moveaftertyping=0;
3793 c=get_dvi_number(fp,0,c+1-put1);
3794 @<Typeset character |c| on the current layer@>;
3795 } @+else if(c==eop) {
3796 break;
3797 } @+else if(c==push) {
3798 if(dvi_stack) @<Push DVI registers to stack@>;
3799 } @+else if(c==pop) {
3800 if(dvi_stack) @<Pop DVI registers from stack@>;
3801 } @+else if(upto4(c,right1)) {
3802 c=get_dvi_number(fp,1,c+1-right1);
3803 horizontal_movement(c);
3804 } @+else if(c==w0) {
3805 horizontal_movement(quan('W'));
3806 } @+else if(upto4(c,w1)) {
3807 c=get_dvi_number(fp,1,c+1-w1);
3808 horizontal_movement(quan('W')=c);
3809 } @+else if(c==x0) {
3810 horizontal_movement(quan('X'));
3811 } @+else if(upto4(c,x1)) {
3812 c=get_dvi_number(fp,1,c+1-x1);
3813 horizontal_movement(quan('X')=c);
3814 } @+else if(upto4(c,down1)) {
3815 c=get_dvi_number(fp,1,c+1-down1);
3816 vertical_movement(c);
3817 } @+else if(c==y0) {
3818 vertical_movement(quan('Y'));
3819 } @+else if(upto4(c,y1)) {
3820 c=get_dvi_number(fp,1,c+1-y1);
3821 vertical_movement(quan('Y')=c);
3822 } @+else if(c==z0) {
3823 vertical_movement(quan('Z'));
3824 } @+else if(upto4(c,z1)) {
3825 c=get_dvi_number(fp,1,c+1-z1);
3826 vertical_movement(quan('Z')=c);
3827 } @+else if(c>=fnt_num_0 && c<fnt1) {
3828 quan('F')=c-fnt_num_0;
3829 } @+else if(upto4(c,fnt1)) {
3830 quan('F')=get_dvi_number(fp,0,c+1-fnt1);
3831 } @+else if(upto4(c,xxx1)) {
3832 c=get_dvi_number(fp,0,c+1-xxx1);
3833 @<Read a special of length |c|@>;
3834 } @+else if(upto4(c,fnt_def1)) {
3835 @<Skip a font definition@>;
3836 } @+else if(c!=nop) {
3837 dvi_error(fp,"Unknown DVI command");
3842 @ @<Push DVI registers to stack@>= {
3843 dvi_stack_ptr->h=quan('H');
3844 dvi_stack_ptr->v=quan('V');
3845 dvi_stack_ptr->w=quan('W');
3846 dvi_stack_ptr->x=quan('X');
3847 dvi_stack_ptr->y=quan('Y');
3848 dvi_stack_ptr->z=quan('Z');
3849 dvi_stack_ptr->hh=quan('I');
3850 dvi_stack_ptr->vv=quan('J');
3851 ++dvi_stack_ptr;
3854 @ @<Pop DVI registers from stack@>= {
3855 --dvi_stack_ptr;
3856 quan('H')=dvi_stack_ptr->h;
3857 quan('V')=dvi_stack_ptr->v;
3858 quan('W')=dvi_stack_ptr->w;
3859 quan('X')=dvi_stack_ptr->x;
3860 quan('Y')=dvi_stack_ptr->y;
3861 quan('Z')=dvi_stack_ptr->z;
3862 quan('I')=dvi_stack_ptr->hh;
3863 quan('J')=dvi_stack_ptr->vv;
3866 @ A special in \TeX nicard is used to execute a special code while reading
3867 the DVI file. Uses might be additional calculations, changes of registers,
3868 special effects, layer selection, etc. All of these possible commands are
3869 dealt with elsewhere in this program. All we do here is to read it and to
3870 send it to the |execute_program| subroutine.
3872 @^specials@>
3874 @<Read a special of length |c|@>= {
3875 char*buf=malloc(c+1);
3876 fread(buf,1,c,fp);
3877 buf[c]=0;
3878 @<Set \.X and \.Y registers to prepare for the special@>;
3879 execute_program(buf);
3880 free(buf);
3883 @ @<Set \.X and \.Y registers to prepare for the special@>= {
3884 registers['X'].is_string=registers['Y'].is_string=0;
3885 registers['X'].number=quan('I');
3886 registers['Y'].number=quan('J');
3889 @ In order to read all the pages for each card, we can skip backwards by
3890 using the back pointers. Either we will print all cards (in reverse
3891 order), or we will print cards listed on the command-line, or we will
3892 print cards listed in a file (this last way might be used to print decks
3893 or booster packs).
3895 Card numbers should be one-based, and should not be negative. Any pages
3896 with negative page numbers will be ignored when it is in the mode for
3897 printing all cards.
3899 @d printing_all_cards 0
3900 @d printing_list 1
3901 @d printing_list_from_file 2
3903 @<Global variables@>=
3904 unsigned char printing_mode;
3905 char*printlisttext;
3906 FILE*printlistfile;
3908 @ @<Read the pages for each card@>= {
3909 dvi_number page_ptr=last_page_ptr;
3910 dvi_number e=0,n; // page numbers
3911 boolean pagenotfound=0;
3912 for(;;) {
3913 @<Read the next entry from the list of pages (if applicable)@>;
3914 try_next_page:
3915 @<Seek the next page to print@>;
3916 @<Read the heading for this page@>;
3917 @<If this page shouldn't be printed now, |goto try_next_page|@>;
3918 pagenotfound=0;
3919 read_dvi_page(fp);
3921 @#done_printing:;
3924 @ @<Read the next entry from the list of pages (if applicable)@>= {
3925 if(printing_mode==printing_list) {
3926 if(!*printlisttext) goto done_printing;
3927 e=strtol(printlisttext,&printlisttext,10);
3928 if(!e) goto done_printing;
3929 if(*printlisttext) printlisttext++;
3930 } @+else if(printing_mode==printing_list_from_file) {
3931 char buf[256];
3932 if(!printlistfile || feof(printlistfile)) goto done_printing;
3933 if(!fgets(buf,255,printlistfile)) goto done_printing;
3934 e=strtol(buf,0,10);
3938 @ @<Seek the next page to print@>= {
3939 if(page_ptr==-1) {
3940 if(pagenotfound) {
3941 fprintf(stderr,"No page found: %d\n",e);
3942 @.No page found...@>
3943 exit(1);
3945 page_ptr=last_page_ptr;
3946 if(printing_mode==printing_all_cards) goto done_printing;
3947 pagenotfound=1;
3949 fseek(fp,page_ptr+1,SEEK_SET);
3952 @ @<Read the heading for this page@>= {
3953 n=quan('P')=get_dvi_number(fp,1,4);
3954 fseek(fp,4,SEEK_CUR);
3955 layer_width=get_dvi_number(fp,1,4);
3956 layer_height=get_dvi_number(fp,1,4);
3957 fseek(fp,4*6,SEEK_CUR);
3958 page_ptr=get_dvi_number(fp,1,4);
3961 @ @<If this page shouldn't be printed now, |goto try_next_page|@>= {
3962 if(n<=0 && printing_mode==printing_all_cards) goto try_next_page;
3963 if(n!=e && printing_mode!=printing_all_cards) goto try_next_page;
3966 @*DVI Font Metrics. Here, the fonts are loaded. It is assumed all fonts
3967 are in the current directory, and the ``area'' of the font name is
3968 ignored. The checksum will also be ignored (it can be checked with
3969 external programs if necessary).
3971 @^area@>
3972 @^font loading@>
3974 @<Read the font definitions and load the fonts@>= {
3975 int c;
3976 for(;;) {
3977 c=fgetc(fp);
3978 if(c==post_post) break;
3979 if(c>=fnt_def1 && c<fnt_def1+4) {
3980 int k=get_dvi_number(fp,0,c+1-fnt_def1);
3981 if(k&~0xFF) dvi_error(fp,"Too many fonts");
3982 memusage_log("Loading font",k);
3983 @<Read the definition for font |k| and load it@>;
3984 } @+else if(c!=nop) {
3985 dvi_error(fp,"Bad command in postamble");
3988 memusage_log("End of postamble",c);
3991 @ When reading fonts, it will be necessary to keep a list of the fonts
3992 and their character indices. Only 256 fonts are permitted in one job.
3994 @<Global variables@>=
3995 data_index fontindex[256];
3997 @ @<Read the definition for font |k| and load it@>= {
3998 dvi_number c=get_dvi_number(fp,0,4); // checksum (unused)
3999 dvi_number s=get_dvi_number(fp,0,4); // scale factor
4000 dvi_number d=get_dvi_number(fp,0,4); // design size
4001 int a=get_dvi_number(fp,0,1); // length of area
4002 int l=get_dvi_number(fp,0,1); // length of name
4003 char n[257];
4004 fseek(fp,a,SEEK_CUR);
4005 fread(n,1,l,fp);
4006 n[l]=0;
4007 if((fontindex[k]=read_gf_file(n,s,d))==none) fonts_okay=0;
4010 @ An important part of reading the font metrics is the width computation,
4011 which involves multiplying the relative widths in the \.{TFM} file (or
4012 \.{GF} file) by the scaling factor in the \.{DVI} file. This
4013 multiplication must be done in precisely the same way by all \.{DVI}
4014 reading programs, in order to validate the assumptions made by \.{DVI}-%
4015 writing programs such as \TeX.
4017 % (The following paragraph is taken directly from "dvitype.web")
4018 Let us therefore summarize what needs to be done. Each width in a \.{TFM}
4019 file appears as a four-byte quantity called a |fix_word|. A |fix_word|
4020 whose respective bytes are $(a,b,c,d)$ represents the number
4021 $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
4022 b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
4023 -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
4024 (No other choices of $a$ are allowed, since the magnitude of a \.{TFM}
4025 dimension must be less than 16.) We want to multiply this quantity by the
4026 integer~|z|, which is known to be less than $2^{27}$.
4027 If $|z|<2^{23}$, the individual multiplications $b\cdot z$, $c\cdot z$,
4028 $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2, 4, 8, or
4029 16, to obtain a multiplier less than $2^{23}$, and we can compensate for
4030 this later. If |z| has thereby been replaced by $|z|^\prime=|z|/2^e$, let
4031 $\beta=2^{4-e}$; we shall compute
4032 $$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$ if $a=0$,
4033 or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
4034 This calculation must be
4035 done exactly, for the reasons stated above; the following program does the
4036 job in a system-independent way, assuming that arithmetic is exact on
4037 numbers less than $2^{31}$ in magnitude.
4039 \def\zprime{z'}
4041 @f alpha TeX
4042 @f beta TeX
4043 @f zprime TeX
4045 @<Compute |zprime|, |alpha|, and |beta|@>= {
4046 zprime=s; @+ alpha=16;
4047 while(zprime>=040000000) {
4048 zprime>>=1; @+ alpha<<=1;
4050 beta=256/alpha; @+ alpha*=zprime;
4053 @ @<Compute the character width |w|@>= {
4054 w=(((((b3*zprime)>>8)+(b2*zprime))>>8)+(b1*zprime))/beta;
4055 if(b0) w-=alpha;
4058 @*GF Reading. The \.{GF} format is a ``generic font'' format. It has a lot
4059 in common with \.{DVI} format.
4061 At first, names will be given for the commands in a \.{GF} file. Many
4062 commands have the same numbers as they do in a \.{DVI} file (described in
4063 the previous chapter), which makes it very convenient\biblio{This is
4064 probably on purpose for the this very reason, so that a WEB or CWEB
4065 program can use one set of named constants for reading both files.}.
4067 @d paint_0 0 // Paint $d$ pixels black or white [up to 63]
4068 @d paint1 64 // Take parameter, paint pixels [up to 66]
4069 @d boc 67 // Beginning of a character picture
4070 @d boc1 68 // Short form of |boc|
4071 @d eoc 69 // End of a character picture
4072 @d skip0 70 // Skip some rows
4073 @d skip1 71 // Skip some rows [up to 73]
4074 @d new_row_0 74 // Start a new row and move right [up to 238]
4075 @d yyy 243 // Numeric specials
4076 @d no_op 244 // No operation
4077 @d char_loc 245 // Character locator
4078 @d char_loc0 246 // Short form of |char_loc|
4080 @ The |font_struct| structure stores the information for each character in
4081 a font. The |raster| field points to a bitmap with eight pixels per octet,
4082 most significant bit for the leftmost pixel, each row always padded to a
4083 multiple of eight pixels.
4085 While it is reading the postamble, it will fill in this structure with the
4086 |ptr| field set. After the postamble is read, it will fill in the other
4087 fields belonging to its union.
4089 @<Typedefs@>=
4090 typedef struct {
4091 dvi_number dx; // character escapement in pixels
4092 dvi_number w; // width in DVI units
4093 union {
4094 struct {
4095 dvi_number min_n,max_n,min_m,max_m; // bounding box (in pixels)
4096 unsigned short n; // character code number
4097 unsigned char*raster;
4098 unsigned char flag; // bitfield of flags for this character
4099 }@+;
4100 dvi_number ptr;
4101 }@+;
4102 data_index next;
4103 } font_struct;
4105 @ List of flags follows. Some of these flags might be used in order to
4106 allow$\mathord{}>256$ characters per font, since {\TeX} does not have a
4107 command to enter characters with codes more than one byte long. These
4108 flags are specified using numeric specials.
4110 @d ff_select 0x01 // set high octet all characters
4111 @d ff_prefix 0x02 // set high octet for codes 128-255
4112 @d ff_roundafter 0x04 // round $\it hh$ after sending character
4113 @d ff_roundbefore 0x08 // round $\it hh$ before sending character
4114 @d ff_reset 0x10 // reset high octet
4115 @d ff_strip 0x20 // strip highest bit of prefix
4116 @d ff_space 0x40 // do not save the raster (space only)
4117 @d ff_reserved 0x80 // {\bf DO NOT USE}
4119 @ @<Global variables@>=
4120 memory_of(font_struct) font_data;
4122 @ @<Initialize memory@>= init_memory(font_data,4);
4124 @ When loading a \.{GF} font, the filename will contain the resolution
4125 in dots per inch.
4127 @^font loading@>
4129 @-p data_index read_gf_file(char*fontname,dvi_measure s,dvi_measure d) {
4130 unsigned int dpi=(resolution*unit_mag*s+500*d)/(100000*d);
4131 FILE*fp;
4132 data_index index=none;
4133 data_index first_index=none;
4134 data_index last_index=none;
4135 dvi_number zprime,alpha,beta; // used for width computation
4136 @<Compute |zprime|, |alpha|, and |beta|@>;
4137 @<Figure out the filename and open the file, |return none| if it can't@>;
4138 @<Skip to the postamble of the \.{GF} file@>;
4139 @<Read the character locators@>;
4140 @<Read the character rasters and flags@>;
4141 fclose(fp);
4142 return last_index;
4145 @ When figuring out the filename, it will send it to standard output so
4146 that a list can be made of the required fonts.
4148 @<Figure out the filename and open the file, ...@>= {
4149 char n[295];
4150 sprintf(n,"%s.%dgf",fontname,dpi);
4151 printf("%s\n",n);
4152 fp=open_file(n,"rb");
4153 if(!fp) return none;
4156 @ @<Skip to the postamble of the \.{GF} file@>= {
4157 int c;
4158 fseek(fp,-4,SEEK_END);
4159 while(fgetc(fp)==223) fseek(fp,-2,SEEK_CUR);
4160 fseek(fp,-5,SEEK_CUR);
4161 fseek(fp,get_dvi_number(fp,0,4)+37,SEEK_SET); // nothing matters anymore
4164 @ @<Read the character locators@>= {
4165 int c,b0,b1,b2,b3;
4166 dvi_number dx,w,p;
4167 for(;;) {
4168 c=fgetc(fp);
4169 if(c==post_post) break;
4170 p=-1;
4171 if(c==char_loc) {
4172 @<Read a long character locator@>;
4173 } @+else if(c==char_loc0) {
4174 @<Read a short character locator@>;
4175 } @+else if(c!=no_op) {
4176 fprintf(stderr,"Bad command in GF postamble.\n");
4177 @.Bad command in GF postamble@>
4178 fprintf(stderr,"(Command %d, address %08X)\n",c,ftell(fp)-1);
4179 exit(1);
4181 if(p!=-1) @<Defer this character locator into |font_data|@>;
4183 last_index=index;
4186 @ There are some parameters we do not care about. First is $c$, which is
4187 the character code residue (modulo 256). This is not important since it
4188 is duplicated in the |boc| heading for each character. The second
4189 parameter which we do not care about is the $\it dy$ parameter, since it
4190 should be zero for \.{DVI} files.
4192 @<Read a long character locator@>= {
4193 fseek(fp,1,SEEK_CUR);
4194 dx=get_dvi_number(fp,1,4)>>16;
4195 fseek(fp,4,SEEK_CUR);
4196 @<Read four bytes@>;
4197 p=get_dvi_number(fp,1,4);
4200 @ @<Read a short character locator@>= {
4201 fseek(fp,1,SEEK_CUR);
4202 dx=get_dvi_number(fp,0,1);
4203 @<Read four bytes@>;
4204 p=get_dvi_number(fp,1,4);
4207 @ @<Read four bytes@>= {
4208 b0=fgetc(fp);@+b1=fgetc(fp);@+b2=fgetc(fp);@+b3=fgetc(fp);
4211 @ This processing is deferred, and the rest of the parameters will be
4212 filled in later (and the |ptr| field will be overwritten since it will
4213 no longer be needed at that time).
4215 @<Defer this character locator into |font_data|@>= {
4216 data_index n=new_record(font_data);
4217 @<Compute the character width |w|@>;
4218 font_data.data[n].next=index;
4219 font_data.data[n].dx=dx;
4220 font_data.data[n].w=w;
4221 font_data.data[n].ptr=p;
4222 if(index==none) first_index=n;
4223 index=n;
4226 @ Now is time to go through the list we made up and this time actually
4227 fill in the parameters and pictures.
4229 @<Read the character rasters and flags@>= {
4230 while(index!=none) {
4231 fseek(fp,font_data.data[index].ptr,SEEK_SET);
4232 font_data.data[index].flag=0;
4233 font_data.data[index].raster=0;
4234 @<Read commands for this character@>;
4235 @#index=font_data.data[index].next;
4239 @ Painting the picture uses the value of |paint_switch| to determine
4240 to draw or skip. The current position in the array |raster| is also
4241 pointed by the |pic| pointer. Note that |black| and |white| are not
4242 necessary black and white (but they are on normal paper).
4244 Note the value of $n$ is not needed since the |pic| pointer automatically
4245 keeps track of this kinds of stuff. However, |m| is needed because of
4246 commands that can skip rows, to know how many columns must be skipped to
4247 reach the next row. There is also |b|, which keeps track of the bit
4248 position in the current byte.
4250 @d white 0
4251 @d black 1
4253 @d reset_m
4254 m=(font_data.data[index].max_m-font_data.data[index].min_m)/8+1@;
4256 @<Read commands for this character@>= {
4257 unsigned int c,m,b;
4258 unsigned char*pic;
4259 boolean paint_switch;
4260 for(;;) {
4261 c=fgetc(fp);
4262 if(c<paint1) {
4263 @<Paint |c| pixels |black| or |white|@>;
4264 } @+else if(c>=paint1 && c<paint1+3) {
4265 c=get_dvi_number(fp,0,c+1-paint1);
4266 @<Paint |c| pixels |black| or |white|@>;
4267 } @+else if(c==boc) {
4268 @<Initialize parameters and picture (long form)@>;
4269 } @+else if(c==boc1) {
4270 @<Initialize parameters and picture (short form)@>;
4271 } @+else if(c==eoc) {
4272 break; // Well Done!
4273 } @+else if(upto4(c,skip0)) {
4274 if(c==skip0) c=0;
4275 else c=get_dvi_number(fp,0,c+1-skip1);
4276 @<Finish a row and skip |c| rows@>;
4277 } @+else if(c>=new_row_0 && c<=new_row_0+164) {
4278 c-=new_row_0;
4279 @<Finish a row and skip |c| columns@>;
4280 } @+else if(c==yyy) {
4281 font_data.data[index].flag|=get_dvi_number(fp,0,4)>>16;
4282 } @+else if(c!=no_op) {
4283 fprintf(stderr,"Unknown GF command!\n");
4284 @.Unknown GF command@>
4285 fprintf(stderr,"(Command %d, address %08X)\n",c,ftell(fp)-1);
4290 @ Actually |m| is something a bit different than the standard, because |m|
4291 now tells how many bytes are remaining in the current row.
4293 @d pic_rows (1+font_data.data[index].max_n-font_data.data[index].min_n)
4295 @<Initialize parameters and picture (long form)@>= {
4296 font_data.data[index].n=get_dvi_number(fp,0,4);
4297 @<Deal with $p$ (pointer to previous character with same metrics)@>;
4298 font_data.data[index].min_m=get_dvi_number(fp,1,4);
4299 font_data.data[index].max_m=get_dvi_number(fp,1,4);
4300 font_data.data[index].min_n=get_dvi_number(fp,1,4);
4301 font_data.data[index].max_n=get_dvi_number(fp,1,4);
4302 @<Initialize picture@>;
4305 @ @<Initialize picture@>= {
4306 if(font_data.data[index].flag&ff_space) break;
4307 paint_switch=white;
4308 reset_m;
4309 b=0;
4310 pic=font_data.data[index].raster=malloc(m*pic_rows+1);
4311 memset(pic,0,m*pic_rows);
4314 @ @<Initialize parameters and picture (short form)@>= {
4315 int d;
4316 font_data.data[index].n=get_dvi_number(fp,0,1);
4317 d=get_dvi_number(fp,0,1);
4318 font_data.data[index].max_m=get_dvi_number(fp,0,1);
4319 font_data.data[index].min_m=font_data.data[index].max_m-d;
4320 d=get_dvi_number(fp,0,1);
4321 font_data.data[index].max_n=get_dvi_number(fp,0,1);
4322 font_data.data[index].min_n=font_data.data[index].max_n-d;
4323 @<Initialize picture@>;
4326 @ The pointers to other characters will also be deferred in the same way
4327 as the character locators, but this time from the other end. Now, once it
4328 is finished all the characters, it will {\sl automatically} know to read
4329 the next one properly! (Now you can see what the purpose of the
4330 |@!first_index| variable is.)
4332 @<Deal with $p$ (pointer to previous character with same metrics)@>= {
4333 dvi_number p=get_dvi_number(fp,1,4);
4334 if(p!=-1) {
4335 data_index i=new_record(font_data);
4336 font_data.data[i].next=none;
4337 font_data.data[i].dx=font_data.data[index].dx;
4338 font_data.data[i].w=font_data.data[index].w;
4339 font_data.data[i].ptr=p;
4340 font_data.data[first_index].next=i;
4341 first_index=i;
4345 @ Now we get to the actual painting. We can assume the value of |m| is
4346 never negative and that everything else is also okay.
4348 @<Paint |c| pixels |black| or |white|@>= {
4349 if(paint_switch) {
4350 if(b+c<=8) {
4351 @<Paint a small block of pixels in the current byte@>;
4352 } @+else {
4353 @<Paint the rest of the pixels in the current byte@>;
4354 @<Fill up the bytes in the middle@>;
4355 @<Clear the pixels needed clearing at the end@>;
4358 @<Update |paint_switch|, |pic|, |b|, and |m|@>;
4361 @ @<Update |paint_switch|, |pic|, |b|, and |m|@>= {
4362 paint_switch^=1;
4363 b+=c;
4364 pic+=b>>3;
4365 m-=b>>3;
4366 b&=7;
4369 @ @<Paint a small block of pixels in the current byte@>= {
4370 *pic|=(0xFF>>b)&~(0xFF>>(b+c));
4373 @ @<Paint the rest of the pixels in the current byte@>= {
4374 *pic|=0xFF>>b;
4377 @ @<Fill up the bytes in the middle@>= {
4378 memset(pic+1,0xFF,(c+b)>>3);
4381 @ @<Clear the pixels needed clearing at the end@>= {
4382 pic[(c+b)>>3]&=~(0xFF>>((c+b)&7));
4385 @ @<Finish a row and skip |c| rows@>= {
4386 pic+=m;
4387 b=0;
4388 reset_m;
4389 pic+=m*c;
4390 paint_switch=white;
4393 @ @<Finish a row and skip |c| columns@>= {
4394 pic+=m;
4395 reset_m;
4396 m-=c>>3;
4397 pic+=c>>3;
4398 b=c&7;
4399 paint_switch=black;
4402 @ @<Display font information@>= {
4403 data_index i;
4404 foreach(i,font_data) {
4405 printf("[%d] box=(%d,%d,%d,%d) dx=%d w=%d n=%d flag=%d [%d]\n"
4406 ,i,font_data.data[i].min_n,font_data.data[i].max_n
4407 ,font_data.data[i].min_m,font_data.data[i].max_m
4408 ,font_data.data[i].dx,font_data.data[i].w,font_data.data[i].n
4409 ,font_data.data[i].flag,font_data.data[i].next
4414 @*Layer Computation. Now is the chapter for actually deciding rendering on
4415 the page, where everything should go, etc.$^{[\TeXwareBiblio]}$
4417 @<Global variables@>=
4418 dvi_measure unit_num; // Numerator for units of measurement
4419 dvi_measure unit_den; // Denominator for units of measurement
4420 dvi_measure unit_mag; // Magnification for measurement
4421 dvi_measure unit_conv; // Conversion factor
4423 @ There are also a number of ``internal typesetting quantities''. These
4424 are parameters stored in a separate array, and are used to keep track of
4425 the current state of the typesetting. They are labeled with letters from
4426 \.A to \.Z. They can be modified inside of specials, although some of them
4427 probably shouldn't be modified in this way. Here is the list of them:
4429 \.A, \.B: Horizontal and vertical offset added to \.I and \.J.
4431 \.C: Character code prefix. If bit eight is not set, it only affects
4432 character codes with bit seven set.
4434 \.D: Maximum horizontal drift (in pixels), meaning how far away the \.I
4435 and \.J parameters are allowed to be from the correctly rounded values.
4437 \.E: Maximum vertical drift.
4439 \.F: The current font.
4441 \.H: The horizontal position on the page, in DVI units.
4443 \.I: The horizontal position on the page, in pixels.
4445 \.J: The vertical position on the page, in pixels.
4447 \.L: The current layer number. If this is zero, nothing is placed on the
4448 page, although the positions can still be changed and specials can still
4449 be used.
4451 \.P: Page number. This is used to determine the filename of output.
4453 \.R, \.S: The limits for when horizontal motion should add the number of
4454 pixels or when it should recalculate the pixels entirely.
4456 \.T, \.U: Like \.R and \.S, but for vertical motions.
4458 \.V: The vertical position on the page, in DVI units.
4460 \.W, \.X, \.Y, \.Z: The current spacing amounts, in DVI units.
4462 @d quan(_name) (type_quan[(_name)&0x1F])
4464 @<Global variables@>=
4465 dvi_number type_quan[32];
4467 @ @<Cases for system commands@>=
4468 @-case 'm': {
4469 // Modify an internal typesetting quantity
4470 if(stack_ptr->is_string) program_error("Type mismatch");
4471 quan(*++ptr)=pop_num();
4472 break;
4475 @ The conversion factor |unit_conv| is figured as follows: There are
4476 exactly |unit_num/unit_den| decimicrons per DVI unit, and 254000
4477 decimicrons per inch, and |resolution/100| pixels per inch. Then we have
4478 to adjust this by the magnification |unit_mag|.
4480 Division must be done slightly carefully to avoid overflow.
4482 @d resolution (registers['D'].number)
4484 @<Compute the conversion factor@>= {
4485 unit_conv=make_fraction(unit_num*resolution*unit_mag,unit_den*100000);
4486 unit_conv/=254000;
4489 @ Here are the codes to compute movements. The definition of \.{DVI} files
4490 refers to six registers which hold integer values in DVI units. However,
4491 we also have two more registers, for horizontal and vertical pixel units.
4493 A sequence of characters or rules might cause the pixel values to drift
4494 from their correctly rounded values, since they are not usually an exact
4495 integer number of pixels.
4497 @d to_pixels(_val) round((_val)*unit_conv)
4499 @-p void horizontal_movement(dvi_number x) {
4500 quan('H')+=x;
4501 if(x>quan('S') || x<quan('R')) {
4502 quan('I')=to_pixels(quan('H'));
4503 } @+else {
4504 quan('I')+=to_pixels(x);
4505 if(to_pixels(quan('H'))-quan('I')>quan('D'))
4506 quan('I')=to_pixels(quan('H'))+quan('D');
4507 if(to_pixels(quan('H'))-quan('I')<-quan('D'))
4508 quan('I')=to_pixels(quan('H'))-quan('D');
4512 @ @-p void vertical_movement(dvi_number x) {
4513 quan('V')+=x;
4514 if(x>quan('U') || x<quan('T')) {
4515 quan('J')=to_pixels(quan('V'));
4516 } @+else {
4517 quan('J')+=to_pixels(x);
4518 if(to_pixels(quan('V'))-quan('J')>quan('E'))
4519 quan('J')=to_pixels(quan('V'))+quan('E');
4520 if(to_pixels(quan('V'))-quan('J')<-quan('E'))
4521 quan('J')=to_pixels(quan('V'))-quan('E');
4525 @ This is now the part that does actual sending. When many characters
4526 come next to each other, the rounding will be done such that the number
4527 of pixels between two letters will always be the same whenever those two
4528 letters occur next to each other.
4530 @<Typeset character |c| on the current layer@>= {
4531 data_index n=fontindex[quan('F')&0xFF];
4532 if((quan('C')&0x100) || (c&0x80)) c|=quan('C')<<8;
4533 while(n!=none && c!=font_data.data[n].n)
4534 n=font_data.data[n].next;
4535 if(n==none) dvi_error(fp,"Character not in font");
4536 @<Typeset the character and update the current position@>;
4537 @<Update the character code prefix@>;
4540 @ @<Typeset the character and update the current position@>= {
4541 if(font_data.data[n].flag&ff_roundbefore)
4542 quan('I')=to_pixels(quan('H'));
4543 if(quan('L') && font_data.data[n].raster) typeset_char_here(n);
4544 if(moveaftertyping) {
4545 quan('H')+=font_data.data[n].w;
4546 quan('I')+=font_data.data[n].dx;
4547 if(font_data.data[n].flag&ff_roundafter)
4548 quan('I')=to_pixels(quan('H'));
4549 else horizontal_movement(0);
4553 @ If you have a typesetting program that can ship out characters with
4554 codes more than eight bits long, you won't need this. It is provided for
4555 use with normal {\TeX} system.
4557 @<Update the character code prefix@>= {
4558 if(font_data.data[n].flag&ff_strip) c&=0x7F; else c&=0xFF;
4559 if(font_data.data[n].flag&ff_select) quan('C')=c|0x100;
4560 if(font_data.data[n].flag&ff_prefix) quan('C')=c;
4561 if(font_data.data[n].flag&ff_reset) quan('C')=0;
4564 @ The number of pixels in the height or width of a rule will always be
4565 rounded up. However, unlike DVItype, this program has no floating point
4566 rounding errors.
4568 @d to_rule_pixels(_val) ceiling((_val)*unit_conv)
4570 @<Typeset |a| by |c| rule on the current layer@>= {
4571 dvi_number x=to_rule_pixels(a);
4572 dvi_number y=to_rule_pixels(c);
4573 if(quan('L') && a>0 && c>0) typeset_rule_here(x,y);
4574 if(moveaftertyping) {
4575 quan('I')+=x;
4576 horizontal_movement(0);
4580 @ Sometimes you might want DVI units converted to pixels inside of a user
4581 program contained in a DVI file. Here is how it is done.
4583 @<Cases for system commands@>=
4584 @-case 'C': {
4585 // Convert DVI units to pixels
4586 if(stack_ptr->is_string) program_error("Type mismatch");
4587 stack_ptr->number=to_pixels(stack_ptr->number);
4588 break;
4591 @*Layer Rendering. Please note, these numbers are |short|, which means
4592 that you cannot have more than 65536 pixels in width or in height. This
4593 should not be a problem, because even if you have 3000 dots per inch, and
4594 each card is 10 inches long, that is still only 30000 which is less than
4595 half of the available width. (All units here are in pixels.)
4597 In order to save memory, all typeset nodes are stored in one list at
4598 first, and then rendered to a pixel buffer as each layer is being written
4599 out to the \.{PBM} file, and then the buffer can be freed (or reset to
4600 zero) afterwards to save memory.
4602 @<Typedefs@>=
4603 typedef struct {
4604 unsigned short x; // X position on page
4605 unsigned short y; // Y position on page
4606 union {
4607 struct {
4608 unsigned short w; // Width of rule
4609 unsigned short h; // Height of rule
4610 }@+;
4611 data_index c; // Character index in |font_data|
4612 }@+;
4613 unsigned char l; // Layer (high bit set for rules)
4614 } typeset_node;
4616 @ @<Global variables@>=
4617 memory_of(typeset_node) typeset_nodes;
4619 @ @<Initialize memory@>= init_memory(typeset_nodes,8);
4621 @ We also have variables for the layer size (loaded from \.{\\count2}
4622 and \.{\\count3} registers for the current page). If they are both zero,
4623 then nothing will be rendered.
4625 @<Global variables@>=
4626 unsigned short layer_width;
4627 unsigned short layer_height;
4629 @ Here are the subroutines which typeset characters and rules onto the
4630 page buffer. They are not rendered into a picture yet.
4632 @d typeset_new_page() (typeset_nodes.used=0)
4633 @d typeset_rule_here(_w,_h) typeset_rule(quan('I'),quan('J'),(_w),(_h));
4634 @d typeset_char_here(_ch) typeset_char(quan('I'),quan('J'),(_ch));
4636 @-p void typeset_rule(int x,int y,int w,int h) {
4637 data_index n=new_record(typeset_nodes);
4638 @<Ensure |w| and |h| are not too large to fit on the page@>;
4639 typeset_nodes.data[n].x=x;
4640 typeset_nodes.data[n].y=y;
4641 typeset_nodes.data[n].w=w;
4642 typeset_nodes.data[n].h=h;
4643 typeset_nodes.data[n].l=quan('L')|0x80;
4646 @ @<Ensure |w| and |h| are not too large to fit on the page@>= {
4647 if(x+w>layer_width) w=layer_width-x;
4648 if(y+h>layer_height) h=layer_height-y;
4651 @ @-p void typeset_char(int x,int y,data_index c) {
4652 data_index n=new_record(typeset_nodes);
4653 typeset_nodes.data[n].x=x;
4654 typeset_nodes.data[n].y=y;
4655 typeset_nodes.data[n].c=c;
4656 typeset_nodes.data[n].l=quan('L');
4659 @ Here is a variable |image|. This is a pointer to the buffer for the
4660 picture of the current layer, in \.{PBM} format. The internal quantity
4661 \.L should be set now to the largest layer number in use, at the end of
4662 the page, because it is used to determine how many layers must be sent to
4663 the output.
4665 @d image_max (image+layer_size)
4667 @<Global variables@>=
4668 unsigned char*image;
4670 @ @<Render this page@>= {
4671 unsigned int row_size=((layer_width+7)>>3);
4672 unsigned int layer_size=row_size*layer_height;
4673 image=malloc(layer_size+1);
4674 while(quan('L')) {
4675 memset(image,0,layer_size);
4676 @<Read the |typeset_nodes| list and render any applicable nodes@>;
4677 @<Send the current layer to a file@>;
4678 --quan('L');
4680 free(image);
4683 @ @<Read the |typeset_nodes| list and render any applicable nodes@>= {
4684 data_index i;
4685 foreach(i,typeset_nodes) {
4686 if((typeset_nodes.data[i].l&0x7F)==quan('L')) {
4687 if(typeset_nodes.data[i].l&0x80) {
4688 @<Render a rule node@>;
4689 } @+else {
4690 @<Render a character node@>;
4696 @ In order to render a rule node (which is a filled |black| rectangle), it
4697 is split into rows, and each row is split into three parts: the left end,
4698 the filling, and the right end. However, if the width is sufficiently
4699 small, it will fit in one byte and will not have to be split in this way.
4701 There are also some checks to ensure that the entire rectangle will be
4702 within the bounds of the image.
4704 @<Render a rule node@>= {
4705 int y=1+typeset_nodes.data[i].y-typeset_nodes.data[i].h;
4706 int x=typeset_nodes.data[i].x;
4707 int w=typeset_nodes.data[i].w;
4708 if(y<0) y=0;
4709 if(typeset_nodes.data[i].y>=layer_height)
4710 typeset_nodes.data[i].y=layer_height-1;
4711 if((x&7)+w<=8) {
4712 @<Render a small rule node@>;
4713 } @+else {
4714 @<Render a large rule node@>;
4718 @ @<Render a small rule node@>= {
4719 for(;y<=typeset_nodes.data[i].y;y++) {
4720 image[y*row_size+(x>>3)]|=(0xFF>>(x&7))&~(0xFF>>((x&7)+w));
4724 @ @<Render a large rule node@>= {
4725 for(;y<=typeset_nodes.data[i].y;y++) {
4726 unsigned char*p=image+(y*row_size+(x>>3));
4727 *p++|=0xFF>>(x&7); // left
4728 memset(p,0xFF,((x&7)+w)>>3); // filling
4729 p[((x&7)+w)>>3]|=~(0xFF>>((x+w)&7)); // right
4733 @ Character nodes are a bit different. The pictures are already stored,
4734 now we have to paste them into the layer picture. Since they will not
4735 always be aligned to a multiple to eight columns (one byte), it will have
4736 to shift out and shift in.
4738 Again, it is necessary to ensure it doesn't go out of bounds. It has to be
4739 a bit more careful for characters than it does for rules. Also note that
4740 the \.{GF} format does not require that |min_m| and so on are the tightest
4741 bounds possible.
4743 @<Render a character node@>= {
4744 unsigned int ch=typeset_nodes.data[i].c;
4745 unsigned int x=typeset_nodes.data[i].x+font_data.data[ch].min_m;
4746 unsigned int y=typeset_nodes.data[i].y-font_data.data[ch].max_n;
4747 unsigned int z=typeset_nodes.data[i].y-font_data.data[ch].min_n;
4748 unsigned int w=(font_data.data[ch].max_m-font_data.data[ch].min_m)/8+1;
4749 register unsigned char sh=x&7; // shifting amount for right shift
4750 register unsigned char lsh=8-sh; // shifting amount for left shift
4751 unsigned char*p=image+(y*row_size+(x>>3));
4752 unsigned char*q=font_data.data[ch].raster;
4753 @<Cut off the part of character above the top of the layer image@>;
4754 while(y<=z && p+w<image_max) {
4755 @<Render the current row of the character raster@>;
4756 @<Advance to the next row of the character@>;
4760 @ @<Cut off the part of character above the top of the layer image@>= {
4761 if(y<0) {
4762 p-=row_size*y;
4763 q-=w*y;
4764 y=0;
4766 if(p<image) p=image;
4769 @ @<Render the current row of the character raster@>= {
4770 int j;
4771 for(j=0;j<w;j++) {
4772 p[j]|=q[j]>>sh;
4773 p[j+1]|=q[j]<<lsh;
4777 @ @<Advance to the next row of the character@>= {
4778 y++;
4779 q+=w;
4780 p+=row_size;
4783 @ Layer files are output in \.{PBM} format, which is very similar to the
4784 format which this program uses internally. ImageMagick is capable of
4785 reading this format.
4787 @.PBM@>
4788 @^Portable Bitmap@>
4789 @^ImageMagick@>
4790 @^output@>
4792 @<Send the current layer to a file@>= {
4793 FILE*fp;
4794 char filename[256];
4795 sprintf(filename,"P%dL%d.pbm",quan('P'),quan('L'));
4796 fp=fopen(filename,"wb");
4797 fprintf(fp,"P4%d %d ",layer_width,layer_height);
4798 fwrite(image,1,layer_size,fp);
4799 fclose(fp);
4802 @ @<Display the list of typeset nodes@>= {
4803 data_index i;
4804 foreach(i,typeset_nodes) {
4805 if(typeset_nodes.data[i].l&0x80) {
4806 printf("[%d] %dx%d%+d%+d\n",typeset_nodes.data[i].l&0x7F
4807 ,typeset_nodes.data[i].w,typeset_nodes.data[i].h
4808 ,typeset_nodes.data[i].x,typeset_nodes.data[i].y
4810 } @+else {
4811 printf("[%d] %d(%d) %+d%+d\n",typeset_nodes.data[i].l
4812 ,typeset_nodes.data[i].c,font_data.data[typeset_nodes.data[i].c].n
4813 ,typeset_nodes.data[i].x,typeset_nodes.data[i].y
4819 @ @<Display typesetting diagnostics@>= {
4820 int i;
4821 for(i=0;i<32;i++) {
4822 if(type_quan[i]) printf("%c=%d\n",i+'@@',type_quan[i]);
4824 printf("unit_conv: %lld [%d]\n",unit_conv,round(unit_conv));
4825 printf("nodes: %d/%d\n",typeset_nodes.used,typeset_nodes.allocated);
4826 printf("fonts: %d/%d\n",font_data.used,font_data.allocated);
4827 if(dvi_stack) printf("stack: %d\n",dvi_stack_ptr-dvi_stack);
4830 @*Process of ImageMagick. The filename of ImageMagick \.{convert} is found
4831 by using the \.{IMCONVERT} environment variable. The entire command-line
4832 is stored in the \.Q register, with arguments separated by spaces, and it
4833 might be very long.
4835 @^ImageMagick@>
4836 @.IMCONVERT@>
4838 @d add_magick_arg(_val) magick_args.data[new_record(magick_args)]=_val
4840 @<Typedefs@>=
4841 typedef char*char_ptr;
4843 @ @<Global variables@>=
4844 memory_of(char_ptr) magick_args;
4846 @ @<Switch to ImageMagick@>= {
4847 init_memory(magick_args,4);
4848 add_magick_arg("convert"); // |argv[0]| (program name)
4849 @<Add arguments from \.Q register@>;
4850 add_magick_arg(0); // (terminator)
4851 @<Call the ImageMagick executable file@>;
4854 @ The \.Q register will be clobbered here. But that is OK since it will no
4855 longer be used within \TeX nicard.
4857 @<Add arguments from \.Q register@>= {
4858 char*q=registers['Q'].text;
4859 char*p;
4860 while(q && *q) {
4861 p=q;
4862 if(q=strchr(q,' ')) *q++=0;
4863 if(*p) add_magick_arg(p);
4867 @ @<Call the ImageMagick executable file@>= {
4868 char*e=getenv("IMCONVERT");
4869 if(!e) @<Display the arguments and quit@>;
4870 execv(e,magick_args.data);
4871 fprintf(stderr,"Unable to run ImageMagick\n");
4872 @.Unable to run ImageMagick@>
4873 return 1;
4876 @ @<Display the arguments and quit@>= {
4877 data_index i;
4878 char*p;
4879 foreach(i,magick_args) if(p=magick_args.data[i]) printf("%s\n",p);
4880 return 0;
4883 @*Internal Typesetting. Until now, we only had the codes for doing
4884 external typesetting and image manipulation (which was the original plan
4885 for this program). Now, we are adding internal typesetting and image
4886 manipulation as well, to avoid external dependencies.
4888 Some of the algorithms of \TeX\ will be used here, with some changes. For
4889 example, there are no leaders, marks, footnotes, alignments, mathematical
4890 formulas, or hyphenation. Ligature nodes are not needed either, because
4891 there is no hyphenation, so we can just use normal character nodes for
4892 ligatures.
4894 There is also no page breaking, although you can still do vertical
4895 splitting if you want multiple columns of text on a card, or for the text
4896 to be interrupted in the middle.
4898 @ Here is a list of the category codes used for internal typesetting, and
4899 the code to initialize that table and the other tables. There are also
4900 category codes from 32 to 255, which mean that it is a register number
4901 containing a code to execute (we set up |tabulation| and |escape_code| to
4902 call registers \.t and \.e, although it is unlikely to use these tokens).
4904 @d cat_ignore 0 // Ignore this token
4905 @d cat_norm 1 // Add a character from the current font
4906 @d cat_space 2 // Add a glue node with the current space factor
4907 @d cat_exit 3 // Exit the current block
4908 @d cat_accent 4 // Add an accent to the next character
4909 @d cat_xaccent 5 // As above, but XOR 128
4911 @<Initialize tables for internal typesetting@>= {
4912 for(i=0;i<256;i++) {
4913 tables['E'][i]=1;
4914 tables['F'][i]=40;
4915 tables['J'][i]=tables['K'][i]=128;
4917 tables['E'][null_char]=cat_ignore;
4918 tables['E'][end_transmission]=cat_exit; // Not actually used
4919 tables['E'][tabulation]='t';
4920 tables['E'][escape_code]='e';
4921 tables['E'][record_separator]=cat_exit;
4922 tables['E'][field_separator]=cat_exit;
4923 tables['E'][' ']=cat_space;
4926 @ All dimensions are stored in units of scaled points (where there are
4927 65536 scaled points in one point, and $72.27$ points in one inch).
4929 There will also be a type for glue ratios, which is used to multiply by
4930 glue stretch and shrink inside of a box, where a value of |0x100000000|
4931 means 100\char`\%\relax\space stretch or shrink, or 1pt per fil unit.
4933 @<Typedefs@>=
4934 typedef signed int scaled;
4935 typedef signed long long int glue_ratio;
4937 @*Data Structures for Boxes. Typesetting is done first by storing
4938 horizontal and vertical boxes of nodes. These boxes may then be included
4939 in other boxes, or shipped out to the next part of the program, which is
4940 image manipulation.
4942 Here we list the possible kind of nodes. These are four-bit numbers, with
4943 bit 3 set for a breakable\slash discardable node. The four high bits are
4944 used as a small parameter for the node.
4946 There are structures for many kinds of nodes, but only one pointer type
4947 will be used. Unions are used to allow many kinds of nodes at once.
4949 @d chars_node 00 // One word of text (including kerns, ligatures, accents)
4950 @d hlist_node 01 // Horizontal box
4951 @d vlist_node 02 // Vertical box
4952 @d rule_node 03 // Filled rectangle
4953 @d adjust_node 04 // Add material before or after current line
4954 @d special_node 05 // Execute commands when this node is found
4955 @d layer_node 06 // Like |special_node| but with only one purpose
4956 @d kern_node 010 // Fixed movement
4957 @d glue_node 011 // Variable movement
4958 @d penalty_node 012 // Tell how bad it is to break a line/page here
4960 @d type_of(_node) ((_node)->type_and_subtype&0x0F)
4961 @d subtype_of(_node) ((_node)->type_and_subtype>>4)
4962 @s box_node int
4963 @d calc_size(_members) (sizeof(struct{
4964 struct box_node*y;unsigned char z;struct{_members}@+;
4967 @<Typedefs@>=
4968 typedef struct box_node {
4969 struct box_node*next; // next node, or 0
4970 unsigned char type_and_subtype;
4971 union @+{
4972 @<Structure of a |chars_node|@>;
4973 @<Structure of a |hlist_node|, |vlist_node|, or |rule_node|@>;
4974 @<Structure of a |adjust_node|@>;
4975 @<Structure of a |special_node|@>;
4976 @<Structure of a |layer_node|@>;
4977 @<Structure of a |kern_node|@>;
4978 @<Structure of a |glue_node|@>;
4979 @<Structure of a |penalty_node|@>;
4980 }@+;
4981 } box_node;
4984 @ In a |chars_node|, there is a font number (0 to 255), and then sixteen
4985 bits for each character, accent, or kern. Data |0x0000| to |0x7FFF| adds a
4986 character (so only 32768 characters are available, while \TeX\ supports
4987 only 256 characters, so it is still more than \TeX), data |0x8000| to
4988 |0xBFFF| specifies an accent for the next character (so only characters
4989 numbered 0 to 16383 can be used as accents), |0xC000| to |0xFFFE| are
4990 implicit kerns (allowing only 16383 possible kerns, although most fonts
4991 use only ten or so, certainly not as many as sixteen thousand), and data
4992 |0xFFFF| is a terminator. All characters are from the same font.
4994 If an accent is specified, it is added to the immediately next character
4995 in this list.
4997 @d sizeof_chars_node calc_size(unsigned char a;unsigned short b[0];)
4999 @<Structure of a |chars_node|@>=
5000 struct {
5001 unsigned char font;
5002 unsigned short chars[0];
5005 @ An |hlist_node|, |vlist_node|, and |rule_node| are all similar to each
5006 other, except that a |rule_node| does not have a |list| or |glue_set|, and
5007 a |hlist_node| has an additional |tracking| parameter.
5009 Tracking is 128 for normal width of each letter. They can be adjusted to a
5010 lesser number to make the letters closer together, or greater to make
5011 farther apart leters, for example 64 means half of normal width.
5013 The |subtype_of| a |hlist_node| or |vlist_node| is the glue set order,
5014 setting the high bit for shrinking (otherwise it is stretching).
5016 @d sizeof_hlist_node calc_size(
5017 scaled a;scaled b;scaled c;scaled d;
5018 struct box_node*e;glue_ratio f;unsigned char g;
5020 @d sizeof_vlist_node calc_size(
5021 scaled a;scaled b;scaled c;scaled d;
5022 struct box_node*e;glue_ratio f;
5024 @d sizeof_rule_node calc_size(scaled a;scaled b;scaled c;scaled d;)
5026 @<Structure of a |hlist_node|...@>=
5027 struct {
5028 scaled width;
5029 scaled height;
5030 scaled depth;
5031 scaled shift_amount; // shift this box by the specified amount
5033 struct box_node*list; // pointer to first child node
5034 glue_ratio glue_set;
5036 unsigned char tracking; // adjust letter spacing
5039 @ An |adjust_node| has only a pointer to the sublist, and the |subtype_of|
5040 should be zero to append the vertical material after this line of the
5041 paragraph, or one to put it before this line of the paragraph.
5043 @d sizeof_adjust_node calc_size(struct box_node*a;)
5045 @<Structure of a |adjust_node|@>=
5046 struct {
5047 struct box_node*sublist; // pointer to first child node
5050 @ A |special_node| contains a null-terminated C string. The |subtype_of|
5051 specifies how it is used; they are listed below.
5053 @d spec_measure 1 // Measuring the length of a line in a paragraph
5054 @d spec_break 2 // Breaking a paragraph
5055 @d spec_pack 3 // Packaging a box
5056 @d spec_vbreak 4 // Breaking a vertical box
5057 @d spec_render 5 // Shipping out the nodes to the page
5059 @d sizeof_special_node calc_size(char a[0];)
5061 @<Structure of a |special_node|@>=
5062 struct {
5063 char program[0];
5066 @ A |layer_node| acts like a |special_node| with subtype |spec_render| and
5067 the |program| set to |"3mL"| if the |layer| parameter is 3. It is probably
5068 a more common kind of special.
5070 For example, it might be used to specify typing in different colors.
5072 @d sizeof_layer_node calc_size(unsigned char a;)
5074 @<Structure of a |layer_node|@>=
5075 struct {
5076 unsigned char layer;
5079 @ A |kern_node| represents a horizontal or vertical movement, such as
5080 where some amount of space is skipped.
5082 @d sizeof_kern_node calc_size(scaled a;)
5084 @<Structure of a |kern_node|@>=
5085 struct {
5086 scaled distance;
5089 @ A |glue_node| is similar to a |kern_node| although there are some
5090 differences. One difference is that it can stretch and shrink. The
5091 |subtype_of| parameter has the stretch order in the low two bits and the
5092 shrink order in the high two bits.
5094 @d finite 0
5095 @d fil 1
5096 @d fill 2
5097 @d filll 3
5099 @d sizeof_glue_node calc_size(scaled a;scaled b;scaled c;)
5101 @<Structure of a |glue_node|@>=
5102 struct {
5103 scaled natural;
5104 scaled stretch;
5105 scaled shrink;
5108 @ A |penalty_node| specifies a valid breakpoint in a paragraph, and in
5109 addition, specifies how bad it is to break here. A penalty value 10000001
5110 is bad enough that it will not break here, and $-10000001$ is good enough
5111 that it will definitely break here.
5113 @d sizeof_penalty_node calc_size(signed int a;)
5115 @<Structure of a |penalty_node|@>=
5116 struct {
5117 signed int penalty;
5120 @ Here are functions for manipulation of box nodes, including creation,
5121 destruction, and so on.
5123 First is simple creation of a node. It sets nothing other than type and
5124 subtype.
5126 @-p box_node*create_node(int type,int subtype,int size) {
5127 box_node*ptr=malloc(size);
5128 ptr->next=0;
5129 ptr->type_and_subtype=(type&0x0F)|(subtype<<4);
5130 return ptr;
5133 @ Now is destruction. It is recursive because some nodes are boxes that
5134 point to other lists too.
5136 @-p void trash_nodes(box_node*this) {
5137 box_node*next;
5138 while(this) {
5139 next=this->next;
5140 @<Recurse if there is a sublist to trash@>;
5141 free(this);
5142 this=next;
5146 @ @<Recurse if there is a sublist to trash@>= {
5147 switch(type_of(this)) {
5148 case hlist_node: case vlist_node: @/
5149 trash_nodes(this->list); @+break;
5150 case adjust_node: @/
5151 trash_nodes(this->sublist); @+break;
5152 default: ; // Do nothing
5156 @ You might realize there are no reference counts. They aren't needed,
5157 because each node is used exactly once. (Later on in the semantic nest, it
5158 is seen that this is not quite true; the box nest also includes a
5159 reference, which is in addition to the |next| pointers of each node, but
5160 this is OK since those are nodes are never isolated or destroyed when
5161 picked off of that list.)
5163 @*Font Metric Data. In order to do internal typesetting, it is necessary
5164 to load the font metric data from a \.{TFM} file. The data in a \.{TFM}
5165 file consists of 32-bit words in big-endian order.
5167 However, the first 6 words are twelve 16-bit integers instead, giving
5168 lengths of various parts of the file.
5170 @s fix_word int
5171 @ The most important data type used here is a |fix_word|, which is a
5172 32-bit signed number, with 12 integer bits and 20 fractional bits. Most of
5173 the |fix_word| values in a \.{TFM} file range from $-16$ to $+16$.
5175 @<Typedefs@>=
5176 typedef signed int fix_word;
5178 @ The twelve lengths are according to the following:
5180 \hbox to\hsize{\hfil\vbox{\smallskip\halign{\hfil$\it#={}$&#\hfil\cr
5181 lf&length of the entire file, in words\cr
5182 lh&number of words of header data\cr
5183 bc&smallest character code in this font\cr
5184 ec&largest character code in this font\cr
5185 nw&number of words in the width table\cr
5186 nh&number of words in the height table\cr
5187 nd&number of words in the depth table\cr
5188 ni&number of words in the italic correction table\cr
5189 nl&number of words in the ligature/kern program\cr
5190 nk&number of words in the kern table\cr
5191 ne&number of words in the extensible character table\cr
5192 np&number of font parameter words\cr
5193 }\smallskip}\hfil}
5195 \noindent The parts of the file are in the order listed above. Some of the
5196 sections of the file are not used by this program (the extensible
5197 characters and the header words), but they still must be skipped over when
5198 reading the \.{TFM} file. Also, the $\it lf$ parameter is only for
5199 verification, and this program does not attempt to verify it.
5201 @ Here is data structures for storing information about font metrics. It
5202 is a managed memory. Some elements will be shared by multiple fonts that
5203 use the same \.{TFM} file, such as |design_size|, |fontname|, and the
5204 ligature/kerning programs.
5206 @<Late Typedefs@>=
5207 typedef struct {
5208 scaled parameters[16]; // Font parameters (up to sixteen)
5209 scaled at_size; // At size, for figuring out \.{GF} filename
5210 scaled design_size; // Design size, for figuring out \.{GF} filename
5211 char*fontname; // Name of font, without extension or area
5212 scaled*width_base;
5213 scaled*height_base;
5214 scaled*depth_base;
5215 scaled*italic_base;
5216 scaled*kern_base;
5217 unsigned char min_char; // Smallest valid character code
5218 unsigned char max_char; // Largest valid character code
5219 int right_boundary; // If this is |none| then there is no right boundary
5220 unsigned char lig_limit; // Code |x| ligatures if |x<256*lig_limit|
5221 @<More elements of |font_metric_data|@>@;
5222 } font_metric_data;
5224 @ @<Global variables@>=
5225 memory_of(font_metric_data) metrics;
5227 @ @<Initialize memory@>= init_memory(metrics,4);
5229 @ Now the ligature/kerning program. The purpose of these fields is
5230 explained later.
5232 @<Typedefs@>=
5233 typedef struct {
5234 unsigned char skip;
5235 unsigned char next;
5236 unsigned char op;
5237 unsigned char remainder;
5238 } lig_kern_command;
5240 @ Some fonts will have a fake ``left boundary character'', which is
5241 implied at the beginning of each word. This points to the command which
5242 should become active at the beginning of a word. If it is null, then no
5243 ligature/kerning program will be active.
5245 @<More elements of |font_metric_data|@>=
5246 lig_kern_command*left_boundary; // Program for left boundary character
5248 @ Another thing is the character info. These are the same data for
5249 different sizes of the same font, since they are index into the other
5250 arrays, which are different for each font.
5252 @<Typedefs@>=
5253 typedef struct {
5254 unsigned char width; // Index into |width_base|
5255 unsigned char height; // Index into |height_base|
5256 unsigned char depth; // Index into |depth_base|
5257 unsigned char italic; // Index into |italic_base|
5258 lig_kern_command*program; // Program for this character (null if none)
5259 } char_info_data;
5261 @ @<More elements of |font_metric_data|@>=
5262 char_info_data*info; // |info[c]| is info for character code |c|
5264 @ So let's get started, please.
5266 The parameter |fontnum| shall be the font number of the first size of this
5267 font set up. The |fontname| is the name of the font, without extension.
5268 The |at_size| parameter points to the beginning of a zero-terminated list
5269 of at-sizes to load the font at (much of the data is the same for
5270 different at-sizes so that we can save memory in this way). However, the
5271 |at_size| values are |scaled|, while the \.{TFM} expects |fix_word|. This
5272 is easy to correct by right-shifting four spaces.
5274 The |fix_word| values are in the same format as numbers in a \.{DVI} file,
5275 so the same code can be used. A macro is set here to make convenience.
5277 @d get_fix_word(_fp) ((fix_word)get_dvi_number((_fp),1,4))
5279 @-p void load_tfm(unsigned char fontnum,char*fontname,scaled*at_size) {
5280 char filename[max_filename_length+1];
5281 short lengths[12]; // The data described above, now numbered 0 to 11
5282 lig_kern_command*program; // Beginning of ligature/kerning program
5283 font_metric_data common_data; // Data common to all sizes of a font
5284 data_index metrics_index=metrics.used; // Index into |metrics|
5285 int num_sizes=0; // How many fonts we are loading at once
5286 int w_offset; // Offset of width table
5287 FILE*fp;
5288 @<Set up the filename of the \.{TFM} file and try to open the file@>;
5289 @<Load the |lengths| data@>;
5290 @<Set up |common_data| and |program|@>;
5291 @<Skip the header words@>;
5292 @<Load the character info@>;
5293 @<Set |w_offset|, and skip to the ligature/kerning program@>;
5294 @<Load the ligature/kerning program@>;
5295 @<Correct the pointers into the ligature/kerning program@>;
5296 @<Calculate |num_sizes| and allocate font metric structures@>;
5297 @<Load the dimension values for each size of this font@>;
5298 fclose(fp);
5301 @ @<Set up the filename of the \.{TFM} file and try to open the file@>= {
5302 sprintf(filename,"%s.tfm",fontname);
5303 fp=open_file(filename,"rb");
5304 if(!fp) {
5305 fprintf(stderr,"Cannot open font %s\n",filename);
5306 @.Cannot open font...@>
5307 exit(1);
5311 @ @<Load the |lengths| data@>= {
5312 int i;
5313 for(i=0;i<12;i++) {
5314 int x=fgetc(fp);
5315 int y=fgetc(fp);
5316 lengths[i]=(x<<8)|y;
5320 @ @<Set up |common_data| and |program|@>= {
5321 common_data.fontname=strdup(fontname);
5322 common_data.min_char=lengths[2]; // Hopefully should be zero
5323 common_data.max_char=lengths[3];
5324 common_data.right_boundary=none;
5325 common_data.lig_limit=255;
5326 common_data.info=malloc((lengths[3]+1)*sizeof(char_info_data));
5327 program=malloc(lengths[8]*sizeof(lig_kern_command));
5330 @ @<Skip the header words@>= {
5331 fseek(fp,4,SEEK_CUR); // Skip checksum
5332 common_data.design_size=get_fix_word(fp)>>4;
5333 fseek(fp,4*(lengths[1]-2),SEEK_CUR); // Skip everything else
5336 @ The character info is stored in a packed format. This is then unpacked
5337 and loaded into the |common_data.info| array, which has already been
5338 allocated.
5340 @<Load the character info@>= {
5341 char_info_data*info=common_data.info+common_data.min_char;
5342 int i,c;
5343 for(i=common_data.min_char;i<=common_data.max_char;i++) {
5344 info->width=fgetc(fp);
5345 c=fgetc(fp);
5346 info->height=c>>4;
5347 info->depth=c&0xF;
5348 c=fgetc(fp);
5349 info->italic=c>>2;
5350 if((c&0x3)==0x1) {
5351 info->program=program+fgetc(fp);
5352 } @+else {
5353 info->program=0;
5354 fgetc(fp); // Lists and extensible recipes are not used
5356 info++;
5360 @ The ligature/kerning program will be read before the dimensions specific
5361 to the font size, so that the |common_data| can be set up first. And then
5362 we can skip back to |w_offset|, multiple times, once for each size that is
5363 being loaded.
5365 @<Set |w_offset|, and skip to the ligature/kerning program@>= {
5366 w_offset=ftell(fp);
5367 fseek(fp,4*(lengths[4]+lengths[5]+lengths[6]+lengths[7]),SEEK_CUR);
5370 @ @<Load the ligature/kerning program@>= {
5371 int i;
5372 for(i=0;i<lengths[8];i++) {
5373 program[i].skip=fgetc(fp);
5374 program[i].next=fgetc(fp);
5375 program[i].op=fgetc(fp);
5376 program[i].remainder=fgetc(fp);
5380 @ Sometimes you might need large ligature/kerning programs for many
5381 characters, so you can start at addresses other than 0 to 255. This is the
5382 way that specifies how that is done.
5384 @<Correct the pointers into the ligature/kerning program@>= {
5385 int i;
5386 for(i=common_data.min_char;i<=common_data.max_char;i++)
5387 if(common_data.info[i].program &&
5388 common_data.info[i].program->skip>128)
5389 common_data.info[i].program=program+
5390 (common_data.info[i].program->op<<8)+
5391 common_data.info[i].program->remainder;
5394 @ @<Calculate |num_sizes| and allocate font metric structures@>= {
5395 scaled*p=at_size;
5396 data_index n;
5397 while(*p) {
5398 n=new_record(metrics);
5399 memcpy(&(metrics.data[n]),&common_data,sizeof(font_metric_data));
5400 metrics.data[n].at_size=*p;
5401 num_sizes++;
5402 p++;
5406 @ Now to load the widths, heights, depths, italic corrections, and kerning
5407 distances. This is what |w_offset| is for, so that we can skip back to it.
5408 One allocated memory object is used for all dimension values of one size,
5409 and then the points are moved into the fields of the |font_metric_data|.
5411 @d total_font_dimen
5412 (lengths[4]+lengths[5]+lengths[6]+lengths[7]+lengths[9])
5413 @d cur_metrics (metrics.data[metrics_index])
5415 @<Load the dimension values for each size of this font@>= {
5416 scaled*p;
5417 scaled s,z,zprime,alpha,beta;
5418 for(p=at_size;*p;p++,metrics_index++) {
5419 scaled*d=malloc(sizeof(scaled)*total_font_dimen);
5420 int c;
5421 @<Ensure |d| is valid@>;
5422 @<Set the dimension base pointers for this font@>;
5423 z=*p; // The at size is now called |z|
5424 @<Compute |zprime|, |alpha|, and |beta|@>;
5425 fseek(fp,w_offset,SEEK_SET);
5426 c=lengths[4]+lengths[5]+lengths[6]+lengths[7];
5427 @<Load |c| scaled dimension values from |fp| into |d|@>;
5428 fseek(fp,4*lengths[8],SEEK_CUR);
5429 c=lengths[9];
5430 @<Load |c| scaled dimension values from |fp| into |d|@>;
5431 @<Load the font parameters@>;
5435 @ @<Ensure |d| is valid@>= {
5436 if(!d) {
5437 fprintf(stderr,"Out of font memory\n");
5438 exit(1);
5442 @ @<Set the dimension base pointers for this font@>= {
5443 cur_metrics.width_base=d;
5444 cur_metrics.height_base=cur_metrics.width_base+lengths[4];
5445 cur_metrics.depth_base=cur_metrics.height_base+lengths[5];
5446 cur_metrics.italic_base=cur_metrics.depth_base+lengths[6];
5447 cur_metrics.kern_base=cur_metrics.italic_base+lengths[7];
5450 @ @<Load |c| scaled dimension values from |fp| into |d|@>= {
5451 while(c--) {
5452 scaled b3,b2,b1,b0;
5453 b0=fgetc(fp); @+ b1=fgetc(fp); @+ b2=fgetc(fp); @+ b3=fgetc(fp);
5454 *d++=(((((b3*zprime)>>8)+(b2*zprime))>>8)+(b1*zprime))/beta
5455 -(b0?alpha:0);
5459 @ Now there are font parameters. There are up to sixteen font parameters,
5460 but numbered starting at 1. This is the code that makes it to do this.
5462 @<Load the font parameters@>= {
5463 c=lengths[11]-1;
5464 if(c>14) c=14;
5465 if(c<0) c=0;
5466 cur_metrics.parameters[0]=cur_metrics.parameters[1]=0;
5467 if(lengths[11]) cur_metrics.parameters[1]=get_fix_word(fp)>>4;
5468 d=cur_metrics.parameters+2;
5469 @<Load |c| scaled dimension values from |fp| into |d|@>;
5472 @*Semantic Nest. We might be building many boxes at once, nested inside of
5473 each other. So, we need to keep the stack of what kind of boxes are
5474 currently in use, and the associated parameters, such as space factors,
5475 and the previous depth of the box.
5477 There is two kinds, horizontal and vertical. The outer mode is considered
5478 horizontal so that it does not add leading between boxes, although it is
5479 not for making a box of the outer mode.
5481 The currently active modes are stored both forwards and backwards, so that
5482 we can use them as a stack of box nodes. There is a null pointer to mark
5483 the end of the list.
5485 @<Typedefs@>=
5486 typedef box_node*box_node_ptr;
5488 @ @<Global variables@>=
5489 memory_of(box_node_ptr) box_nest;
5491 @ @<Initialize memory@>=
5492 init_memory(box_nest,2);
5494 @ We also have the semantic list with local variables to the current
5495 group. The purpose of the |data| fields depends on whether this state is
5496 in horizontal or vertical mode, and that is why it is a union so that we
5497 can access then by names in that case, although they can also be accessed
5498 by numbers as well.
5500 @<Typedefs@>=
5501 typedef struct nest_state {
5502 struct nest_state*link; // Link to state this one is inside of
5503 boolean is_vertical; // 0 for horizontal, 1 for vertical
5504 data_index box_nest_index; // Index into |box_nest|
5505 union {
5506 scaled data[16];
5507 @<Nest state variables for horizontal mode@>;
5508 @<Nest state variables for vertical mode@>;
5509 }@+;
5510 } nest_state;
5512 @ @<Global variables@>=
5513 nest_state*cur_nest;
5515 @ @<Initialize memory@>= {
5516 cur_nest=malloc(sizeof(nest_state));
5517 cur_nest->link=0; // Means this is the outer level
5518 cur_nest->is_vertical=0; // Horizontal mode, no leading
5519 cur_nest->box_nest_index=new_record(box_nest);
5520 box_nest.data[cur_nest->box_nest_index]=0;
5521 cur_nest->space_factor=40; // Normal spacing
5524 @ @<Nest state variables for horizontal mode@>=
5525 struct {
5526 scaled space_factor; // Really just a number, but I don't care
5529 @ @<Nest state variables for vertical mode@>=
5530 struct {
5531 scaled prev_depth;
5534 @ Here are codes to enter a nest.
5536 @-p void enter_nest(boolean is_vertical) {
5537 nest_state*link=cur_nest;
5538 cur_nest=malloc(sizeof(nest_state));
5539 cur_nest->link=link;
5540 cur_nest->is_vertical=is_vertical;
5541 cur_nest->box_nest_index=new_record(box_nest);
5542 box_nest.data[cur_nest->box_nest_index]=0;
5543 if(is_vertical) cur_nest->prev_depth=0;
5544 else cur_nest->space_factor=40;
5547 @ And we also need codes to leave a nest. This function returns the
5548 pointer to the first node in the box that was being created, and then the
5549 packaging programs can use that to make a box and iterate over the |next|
5550 pointers to read the entire list.
5552 @-p box_node*leave_nest(void) {
5553 nest_state*link=cur_nest->link;
5554 box_node*node;
5555 @<Ensure it is not nest underflow@>;
5556 @<Set |node| to the node at the beginning of the current list@>;
5557 @<Rewind |box_nest| to the end of the parent list@>;
5558 free(cur_nest);
5559 cur_nest=link;
5560 return node;
5563 @ The outer nest should never be left or packaged; it is only used as a
5564 general-purpose stack and a container for other nests. (Unlike \TeX, the
5565 outer nest is never split into pages in \TeX nicard.)
5567 @<Ensure it is not nest underflow@>= {
5568 if(!link) {
5569 fprintf(stderr,"\nNest underflow\n");
5570 exit(1);
5574 @ Note: Sometimes |node| will be a null pointer if the current list is
5575 making an empty box (i.e. no nodes have been pushed).
5577 @<Set |node| to the node at the beginning of the current list@>= {
5578 if(box_nest.used==cur_nest->box_nest_index+1) {
5579 node=0;
5580 } @+else {
5581 node=box_nest.data[cur_nest->box_nest_index+1];
5585 @ @<Rewind |box_nest| to the end of the parent list@>= {
5586 box_nest.used=cur_nest->box_nest_index;
5589 @ And finally we have codes to push and pop nodes in the current list.
5590 These are simple codes since there isn't much to do.
5592 @d top_of_nodelist (box_nest.data[box_nest.used-1])
5594 @-p inline void push_node(box_node*ptr) {
5595 top_of_nodelist->next=ptr;
5596 box_nest.data[new_record(box_nest)]=ptr;
5599 @ @-p box_node*pop_node(void) {
5600 box_node*ptr=top_of_nodelist;
5601 if(ptr) {
5602 box_nest.used--;
5603 top_of_nodelist->next=0;
5605 return ptr;
5608 @*Box Calculation. Here are codes to calculate various things about the
5609 boxes, including badness, width\slash height\slash depth of a string of
5610 characters, and so on.
5612 This function is used to compute the ``badness'' of a glue setting, when a
5613 total $t$ is supposed to be made from amounts that sum to $s$. In this
5614 program, the badness is $1000(t/s)^3$ (ten times as much as \TeX). It does
5615 not have to be extremely accurate, although it is sufficiently accurate to
5616 do line breaking and so on. Ten million occurs when you stretch more than
5617 21 times as much as it should; this should never happen so it is given the
5618 maximum possible badness that can be computed using this. The badness
5619 squared should never exceed sixty-three bits (which it won't).
5621 @!@^badness@>
5623 @d very_bad 10000000
5624 @d too_bad 10000001
5626 @-p int calc_badness(scaled t,scaled s) {
5627 long long int r; // Apprximately $\root3\of{1000\cdot2^{32}}(t/s)$
5628 if(t==0) return 0;
5629 if(s<=0) return very_bad;
5630 r=(16255LL*t)/s;
5631 if(r>2097152LL) return very_bad;
5632 r=(r*r*r+(1LL<<31))>>32;
5633 if(r>very_bad) r=very_bad;
5634 return r;
5637 @ Next we calculate the width, height, and depth of a string of
5638 characters in one font, possibly including accents, kerns, and tracking.
5639 Ligatures will have already been dealt with before this code is reached,
5640 and kerns will already have been added in.
5642 @-p void calc_chars(box_node*b,scaled*w,scaled*h,scaled*d,short t) {
5643 font_metric_data*m=&(metrics.data[b->font]);
5644 unsigned short*c; // Pointer to current character code
5645 scaled junk; // Ensures no segmentation faults are occuring
5646 if(!w) w=&junk;
5647 if(!h) h=&junk;
5648 if(!d) d=&junk;
5649 *w=*h=*d=0;
5650 for(c=b->chars;*c!=0xFFFF;c++) {
5651 if(*c&0x8000) {
5652 if(*c&0x4000) {
5653 @<Process an implicit kern in |calc_chars|@>;
5654 } @+else {
5655 @<Process an accent in |calc_chars|@>;
5657 } @+else {
5658 @<Process a normal character in |calc_chars|@>;
5663 @ @<Process a normal character in |calc_chars|@>= {
5664 scaled width=m->width_base[m->info[*c&0xFF].width];
5665 scaled height=m->height_base[m->info[*c&0xFF].height];
5666 scaled depth=m->depth_base[m->info[*c&0xFF].depth];
5667 if(*h<height) *h=height;
5668 if(*d<depth) *d=depth;
5669 *w+=(t*width)>>7;
5672 @ @<Process an implicit kern in |calc_chars|@>= {
5673 scaled width=m->kern_base[*c&0x3FFF];
5674 *w+=(t*width)>>7;
5677 @ Now to do accents. This requires looking ahead to see the height for the
5678 next character. If the accent has positive height and zero depth, then it
5679 should be adjusted higher in case the letter is taller than an `x' (for
5680 example uppercase letters such as `\'E'). However, if the accent has
5681 positive depth and zero height, then it is an accent that should not be
5682 adjusted for the height of the character (for example `\c C'), although it
5683 might be adjusted for the depth.
5685 It should never happen that the next item is not a normal character (if it
5686 does, then I am not considered responsible for your bad luck).
5688 @<Process an accent in |calc_chars|@>= {
5689 scaled height=m->height_base[m->info[*c&0xFF].height];
5690 scaled depth=m->depth_base[m->info[*c&0xFF].depth];
5691 scaled c_height=m->height_base[m->info[c[1]&0xFF].height];
5692 scaled c_depth=m->height_base[m->info[c[1]&0xFF].depth];
5693 if(height<=0 && depth>0) {
5694 depth+=c_depth;
5695 } @+else {
5696 height+=c_height-m->parameters[5];
5698 if(*h<height) *h=height;
5699 if(*d<depth) *d=depth;
5702 @*Packaging. This is how the nest lists are packaged into boxes and the
5703 width, height, and depth are calculated from them. They are separate for
5704 horizontal and vertical packing, although there are similarities.
5706 The packing code is also used to compute the glue set of the box, and its
5707 badness. Here is the global variable to store the badness.
5709 @<Global variables@>=
5710 int last_badness=too_bad;
5712 @ There are two such subroutines, |hpackage| and |vpackage|, depending on
5713 what kind of box is wanted. Each one also takes three parameters: |first|,
5714 the first node in the box; |at_size|, the intended size, and |factor|, the
5715 amount to multiply the natural size by before adding |at_size|.
5717 @d common_package box_node*first,scaled at_size,signed char factor
5719 @ Horizontal packaging must compute height, width, and depth of characters
5720 and other boxes it contains, as well as compute glue settings, specials,
5721 adjustments, and so on.
5723 For horizontal packaging, there is also a |tracking| parameter for spacing
5724 the letters in the box.
5726 @-p box_node*hpackage(common_package,unsigned char tracking) {
5727 box_node*box=create_node(hlist_node,0,sizeof_hlist_node);
5728 scaled stretchability[4]; // Total stretch of all glue
5729 scaled shrinkability[4]; // Total shrink of all glue
5730 scaled natural=0; // Total width
5731 box_node*this; // Current node
5732 @<Initialize variables for |hpackage|@>;
5733 @<Read all nodes in a horizontal list to package them@>;
5734 #define @!actual @, box->width
5735 actual=(factor*natural)/8+at_size;
5736 @<Compute glue set and badness@>;
5737 #undef actual
5738 return box;
5741 @ @<Initialize variables for |hpackage|@>= {
5742 int o;
5743 box->list=first;
5744 box->tracking=tracking;
5745 box->height=box->depth=box->shift_amount=0;
5746 box->glue_set=0;
5747 for(o=0;o<4;o++) stretchability[o]=shrinkability[o]=0;
5750 @ @<Read all nodes in a horizontal list to package them@>= {
5751 for(this=first;this;this=this->next) {
5752 switch(type_of(this)) {
5753 case chars_node: @<Add word to box size@>; @+break;
5754 case hlist_node: case vlist_node: case rule_node:
5755 @<Apply the size of a box to a horizontal list@>; @+break;
5756 case kern_node: natural+=this->distance; @+break;
5757 case glue_node: @<Add glue to box size@>; @+break;
5758 case special_node:
5759 if(subtype_of(this)==spec_pack) @<Pack a special node@>;
5760 @+break;
5761 default: break; // All other nodes are ignored
5766 @ @<Add word to box size@>= {
5767 scaled w,h,d;
5768 calc_chars(this,&w,&h,&d,tracking<<1);
5769 natural+=w;
5770 if(h>box->height) box->height=h;
5771 if(d>box->depth) box->depth=d;
5774 @ @<Apply the size of a box to a horizontal list@>= {
5775 natural+=this->width;
5776 if(this->height+this->shift_amount>box->height)
5777 box->height=this->height+this->shift_amount;
5778 if(this->depth-this->shift_amount>box->depth)
5779 box->depth=this->depth-this->shift_amount;
5782 @ @<Add glue to box size@>= {
5783 natural+=this->natural;
5784 stretchability[subtype_of(this)&3]+=this->stretch;
5785 shrinkability[subtype_of(this)>>2]+=this->shrink;
5788 @ When packing a special node that has a code to run during packing, it
5789 can read and affect the current width and the intended width; it could
5790 also do other things, such as accumulating boxes for adjustments and so
5793 @<Pack a special node@>= {
5794 push_num(at_size);
5795 push_num(natural);
5796 @# execute_program(this->program); @#
5797 natural=pop_num();
5798 at_size=pop_num();
5801 @ A macro named |actual| is defined above so that this code can be used
5802 for both horizontal and for vertical packaging.
5804 We also have a macro here to decide setting the glue.
5806 @d set_glue(_order,_flag,_diff,_glue)
5807 (box->type_and_subtype|=((_order)<<4)|((_flag)<<7)),
5808 (box->glue_set=make_fraction(_glue,_diff))
5810 @<Compute glue set and badness@>= {
5811 if(actual>natural) {
5812 @<Glue is stretching@>;
5813 } @+else if(actual<natural) {
5814 @<Glue is shrinking@>;
5815 } @+else {
5816 last_badness=0; // Perfect!
5820 @ @<Glue is stretching@>= {
5821 if(stretching[filll]!=0) {
5822 set_glue(filll,0,actual-natural,stretching[filll]);
5823 last_badness=0;
5824 } @+else if(stretching[fill]!=0) {
5825 set_glue(fill,0,actual-natural,stretching[fill]);
5826 last_badness=0;
5827 } @+else if(stretching[fil]!=0) {
5828 set_glue(fil,0,actual-natural,stretching[fil]);
5829 last_badness=0;
5830 } @+else if(stretching[finite]!=0) {
5831 set_glue(finite,0,actual-natural,stretching[finite]);
5832 last_badness=calc_badness(actual-natural,stretching[finite]);
5833 } @+else {
5834 last_badness=too_bad;
5838 @ @<Glue is shrinking@>= {
5839 if(shrinking[filll]!=0) {
5840 set_glue(filll,1,natural-actual,shrinking[filll]);
5841 last_badness=0;
5842 } @+else if(shrinking[fill]!=0) {
5843 set_glue(fill,1,natural-actual,shrinking[fill]);
5844 last_badness=0;
5845 } @+else if(shrinking[fil]!=0) {
5846 set_glue(fil,1,natural-actual,shrinking[fil]);
5847 last_badness=0;
5848 } @+else if(shrinking[finite]>=natural-actual) {
5849 set_glue(finite,1,natural-actual,shrinking[finite]);
5850 last_badness=calc_badness(natural-actual,shrinking[finite]);
5851 } @+else {
5852 set_glue(finite,1,1,1); // Shrink as much as possible
5853 last_badness=too_bad;
5857 @ Now vertical.
5859 For vertical packaging, the two extra parameters are |max_dp|, the maximum
5860 depth; and |align_top|, which should be set true if it is wanted to align
5861 at the top instead of at the bottom.
5863 @-p box_node*vpackage(common_package,scaled max_dp,boolean align_top) {
5864 box_node*box=create_node(vlist_node,0,sizeof_vlist_node);
5865 scaled stretchability[4]; // Total stretch of all glue
5866 scaled shrinkability[4]; // Total shrink of all glue
5867 scaled natural=0; // Total height plus depth
5868 scaled bonnet=0; // Height of first item
5869 scaled boot=0; // Depth of last item
5870 box_node*this; // Current node
5871 @<Initialize variables for |vpackage|@>;
5872 @<Read all nodes in a vertical list to package them@>;
5873 box->height=bonnet; @+ box->depth=boot;
5874 #define @!actual @, (*(align_top?&(box->depth):&(box->height)))
5875 natural-=align_top?bonnet:boot;
5876 actual=(factor*natural)/8+at_size;
5877 @<Compute glue set and badness@>;
5878 #undef actual
5879 @<Move the reference point to match the maximum depth, if applicable@>;
5880 return box;
5883 @ @<Initialize variables for |vpackage|@>= {
5884 int o;
5885 box->list=first;
5886 box->width=box->shift_amount=0;
5887 box->glue_set=0;
5888 for(o=0;o<4;o++) stretchability[o]=shrinkability[o]=0;
5891 @ @<Read all nodes in a vertical list to package them@>= {
5892 for(this=first;this;this=this->next) {
5893 switch(type_of(this)) {
5894 case hlist_node: case vlist_node: case rule_node:
5895 @<Apply the size of a box to a vertical list@>; @+break;
5896 case kern_node: natural+=this->distance; @+boot=0; @+break;
5897 case glue_node: @<Add glue to box size@>; @+break;
5898 case special_node:
5899 if(subtype_of(this)==spec_pack) @<Pack a special node@>;
5900 @+break;
5901 default: break; // All other nodes are ignored
5903 if(this==first) bonnet=natural-boot;
5907 @ @<Apply the size of a box to a vertical list@>= {
5908 natural+=this->height+(boot=this->depth);
5909 if(this->width+this->shift_amount>box->width)
5910 box->width=this->width+this->width;
5913 @ @<Move the reference point to match the maximum depth, if applicable@>= {
5914 if(box->depth>max_dp) {
5915 box->height+=box->depth-max_dp;
5916 box->depth=max_dp;
5920 @*Typesetting Commands. There are various commands available in \TeX
5921 nicard for dealing with typesetting. Another thing it does is to allow you
5922 to enter distances using units.
5924 @<Do a typesetting command@>= {
5925 int c=*++ptr;
5926 if((c>='0' && c<='9') || c=='.') @<Read a distance and units@>@;
5927 else switch(c) {
5928 @<Typesetting commands@>@;
5932 @ The following units are supported:
5934 \halign{\quad\tt#\space\hss&(#)\hss\cr
5935 pt&Point\cr
5936 bp&Desktop publishing point\cr
5937 in&Inch\cr
5938 cm&Centimetre\cr
5939 mm&Millimetre\cr
5940 pc&Pica\cr
5941 qu&Quarter\cr
5942 em&Em width -- font specific\cr
5943 ex&Ex height -- font specific\cr
5946 @d distance_units(_a,_b,_x,_y)
5947 if(c==_a && decim==_b) { num*=_x; den*=_y; }
5949 @<Read a distance and units@>= {
5950 int decim=1; // Multiply denominator per step; reused for second letter
5951 int num=0,den=1; // Numerator and denominator to scale the units
5952 while((c>='0' && c<='9') || c=='.') {
5953 den*=decim;
5954 if(c=='.') decim=10;
5955 else num=10*num+c-'0';
5956 c=*++ptr;
5958 decim=*++ptr;
5959 distance_units('p','t',1,1);
5960 distance_units('b','p',7227,7200);
5961 distance_units('i','n',7227,100);
5962 distance_units('c','m',7227,254);
5963 distance_units('m','m',7227,2540);
5964 distance_units('p','c',12,1);
5965 distance_units('q','u',7227,10160);
5966 push_num(make_fraction(num,den)>>16);
5969 @*Internal Image Rendering. This program uses LodePNG to read/write PNG
5970 files. (The LodePNG included with this program is customized to omit the
5971 things which are not used.)
5973 @^LodePNG@>
5974 @^Portable Network Graphics@>
5976 @<Include files@>=
5977 #include "lodepng/lodepng.h"
5979 @ Here are keeping track of the bitmaps (in PBM format) and graymaps (in
5980 (in 8-bit PGM format). Three or four graymaps are loaded from or saved to
5981 a PNG file and the conversion between is done at that time.
5983 @<Global variables@>=
5984 unsigned char*bitmap[10];
5985 unsigned char*graymap[10];
5987 @ @-p void execute_image_manip(image_manipulator*imp) {
5988 unsigned int b_row_size=((layer_width+7)>>3);
5989 unsigned int b_layer_size=b_row_size*layer_height;
5990 unsigned int g_layer_size=layer_width*layer_height;
5991 while(imp->data_len && imp->data[0]) {
5992 if(imp->data[0]<20) {
5993 @<Perform image manipulator command with no picture registers@>;
5994 } @+else if(imp->data[0]<1000) {
5995 @<Perform image manipulator command with one picture register@>;
5996 } @+else if(imp->data[0]<20000) {
5997 @<Perform image manipulator command with two picture registers@>;
5998 } @+else {
5999 @<Perform image manipulator command with three picture registers@>;
6001 if(imp->next==none) return;
6002 imp=image_manips.data+imp->next;
6006 @ Here are some subroutines to initialize and discard the picture memory.
6008 @-p void init_bitmap(int n) {
6009 unsigned int row_size=((layer_width+7)>>3);
6010 unsigned int layer_size=row_size*layer_height;
6011 if(bitmap[n]) return;
6012 memset(bitmap[n]=malloc(layer_size+1),0,layer_size);
6015 @ @-p void init_graymap(int n) {
6016 unsigned int layer_size=layer_width*layer_height;
6017 if(graymap[n]) return;
6018 memset(graymap[n]=malloc(layer_size),0,layer_size);
6021 @ @-p void trash_bitmap(int n) {
6022 if(bitmap[n]) free(bitmap[n]);
6023 bitmap[n]=0;
6026 @ @-p void trash_graymap(int n) {
6027 if(graymap[n]) free(graymap[n]);
6028 graymap[n]=0;
6031 @ Now we have the commands which appear in an image manipulator.
6033 Since gamma corrections are computed here, \.{math.h} is required.
6035 @^floating point@>
6037 @<Include files@>=
6038 #include <math.h>
6041 @^gamma correction@>
6043 @<Perform image manipulator command with no picture registers@>= {
6044 switch(imp->data[0]) {
6045 case 1: { // Fill multiplication table
6046 unsigned char*t=tables[0];
6047 int i,j;
6048 for(i=0;i<256;i++) {
6049 j=(i*imp->data[1])/2560;
6050 if(j>255) t[i]=255; else t[i]=j;
6052 break;
6054 case 2: { // Fill table by polynomial
6055 unsigned char*t=tables[0];
6056 int i,j,k,n;
6057 for(i=0;i<256;i++) {
6058 j=0;
6059 k=1;
6060 for(n=1;n<imp->data_len;n++) {
6061 j+=k*(int)(imp->data[n]-5120);
6062 k*=i;
6064 j/=2560;
6065 t[i]=j;
6066 if(j>255) t[i]=255;
6067 if(j<0) t[i]=0;
6069 break;
6071 case 3: { // Fill gamma table
6072 unsigned char*t=tables[0];
6073 int i;
6074 double d;
6075 for(i=0;i<256;i++) {
6076 d=pow(i,0.001*(double)(imp->data[1]+1));
6078 break;
6080 case 4: { // Copy table
6081 unsigned char*t=tables[imp->data[1]&0x7F];
6082 unsigned char*u=tables[imp->data[2]&0x7F];
6083 int i;
6084 for(i=0;i<256;i++) t[i]=u[i];
6086 case 5: { // Compose table
6087 unsigned char*t=tables[imp->data[1]&0x7F];
6088 unsigned char*u=tables[imp->data[2]&0x7F];
6089 int i;
6090 for(i=0;i<256;i++) t[i]=u[t[i]];
6095 @<Perform image manipulator command with one picture register@>= {
6096 int rx=imp->data[0]%10;
6097 switch(imp->data[0]/10) {
6098 case 2: { // Clear a bitmap
6099 trash_bitmap(rx);
6100 break;
6102 case 3: { // Clear a graymap
6103 trash_graymap(rx);
6104 break;
6106 case 4: { // Flip a bitmap
6107 init_bitmap(rx);
6108 //TODO
6109 break;
6111 case 5: { // Flip a graymap
6112 init_graymap(rx);
6113 //TODO
6114 break;
6116 case 6: { // Mirror a bitmap
6117 init_bitmap(rx);
6118 //TODO
6119 break;
6121 case 7: { // Mirror a graymap
6122 init_graymap(rx);
6123 //TODO
6124 break;
6126 case 8: { // Fill graymap with value
6127 init_graymap(rx);
6128 memset(graymap[rx],imp->data[1],g_layer_size);
6129 break;
6131 case 9: { // Modify graymap by table
6132 unsigned char*t=tables[imp->data[1]&0x7F];
6133 unsigned int i;
6134 init_graymap(rx);
6135 for(i=0;i<g_layer_size;i++) graymap[rx][i]=t[graymap[rx][i]];
6136 break;
6138 case 10: { // Bitwise NOT of bitmaps
6139 init_bitmap(rx);
6140 unsigned int i;
6141 for(i=0;i<b_layer_size;i++) bitmap[rx][i]^=0xFF;
6142 break;
6144 case 11: { // Shift a bitmap
6145 init_bitmap(rx);
6146 //TODO
6147 break;
6149 case 12: { // Shift a graymap
6150 init_graymap(rx);
6151 //TODO
6152 break;
6157 @<Perform image manipulator command with two picture registers@>= {
6158 int rx=imp->data[0]%10;
6159 int ry=(imp->data[0]/10)%10;
6160 switch(imp->data[0]/100) {
6161 case 10: { // Copy bitmap
6162 init_bitmap(rx); @+ init_bitmap(ry);
6163 memcpy(bitmap[rx],bitmap[ry],b_layer_size);
6164 break;
6166 case 11: { // Copy graymap
6167 init_graymap(rx); @+ init_graymap(ry);
6168 memcpy(graymap[rx],graymap[ry],g_layer_size);
6169 break;
6171 case 12: { // Select maximum of graymaps
6172 unsigned int i;
6173 init_graymap(rx); @+ init_graymap(ry);
6174 for(i=0;i<g_layer_size;i++) {
6175 if(graymap[ry][i]>graymap[rx][i]) graymap[rx][i]=graymap[ry][i];
6177 break;
6179 case 13: { // Select minimum of graymaps
6180 unsigned int i;
6181 init_graymap(rx); @+ init_graymap(ry);
6182 for(i=0;i<g_layer_size;i++) {
6183 if(graymap[ry][i]<graymap[rx][i]) graymap[rx][i]=graymap[ry][i];
6185 break;
6187 case 14: { // Bitwise AND of bitmaps
6188 init_bitmap(rx);
6189 init_bitmap(ry);
6190 unsigned int i;
6191 for(i=0;i<b_layer_size;i++) bitmap[rx][i]&=bitmap[ry][i];
6192 break;
6194 case 15: { // Bitwise OR of bitmaps
6195 init_bitmap(rx);
6196 init_bitmap(ry);
6197 unsigned int i;
6198 for(i=0;i<b_layer_size;i++) bitmap[rx][i]|=bitmap[ry][i];
6199 break;
6201 case 16: { // Bitwise XOR of bitmaps
6202 init_bitmap(rx);
6203 init_bitmap(ry);
6204 unsigned int i;
6205 for(i=0;i<b_layer_size;i++) bitmap[rx][i]^=bitmap[ry][i];
6206 break;
6208 case 17: { // Copy bitmap to graymap
6209 init_bitmap(rx);
6210 init_graymap(ry);
6211 // TODO
6212 break;
6214 case 18: { // Blur graymap by graymap
6215 init_graymap(rx);
6216 init_graymap(ry);
6217 // TODO
6218 break;
6223 @ @<Perform image manipulator command with three picture registers@>= {
6224 int rx=imp->data[0]%10;
6225 int ry=(imp->data[0]/10)%10;
6226 int rz=(imp->data[0]/100)%10;
6227 switch(imp->data[0]/1000) {
6228 case 20: { // Compose graymap to graymap with alpha channel
6229 init_graymap(rx); @+ init_graymap(ry); @+ init_graymap(rz);
6230 // TODO
6231 break;
6233 case 21: { // Apply color transformation matrix
6234 init_graymap(rx); @+ init_graymap(ry); @+ init_graymap(rz);
6235 // TODO
6236 break;
6241 @*Main Program. This is where the program starts and ends. Everything else
6242 in the other chapters is started from here.
6244 @<Include files@>=
6245 #include <signal.h>
6246 #include <stdio.h>
6247 #include <stdlib.h>
6248 #include <string.h>
6249 #include <time.h>
6250 #include <unistd.h>
6252 @ @-p int main(int argc,char**argv) {
6253 boolean dvi_mode=0;
6254 @<Set up signal handler@>;
6255 @<Initialize memory@>;
6256 @<Display the banner message@>;
6257 @<Decide whether in DVI reading mode@>;
6258 if(!dvi_mode) @<Open the main input file@>;
6259 @<Initialize the input states@>;
6260 @<Initialize the tables and registers@>;
6261 @<Initialize the random number generator@>;
6262 @<Set registers according to command-line parameters@>;
6263 if(!dvi_mode) @<Process the input files@>;
6264 if(dvi_mode) dvi_mode=read_dvi_file(argv[1]);
6265 @<Call program in \.Z register if necessary@>;
6266 if(!dvi_mode) @<Send |end_transmission| to each card area@>;
6267 @<Write the output files@>;
6268 if(registers['Q'].is_string && dvi_mode &&
6269 (argv[0][0]!='-' || argv[0][1]!='z')) @<Switch to ImageMagick@>;
6270 return 0;
6273 @ @<Display the banner message@>= {
6274 fprintf(stderr,"TeXnicard version %s\n",version_string);
6275 fprintf(stderr,
6276 "This program is free software and comes with NO WARRANTY.\n");
6277 fflush(stderr);
6280 @ @<Set registers according to command-line parameters@>= {
6281 int i;
6282 for(i=2;i<argc;i++) {
6283 registers[i+('0'-2)].is_string=1;
6284 registers[i+('0'-2)].text=strdup(argv[i]);
6288 @ The main input file will be either the terminal, or another file if the
6289 command-line argument is given.
6291 @<Open the main input file@>= {
6292 if(argc>1 && strcmp(argv[1],"-")!=0) {
6293 --current_input_file;
6294 open_input(argv[1]);
6295 } @+else {
6296 current_fp=0;
6297 strcpy(current_filename,"<Teletype>");
6301 @ @<Call program in \.Z register if necessary@>= {
6302 if(registers['Z'].is_string) execute_program(registers['Z'].text);
6305 @ The alternative mode to run this program is DVI mode. DVI mode is
6306 specified by a command-line switch.
6308 @.DVI@>
6310 @<Decide whether in DVI reading mode@>= {
6311 if(argc>1 && argv[1][0]=='-' && argv[1][1]) {
6312 dvi_mode=1;
6313 argv++; @+ argc--;
6314 if(argv[0][1]=='a') {
6315 printing_mode=printing_all_cards;
6316 } @+else if(argv[0][1]=='f') {
6317 printing_mode=printing_list_from_file;
6318 printlistfile=fopen(argv[1],"r");
6319 argv++; @+ argc--;
6320 } @+else if(argv[0][1]=='n') {
6321 printing_mode=printing_list;
6322 printlisttext=argv[1];
6323 argv++; @+ argc--;
6324 } @+else if(argv[0][1]=='z') {
6325 printing_mode=printing_list;
6326 printlisttext="";
6331 @*Signal Handlers. The |SIGSEGV| signal should be handled in case
6332 something goes wrong in the program and it causes a segmentation fault, it
6333 should attempt to recover what you have before terminating, in order to be
6334 better at diagnosing the error.
6336 @<Set up signal handler@>= {
6337 signal(SIGSEGV,handle_crash);
6340 @ Some things will be more careful here to ensure not to cause the error
6341 again (if it does, it will just quit, though).
6343 @-p void handle_crash(int sig) {
6344 signal(SIGSEGV,SIG_DFL);
6345 @#fprintf(stderr,"\nFatal signal error (%d)\n",sig);
6346 @.Fatal signal error...@>
6347 fprintf(stderr,"cur_state=%d\ncur_name=%d\ncur_data=%d\n",
6348 cur_state,cur_name,cur_data);
6349 if(current_input_file>=input_files && current_input_file<input_files
6350 +max_input_stack) @<Display input stack after a crash@>;
6351 fprintf(stderr,"Program stack level: %d\n",stack_ptr-stack);
6352 fprintf(stderr,"Save stack level: %d\n",save_stack_ptr-save_stack);
6353 @#exit(3);
6356 @ @<Display input stack after a crash@>= {
6357 for(;;) {
6358 fprintf(stderr,"File %s line %d\n",current_filename,current_line);
6359 if(current_input_file--==input_files) break;
6363 @*The Future. Here are some ideas for future versions of this program:
6365 $\bullet$ A customizable Inform7-like parser, that would compile into a C
6366 code (or possibly a Haskell code), so that you can play the cards on
6367 rule-enforcing computer programs.
6368 @^Inform@>
6370 $\bullet$ A database to keep track of how many copies of a card have been
6371 sold, for inventory purposes.
6372 @^commercial viability@>
6373 @^inventory@>
6375 $\bullet$ Full text search, for things such as the Oracle text search.
6376 @^Oracle@>
6378 $\bullet$ Allow more than 256 fonts in one card set.
6380 $\bullet$ Unicode input (UTF-8).
6382 @*Bibliography.
6384 \count255=0 %
6385 \long\def\Par{\csname par\endcsname}%
6386 \loop\ifnum\count255<\bibliocount%
6387 \advance\count255 by 1
6388 \Par$^{[\the\count255]}$\csname biblio \the\count255\endcsname\Par%
6389 \repeat%
6391 @*Index. Here you can find references to the definition and use of all the
6392 variables, subroutines, etc.\ used in this program, as well as a few other
6393 things of interest. Underlined entries indicate where it is defined.
6395 {\bf Important note:} All the numbers in this index are section numbers,
6396 not page numbers.
6398 % End of file "texnicard.w"