ia64/xen-unstable

view xen/tools/figlet/figlet.c @ 17507:4f9284a5d3ab

figlet: Fix handling of full final line of octal output.
It should not be terminated with a backslash.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Apr 23 09:02:15 2008 +0100 (2008-04-23)
parents e87e5d216c0b
children
line source
2 /*
3 * XXXXXXXXXXXXXXXXXXXXXXXXXXX
4 *
5 * This is a HACKED figlet source file for Xen.
6 *
7 * Hacked to output C octal strings for inclusion in a header file.
8 * Support for opening zipped files is removed.
9 *
10 * Go to www.figlet.org for the unhacked Figlet sources.
11 */
13 /****************************************************************************
15 FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai
16 FIGlet Copyright 1996, 1997, 1998, 1999, 2000, 2001 John Cowan
17 FIGlet Copyright 2002 Christiaan Keet
18 Portions written by Paul Burton and Christiaan Keet
19 Internet: <info@figlet.org>
20 FIGlet, along with the various FIGlet fonts and documentation, is
21 copyrighted under the provisions of the Artistic License (as listed
22 in the file "Artistic-license.txt" which is included in this package.
23 ****************************************************************************/
25 #define DATE "13 July 2002"
26 #define VERSION "2.2.1"
27 #define VERSION_INT 20201
29 /* FIGlet (Frank, Ian & Glenn's Letters) */
30 /* by Glenn Chappell */
31 /* Apr 1991 */
32 /* Automatic file addition by Ian Chai May 1991 */
33 /* Punctuation and numbers addition by Ian Chai Jan 1993 */
34 /* Full ASCII by Glenn Chappell Feb 1993 */
35 /* Line-breaking, general rewrite by Glenn Chappell Mar 1993 */
36 /* Hard blanks by Glenn Chappell Apr 1993 */
37 /* Release 2.0 5 Aug 1993 */
38 /* Right-to-left printing, extended char set by Glenn Chappell Dec 1993 */
39 /* Control files by Glenn Chappell Feb 1994 */
40 /* Release 2.1 12 Aug 1994 */
41 /* Release 2.1.1 25 Aug 1994 */
42 /* Release 2.1.2 by Gilbert (Mad Programmer) Healton: Add -A command line
43 option. Sept 8, 1996 */
44 /* Release 2.2 by John Cowan: multibyte inputs, compressed fonts,
45 mapping tables, kerning/smushing options. */
46 /* Release 2.2.1 by Christiaan Keet: minor updates including readmes
47 FAQs and comments. 13 July 2002. The new official FIGlet website is
48 http://www.figlet.org/ */
50 #define DEFAULTFONTDIR "."
51 #define DEFAULTFONTFILE "xen.flf"
53 #include <stdio.h>
54 #ifdef __STDC__
55 #include <stdlib.h>
56 #endif
57 #include <string.h>
58 #include <ctype.h>
59 #include <fcntl.h> /* Needed for get_columns */
61 #ifdef unix
62 #include <sys/ioctl.h> /* Needed for get_columns */
63 #endif
66 #define ZFILE FILE
67 #define Zopen fopen
68 #define Zgetc fgetc
69 #define Zungetc(_x,_y) fseek(_y,-1,SEEK_CUR)
70 #define Zclose fclose
72 #define MYSTRLEN(x) ((int)strlen(x)) /* Eliminate ANSI problem */
74 #define DIRSEP '/'
75 #define DIRSEP2 '\\'
76 /* Leave alone for Unix and MS-DOS/Windows!
77 Note: '/' also used in filename in get_columns(). */
79 #define FONTFILESUFFIX ".flf"
80 #define FONTFILEMAGICNUMBER "flf2"
81 #define FSUFFIXLEN MYSTRLEN(FONTFILESUFFIX)
82 #define CONTROLFILESUFFIX ".flc"
83 #define CONTROLFILEMAGICNUMBER "flc2" /* no longer used in 2.2 */
84 #define CSUFFIXLEN MYSTRLEN(CONTROLFILESUFFIX)
85 #define DEFAULTCOLUMNS 80
88 /****************************************************************************
90 Globals dealing with chars that are read
92 ****************************************************************************/
94 typedef long inchr; /* "char" read from stdin */
96 inchr *inchrline; /* Alloc'd inchr inchrline[inchrlinelenlimit+1]; */
97 /* Note: not null-terminated. */
98 int inchrlinelen,inchrlinelenlimit;
99 inchr deutsch[7] = {196, 214, 220, 228, 246, 252, 223};
100 /* Latin-1 codes for German letters, respectively:
101 LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut
102 LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut
103 LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut
104 LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut
105 LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut
106 LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut
107 LATIN SMALL LETTER SHARP S = ess-zed
108 */
110 int hzmode; /* true if reading double-bytes in HZ mode */
111 int gndbl[4]; /* gndbl[n] is true if Gn is double-byte */
112 inchr gn[4]; /* Gn character sets: ASCII, Latin-1, none, none */
113 int gl; /* 0-3 specifies left-half Gn character set */
114 int gr; /* 0-3 specifies right-half Gn character set */
116 int Myargc; /* to avoid passing around argc and argv */
117 char **Myargv;
119 /****************************************************************************
121 Globals dealing with chars that are written
123 ****************************************************************************/
125 typedef struct fc {
126 inchr ord;
127 char **thechar; /* Alloc'd char thechar[charheight][]; */
128 struct fc *next;
129 } fcharnode;
131 fcharnode *fcharlist;
132 char **currchar;
133 int currcharwidth;
134 int previouscharwidth;
135 char **outputline; /* Alloc'd char outputline[charheight][outlinelenlimit+1]; */
136 int outlinelen;
139 /****************************************************************************
141 Globals dealing with command file storage
143 ****************************************************************************/
145 typedef struct cfn {
146 char *thename;
147 struct cfn *next;
148 } cfnamenode;
150 cfnamenode *cfilelist,**cfilelistend;
152 typedef struct cm {
153 int thecommand;
154 inchr rangelo;
155 inchr rangehi;
156 inchr offset;
157 struct cm *next;
158 } comnode;
160 comnode *commandlist,**commandlistend;
162 /****************************************************************************
164 Globals affected by command line options
166 ****************************************************************************/
168 int deutschflag,justification,paragraphflag,right2left,multibyte;
169 int cmdinput;
171 #define SM_SMUSH 128
172 #define SM_KERN 64
173 #define SM_EQUAL 1
174 #define SM_LOWLINE 2
175 #define SM_HIERARCHY 4
176 #define SM_PAIR 8
177 #define SM_BIGX 16
178 #define SM_HARDBLANK 32
180 int smushmode;
182 #define SMO_NO 0 /* no command-line smushmode */
183 #define SMO_YES 1 /* use command-line smushmode, ignore font smushmode */
184 #define SMO_FORCE 2 /* logically OR command-line and font smushmodes */
186 int smushoverride;
188 int outputwidth;
189 int outlinelenlimit;
190 char *fontdirname,*fontname;
193 /****************************************************************************
195 Globals read from font file
197 ****************************************************************************/
199 char hardblank;
200 int charheight;
203 /****************************************************************************
205 Name of program, used in error messages
207 ****************************************************************************/
209 char *myname;
212 #ifdef TIOCGWINSZ
213 /****************************************************************************
215 get_columns
217 Determines the number of columns of /dev/tty. Returns the number of
218 columns, or -1 if error. May return 0 if columns unknown.
219 Requires include files <fcntl.h> and <sys/ioctl.h>.
220 by Glenn Chappell & Ian Chai 14 Apr 1993
222 ****************************************************************************/
224 int get_columns()
225 {
226 struct winsize ws;
227 int fd,result;
229 if ((fd = open("/dev/tty",O_WRONLY))<0) return -1;
230 result = ioctl(fd,TIOCGWINSZ,&ws);
231 close(fd);
232 return result?-1:ws.ws_col;
233 }
234 #endif /* ifdef TIOCGWINSZ */
237 /****************************************************************************
239 myalloc
241 Calls malloc. If malloc returns error, prints error message and
242 quits.
244 ****************************************************************************/
246 #ifdef __STDC__
247 char *myalloc(size_t size)
248 #else
249 char *myalloc(size)
250 int size;
251 #endif
252 {
253 char *ptr;
254 #ifndef __STDC__
255 extern void *malloc();
256 #endif
258 if ((ptr = (char*)malloc(size))==NULL) {
259 fprintf(stderr,"%s: Out of memory\n",myname);
260 exit(1);
261 }
262 else {
263 return ptr;
264 }
265 }
268 /****************************************************************************
270 hasdirsep
272 Returns true if s1 contains a DIRSEP or DIRSEP2 character.
274 ****************************************************************************/
276 int hasdirsep(s1)
277 char *s1;
278 {
279 if (strchr(s1, DIRSEP)) return 1;
280 else if (strchr(s1, DIRSEP2)) return 1;
281 else return 0;
282 }
284 /****************************************************************************
286 suffixcmp
288 Returns true if s2 is a suffix of s1; uses case-blind comparison.
290 ****************************************************************************/
292 int suffixcmp(s1, s2)
293 char *s1;
294 char *s2;
295 {
296 int len1, len2;
298 len1 = MYSTRLEN(s1);
299 len2 = MYSTRLEN(s2);
300 if (len2 > len1) return 0;
301 s1 += len1 - len2;
302 while (*s1) {
303 if (tolower(*s1) != tolower(*s2)) return 0;
304 s1++;
305 s2++;
306 }
307 return 1;
308 }
310 /****************************************************************************
312 skiptoeol
314 Skips to the end of a line, given a stream. Handles \r, \n, or \r\n.
316 ****************************************************************************/
318 void skiptoeol(fp)
319 ZFILE *fp;
320 {
321 int dummy;
323 while (dummy=Zgetc(fp),dummy!=EOF) {
324 if (dummy == '\n') return;
325 if (dummy == '\r') {
326 dummy = Zgetc(fp);
327 if (dummy != EOF && dummy != '\n') Zungetc(dummy,fp);
328 return;
329 }
330 }
331 }
334 /****************************************************************************
336 myfgets
338 Local version of fgets. Handles \r, \n, and \r\n terminators.
340 ****************************************************************************/
342 char *myfgets(line,maxlen,fp)
343 char *line;
344 int maxlen;
345 ZFILE *fp;
346 {
347 int c = 0;
348 char *p;
350 p = line;
351 while((c=Zgetc(fp))!=EOF&&maxlen) {
352 *p++ = c;
353 maxlen--;
354 if (c=='\n') break;
355 if (c=='\r') {
356 c = Zgetc(fp);
357 if (c != EOF && c != '\n') Zungetc(c,fp);
358 *(p-1) = '\n';
359 break;
360 }
361 }
362 *p = 0;
363 return (c==EOF) ? NULL : line;
364 }
366 /****************************************************************************
368 usageerr
370 Prints "Usage: ...." line to the given stream.
372 ****************************************************************************/
374 void printusage(out)
375 FILE *out;
376 {
377 fprintf(out,
378 "Usage: %s [ -cklnoprstvxDELNRSWX ] [ -d fontdirectory ]\n",
379 myname);
380 fprintf(out,
381 " [ -f fontfile ] [ -m smushmode ] [ -w outputwidth ]\n");
382 fprintf(out,
383 " [ -C controlfile ] [ -I infocode ] [ message ]\n");
384 }
387 /****************************************************************************
389 printinfo
391 Prints version and copyright message, or utility information.
393 ****************************************************************************/
395 void printinfo(infonum)
396 int infonum;
397 {
398 switch (infonum) {
399 case 0: /* Copyright message */
400 printf("FIGlet Copyright 1991-2002 Glenn Chappell, Ian Chai, ");
401 printf("John Cowan, Christiaan Keet\n");
402 printf("Internet: <info@figlet.org> ");
403 printf("Version: %s, date: %s\n\n",VERSION,DATE);
404 printf("FIGlet, along with the various FIGlet fonts");
405 printf(" and documentation, may be\n");
406 printf("freely copied and distributed.\n\n");
407 printf("If you use FIGlet, please send an");
408 printf(" e-mail message to <info@figlet.org>.\n\n");
409 printf("The latest version of FIGlet is available from the");
410 printf(" web site,\n\thttp://www.figlet.org/\n\n");
411 printusage(stdout);
412 break;
413 case 1: /* Version (integer) */
414 printf("%d\n",VERSION_INT);
415 break;
416 case 2: /* Font directory */
417 printf("%s\n",fontdirname);
418 break;
419 case 3: /* Font */
420 printf("%s\n",fontname);
421 break;
422 case 4: /* Outputwidth */
423 printf("%d\n",outputwidth);
424 }
425 }
428 /****************************************************************************
430 readmagic
432 Reads a four-character magic string from a stream.
434 ****************************************************************************/
435 void readmagic(fp,magic)
436 ZFILE *fp;
437 char *magic;
438 {
439 int i;
441 for (i=0;i<4;i++) {
442 magic[i] = Zgetc(fp);
443 }
444 magic[4] = 0;
445 }
447 /****************************************************************************
449 skipws
451 Skips whitespace characters from a stream.
453 ****************************************************************************/
454 void skipws(fp)
455 ZFILE *fp;
456 {
457 int c;
458 while (c=Zgetc(fp),isascii(c)&&isspace(c)) ;
459 Zungetc(c,fp);
460 }
462 /****************************************************************************
464 readnum
466 Reads a number from a stream. Accepts "0" prefix for octal and
467 "0x" or "0X" for hexadecimal. Ignores leading whitespace.
469 ****************************************************************************/
470 void readnum(fp,nump)
471 ZFILE *fp;
472 inchr *nump;
473 {
474 int acc = 0;
475 char *p;
476 int c;
477 int base;
478 int sign = 1;
479 char digits[] = "0123456789ABCDEF";
481 skipws(fp);
482 c = Zgetc(fp);
483 if (c=='-') {
484 sign = -1;
485 }
486 else {
487 Zungetc(c,fp);
488 }
489 c = Zgetc(fp);
490 if (c=='0') {
491 c = Zgetc(fp);
492 if (c=='x'||c=='X') {
493 base = 16;
494 }
495 else {
496 base = 8;
497 Zungetc(c,fp);
498 }
499 }
500 else {
501 base = 10;
502 Zungetc(c,fp);
503 }
505 while((c=Zgetc(fp))!=EOF) {
506 c=toupper(c);
507 p=strchr(digits,c);
508 if (!p) {
509 Zungetc(c,fp);
510 *nump = acc * sign;
511 return;
512 }
513 acc = acc*base+(p-digits);
514 }
515 *nump = acc * sign;
516 }
518 /****************************************************************************
520 readTchar
522 Reads a control file "T" command character specification.
524 Character is a single byte, an escape sequence, or
525 an escaped numeric.
527 ****************************************************************************/
529 inchr readTchar(fp)
530 ZFILE *fp;
531 {
532 inchr thechar;
533 char next;
535 thechar=Zgetc(fp);
536 if (thechar=='\n' || thechar=='\r') { /* Handle badly-formatted file */
537 Zungetc(thechar,fp);
538 return '\0';
539 }
540 if (thechar!='\\') return thechar;
541 next=Zgetc(fp);
542 switch(next) {
543 case 'a':
544 return 7;
545 case 'b':
546 return 8;
547 case 'e':
548 return 27;
549 case 'f':
550 return 12;
551 case 'n':
552 return 10;
553 case 'r':
554 return 13;
555 case 't':
556 return 9;
557 case 'v':
558 return 11;
559 default:
560 if (next=='-' || next=='x' || (next>='0' && next<='9')) {
561 Zungetc(next,fp);
562 readnum(fp,&thechar);
563 return thechar;
564 }
565 return next;
566 }
567 }
569 /****************************************************************************
571 charsetname
573 Get a Tchar representing a charset name, or 0 if none available.
574 Called in getcharset().
576 ****************************************************************************/
578 inchr charsetname(fp)
579 ZFILE *fp;
580 {
581 inchr result;
583 result = readTchar(fp);
584 if (result == '\n' || result == '\r') {
585 result = 0;
586 Zungetc(result,fp);
587 }
588 return result;
589 }
591 /****************************************************************************
593 charset
595 Processes "g[0123]" character set specifier
596 Called in readcontrol().
598 ****************************************************************************/
600 void charset(n, controlfile)
601 int n;
602 ZFILE *controlfile;
603 {
604 int ch;
606 skipws(controlfile);
607 if (Zgetc(controlfile) != '9') {
608 skiptoeol(controlfile);
609 return;
610 }
611 ch = Zgetc(controlfile);
612 if (ch == '6') {
613 gn[n] = 65536L * charsetname(controlfile) + 0x80;
614 gndbl[n] = 0;
615 skiptoeol(controlfile);
616 return;
617 }
618 if (ch != '4') {
619 skiptoeol(controlfile);
620 return;
621 }
622 ch = Zgetc(controlfile);
623 if (ch == 'x') {
624 if (Zgetc(controlfile) != '9') {
625 skiptoeol(controlfile);
626 return;
627 }
628 if (Zgetc(controlfile) != '4') {
629 skiptoeol(controlfile);
630 return;
631 }
632 skipws(controlfile);
633 gn[n] = 65536L * charsetname(controlfile);
634 gndbl[n] = 1;
635 skiptoeol(controlfile);
636 return;
637 }
638 Zungetc(ch, controlfile);
639 skipws(controlfile);
640 gn[n] = 65536L * charsetname(controlfile);
641 gndbl[n] = 0;
642 return;
643 }
645 /****************************************************************************
647 readcontrol
649 Allocates memory and reads in the given control file.
650 Called in readcontrolfiles().
652 ****************************************************************************/
654 void readcontrol(controlname)
655 char *controlname;
656 {
657 inchr firstch,lastch;
658 char dashcheck;
659 inchr offset;
660 char *controlpath,magicnum[5];
661 int command;
662 ZFILE *controlfile;
663 int namelen;
665 namelen = MYSTRLEN(fontdirname);
666 controlpath = (char*)myalloc(sizeof(char)
667 *(namelen+MYSTRLEN(controlname)+CSUFFIXLEN+2));
668 controlfile = NULL;
669 if (!hasdirsep(controlname)) {
670 strcpy(controlpath,fontdirname);
671 controlpath[namelen] = DIRSEP;
672 controlpath[namelen+1] = '\0';
673 strcat(controlpath,controlname);
674 strcat(controlpath,CONTROLFILESUFFIX);
675 controlfile = Zopen(controlpath,"rb");
676 }
677 if (controlfile==NULL) {
678 strcpy(controlpath,controlname);
679 strcat(controlpath,CONTROLFILESUFFIX);
680 controlfile = Zopen(controlpath,"rb");
681 if (controlfile==NULL) {
682 fprintf(stderr,"%s: %s: Unable to open control file\n",myname,
683 controlpath);
684 exit(1);
685 }
686 }
688 free(controlpath);
690 (*commandlistend) = (comnode*)myalloc(sizeof(comnode));
691 (*commandlistend)->thecommand = 0; /* Begin with a freeze command */
692 commandlistend = &(*commandlistend)->next;
693 (*commandlistend) = NULL;
695 while(command=Zgetc(controlfile),command!=EOF) {
696 switch (command) {
697 case 't': /* Translate */
698 skipws(controlfile);
699 firstch=readTchar(controlfile);
700 if ((dashcheck=Zgetc(controlfile))=='-') {
701 lastch=readTchar(controlfile);
702 }
703 else {
704 Zungetc(dashcheck,controlfile);
705 lastch=firstch;
706 }
707 skipws(controlfile);
708 offset=readTchar(controlfile)-firstch;
709 skiptoeol(controlfile);
710 (*commandlistend) = (comnode*)myalloc(sizeof(comnode));
711 (*commandlistend)->thecommand = 1;
712 (*commandlistend)->rangelo = firstch;
713 (*commandlistend)->rangehi = lastch;
714 (*commandlistend)->offset = offset;
715 commandlistend = &(*commandlistend)->next;
716 (*commandlistend) = NULL;
717 break;
718 case '0': case '1': case '2': case '3': case '4':
719 case '5': case '6': case '7': case '8': case '9':
720 case '-':
721 /* Mapping table entry */
722 Zungetc(command,controlfile);
723 readnum(controlfile,&firstch);
724 skipws(controlfile);
725 readnum(controlfile,&lastch);
726 offset=lastch-firstch;
727 lastch=firstch;
728 skiptoeol(controlfile);
729 (*commandlistend) = (comnode*)myalloc(sizeof(comnode));
730 (*commandlistend)->thecommand = 1;
731 (*commandlistend)->rangelo = firstch;
732 (*commandlistend)->rangehi = lastch;
733 (*commandlistend)->offset = offset;
734 commandlistend = &(*commandlistend)->next;
735 (*commandlistend) = NULL;
736 break;
737 case 'f': /* freeze */
738 skiptoeol(controlfile);
739 (*commandlistend) = (comnode*)myalloc(sizeof(comnode));
740 (*commandlistend)->thecommand = 0;
741 commandlistend = &(*commandlistend)->next;
742 (*commandlistend) = NULL;
743 break;
744 case 'b': /* DBCS input mode */
745 multibyte = 1;
746 break;
747 case 'u': /* UTF-8 input mode */
748 multibyte = 2;
749 break;
750 case 'h': /* HZ input mode */
751 multibyte = 3;
752 break;
753 case 'j': /* Shift-JIS input mode */
754 multibyte = 4;
755 break;
756 case 'g': /* ISO 2022 character set choices */
757 multibyte = 0;
758 skipws(controlfile);
759 command=Zgetc(controlfile);
760 switch (command) {
761 case '0': /* define G0 charset */
762 charset(0, controlfile);
763 break;
764 case '1': /* set G1 charset */
765 charset(1, controlfile);
766 break;
767 case '2': /* set G2 charset */
768 charset(2, controlfile);
769 break;
770 case '3': /* set G3 charset */
771 charset(3, controlfile);
772 break;
773 case 'l': case 'L': /* define left half */
774 skipws(controlfile);
775 gl = Zgetc(controlfile) - '0';
776 skiptoeol(controlfile);
777 break;
778 case 'r': case 'R': /* define right half */
779 skipws(controlfile);
780 gr = Zgetc(controlfile) - '0';
781 skiptoeol(controlfile);
782 break;
783 default: /* meaningless "g" command */
784 skiptoeol(controlfile);
785 }
786 case '\r': case '\n': /* blank line */
787 break;
788 default: /* Includes '#' */
789 skiptoeol(controlfile);
790 }
791 }
792 Zclose(controlfile);
793 }
796 /****************************************************************************
798 readcontrolfiles
800 Reads in the controlfiles names in cfilelist. Uses readcontrol.
801 Called in main().
803 ****************************************************************************/
805 void readcontrolfiles()
806 {
807 cfnamenode *cfnptr;
809 for (cfnptr=cfilelist;cfnptr!=NULL;cfnptr=cfnptr->next) {
810 readcontrol(cfnptr->thename);
811 }
812 }
815 /****************************************************************************
817 clearcfilelist
819 Clears the control file list. Assumes thename does not need freeing.
821 ****************************************************************************/
823 void clearcfilelist()
824 {
825 cfnamenode *cfnptr1,*cfnptr2;
827 cfnptr1 = cfilelist;
828 while (cfnptr1 != NULL) {
829 cfnptr2 = cfnptr1->next;
830 free(cfnptr1);
831 cfnptr1 = cfnptr2;
832 }
833 cfilelist = NULL;
834 cfilelistend = &cfilelist;
835 }
838 /****************************************************************************
840 getparams
842 Handles all command-line parameters. Puts all parameters within
843 bounds.
845 ****************************************************************************/
847 void getparams()
848 {
849 extern char *optarg;
850 extern int optind;
851 int c; /* "Should" be a char -- need int for "!= -1" test*/
852 int columns,firstfont,infoprint;
853 char *controlname;
855 if ((myname = strrchr(Myargv[0],DIRSEP))!=NULL) {
856 myname++;
857 }
858 else {
859 myname = Myargv[0];
860 }
861 fontdirname = DEFAULTFONTDIR;
862 firstfont = 1;
863 fontname = (char*)myalloc(sizeof(char)*(MYSTRLEN(DEFAULTFONTFILE)+1));
864 strcpy(fontname,DEFAULTFONTFILE); /* Some systems don't have strdup() */
865 if (suffixcmp(fontname,FONTFILESUFFIX)) {
866 fontname[MYSTRLEN(fontname)-FSUFFIXLEN]='\0';
867 }
868 cfilelist = NULL;
869 cfilelistend = &cfilelist;
870 commandlist = NULL;
871 commandlistend = &commandlist;
872 smushoverride = SMO_NO;
873 deutschflag = 0;
874 justification = -1;
875 right2left = -1;
876 paragraphflag = 0;
877 infoprint = -1;
878 cmdinput = 0;
879 outputwidth = DEFAULTCOLUMNS;
880 gn[1] = 0x80;
881 gr = 1;
882 while ((c = getopt(Myargc,Myargv,"ADEXLRI:xlcrpntvm:w:d:f:C:NFskSWo"))!= -1) {
883 /* Note: -F is not a legal option -- prints a special err message. */
884 switch (c) {
885 case 'A':
886 cmdinput = 1;
887 break;
888 case 'D':
889 deutschflag = 1;
890 break;
891 case 'E':
892 deutschflag = 0;
893 break;
894 case 'X':
895 right2left = -1;
896 break;
897 case 'L':
898 right2left = 0;
899 break;
900 case 'R':
901 right2left = 1;
902 break;
903 case 'x':
904 justification = -1;
905 break;
906 case 'l':
907 justification = 0;
908 break;
909 case 'c':
910 justification = 1;
911 break;
912 case 'r':
913 justification = 2;
914 break;
915 case 'p':
916 paragraphflag = 1;
917 break;
918 case 'n':
919 paragraphflag = 0;
920 break;
921 case 's':
922 smushoverride = SMO_NO;
923 break;
924 case 'k':
925 smushmode = SM_KERN;
926 smushoverride = SMO_YES;
927 break;
928 case 'S':
929 smushmode = SM_SMUSH;
930 smushoverride = SMO_FORCE;
931 break;
932 case 'o':
933 smushmode = SM_SMUSH;
934 smushoverride = SMO_YES;
935 break;
936 case 'W':
937 smushmode = 0;
938 smushoverride = SMO_YES;
939 break;
940 case 't':
941 #ifdef TIOCGWINSZ
942 columns = get_columns();
943 if (columns>0) {
944 outputwidth = columns;
945 }
946 #else /* ifdef TIOCGWINSZ */
947 fprintf(stderr,
948 "%s: \"-t\" is disabled, since ioctl is not fully implemented.\n",
949 myname);
950 #endif /* ifdef TIOCGWINSZ */
951 break;
952 case 'v':
953 infoprint = 0;
954 break;
955 case 'I':
956 infoprint = atoi(optarg);
957 break;
958 case 'm':
959 smushmode = atoi(optarg);
960 if (smushmode < -1) {
961 smushoverride = SMO_NO;
962 break;
963 }
964 if (smushmode == 0) smushmode = SM_KERN;
965 else if (smushmode == -1) smushmode = 0;
966 else smushmode = (smushmode & 63) | SM_SMUSH;
967 smushoverride = SMO_YES;
968 break;
969 case 'w':
970 columns = atoi(optarg);
971 if (columns>0) {
972 outputwidth = columns;
973 }
974 break;
975 case 'd':
976 fontdirname = optarg;
977 break;
978 case 'f':
979 if (firstfont) {
980 free(fontname);
981 firstfont = 0;
982 }
983 fontname = optarg;
984 if (suffixcmp(fontname,FONTFILESUFFIX)) {
985 fontname[MYSTRLEN(fontname)-FSUFFIXLEN] = '\0';
986 }
987 break;
988 case 'C':
989 controlname = optarg;
990 if (suffixcmp(controlname, CONTROLFILESUFFIX)) {
991 controlname[MYSTRLEN(controlname)-CSUFFIXLEN] = '\0';
992 }
993 (*cfilelistend) = (cfnamenode*)myalloc(sizeof(cfnamenode));
994 (*cfilelistend)->thename = controlname;
995 cfilelistend = &(*cfilelistend)->next;
996 (*cfilelistend) = NULL;
997 break;
998 case 'N':
999 clearcfilelist();
1000 multibyte = 0;
1001 gn[0] = 0;
1002 gn[1] = 0x80;
1003 gn[2] = gn[3] = 0;
1004 gndbl[0] = gndbl[1] = gndbl[2] = gndbl[3] = 0;
1005 gl = 0;
1006 gr = 1;
1007 break;
1008 case 'F': /* Not a legal option */
1009 fprintf(stderr,"%s: illegal option -- F\n",myname);
1010 printusage(stderr);
1011 fprintf(stderr,"\nBecause of numerous incompatibilities, the");
1012 fprintf(stderr," \"-F\" option has been\n");
1013 fprintf(stderr,"removed. It has been replaced by the \"figlist\"");
1014 fprintf(stderr," program, which is now\n");
1015 fprintf(stderr,"included in the basic FIGlet package. \"figlist\"");
1016 fprintf(stderr," is also available\n");
1017 fprintf(stderr,"from http://www.figlet.org/");
1018 fprintf(stderr,"under UNIX utilities.\n");
1019 exit(1);
1020 break;
1021 default:
1022 printusage(stderr);
1023 exit(1);
1026 if (optind!=Myargc) cmdinput = 1; /* force cmdinput if more arguments */
1027 outlinelenlimit = outputwidth-1;
1028 if (infoprint>=0) {
1029 printinfo(infoprint);
1030 exit(0);
1035 /****************************************************************************
1037 clearline
1039 Clears both the input (inchrline) and output (outputline) storage.
1041 ****************************************************************************/
1043 void clearline()
1045 int i;
1047 for (i=0;i<charheight;i++) {
1048 outputline[i][0] = '\0';
1050 outlinelen = 0;
1051 inchrlinelen = 0;
1055 /****************************************************************************
1057 readfontchar
1059 Reads a font character from the font file, and places it in a
1060 newly-allocated entry in the list.
1062 ****************************************************************************/
1064 void readfontchar(file,theord,line,maxlen)
1065 ZFILE *file;
1066 inchr theord;
1067 char *line;
1068 int maxlen;
1070 int row,k;
1071 char endchar;
1072 fcharnode *fclsave;
1074 fclsave = fcharlist;
1075 fcharlist = (fcharnode*)myalloc(sizeof(fcharnode));
1076 fcharlist->ord = theord;
1077 fcharlist->thechar = (char**)myalloc(sizeof(char*)*charheight);
1078 fcharlist->next = fclsave;
1079 for (row=0;row<charheight;row++) {
1080 if (myfgets(line,maxlen+1,file)==NULL) {
1081 line[0] = '\0';
1083 k = MYSTRLEN(line)-1;
1084 while (k>=0 && isspace(line[k])) {
1085 k--;
1087 if (k>=0) {
1088 endchar = line[k];
1089 while (k>=0 ? line[k]==endchar : 0) {
1090 k--;
1093 line[k+1] = '\0';
1094 fcharlist->thechar[row] = (char*)myalloc(sizeof(char)*(k+2));
1095 strcpy(fcharlist->thechar[row],line);
1100 /****************************************************************************
1102 readfont
1104 Allocates memory, initializes variables, and reads in the font.
1105 Called near beginning of main().
1107 ****************************************************************************/
1109 void readfont()
1111 #define MAXFIRSTLINELEN 1000
1112 int i,row,numsread;
1113 inchr theord;
1114 int maxlen,cmtlines,ffright2left;
1115 int smush,smush2;
1116 char *fontpath,*fileline,magicnum[5];
1117 ZFILE *fontfile;
1118 int namelen;
1120 namelen = MYSTRLEN(fontdirname);
1121 fontpath = (char*)myalloc(sizeof(char)
1122 *(namelen+MYSTRLEN(fontname)+FSUFFIXLEN+2));
1123 fontfile = NULL;
1124 if (!hasdirsep(fontname)) {
1125 strcpy(fontpath,fontdirname);
1126 fontpath[namelen] = DIRSEP;
1127 fontpath[namelen+1] = '\0';
1128 strcat(fontpath,fontname);
1129 strcat(fontpath,FONTFILESUFFIX);
1130 fontfile = Zopen(fontpath,"rb");
1132 if (fontfile==NULL) {
1133 strcpy(fontpath,fontname);
1134 strcat(fontpath,FONTFILESUFFIX);
1135 fontfile = Zopen(fontpath,"rb");
1136 if (fontfile==NULL) {
1137 fprintf(stderr,"%s: %s: Unable to open font file\n",myname,fontpath);
1138 exit(1);
1142 readmagic(fontfile,magicnum);
1143 fileline = (char*)myalloc(sizeof(char)*(MAXFIRSTLINELEN+1));
1144 if (myfgets(fileline,MAXFIRSTLINELEN+1,fontfile)==NULL) {
1145 fileline[0] = '\0';
1147 if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) {
1148 skiptoeol(fontfile);
1150 numsread = sscanf(fileline,"%*c%c %d %*d %d %d %d %d %d",
1151 &hardblank,&charheight,&maxlen,&smush,&cmtlines,
1152 &ffright2left,&smush2);
1153 free(fileline);
1154 if (strcmp(magicnum,FONTFILEMAGICNUMBER) || numsread<5) {
1155 fprintf(stderr,"%s: %s: Not a FIGlet 2 font file\n",myname,fontpath);
1156 exit(1);
1158 for (i=1;i<=cmtlines;i++) {
1159 skiptoeol(fontfile);
1161 free(fontpath);
1163 if (numsread<6) {
1164 ffright2left = 0;
1167 if (numsread<7) { /* if no smush2, decode smush into smush2 */
1168 if (smush == 0) smush2 = SM_KERN;
1169 else if (smush < 0) smush2 = 0;
1170 else smush2 = (smush & 31) | SM_SMUSH;
1173 if (charheight<1) {
1174 charheight = 1;
1177 if (maxlen<1) {
1178 maxlen = 1;
1181 maxlen += 100; /* Give ourselves some extra room */
1183 if (smushoverride == SMO_NO)
1184 smushmode = smush2;
1185 else if (smushoverride == SMO_FORCE)
1186 smushmode |= smush2;
1188 if (right2left<0) {
1189 right2left = ffright2left;
1192 if (justification<0) {
1193 justification = 2*right2left;
1196 fileline = (char*)myalloc(sizeof(char)*(maxlen+1));
1197 /* Allocate "missing" character */
1198 fcharlist = (fcharnode*)myalloc(sizeof(fcharnode));
1199 fcharlist->ord = 0;
1200 fcharlist->thechar = (char**)myalloc(sizeof(char*)*charheight);
1201 fcharlist->next = NULL;
1202 for (row=0;row<charheight;row++) {
1203 fcharlist->thechar[row] = (char*)myalloc(sizeof(char));
1204 fcharlist->thechar[row][0] = '\0';
1206 for (theord=' ';theord<='~';theord++) {
1207 readfontchar(fontfile,theord,fileline,maxlen);
1209 for (theord=0;theord<=6;theord++) {
1210 readfontchar(fontfile,deutsch[theord],fileline,maxlen);
1212 while (myfgets(fileline,maxlen+1,fontfile)==NULL?0:
1213 sscanf(fileline,"%li",&theord)==1) {
1214 readfontchar(fontfile,theord,fileline,maxlen);
1216 Zclose(fontfile);
1217 free(fileline);
1221 /****************************************************************************
1223 linealloc
1225 Allocates & clears outputline, inchrline. Sets inchrlinelenlimit.
1226 Called near beginning of main().
1228 ****************************************************************************/
1230 void linealloc()
1232 int row;
1234 outputline = (char**)myalloc(sizeof(char*)*charheight);
1235 for (row=0;row<charheight;row++) {
1236 outputline[row] = (char*)myalloc(sizeof(char)*(outlinelenlimit+1));
1238 inchrlinelenlimit = outputwidth*4+100;
1239 inchrline = (inchr*)myalloc(sizeof(inchr)*(inchrlinelenlimit+1));
1240 clearline();
1244 /****************************************************************************
1246 getletter
1248 Sets currchar to point to the font entry for the given character.
1249 Sets currcharwidth to the width of this character.
1251 ****************************************************************************/
1253 void getletter(c)
1254 inchr c;
1256 fcharnode *charptr;
1258 for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=c;
1259 charptr=charptr->next) ;
1260 if (charptr!=NULL) {
1261 currchar = charptr->thechar;
1263 else {
1264 for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=0;
1265 charptr=charptr->next) ;
1266 currchar = charptr->thechar;
1268 previouscharwidth = currcharwidth;
1269 currcharwidth = MYSTRLEN(currchar[0]);
1273 /****************************************************************************
1275 smushem
1277 Given 2 characters, attempts to smush them into 1, according to
1278 smushmode. Returns smushed character or '\0' if no smushing can be
1279 done.
1281 smushmode values are sum of following (all values smush blanks):
1282 1: Smush equal chars (not hardblanks)
1283 2: Smush '_' with any char in hierarchy below
1284 4: hierarchy: "|", "/\", "[]", "{}", "()", "<>"
1285 Each class in hier. can be replaced by later class.
1286 8: [ + ] -> |, { + } -> |, ( + ) -> |
1287 16: / + \ -> X, > + < -> X (only in that order)
1288 32: hardblank + hardblank -> hardblank
1290 ****************************************************************************/
1292 char smushem(lch,rch)
1293 char lch,rch;
1295 if (lch==' ') return rch;
1296 if (rch==' ') return lch;
1298 if (previouscharwidth<2 || currcharwidth<2) return '\0';
1299 /* Disallows overlapping if the previous character */
1300 /* or the current character has a width of 1 or zero. */
1302 if ((smushmode & SM_SMUSH) == 0) return '\0'; /* kerning */
1304 if ((smushmode & 63) == 0) {
1305 /* This is smushing by universal overlapping. */
1306 if (lch==' ') return rch;
1307 if (rch==' ') return lch;
1308 if (lch==hardblank) return rch;
1309 if (rch==hardblank) return lch;
1310 /* Above four lines ensure overlapping preference to */
1311 /* visible characters. */
1312 if (right2left==1) return lch;
1313 /* Above line ensures that the dominant (foreground) */
1314 /* fig-character for overlapping is the latter in the */
1315 /* user's text, not necessarily the rightmost character. */
1316 return rch;
1317 /* Occurs in the absence of above exceptions. */
1320 if (smushmode & SM_HARDBLANK) {
1321 if (lch==hardblank && rch==hardblank) return lch;
1324 if (lch==hardblank || rch==hardblank) return '\0';
1326 if (smushmode & SM_EQUAL) {
1327 if (lch==rch) return lch;
1330 if (smushmode & SM_LOWLINE) {
1331 if (lch=='_' && strchr("|/\\[]{}()<>",rch)) return rch;
1332 if (rch=='_' && strchr("|/\\[]{}()<>",lch)) return lch;
1335 if (smushmode & SM_HIERARCHY) {
1336 if (lch=='|' && strchr("/\\[]{}()<>",rch)) return rch;
1337 if (rch=='|' && strchr("/\\[]{}()<>",lch)) return lch;
1338 if (strchr("/\\",lch) && strchr("[]{}()<>",rch)) return rch;
1339 if (strchr("/\\",rch) && strchr("[]{}()<>",lch)) return lch;
1340 if (strchr("[]",lch) && strchr("{}()<>",rch)) return rch;
1341 if (strchr("[]",rch) && strchr("{}()<>",lch)) return lch;
1342 if (strchr("{}",lch) && strchr("()<>",rch)) return rch;
1343 if (strchr("{}",rch) && strchr("()<>",lch)) return lch;
1344 if (strchr("()",lch) && strchr("<>",rch)) return rch;
1345 if (strchr("()",rch) && strchr("<>",lch)) return lch;
1348 if (smushmode & SM_PAIR) {
1349 if (lch=='[' && rch==']') return '|';
1350 if (rch=='[' && lch==']') return '|';
1351 if (lch=='{' && rch=='}') return '|';
1352 if (rch=='{' && lch=='}') return '|';
1353 if (lch=='(' && rch==')') return '|';
1354 if (rch=='(' && lch==')') return '|';
1357 if (smushmode & SM_BIGX) {
1358 if (lch=='/' && rch=='\\') return '|';
1359 if (rch=='/' && lch=='\\') return 'Y';
1360 if (lch=='>' && rch=='<') return 'X';
1361 /* Don't want the reverse of above to give 'X'. */
1364 return '\0';
1368 /****************************************************************************
1370 smushamt
1372 Returns the maximum amount that the current character can be smushed
1373 into the current line.
1375 ****************************************************************************/
1377 int smushamt()
1379 int maxsmush,amt;
1380 int row,linebd,charbd;
1381 char ch1,ch2;
1383 if ((smushmode & (SM_SMUSH | SM_KERN)) == 0) {
1384 return 0;
1386 maxsmush = currcharwidth;
1387 for (row=0;row<charheight;row++) {
1388 if (right2left) {
1389 for (charbd=MYSTRLEN(currchar[row]);
1390 ch1=currchar[row][charbd],(charbd>0&&(!ch1||ch1==' '));charbd--) ;
1391 for (linebd=0;ch2=outputline[row][linebd],ch2==' ';linebd++) ;
1392 amt = linebd+currcharwidth-1-charbd;
1394 else {
1395 for (linebd=MYSTRLEN(outputline[row]);
1396 ch1 = outputline[row][linebd],(linebd>0&&(!ch1||ch1==' '));linebd--) ;
1397 for (charbd=0;ch2=currchar[row][charbd],ch2==' ';charbd++) ;
1398 amt = charbd+outlinelen-1-linebd;
1400 if (!ch1||ch1==' ') {
1401 amt++;
1403 else if (ch2) {
1404 if (smushem(ch1,ch2)!='\0') {
1405 amt++;
1408 if (amt<maxsmush) {
1409 maxsmush = amt;
1412 return maxsmush;
1416 /****************************************************************************
1418 addchar
1420 Attempts to add the given character onto the end of the current line.
1421 Returns 1 if this can be done, 0 otherwise.
1423 ****************************************************************************/
1425 int addchar(c)
1426 inchr c;
1428 int smushamount,row,k;
1429 char *templine;
1431 getletter(c);
1432 smushamount = smushamt();
1433 if (outlinelen+currcharwidth-smushamount>outlinelenlimit
1434 ||inchrlinelen+1>inchrlinelenlimit) {
1435 return 0;
1438 templine = (char*)myalloc(sizeof(char)*(outlinelenlimit+1));
1439 for (row=0;row<charheight;row++) {
1440 if (right2left) {
1441 strcpy(templine,currchar[row]);
1442 for (k=0;k<smushamount;k++) {
1443 templine[currcharwidth-smushamount+k] =
1444 smushem(templine[currcharwidth-smushamount+k],outputline[row][k]);
1446 strcat(templine,outputline[row]+smushamount);
1447 strcpy(outputline[row],templine);
1449 else {
1450 for (k=0;k<smushamount;k++) {
1451 if (outlinelen-smushamount+k >= 0)
1452 outputline[row][outlinelen-smushamount+k] =
1453 smushem(outputline[row][outlinelen-smushamount+k],currchar[row][k]);
1455 strcat(outputline[row],currchar[row]+smushamount);
1458 free(templine);
1459 outlinelen = MYSTRLEN(outputline[0]);
1460 inchrline[inchrlinelen++] = c;
1461 return 1;
1465 /****************************************************************************
1467 putstring
1469 Prints out the given null-terminated string, substituting blanks
1470 for hardblanks. If outputwidth is 1, prints the entire string;
1471 otherwise prints at most outputwidth-1 characters. Prints a newline
1472 at the end of the string. The string is left-justified, centered or
1473 right-justified (taking outputwidth as the screen width) if
1474 justification is 0, 1 or 2, respectively.
1476 ****************************************************************************/
1478 static int nr_chars=0;
1479 static void myputchar(unsigned char c)
1481 static int startline = 1;
1483 if ( startline )
1485 startline = 0;
1486 myputchar(' ');
1489 putc(c, stderr);
1491 if ( nr_chars == 18 )
1493 nr_chars = 0;
1494 putchar('"');
1495 putchar(' ');
1496 putchar('\\');
1497 putchar('\n');
1500 if ( nr_chars++ == 0 )
1501 putchar('"');
1503 putchar('\\');
1504 putchar('0' + ((c>>6)&7));
1505 putchar('0' + ((c>>3)&7));
1506 putchar('0' + ((c>>0)&7));
1508 if ( c == '\n' )
1509 startline = 1;
1512 void putstring(string)
1513 char *string;
1515 int i,len;
1517 len = MYSTRLEN(string);
1518 if (outputwidth>1) {
1519 if (len>outputwidth-1) {
1520 len = outputwidth-1;
1522 if (justification>0) {
1523 for (i=1;(3-justification)*i+len+justification-2<outputwidth;i++) {
1524 myputchar(' ');
1528 for (i=0;i<len;i++) {
1529 myputchar(string[i]==hardblank?' ':string[i]);
1531 myputchar('\n');
1535 /****************************************************************************
1537 printline
1539 Prints outputline using putstring, then clears the current line.
1541 ****************************************************************************/
1543 void printline()
1545 int i;
1547 for (i=0;i<charheight;i++) {
1548 putstring(outputline[i]);
1550 clearline();
1554 /****************************************************************************
1556 splitline
1558 Splits inchrline at the last word break (bunch of consecutive blanks).
1559 Makes a new line out of the first part and prints it using
1560 printline. Makes a new line out of the second part and returns.
1562 ****************************************************************************/
1564 void splitline()
1566 int i,gotspace,lastspace,len1,len2;
1567 inchr *part1,*part2;
1569 part1 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));
1570 part2 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));
1571 gotspace = 0;
1572 for (i=inchrlinelen-1;i>=0;i--) {
1573 if (!gotspace && inchrline[i]==' ') {
1574 gotspace = 1;
1575 lastspace = i;
1577 if (gotspace && inchrline[i]!=' ') {
1578 break;
1581 len1 = i+1;
1582 len2 = inchrlinelen-lastspace-1;
1583 for (i=0;i<len1;i++) {
1584 part1[i] = inchrline[i];
1586 for (i=0;i<len2;i++) {
1587 part2[i] = inchrline[lastspace+1+i];
1589 clearline();
1590 for (i=0;i<len1;i++) {
1591 addchar(part1[i]);
1593 printline();
1594 for (i=0;i<len2;i++) {
1595 addchar(part2[i]);
1597 free(part1);
1598 free(part2);
1602 /****************************************************************************
1604 handlemapping
1606 Given an input character (type inchr), executes re-mapping commands
1607 read from control files. Returns re-mapped character (inchr).
1609 ****************************************************************************/
1611 inchr handlemapping(c)
1612 inchr c;
1614 comnode *cmptr;
1616 cmptr=commandlist;
1617 while (cmptr!=NULL) {
1618 if (cmptr->thecommand ?
1619 (c >= cmptr->rangelo && c <= cmptr->rangehi) : 0) {
1620 c += cmptr->offset;
1621 while(cmptr!=NULL ? cmptr->thecommand : 0) {
1622 cmptr=cmptr->next;
1625 else {
1626 cmptr=cmptr->next;
1629 return c;
1632 /****************************************************************************
1634 Agetchar
1636 Replacement to getchar().
1637 Acts exactly like getchar if -A is NOT specified,
1638 else obtains input from All remaining command line words.
1640 ****************************************************************************/
1642 int Agetchar()
1644 extern int optind; /* current argv[] element under study */
1645 static AgetMode = 0; /* >= 0 for displacement into argv[n], <0 EOF */
1646 char *arg; /* pointer to active character */
1647 int c; /* current character */
1649 if ( ! cmdinput ) /* is -A active? */
1650 return( getchar() ); /* no: return stdin character */
1652 if ( AgetMode < 0 || optind >= Myargc ) /* EOF is sticky: */
1653 return( EOF ); /* **ensure it now and forever more */
1655 /* find next character */
1656 arg = Myargv[optind]; /* pointer to active arg */
1657 c = arg[AgetMode++]&0xFF; /* get appropriate char of arg */
1659 if ( ! c ) /* at '\0' that terminates word? */
1660 { /* at end of word: return ' ' if normal word, '\n' if empty */
1661 c = ' '; /* suppose normal word and return blank */
1662 if ( AgetMode == 1 ) /* if ran out in very 1st char, force \n */
1663 c = '\n'; /* (allows "hello '' world" to do \n at '') */
1664 AgetMode = 0; /* return to char 0 in NEXT word */
1665 if ( ++optind >= Myargc ) /* run up word count and check if at "EOF" */
1666 { /* just ran out of arguments */
1667 c = EOF; /* return EOF */
1668 AgetMode = -1; /* ensure all future returns return EOF */
1672 return( c ); /* return appropriate character */
1674 } /* end: Agetchar() */
1677 /****************************************************************************
1679 iso2022
1681 Called by getinchr. Interprets ISO 2022 sequences
1683 ******************************************************************************/
1685 inchr iso2022()
1687 inchr ch;
1688 inchr ch2;
1689 int save_gl;
1690 int save_gr;
1692 ch = Agetchar();
1693 if (ch == EOF) return ch;
1694 if (ch == 27) ch = Agetchar() + 0x100; /* ESC x */
1695 if (ch == 0x100 + '$') ch = Agetchar() + 0x200; /* ESC $ x */
1696 switch (ch) {
1697 case 14: /* invoke G0 into GL */
1698 gl = 0;
1699 return iso2022();
1700 case 15: /* invoke G1 into GL */
1701 gl = 1;
1702 return iso2022();
1703 case 142: case 'N' + 0x100: /* invoke G2 into GL for next char */
1704 save_gl = gl; save_gr = gr;
1705 gl = gr = 2;
1706 ch = iso2022();
1707 gl = save_gl; gr = save_gr;
1708 return ch;
1709 case 143: case 'O' + 0x100: /* invoke G3 into GL for next char */
1710 save_gl = gl; save_gr = gr;
1711 gl = gr = 3;
1712 ch = iso2022();
1713 gl = save_gl; gr = save_gr;
1714 return ch;
1715 case 'n' + 0x100: /* invoke G2 into GL */
1716 gl = 2;
1717 return iso2022();
1718 case 'o' + 0x100: /* invoke G3 into GL */
1719 gl = 3;
1720 return iso2022();
1721 case '~' + 0x100: /* invoke G1 into GR */
1722 gr = 1;
1723 return iso2022();
1724 case '}' + 0x100: /* invoke G2 into GR */
1725 gr = 2;
1726 return iso2022();
1727 case '|' + 0x100: /* invoke G3 into GR */
1728 gr = 3;
1729 return iso2022();
1730 case '(' + 0x100: /* set G0 to 94-char set */
1731 ch = Agetchar();
1732 if (ch == 'B') ch = 0; /* ASCII */
1733 gn[0] = ch << 16;
1734 gndbl[0] = 0;
1735 return iso2022();
1736 case ')' + 0x100: /* set G1 to 94-char set */
1737 ch = Agetchar();
1738 if (ch == 'B') ch = 0;
1739 gn[1] = ch << 16;
1740 gndbl[1] = 0;
1741 return iso2022();
1742 case '*' + 0x100: /* set G2 to 94-char set */
1743 ch = Agetchar();
1744 if (ch == 'B') ch = 0;
1745 gn[2] = ch << 16;
1746 gndbl[2] = 0;
1747 return iso2022();
1748 case '+' + 0x100: /* set G3 to 94-char set */
1749 ch = Agetchar();
1750 if (ch == 'B') ch = 0;
1751 gn[3] = ch << 16;
1752 gndbl[3] = 0;
1753 return iso2022();
1754 case '-' + 0x100: /* set G1 to 96-char set */
1755 ch = Agetchar();
1756 if (ch == 'A') ch = 0; /* Latin-1 top half */
1757 gn[1] = (ch << 16) | 0x80;
1758 gndbl[1] = 0;
1759 return iso2022();
1760 case '.' + 0x100: /* set G2 to 96-char set */
1761 ch = Agetchar();
1762 if (ch == 'A') ch = 0;
1763 gn[2] = (ch << 16) | 0x80;
1764 gndbl[2] = 0;
1765 return iso2022();
1766 case '/' + 0x100: /* set G3 to 96-char set */
1767 ch = Agetchar();
1768 if (ch == 'A') ch = 0;
1769 gn[3] = (ch << 16) | 0x80;
1770 gndbl[3] = 0;
1771 return iso2022();
1772 case '(' + 0x200: /* set G0 to 94 x 94 char set */
1773 ch = Agetchar();
1774 gn[0] = ch << 16;
1775 gndbl[0] = 1;
1776 return iso2022();
1777 case ')' + 0x200: /* set G1 to 94 x 94 char set */
1778 ch = Agetchar();
1779 gn[1] = ch << 16;
1780 gndbl[1] = 1;
1781 return iso2022();
1782 case '*' + 0x200: /* set G2 to 94 x 94 char set */
1783 ch = Agetchar();
1784 gn[2] = ch << 16;
1785 gndbl[2] = 1;
1786 return iso2022();
1787 case '+' + 0x200: /* set G3 to 94 x 94 char set */
1788 ch = Agetchar();
1789 gn[3] = ch << 16;
1790 gndbl[3] = 1;
1791 return iso2022();
1792 default:
1793 if (ch & 0x200) { /* set G0 to 94 x 94 char set (deprecated) */
1794 gn[0] = (ch & ~0x200) << 16;
1795 gndbl[0] = 1;
1796 return iso2022();
1800 if (ch >= 0x21 && ch <= 0x7E) { /* process GL */
1801 if (gndbl[gl]) {
1802 ch2 = Agetchar();
1803 return gn[gl] | (ch << 8) | ch2;
1805 else return gn[gl] | ch;
1807 else if (ch >= 0xA0 && ch <= 0xFF) { /* process GR */
1808 if (gndbl[gr]) {
1809 ch2 = Agetchar();
1810 return gn[gr] | (ch << 8) | ch2;
1812 else return gn[gr] | (ch & ~0x80);
1814 else return ch;
1817 /****************************************************************************
1819 ungetinchr
1821 Called by main. Pushes back an "inchr" to be read by getinchr
1822 on the next call.
1824 ******************************************************************************/
1825 inchr getinchr_buffer;
1826 int getinchr_flag;
1828 inchr ungetinchr(c)
1829 inchr c;
1831 getinchr_buffer = c;
1832 getinchr_flag = 1;
1833 return c;
1836 /*****************************************************************************
1838 getinchr
1840 Called by main. Processes multibyte characters. Invokes Agetchar.
1841 If multibyte = 0, ISO 2022 mode (see iso2022 routine).
1842 If multibyte = 1, double-byte mode (0x00-0x7f bytes are characters,
1843 0x80-0xFF bytes are first byte of a double-byte character).
1844 If multibyte = 2, Unicode UTF-8 mode (0x00-0x7F bytes are characters,
1845 0x80-0xBF bytes are nonfirst byte of a multibyte character,
1846 0xC0-0xFD bytes are first byte of a multibyte character,
1847 0xFE-0xFF bytes are errors (all errors return code 0x0080)).
1848 If multibyte = 3, HZ mode ("~{" starts double-byte mode, "}~" ends it,
1849 "~~" is a tilde, "~x" for all other x is ignored).
1850 If multibyte = 4, Shift-JIS mode (0x80-0x9F and 0xE0-0xEF are first byte
1851 of a double-byte character, all other bytes are characters).
1854 *****************************************************************************/
1856 inchr getinchr()
1858 int ch, ch2, ch3, ch4, ch5, ch6;
1860 if (getinchr_flag) {
1861 getinchr_flag = 0;
1862 return getinchr_buffer;
1865 switch(multibyte) {
1866 case 0: /* single-byte */
1867 return iso2022();
1868 case 1: /* DBCS */
1869 ch = Agetchar();
1870 if ((ch >= 0x80 && ch <= 0x9F) ||
1871 (ch >= 0xE0 && ch <= 0xEF)) {
1872 ch = (ch << 8) + Agetchar();
1874 return ch;
1875 case 2: /* UTF-8 */
1876 ch = Agetchar();
1877 if (ch < 0x80) return ch; /* handles EOF, too */
1878 if (ch < 0xC0 || ch > 0xFD)
1879 return 0x0080; /* illegal first character */
1880 ch2 = Agetchar() & 0x3F;
1881 if (ch < 0xE0) return ((ch & 0x1F) << 6) + ch2;
1882 ch3 = Agetchar() & 0x3F;
1883 if (ch < 0xF0)
1884 return ((ch & 0x0F) << 12) + (ch2 << 6) + ch3;
1885 ch4 = Agetchar() & 0x3F;
1886 if (ch < 0xF8)
1887 return ((ch & 0x07) << 18) + (ch2 << 12) + (ch3 << 6) + ch4;
1888 ch5 = Agetchar() & 0x3F;
1889 if (ch < 0xFC)
1890 return ((ch & 0x03) << 24) + (ch2 << 18) + (ch3 << 12) +
1891 (ch4 << 6) + ch5;
1892 ch6 = Agetchar() & 0x3F;
1893 return ((ch & 0x01) << 30) + (ch2 << 24) + (ch3 << 18) +
1894 (ch4 << 12) + (ch5 << 6) + ch6;
1895 case 3: /* HZ */
1896 ch = Agetchar();
1897 if (ch == EOF) return ch;
1898 if (hzmode) {
1899 ch = (ch << 8) + Agetchar();
1900 if (ch == ('}' << 8) + '~') {
1901 hzmode = 0;
1902 return getinchr();
1904 return ch;
1906 else if (ch == '~') {
1907 ch = Agetchar();
1908 if (ch == '{') {
1909 hzmode = 1;
1910 return getinchr();
1912 else if (ch == '~') {
1913 return ch;
1915 else {
1916 return getinchr();
1919 else return ch;
1920 case 4: /* Shift-JIS */
1921 ch = Agetchar();
1922 if ((ch >= 0x80 && ch <= 0x9F) ||
1923 (ch >= 0xE0 && ch <= 0xEF)) {
1924 ch = (ch << 8) + Agetchar();
1926 return ch;
1927 default:
1928 return 0x80;
1932 /****************************************************************************
1934 main
1936 The main program, of course.
1937 Reads characters 1 by 1 from stdin, and makes lines out of them using
1938 addchar. Handles line breaking, (which accounts for most of the
1939 complexity in this function).
1941 ****************************************************************************/
1943 int main(argc,argv)
1944 int argc;
1945 char *argv[];
1947 inchr c,c2;
1948 int i;
1949 int last_was_eol_flag;
1950 /*---------------------------------------------------------------------------
1951 wordbreakmode:
1952 -1: /^$/ and blanks are to be absorbed (when line break was forced
1953 by a blank or character larger than outlinelenlimit)
1954 0: /^ *$/ and blanks are not to be absorbed
1955 1: /[^ ]$/ no word break yet
1956 2: /[^ ] *$/
1957 3: /[^ ]$/ had a word break
1958 ---------------------------------------------------------------------------*/
1959 int wordbreakmode;
1960 int char_not_added;
1962 Myargc = argc;
1963 Myargv = argv;
1964 getparams();
1965 readcontrolfiles();
1966 readfont();
1967 linealloc();
1969 wordbreakmode = 0;
1970 last_was_eol_flag = 0;
1972 while ((c = getinchr())!=EOF) {
1974 if (c=='\n'&&paragraphflag&&!last_was_eol_flag) {
1975 ungetinchr(c2 = getinchr());
1976 c = ((isascii(c2)&&isspace(c2))?'\n':' ');
1978 last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' ');
1980 if (deutschflag) {
1981 if (c>='[' && c<=']') {
1982 c = deutsch[c-'['];
1984 else if (c >='{' && c <= '~') {
1985 c = deutsch[c-'{'+3];
1989 c = handlemapping(c);
1991 if (isascii(c)&&isspace(c)) {
1992 c = (c=='\t'||c==' ') ? ' ' : '\n';
1995 if ((c>'\0' && c<' ' && c!='\n') || c==127) continue;
1997 /*
1998 Note: The following code is complex and thoroughly tested.
1999 Be careful when modifying!
2000 */
2002 do {
2003 char_not_added = 0;
2005 if (wordbreakmode== -1) {
2006 if (c==' ') {
2007 break;
2009 else if (c=='\n') {
2010 wordbreakmode = 0;
2011 break;
2013 wordbreakmode = 0;
2016 if (c=='\n') {
2017 printline();
2018 wordbreakmode = 0;
2021 else if (addchar(c)) {
2022 if (c!=' ') {
2023 wordbreakmode = (wordbreakmode>=2)?3:1;
2025 else {
2026 wordbreakmode = (wordbreakmode>0)?2:0;
2030 else if (outlinelen==0) {
2031 for (i=0;i<charheight;i++) {
2032 if (right2left && outputwidth>1) {
2033 putstring(currchar[i]+MYSTRLEN(currchar[i])-outlinelenlimit);
2035 else {
2036 putstring(currchar[i]);
2039 wordbreakmode = -1;
2042 else if (c==' ') {
2043 if (wordbreakmode==2) {
2044 splitline();
2046 else {
2047 printline();
2049 wordbreakmode = -1;
2052 else {
2053 if (wordbreakmode>=2) {
2054 splitline();
2056 else {
2057 printline();
2059 wordbreakmode = (wordbreakmode==3)?1:0;
2060 char_not_added = 1;
2063 } while (char_not_added);
2066 if (outlinelen!=0) {
2067 printline();
2070 /* XXX Xen hack -- finish off the C macro output */
2071 if ( nr_chars != 0 )
2072 putchar('"');
2073 putchar('\n');
2075 exit(0);