ia64/xen-unstable

view xen/figlet/figlet.c @ 2828:62d5a53a46e2

bitkeeper revision 1.1159.1.338 (4187ca95yoh3y8SwBJw4uTmgIxLCTw)

A new install script to install from the intermediate 'install' subdir.
Also now a bit more careful in use of 'cp -a'. When installing to
system-wide directories we probably do not want to preserve ownership
of the random unprivileged user that originally built the binaries.
The user who does the install (probably root) is the correct person
to own the target files.
author kaf24@freefall.cl.cam.ac.uk
date Tue Nov 02 17:57:41 2004 +0000 (2004-11-02)
parents cda0735bdc4c
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 outputline[row][outlinelen-smushamount+k] =
1452 smushem(outputline[row][outlinelen-smushamount+k],currchar[row][k]);
1454 strcat(outputline[row],currchar[row]+smushamount);
1457 free(templine);
1458 outlinelen = MYSTRLEN(outputline[0]);
1459 inchrline[inchrlinelen++] = c;
1460 return 1;
1464 /****************************************************************************
1466 putstring
1468 Prints out the given null-terminated string, substituting blanks
1469 for hardblanks. If outputwidth is 1, prints the entire string;
1470 otherwise prints at most outputwidth-1 characters. Prints a newline
1471 at the end of the string. The string is left-justified, centered or
1472 right-justified (taking outputwidth as the screen width) if
1473 justification is 0, 1 or 2, respectively.
1475 ****************************************************************************/
1477 static int nr_chars=0;
1478 static void myputchar(unsigned char c)
1480 static int startline = 1;
1482 if ( startline )
1484 startline = 0;
1485 myputchar(' ');
1488 putc(c, stderr);
1490 if ( nr_chars == 0 )
1491 putchar('"');
1493 putchar('\\');
1494 putchar('0' + ((c>>6)&7));
1495 putchar('0' + ((c>>3)&7));
1496 putchar('0' + ((c>>0)&7));
1498 if ( c == '\n' )
1499 startline = 1;
1501 if ( ++nr_chars == 18 )
1503 nr_chars = 0;
1504 putchar('"');
1505 putchar(' ');
1506 putchar('\\');
1507 putchar('\n');
1511 void putstring(string)
1512 char *string;
1514 int i,len;
1516 len = MYSTRLEN(string);
1517 if (outputwidth>1) {
1518 if (len>outputwidth-1) {
1519 len = outputwidth-1;
1521 if (justification>0) {
1522 for (i=1;(3-justification)*i+len+justification-2<outputwidth;i++) {
1523 myputchar(' ');
1527 for (i=0;i<len;i++) {
1528 myputchar(string[i]==hardblank?' ':string[i]);
1530 myputchar('\n');
1534 /****************************************************************************
1536 printline
1538 Prints outputline using putstring, then clears the current line.
1540 ****************************************************************************/
1542 void printline()
1544 int i;
1546 for (i=0;i<charheight;i++) {
1547 putstring(outputline[i]);
1549 clearline();
1553 /****************************************************************************
1555 splitline
1557 Splits inchrline at the last word break (bunch of consecutive blanks).
1558 Makes a new line out of the first part and prints it using
1559 printline. Makes a new line out of the second part and returns.
1561 ****************************************************************************/
1563 void splitline()
1565 int i,gotspace,lastspace,len1,len2;
1566 inchr *part1,*part2;
1568 part1 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));
1569 part2 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));
1570 gotspace = 0;
1571 for (i=inchrlinelen-1;i>=0;i--) {
1572 if (!gotspace && inchrline[i]==' ') {
1573 gotspace = 1;
1574 lastspace = i;
1576 if (gotspace && inchrline[i]!=' ') {
1577 break;
1580 len1 = i+1;
1581 len2 = inchrlinelen-lastspace-1;
1582 for (i=0;i<len1;i++) {
1583 part1[i] = inchrline[i];
1585 for (i=0;i<len2;i++) {
1586 part2[i] = inchrline[lastspace+1+i];
1588 clearline();
1589 for (i=0;i<len1;i++) {
1590 addchar(part1[i]);
1592 printline();
1593 for (i=0;i<len2;i++) {
1594 addchar(part2[i]);
1596 free(part1);
1597 free(part2);
1601 /****************************************************************************
1603 handlemapping
1605 Given an input character (type inchr), executes re-mapping commands
1606 read from control files. Returns re-mapped character (inchr).
1608 ****************************************************************************/
1610 inchr handlemapping(c)
1611 inchr c;
1613 comnode *cmptr;
1615 cmptr=commandlist;
1616 while (cmptr!=NULL) {
1617 if (cmptr->thecommand ?
1618 (c >= cmptr->rangelo && c <= cmptr->rangehi) : 0) {
1619 c += cmptr->offset;
1620 while(cmptr!=NULL ? cmptr->thecommand : 0) {
1621 cmptr=cmptr->next;
1624 else {
1625 cmptr=cmptr->next;
1628 return c;
1631 /****************************************************************************
1633 Agetchar
1635 Replacement to getchar().
1636 Acts exactly like getchar if -A is NOT specified,
1637 else obtains input from All remaining command line words.
1639 ****************************************************************************/
1641 int Agetchar()
1643 extern int optind; /* current argv[] element under study */
1644 static AgetMode = 0; /* >= 0 for displacement into argv[n], <0 EOF */
1645 char *arg; /* pointer to active character */
1646 int c; /* current character */
1648 if ( ! cmdinput ) /* is -A active? */
1649 return( getchar() ); /* no: return stdin character */
1651 if ( AgetMode < 0 || optind >= Myargc ) /* EOF is sticky: */
1652 return( EOF ); /* **ensure it now and forever more */
1654 /* find next character */
1655 arg = Myargv[optind]; /* pointer to active arg */
1656 c = arg[AgetMode++]&0xFF; /* get appropriate char of arg */
1658 if ( ! c ) /* at '\0' that terminates word? */
1659 { /* at end of word: return ' ' if normal word, '\n' if empty */
1660 c = ' '; /* suppose normal word and return blank */
1661 if ( AgetMode == 1 ) /* if ran out in very 1st char, force \n */
1662 c = '\n'; /* (allows "hello '' world" to do \n at '') */
1663 AgetMode = 0; /* return to char 0 in NEXT word */
1664 if ( ++optind >= Myargc ) /* run up word count and check if at "EOF" */
1665 { /* just ran out of arguments */
1666 c = EOF; /* return EOF */
1667 AgetMode = -1; /* ensure all future returns return EOF */
1671 return( c ); /* return appropriate character */
1673 } /* end: Agetchar() */
1676 /****************************************************************************
1678 iso2022
1680 Called by getinchr. Interprets ISO 2022 sequences
1682 ******************************************************************************/
1684 inchr iso2022()
1686 inchr ch;
1687 inchr ch2;
1688 int save_gl;
1689 int save_gr;
1691 ch = Agetchar();
1692 if (ch == EOF) return ch;
1693 if (ch == 27) ch = Agetchar() + 0x100; /* ESC x */
1694 if (ch == 0x100 + '$') ch = Agetchar() + 0x200; /* ESC $ x */
1695 switch (ch) {
1696 case 14: /* invoke G0 into GL */
1697 gl = 0;
1698 return iso2022();
1699 case 15: /* invoke G1 into GL */
1700 gl = 1;
1701 return iso2022();
1702 case 142: case 'N' + 0x100: /* invoke G2 into GL for next char */
1703 save_gl = gl; save_gr = gr;
1704 gl = gr = 2;
1705 ch = iso2022();
1706 gl = save_gl; gr = save_gr;
1707 return ch;
1708 case 143: case 'O' + 0x100: /* invoke G3 into GL for next char */
1709 save_gl = gl; save_gr = gr;
1710 gl = gr = 3;
1711 ch = iso2022();
1712 gl = save_gl; gr = save_gr;
1713 return ch;
1714 case 'n' + 0x100: /* invoke G2 into GL */
1715 gl = 2;
1716 return iso2022();
1717 case 'o' + 0x100: /* invoke G3 into GL */
1718 gl = 3;
1719 return iso2022();
1720 case '~' + 0x100: /* invoke G1 into GR */
1721 gr = 1;
1722 return iso2022();
1723 case '}' + 0x100: /* invoke G2 into GR */
1724 gr = 2;
1725 return iso2022();
1726 case '|' + 0x100: /* invoke G3 into GR */
1727 gr = 3;
1728 return iso2022();
1729 case '(' + 0x100: /* set G0 to 94-char set */
1730 ch = Agetchar();
1731 if (ch == 'B') ch = 0; /* ASCII */
1732 gn[0] = ch << 16;
1733 gndbl[0] = 0;
1734 return iso2022();
1735 case ')' + 0x100: /* set G1 to 94-char set */
1736 ch = Agetchar();
1737 if (ch == 'B') ch = 0;
1738 gn[1] = ch << 16;
1739 gndbl[1] = 0;
1740 return iso2022();
1741 case '*' + 0x100: /* set G2 to 94-char set */
1742 ch = Agetchar();
1743 if (ch == 'B') ch = 0;
1744 gn[2] = ch << 16;
1745 gndbl[2] = 0;
1746 return iso2022();
1747 case '+' + 0x100: /* set G3 to 94-char set */
1748 ch = Agetchar();
1749 if (ch == 'B') ch = 0;
1750 gn[3] = ch << 16;
1751 gndbl[3] = 0;
1752 return iso2022();
1753 case '-' + 0x100: /* set G1 to 96-char set */
1754 ch = Agetchar();
1755 if (ch == 'A') ch = 0; /* Latin-1 top half */
1756 gn[1] = (ch << 16) | 0x80;
1757 gndbl[1] = 0;
1758 return iso2022();
1759 case '.' + 0x100: /* set G2 to 96-char set */
1760 ch = Agetchar();
1761 if (ch == 'A') ch = 0;
1762 gn[2] = (ch << 16) | 0x80;
1763 gndbl[2] = 0;
1764 return iso2022();
1765 case '/' + 0x100: /* set G3 to 96-char set */
1766 ch = Agetchar();
1767 if (ch == 'A') ch = 0;
1768 gn[3] = (ch << 16) | 0x80;
1769 gndbl[3] = 0;
1770 return iso2022();
1771 case '(' + 0x200: /* set G0 to 94 x 94 char set */
1772 ch = Agetchar();
1773 gn[0] = ch << 16;
1774 gndbl[0] = 1;
1775 return iso2022();
1776 case ')' + 0x200: /* set G1 to 94 x 94 char set */
1777 ch = Agetchar();
1778 gn[1] = ch << 16;
1779 gndbl[1] = 1;
1780 return iso2022();
1781 case '*' + 0x200: /* set G2 to 94 x 94 char set */
1782 ch = Agetchar();
1783 gn[2] = ch << 16;
1784 gndbl[2] = 1;
1785 return iso2022();
1786 case '+' + 0x200: /* set G3 to 94 x 94 char set */
1787 ch = Agetchar();
1788 gn[3] = ch << 16;
1789 gndbl[3] = 1;
1790 return iso2022();
1791 default:
1792 if (ch & 0x200) { /* set G0 to 94 x 94 char set (deprecated) */
1793 gn[0] = (ch & ~0x200) << 16;
1794 gndbl[0] = 1;
1795 return iso2022();
1799 if (ch >= 0x21 && ch <= 0x7E) { /* process GL */
1800 if (gndbl[gl]) {
1801 ch2 = Agetchar();
1802 return gn[gl] | (ch << 8) | ch2;
1804 else return gn[gl] | ch;
1806 else if (ch >= 0xA0 && ch <= 0xFF) { /* process GR */
1807 if (gndbl[gr]) {
1808 ch2 = Agetchar();
1809 return gn[gr] | (ch << 8) | ch2;
1811 else return gn[gr] | (ch & ~0x80);
1813 else return ch;
1816 /****************************************************************************
1818 ungetinchr
1820 Called by main. Pushes back an "inchr" to be read by getinchr
1821 on the next call.
1823 ******************************************************************************/
1824 inchr getinchr_buffer;
1825 int getinchr_flag;
1827 inchr ungetinchr(c)
1828 inchr c;
1830 getinchr_buffer = c;
1831 getinchr_flag = 1;
1832 return c;
1835 /*****************************************************************************
1837 getinchr
1839 Called by main. Processes multibyte characters. Invokes Agetchar.
1840 If multibyte = 0, ISO 2022 mode (see iso2022 routine).
1841 If multibyte = 1, double-byte mode (0x00-0x7f bytes are characters,
1842 0x80-0xFF bytes are first byte of a double-byte character).
1843 If multibyte = 2, Unicode UTF-8 mode (0x00-0x7F bytes are characters,
1844 0x80-0xBF bytes are nonfirst byte of a multibyte character,
1845 0xC0-0xFD bytes are first byte of a multibyte character,
1846 0xFE-0xFF bytes are errors (all errors return code 0x0080)).
1847 If multibyte = 3, HZ mode ("~{" starts double-byte mode, "}~" ends it,
1848 "~~" is a tilde, "~x" for all other x is ignored).
1849 If multibyte = 4, Shift-JIS mode (0x80-0x9F and 0xE0-0xEF are first byte
1850 of a double-byte character, all other bytes are characters).
1853 *****************************************************************************/
1855 inchr getinchr()
1857 int ch, ch2, ch3, ch4, ch5, ch6;
1859 if (getinchr_flag) {
1860 getinchr_flag = 0;
1861 return getinchr_buffer;
1864 switch(multibyte) {
1865 case 0: /* single-byte */
1866 return iso2022();
1867 case 1: /* DBCS */
1868 ch = Agetchar();
1869 if ((ch >= 0x80 && ch <= 0x9F) ||
1870 (ch >= 0xE0 && ch <= 0xEF)) {
1871 ch = (ch << 8) + Agetchar();
1873 return ch;
1874 case 2: /* UTF-8 */
1875 ch = Agetchar();
1876 if (ch < 0x80) return ch; /* handles EOF, too */
1877 if (ch < 0xC0 || ch > 0xFD)
1878 return 0x0080; /* illegal first character */
1879 ch2 = Agetchar() & 0x3F;
1880 if (ch < 0xE0) return ((ch & 0x1F) << 6) + ch2;
1881 ch3 = Agetchar() & 0x3F;
1882 if (ch < 0xF0)
1883 return ((ch & 0x0F) << 12) + (ch2 << 6) + ch3;
1884 ch4 = Agetchar() & 0x3F;
1885 if (ch < 0xF8)
1886 return ((ch & 0x07) << 18) + (ch2 << 12) + (ch3 << 6) + ch4;
1887 ch5 = Agetchar() & 0x3F;
1888 if (ch < 0xFC)
1889 return ((ch & 0x03) << 24) + (ch2 << 18) + (ch3 << 12) +
1890 (ch4 << 6) + ch5;
1891 ch6 = Agetchar() & 0x3F;
1892 return ((ch & 0x01) << 30) + (ch2 << 24) + (ch3 << 18) +
1893 (ch4 << 12) + (ch5 << 6) + ch6;
1894 case 3: /* HZ */
1895 ch = Agetchar();
1896 if (ch == EOF) return ch;
1897 if (hzmode) {
1898 ch = (ch << 8) + Agetchar();
1899 if (ch == ('}' << 8) + '~') {
1900 hzmode = 0;
1901 return getinchr();
1903 return ch;
1905 else if (ch == '~') {
1906 ch = Agetchar();
1907 if (ch == '{') {
1908 hzmode = 1;
1909 return getinchr();
1911 else if (ch == '~') {
1912 return ch;
1914 else {
1915 return getinchr();
1918 else return ch;
1919 case 4: /* Shift-JIS */
1920 ch = Agetchar();
1921 if ((ch >= 0x80 && ch <= 0x9F) ||
1922 (ch >= 0xE0 && ch <= 0xEF)) {
1923 ch = (ch << 8) + Agetchar();
1925 return ch;
1926 default:
1927 return 0x80;
1931 /****************************************************************************
1933 main
1935 The main program, of course.
1936 Reads characters 1 by 1 from stdin, and makes lines out of them using
1937 addchar. Handles line breaking, (which accounts for most of the
1938 complexity in this function).
1940 ****************************************************************************/
1942 int main(argc,argv)
1943 int argc;
1944 char *argv[];
1946 inchr c,c2;
1947 int i;
1948 int last_was_eol_flag;
1949 /*---------------------------------------------------------------------------
1950 wordbreakmode:
1951 -1: /^$/ and blanks are to be absorbed (when line break was forced
1952 by a blank or character larger than outlinelenlimit)
1953 0: /^ *$/ and blanks are not to be absorbed
1954 1: /[^ ]$/ no word break yet
1955 2: /[^ ] *$/
1956 3: /[^ ]$/ had a word break
1957 ---------------------------------------------------------------------------*/
1958 int wordbreakmode;
1959 int char_not_added;
1961 Myargc = argc;
1962 Myargv = argv;
1963 getparams();
1964 readcontrolfiles();
1965 readfont();
1966 linealloc();
1968 wordbreakmode = 0;
1969 last_was_eol_flag = 0;
1971 while ((c = getinchr())!=EOF) {
1973 if (c=='\n'&&paragraphflag&&!last_was_eol_flag) {
1974 ungetinchr(c2 = getinchr());
1975 c = ((isascii(c2)&&isspace(c2))?'\n':' ');
1977 last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' ');
1979 if (deutschflag) {
1980 if (c>='[' && c<=']') {
1981 c = deutsch[c-'['];
1983 else if (c >='{' && c <= '~') {
1984 c = deutsch[c-'{'+3];
1988 c = handlemapping(c);
1990 if (isascii(c)&&isspace(c)) {
1991 c = (c=='\t'||c==' ') ? ' ' : '\n';
1994 if ((c>'\0' && c<' ' && c!='\n') || c==127) continue;
1996 /*
1997 Note: The following code is complex and thoroughly tested.
1998 Be careful when modifying!
1999 */
2001 do {
2002 char_not_added = 0;
2004 if (wordbreakmode== -1) {
2005 if (c==' ') {
2006 break;
2008 else if (c=='\n') {
2009 wordbreakmode = 0;
2010 break;
2012 wordbreakmode = 0;
2015 if (c=='\n') {
2016 printline();
2017 wordbreakmode = 0;
2020 else if (addchar(c)) {
2021 if (c!=' ') {
2022 wordbreakmode = (wordbreakmode>=2)?3:1;
2024 else {
2025 wordbreakmode = (wordbreakmode>0)?2:0;
2029 else if (outlinelen==0) {
2030 for (i=0;i<charheight;i++) {
2031 if (right2left && outputwidth>1) {
2032 putstring(currchar[i]+MYSTRLEN(currchar[i])-outlinelenlimit);
2034 else {
2035 putstring(currchar[i]);
2038 wordbreakmode = -1;
2041 else if (c==' ') {
2042 if (wordbreakmode==2) {
2043 splitline();
2045 else {
2046 printline();
2048 wordbreakmode = -1;
2051 else {
2052 if (wordbreakmode>=2) {
2053 splitline();
2055 else {
2056 printline();
2058 wordbreakmode = (wordbreakmode==3)?1:0;
2059 char_not_added = 1;
2062 } while (char_not_added);
2065 if (outlinelen!=0) {
2066 printline();
2069 /* XXX Xen hack -- finish off the C macro output */
2070 if ( nr_chars != 0 )
2071 putchar('"');
2072 putchar('\n');
2074 exit(0);