source: trunk/packages/xen-common/xen-common/xen/tools/figlet/figlet.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 52.6 KB
Line 
1
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 */
12
13/****************************************************************************
14
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****************************************************************************/
24
25#define DATE "13 July 2002"
26#define VERSION "2.2.1"
27#define VERSION_INT 20201
28
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/  */
49
50#define DEFAULTFONTDIR "."
51#define DEFAULTFONTFILE "xen.flf"
52
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 */
60
61#ifdef unix
62#include <sys/ioctl.h> /* Needed for get_columns */
63#endif
64
65
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
71
72#define MYSTRLEN(x) ((int)strlen(x)) /* Eliminate ANSI problem */
73
74#define DIRSEP '/'
75#define DIRSEP2 '\\'
76/* Leave alone for Unix and MS-DOS/Windows!
77Note: '/' also used in filename in get_columns(). */
78
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
86
87
88/****************************************************************************
89
90  Globals dealing with chars that are read
91
92****************************************************************************/
93
94typedef long inchr; /* "char" read from stdin */
95
96inchr *inchrline;  /* Alloc'd inchr inchrline[inchrlinelenlimit+1]; */
97                   /* Note: not null-terminated. */
98int inchrlinelen,inchrlinelenlimit;
99inchr 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  */
109
110int hzmode;  /* true if reading double-bytes in HZ mode */
111int gndbl[4]; /* gndbl[n] is true if Gn is double-byte */
112inchr gn[4]; /* Gn character sets: ASCII, Latin-1, none, none */
113int gl; /* 0-3 specifies left-half Gn character set */
114int gr; /* 0-3 specifies right-half Gn character set */
115
116int Myargc;  /* to avoid passing around argc and argv */
117char **Myargv;
118
119/****************************************************************************
120
121  Globals dealing with chars that are written
122
123****************************************************************************/
124
125typedef struct fc {
126  inchr ord;
127  char **thechar;  /* Alloc'd char thechar[charheight][]; */
128  struct fc *next;
129  } fcharnode;
130
131fcharnode *fcharlist;
132char **currchar;
133int currcharwidth;
134int previouscharwidth;
135char **outputline;    /* Alloc'd char outputline[charheight][outlinelenlimit+1]; */
136int outlinelen;
137
138
139/****************************************************************************
140
141  Globals dealing with command file storage
142
143****************************************************************************/
144
145typedef struct cfn {
146  char *thename;
147  struct cfn *next;
148  } cfnamenode;
149
150cfnamenode *cfilelist,**cfilelistend;
151
152typedef struct cm {
153  int thecommand;
154  inchr rangelo;
155  inchr rangehi;
156  inchr offset;
157  struct cm *next;
158  } comnode;
159
160comnode *commandlist,**commandlistend;
161
162/****************************************************************************
163
164  Globals affected by command line options
165
166****************************************************************************/
167
168int deutschflag,justification,paragraphflag,right2left,multibyte;
169int cmdinput;
170
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
179
180int smushmode;
181
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 */
185
186int smushoverride;
187
188int outputwidth;
189int outlinelenlimit;
190char *fontdirname,*fontname;
191
192
193/****************************************************************************
194
195  Globals read from font file
196
197****************************************************************************/
198
199char hardblank;
200int charheight;
201
202
203/****************************************************************************
204
205  Name of program, used in error messages
206
207****************************************************************************/
208
209char *myname;
210
211
212#ifdef TIOCGWINSZ
213/****************************************************************************
214
215  get_columns
216
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
221
222****************************************************************************/
223
224int get_columns()
225{
226  struct winsize ws;
227  int fd,result;
228
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 */
235
236
237/****************************************************************************
238
239  myalloc
240
241  Calls malloc.  If malloc returns error, prints error message and
242  quits.
243
244****************************************************************************/
245
246#ifdef __STDC__
247char *myalloc(size_t size)
248#else
249char *myalloc(size)
250int size;
251#endif
252{
253  char *ptr;
254#ifndef __STDC__
255  extern void *malloc();
256#endif
257
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}
266
267
268/****************************************************************************
269
270  hasdirsep
271
272  Returns true if s1 contains a DIRSEP or DIRSEP2 character.
273
274****************************************************************************/
275
276int hasdirsep(s1)
277char *s1;
278{
279  if (strchr(s1, DIRSEP)) return 1;
280  else if (strchr(s1, DIRSEP2)) return 1;
281  else return 0;
282}
283
284/****************************************************************************
285
286  suffixcmp
287
288  Returns true if s2 is a suffix of s1; uses case-blind comparison.
289
290****************************************************************************/
291
292int suffixcmp(s1, s2)
293char *s1;
294char *s2;
295{
296  int len1, len2;
297
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}
309   
310/****************************************************************************
311
312  skiptoeol
313
314  Skips to the end of a line, given a stream.  Handles \r, \n, or \r\n.
315
316****************************************************************************/
317
318void skiptoeol(fp)
319ZFILE *fp;
320{
321  int dummy;
322
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}
332
333
334/****************************************************************************
335
336  myfgets
337
338  Local version of fgets.  Handles \r, \n, and \r\n terminators.
339
340****************************************************************************/
341
342char *myfgets(line,maxlen,fp)
343char *line;
344int maxlen;
345ZFILE *fp;
346{
347  int c = 0;
348  char *p;
349
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}
365
366/****************************************************************************
367
368  usageerr
369
370  Prints "Usage: ...." line to the given stream.
371
372****************************************************************************/
373
374void printusage(out)
375FILE *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}
385
386
387/****************************************************************************
388
389  printinfo
390
391  Prints version and copyright message, or utility information.
392
393****************************************************************************/
394
395void printinfo(infonum)
396int 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}
426
427
428/****************************************************************************
429
430  readmagic
431
432  Reads a four-character magic string from a stream.
433
434****************************************************************************/
435void readmagic(fp,magic)
436ZFILE *fp;
437char *magic;
438{
439  int i;
440
441  for (i=0;i<4;i++) {
442    magic[i] = Zgetc(fp);
443    }
444  magic[4] = 0;
445  }
446 
447/****************************************************************************
448
449  skipws
450
451  Skips whitespace characters from a stream.
452
453****************************************************************************/
454void skipws(fp)
455ZFILE *fp;
456{
457  int c;
458  while (c=Zgetc(fp),isascii(c)&&isspace(c)) ;
459  Zungetc(c,fp);
460  }
461
462/****************************************************************************
463
464  readnum
465
466  Reads a number from a stream.  Accepts "0" prefix for octal and
467  "0x" or "0X" for hexadecimal.  Ignores leading whitespace.
468
469****************************************************************************/
470void readnum(fp,nump)
471ZFILE *fp;
472inchr *nump;
473{
474  int acc = 0;
475  char *p;
476  int c;
477  int base;
478  int sign = 1;
479  char digits[] = "0123456789ABCDEF";
480
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    }
504
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  } 
517
518/****************************************************************************
519
520  readTchar
521
522  Reads a control file "T" command character specification.
523
524  Character is a single byte, an escape sequence, or
525  an escaped numeric.
526
527****************************************************************************/
528
529inchr readTchar(fp)
530ZFILE *fp;
531{
532  inchr thechar;
533  char next;
534
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}
568
569/****************************************************************************
570
571  charsetname
572
573  Get a Tchar representing a charset name, or 0 if none available.
574  Called in getcharset().
575
576****************************************************************************/
577
578inchr charsetname(fp)
579ZFILE *fp;
580{
581  inchr result;
582
583  result = readTchar(fp);
584  if (result == '\n' || result == '\r') {
585    result = 0;
586    Zungetc(result,fp);
587    }
588  return result;
589  }
590
591/****************************************************************************
592
593  charset
594
595  Processes "g[0123]" character set specifier
596  Called in readcontrol().
597
598****************************************************************************/
599
600void charset(n, controlfile)
601int n;
602ZFILE *controlfile;
603{
604  int ch;
605
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  }
644
645/****************************************************************************
646
647  readcontrol
648
649  Allocates memory and reads in the given control file.
650  Called in readcontrolfiles().
651
652****************************************************************************/
653
654void readcontrol(controlname)
655char *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;
664
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    }
687
688  free(controlpath);
689
690  (*commandlistend) = (comnode*)myalloc(sizeof(comnode));
691  (*commandlistend)->thecommand = 0; /* Begin with a freeze command */
692  commandlistend = &(*commandlistend)->next;
693  (*commandlistend) = NULL;
694
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}
794
795
796/****************************************************************************
797
798  readcontrolfiles
799
800  Reads in the controlfiles names in cfilelist.  Uses readcontrol.
801  Called in main().
802
803****************************************************************************/
804
805void readcontrolfiles()
806{
807  cfnamenode *cfnptr;
808
809  for (cfnptr=cfilelist;cfnptr!=NULL;cfnptr=cfnptr->next) {
810    readcontrol(cfnptr->thename);
811    }
812}
813
814
815/****************************************************************************
816
817  clearcfilelist
818
819  Clears the control file list.  Assumes thename does not need freeing.
820
821****************************************************************************/
822
823void clearcfilelist()
824{
825  cfnamenode *cfnptr1,*cfnptr2;
826
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}
836
837
838/****************************************************************************
839
840  getparams
841
842  Handles all command-line parameters.  Puts all parameters within
843  bounds.
844
845****************************************************************************/
846
847void 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;
854
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);
1024      }
1025    }
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);
1031    }
1032}
1033
1034
1035/****************************************************************************
1036
1037  clearline
1038
1039  Clears both the input (inchrline) and output (outputline) storage.
1040
1041****************************************************************************/
1042
1043void clearline()
1044{
1045  int i;
1046
1047  for (i=0;i<charheight;i++) {
1048    outputline[i][0] = '\0';
1049    }
1050  outlinelen = 0;
1051  inchrlinelen = 0;
1052}
1053
1054
1055/****************************************************************************
1056
1057  readfontchar
1058
1059  Reads a font character from the font file, and places it in a
1060  newly-allocated entry in the list.
1061
1062****************************************************************************/
1063
1064void readfontchar(file,theord,line,maxlen)
1065ZFILE *file;
1066inchr theord;
1067char *line;
1068int maxlen;
1069{
1070  int row,k;
1071  char endchar;
1072  fcharnode *fclsave;
1073
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';
1082      }
1083    k = MYSTRLEN(line)-1;
1084    while (k>=0 && isspace(line[k])) {
1085      k--;
1086      }
1087    if (k>=0) {
1088      endchar = line[k];
1089      while (k>=0 ? line[k]==endchar : 0) {
1090        k--;
1091        }
1092      }
1093    line[k+1] = '\0';
1094    fcharlist->thechar[row] = (char*)myalloc(sizeof(char)*(k+2));
1095    strcpy(fcharlist->thechar[row],line);
1096    }
1097}
1098
1099
1100/****************************************************************************
1101
1102  readfont
1103
1104  Allocates memory, initializes variables, and reads in the font.
1105  Called near beginning of main().
1106
1107****************************************************************************/
1108
1109void readfont()
1110{
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;
1119
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");
1131    }
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);
1139      }
1140    }
1141
1142  readmagic(fontfile,magicnum);
1143  fileline = (char*)myalloc(sizeof(char)*(MAXFIRSTLINELEN+1));
1144  if (myfgets(fileline,MAXFIRSTLINELEN+1,fontfile)==NULL) {
1145    fileline[0] = '\0';
1146    }
1147  if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) {
1148    skiptoeol(fontfile);
1149    }
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);
1157    }
1158  for (i=1;i<=cmtlines;i++) {
1159    skiptoeol(fontfile);
1160    }
1161  free(fontpath);
1162
1163  if (numsread<6) {
1164    ffright2left = 0;
1165    }
1166
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;
1171    }
1172
1173  if (charheight<1) {
1174    charheight = 1;
1175    }
1176
1177  if (maxlen<1) {
1178    maxlen = 1;
1179    }
1180
1181  maxlen += 100; /* Give ourselves some extra room */
1182
1183  if (smushoverride == SMO_NO)
1184     smushmode = smush2;
1185  else if (smushoverride == SMO_FORCE)
1186     smushmode |= smush2;
1187
1188  if (right2left<0) {
1189    right2left = ffright2left;
1190    }
1191
1192  if (justification<0) {
1193    justification = 2*right2left;
1194    }
1195
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';
1205    }
1206  for (theord=' ';theord<='~';theord++) {
1207    readfontchar(fontfile,theord,fileline,maxlen);
1208    }
1209  for (theord=0;theord<=6;theord++) {
1210    readfontchar(fontfile,deutsch[theord],fileline,maxlen);
1211    }
1212  while (myfgets(fileline,maxlen+1,fontfile)==NULL?0:
1213    sscanf(fileline,"%li",&theord)==1) {
1214    readfontchar(fontfile,theord,fileline,maxlen);
1215    }
1216  Zclose(fontfile);
1217  free(fileline);
1218}
1219
1220
1221/****************************************************************************
1222
1223  linealloc
1224
1225  Allocates & clears outputline, inchrline. Sets inchrlinelenlimit.
1226  Called near beginning of main().
1227
1228****************************************************************************/
1229
1230void linealloc()
1231{
1232  int row; 
1233
1234  outputline = (char**)myalloc(sizeof(char*)*charheight);
1235  for (row=0;row<charheight;row++) {
1236    outputline[row] = (char*)myalloc(sizeof(char)*(outlinelenlimit+1));
1237    }
1238  inchrlinelenlimit = outputwidth*4+100;
1239  inchrline = (inchr*)myalloc(sizeof(inchr)*(inchrlinelenlimit+1));
1240  clearline();
1241}
1242
1243
1244/****************************************************************************
1245
1246  getletter
1247
1248  Sets currchar to point to the font entry for the given character.
1249  Sets currcharwidth to the width of this character.
1250
1251****************************************************************************/
1252
1253void getletter(c)
1254inchr c;
1255{
1256  fcharnode *charptr;
1257
1258  for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=c;
1259    charptr=charptr->next) ;
1260  if (charptr!=NULL) {
1261    currchar = charptr->thechar;
1262    }
1263  else {
1264    for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=0;
1265      charptr=charptr->next) ;
1266    currchar = charptr->thechar;
1267    }
1268  previouscharwidth = currcharwidth;
1269  currcharwidth = MYSTRLEN(currchar[0]);
1270}
1271
1272
1273/****************************************************************************
1274
1275  smushem
1276
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.
1280
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
1289
1290****************************************************************************/
1291
1292char smushem(lch,rch)
1293char lch,rch;
1294{
1295  if (lch==' ') return rch;
1296  if (rch==' ') return lch;
1297
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. */
1301
1302  if ((smushmode & SM_SMUSH) == 0) return '\0';  /* kerning */
1303
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. */
1318    }
1319 
1320  if (smushmode & SM_HARDBLANK) {
1321    if (lch==hardblank && rch==hardblank) return lch;
1322    }
1323
1324  if (lch==hardblank || rch==hardblank) return '\0';
1325
1326  if (smushmode & SM_EQUAL) {
1327    if (lch==rch) return lch;
1328    }
1329
1330  if (smushmode & SM_LOWLINE) {
1331    if (lch=='_' && strchr("|/\\[]{}()<>",rch)) return rch;
1332    if (rch=='_' && strchr("|/\\[]{}()<>",lch)) return lch;
1333    }
1334
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;
1346    }
1347
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 '|';
1355    }
1356
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'. */
1362    }
1363
1364  return '\0';
1365}
1366
1367
1368/****************************************************************************
1369
1370  smushamt
1371
1372  Returns the maximum amount that the current character can be smushed
1373  into the current line.
1374
1375****************************************************************************/
1376
1377int smushamt()
1378{
1379  int maxsmush,amt;
1380  int row,linebd,charbd;
1381  char ch1,ch2;
1382
1383  if ((smushmode & (SM_SMUSH | SM_KERN)) == 0) {
1384    return 0;
1385    }
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;
1393      }
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;
1399      }
1400    if (!ch1||ch1==' ') {
1401      amt++;
1402      }
1403    else if (ch2) {
1404      if (smushem(ch1,ch2)!='\0') {
1405        amt++;
1406        }
1407      }
1408    if (amt<maxsmush) {
1409      maxsmush = amt;
1410      }
1411    }
1412  return maxsmush;
1413}
1414
1415
1416/****************************************************************************
1417
1418  addchar
1419
1420  Attempts to add the given character onto the end of the current line.
1421  Returns 1 if this can be done, 0 otherwise.
1422
1423****************************************************************************/
1424
1425int addchar(c)
1426inchr c;
1427{
1428  int smushamount,row,k;
1429  char *templine;
1430
1431  getletter(c);
1432  smushamount = smushamt();
1433  if (outlinelen+currcharwidth-smushamount>outlinelenlimit
1434      ||inchrlinelen+1>inchrlinelenlimit) {
1435    return 0;
1436    }
1437
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]);
1445        }
1446      strcat(templine,outputline[row]+smushamount);
1447      strcpy(outputline[row],templine);
1448      }
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]);
1454        }
1455      strcat(outputline[row],currchar[row]+smushamount);
1456      }
1457    }
1458  free(templine);
1459  outlinelen = MYSTRLEN(outputline[0]);
1460  inchrline[inchrlinelen++] = c;
1461  return 1;
1462}
1463
1464
1465/****************************************************************************
1466
1467  putstring
1468
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.
1475
1476****************************************************************************/
1477
1478static int nr_chars=0;
1479static void myputchar(unsigned char c)
1480{
1481    static int startline = 1;
1482
1483    if ( startline )
1484    {
1485        startline = 0;
1486        myputchar(' ');
1487    }
1488
1489    putc(c, stderr);
1490
1491    if ( nr_chars == 0 )
1492        putchar('"');
1493
1494    putchar('\\');
1495    putchar('0' + ((c>>6)&7));
1496    putchar('0' + ((c>>3)&7));
1497    putchar('0' + ((c>>0)&7));
1498
1499    if ( c == '\n' )
1500        startline = 1;
1501
1502    if ( ++nr_chars == 18 ) 
1503    {
1504        nr_chars = 0;
1505        putchar('"');
1506        putchar(' ');
1507        putchar('\\');
1508        putchar('\n');
1509    }
1510}
1511
1512void putstring(string)
1513char *string;
1514{
1515  int i,len;
1516
1517  len = MYSTRLEN(string);
1518  if (outputwidth>1) {
1519    if (len>outputwidth-1) {
1520      len = outputwidth-1;
1521      }
1522    if (justification>0) {
1523      for (i=1;(3-justification)*i+len+justification-2<outputwidth;i++) {
1524        myputchar(' ');
1525        }
1526      }
1527    }
1528  for (i=0;i<len;i++) {
1529    myputchar(string[i]==hardblank?' ':string[i]);
1530    }
1531  myputchar('\n');
1532}
1533
1534
1535/****************************************************************************
1536
1537  printline
1538
1539  Prints outputline using putstring, then clears the current line.
1540
1541****************************************************************************/
1542
1543void printline()
1544{
1545  int i;
1546
1547  for (i=0;i<charheight;i++) {
1548    putstring(outputline[i]);
1549    }
1550  clearline();
1551}
1552
1553
1554/****************************************************************************
1555
1556  splitline
1557
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.
1561
1562****************************************************************************/
1563
1564void splitline()
1565{
1566  int i,gotspace,lastspace,len1,len2;
1567  inchr *part1,*part2;
1568
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;
1576      }
1577    if (gotspace && inchrline[i]!=' ') {
1578      break;
1579      }
1580    }
1581  len1 = i+1;
1582  len2 = inchrlinelen-lastspace-1;
1583  for (i=0;i<len1;i++) {
1584    part1[i] = inchrline[i];
1585    }
1586  for (i=0;i<len2;i++) {
1587    part2[i] = inchrline[lastspace+1+i];
1588    }
1589  clearline();
1590  for (i=0;i<len1;i++) {
1591    addchar(part1[i]);
1592    }
1593  printline();
1594  for (i=0;i<len2;i++) {
1595    addchar(part2[i]);
1596    }
1597  free(part1);
1598  free(part2);
1599}
1600
1601
1602/****************************************************************************
1603
1604  handlemapping
1605
1606  Given an input character (type inchr), executes re-mapping commands
1607  read from control files.  Returns re-mapped character (inchr).
1608
1609****************************************************************************/
1610
1611inchr handlemapping(c)
1612inchr c;
1613{
1614  comnode *cmptr;
1615
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;
1623        }
1624      }
1625    else {
1626      cmptr=cmptr->next;
1627      }
1628    }
1629  return c;
1630}
1631
1632/****************************************************************************
1633
1634  Agetchar
1635
1636  Replacement to getchar().
1637  Acts exactly like getchar if -A is NOT specified,
1638  else obtains input from All remaining command line words.
1639
1640****************************************************************************/
1641
1642int Agetchar()
1643{
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 */
1648
1649    if ( ! cmdinput )           /* is -A active? */
1650        return( getchar() );    /* no: return stdin character */
1651
1652    if ( AgetMode < 0 || optind >= Myargc )             /* EOF is sticky: */
1653        return( EOF );          /* **ensure it now and forever more */
1654
1655    /* find next character */
1656    arg = Myargv[optind];               /* pointer to active arg */
1657    c = arg[AgetMode++]&0xFF;   /* get appropriate char of arg */
1658
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 */
1669        }
1670    }
1671
1672    return( c );                /* return appropriate character */
1673
1674}       /* end: Agetchar() */
1675
1676
1677/****************************************************************************
1678
1679  iso2022
1680
1681  Called by getinchr.  Interprets ISO 2022 sequences
1682
1683******************************************************************************/
1684
1685inchr iso2022()
1686{
1687  inchr ch;
1688  inchr ch2;
1689  int save_gl;
1690  int save_gr;
1691
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();
1797        }
1798      }
1799
1800  if (ch >= 0x21 && ch <= 0x7E) { /* process GL */
1801    if (gndbl[gl]) {
1802      ch2 = Agetchar();
1803      return gn[gl] | (ch << 8) | ch2;
1804      }
1805    else return gn[gl] | ch;
1806    }
1807  else if (ch >= 0xA0 && ch <= 0xFF) { /* process GR */
1808    if (gndbl[gr]) {
1809      ch2 = Agetchar();
1810      return gn[gr] | (ch << 8) | ch2;
1811      }
1812    else return gn[gr] | (ch & ~0x80);
1813    }
1814  else return ch;
1815  }
1816
1817/****************************************************************************
1818
1819  ungetinchr
1820
1821  Called by main.  Pushes back an "inchr" to be read by getinchr
1822  on the next call.
1823
1824******************************************************************************/
1825inchr getinchr_buffer;
1826int getinchr_flag;
1827
1828inchr ungetinchr(c)
1829inchr c;
1830{
1831  getinchr_buffer = c;
1832  getinchr_flag = 1;
1833  return c;
1834}
1835
1836/*****************************************************************************
1837
1838  getinchr
1839
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).
1852 
1853
1854*****************************************************************************/
1855
1856inchr getinchr()
1857{
1858  int ch, ch2, ch3, ch4, ch5, ch6;
1859
1860  if (getinchr_flag) {
1861    getinchr_flag = 0;
1862    return getinchr_buffer;
1863    }
1864
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();
1873       }
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();
1903         }
1904       return ch;
1905       }
1906     else if (ch == '~') {
1907       ch = Agetchar();
1908       if (ch == '{') {
1909          hzmode = 1;
1910          return getinchr();
1911          }
1912      else if (ch == '~') {
1913        return ch;
1914        }
1915      else {
1916        return getinchr();
1917        }
1918      }
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();
1925       }
1926     return ch;
1927   default:
1928     return 0x80;
1929    }
1930  }
1931
1932/****************************************************************************
1933
1934  main
1935
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).
1940
1941****************************************************************************/
1942
1943int main(argc,argv)
1944int argc;
1945char *argv[];
1946{
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;
1961
1962  Myargc = argc;
1963  Myargv = argv;
1964  getparams();
1965  readcontrolfiles();
1966  readfont();
1967  linealloc();
1968
1969  wordbreakmode = 0;
1970  last_was_eol_flag = 0;
1971
1972  while ((c = getinchr())!=EOF) {
1973
1974    if (c=='\n'&&paragraphflag&&!last_was_eol_flag) {
1975      ungetinchr(c2 = getinchr());
1976      c = ((isascii(c2)&&isspace(c2))?'\n':' ');
1977      }
1978    last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' ');
1979
1980    if (deutschflag) {
1981      if (c>='[' && c<=']') {
1982        c = deutsch[c-'['];
1983        }
1984      else if (c >='{' && c <= '~') {
1985        c = deutsch[c-'{'+3];
1986        }
1987      }
1988
1989    c = handlemapping(c);
1990
1991    if (isascii(c)&&isspace(c)) {
1992      c = (c=='\t'||c==' ') ? ' ' : '\n';
1993      }
1994
1995    if ((c>'\0' && c<' ' && c!='\n') || c==127) continue;
1996
1997/*
1998  Note: The following code is complex and thoroughly tested.
1999  Be careful when modifying!
2000*/
2001
2002    do {
2003      char_not_added = 0;
2004
2005      if (wordbreakmode== -1) {
2006        if (c==' ') {
2007          break;
2008          }
2009        else if (c=='\n') {
2010          wordbreakmode = 0;
2011          break;
2012          }
2013        wordbreakmode = 0;
2014        }
2015
2016      if (c=='\n') {
2017        printline();
2018        wordbreakmode = 0;
2019        }
2020
2021      else if (addchar(c)) {
2022        if (c!=' ') {
2023          wordbreakmode = (wordbreakmode>=2)?3:1;
2024          }
2025        else {
2026          wordbreakmode = (wordbreakmode>0)?2:0;
2027          }
2028        }
2029
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);
2034            }
2035          else {
2036            putstring(currchar[i]);
2037            }
2038          }
2039        wordbreakmode = -1;
2040        }
2041
2042      else if (c==' ') {
2043        if (wordbreakmode==2) {
2044          splitline();
2045          }
2046        else {
2047          printline();
2048          }
2049        wordbreakmode = -1;
2050        }
2051
2052      else {
2053        if (wordbreakmode>=2) {
2054          splitline();
2055          }
2056        else {
2057          printline();
2058          }
2059        wordbreakmode = (wordbreakmode==3)?1:0;
2060        char_not_added = 1;
2061        }
2062
2063      } while (char_not_added);
2064    }
2065
2066  if (outlinelen!=0) {
2067    printline();
2068    }
2069
2070  /* XXX Xen hack -- finish off the C macro output */
2071  if ( nr_chars != 0 )
2072      putchar('"');
2073  putchar('\n');
2074
2075  exit(0);
2076}
Note: See TracBrowser for help on using the repository browser.