/****************************************************************************12FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai3FIGlet Copyright 1996, 1997, 1998, 1999, 2000, 2001 John Cowan4FIGlet Copyright 2002 Christiaan Keet5FIGlet Copyright 2011, 2012 Claudio Matsuoka6Portions written by Paul Burton and Christiaan Keet7Internet: <[email protected]>8FIGlet, along with the various FIGlet fonts and documentation, is9copyrighted under the provisions of the New BSD License (3-clause)10(as listed in the file "LICENSE" which is included in this package)11****************************************************************************/1213#define DATE "31 May 2012"14#define VERSION "2.2.5"15#define VERSION_INT 202051617/* FIGlet (Frank, Ian & Glenn's Letters) */18/* by Glenn Chappell */19/* Apr 1991 */20/* Automatic file addition by Ian Chai May 1991 */21/* Punctuation and numbers addition by Ian Chai Jan 1993 */22/* Full ASCII by Glenn Chappell Feb 1993 */23/* Line-breaking, general rewrite by Glenn Chappell Mar 1993 */24/* Hard blanks by Glenn Chappell Apr 1993 */25/* Release 2.0 5 Aug 1993 */26/* Right-to-left printing, extended char set by Glenn Chappell Dec 1993 */27/* Control files by Glenn Chappell Feb 1994 */28/* Release 2.1 12 Aug 1994 */29/* Release 2.1.1 25 Aug 1994 */30/* Release 2.1.2 by Gilbert (Mad Programmer) Healton: Add -A command line31option. Sept 8, 1996 */32/* Release 2.2 by John Cowan: multibyte inputs, compressed fonts,33mapping tables, kerning/smushing options. */34/* Release 2.2.1 by Christiaan Keet: minor updates including readmes35FAQs and comments. 13 July 2002. The new official FIGlet website is36http://www.figlet.org/ */37/* Release 2.2.2 by Christiaan Keet: License changed from "Artistic License"38to "Academic Free License" as agreed by FIGlet authors. 05 July 2005 */39/* Release 2.2.3 by Claudio Matsuoka, 12 Jan 2011: BSD license, fixes */40/* Release 2.2.4 by Claudio Matsuoka, 26 Jan 2011: tlf2 font support */41/* Release 2.2.5 by Claudio Matsuoka, 31 May 2012: flc licensing, minor fixes */4243/*---------------------------------------------------------------------------44DEFAULTFONTDIR and DEFAULTFONTFILE should be defined in the Makefile.45DEFAULTFONTDIR is the full path name of the directory in which FIGlet46will search first for fonts (the ".flf" files).47DEFAULTFONTFILE is the filename of the font to be used if no other48is specified (standard.flf is recommended, but any other can be49used). This file should reside in the directory specified by50DEFAULTFONTDIR.51---------------------------------------------------------------------------*/52#ifndef DEFAULTFONTDIR53#define DEFAULTFONTDIR "fonts"54#endif55#ifndef DEFAULTFONTFILE56#define DEFAULTFONTFILE "standard.flf"57#endif5859#include <stdio.h>60#ifdef __STDC__61#include <stdlib.h>62#endif63#include <string.h>64#include <ctype.h>65#include <sys/stat.h>66#include <fcntl.h> /* Needed for get_columns */6768#if defined(unix) || defined(__unix__) || defined(__APPLE__)69#include <unistd.h>70#include <sys/ioctl.h> /* Needed for get_columns */71#endif7273#ifdef TLF_FONTS74#include <wchar.h>75#include <wctype.h>76#include "utf8.h"77#endif7879#include "zipio.h" /* Package for reading compressed files */8081#define MYSTRLEN(x) ((int)strlen(x)) /* Eliminate ANSI problem */8283#define DIRSEP '/'84#define DIRSEP2 '\\'85/* Leave alone for Unix and MS-DOS/Windows!86Note: '/' also used in filename in get_columns(). */8788#define FONTFILESUFFIX ".flf"89#define FONTFILEMAGICNUMBER "flf2"90#define FSUFFIXLEN MYSTRLEN(FONTFILESUFFIX)91#define CONTROLFILESUFFIX ".flc"92#define CONTROLFILEMAGICNUMBER "flc2" /* no longer used in 2.2 */93#define CSUFFIXLEN MYSTRLEN(CONTROLFILESUFFIX)94#define DEFAULTCOLUMNS 8095#define MAXLEN 255 /* Maximum character width */9697/* Add support for Sam Hocevar's TOIlet fonts */98#ifdef TLF_FONTS99#define TOILETFILESUFFIX ".tlf"100#define TOILETFILEMAGICNUMBER "tlf2"101#define TSUFFIXLEN MYSTRLEN(TOILETFILESUFFIX)102103int toiletfont; /* true if font is a TOIlet TLF font */104#endif105106107/****************************************************************************108109Globals dealing with chars that are read110111****************************************************************************/112113typedef long inchr; /* "char" read from stdin */114115inchr *inchrline; /* Alloc'd inchr inchrline[inchrlinelenlimit+1]; */116/* Note: not null-terminated. */117int inchrlinelen,inchrlinelenlimit;118inchr deutsch[7] = {196, 214, 220, 228, 246, 252, 223};119/* Latin-1 codes for German letters, respectively:120LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut121LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut122LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut123LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut124LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut125LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut126LATIN SMALL LETTER SHARP S = ess-zed127*/128129int hzmode; /* true if reading double-bytes in HZ mode */130int gndbl[4]; /* gndbl[n] is true if Gn is double-byte */131inchr gn[4]; /* Gn character sets: ASCII, Latin-1, none, none */132int gl; /* 0-3 specifies left-half Gn character set */133int gr; /* 0-3 specifies right-half Gn character set */134135int Myargc; /* to avoid passing around argc and argv */136char **Myargv;137138/****************************************************************************139140Globals dealing with chars that are written141142****************************************************************************/143144#ifdef TLF_FONTS145typedef wchar_t outchr; /* "char" written to stdout */146#define STRLEN(x) wcslen(x)147#define STRCPY(x,y) wcscpy((x),(y))148#define STRCAT(x,y) wcscat((x),(y))149#define ISSPACE(x) iswspace(x)150#else151typedef char outchr; /* "char" written to stdout */152#define STRLEN(x) MYSTRLEN(x)153#define STRCPY(x,y) strcpy((x),(y))154#define STRCAT(x,y) strcat((x),(y))155#define ISSPACE(x) isspace(x)156#endif157158typedef struct fc {159inchr ord;160outchr **thechar; /* Alloc'd char thechar[charheight][]; */161struct fc *next;162} fcharnode;163164fcharnode *fcharlist;165outchr **currchar;166int currcharwidth;167int previouscharwidth;168outchr **outputline; /* Alloc'd char outputline[charheight][outlinelenlimit+1]; */169int outlinelen;170171172/****************************************************************************173174Globals dealing with command file storage175176****************************************************************************/177178typedef struct cfn {179char *thename;180struct cfn *next;181} cfnamenode;182183cfnamenode *cfilelist,**cfilelistend;184185typedef struct cm {186int thecommand;187inchr rangelo;188inchr rangehi;189inchr offset;190struct cm *next;191} comnode;192193comnode *commandlist,**commandlistend;194195/****************************************************************************196197Globals affected by command line options198199****************************************************************************/200201int deutschflag,justification,paragraphflag,right2left,multibyte;202int cmdinput;203204#define SM_SMUSH 128205#define SM_KERN 64206#define SM_EQUAL 1207#define SM_LOWLINE 2208#define SM_HIERARCHY 4209#define SM_PAIR 8210#define SM_BIGX 16211#define SM_HARDBLANK 32212213int smushmode;214215#define SMO_NO 0 /* no command-line smushmode */216#define SMO_YES 1 /* use command-line smushmode, ignore font smushmode */217#define SMO_FORCE 2 /* logically OR command-line and font smushmodes */218219int smushoverride;220221int outputwidth;222int outlinelenlimit;223char *fontdirname,*fontname;224225226/****************************************************************************227228Globals read from font file229230****************************************************************************/231232char hardblank;233int charheight;234235236/****************************************************************************237238Name of program, used in error messages239240****************************************************************************/241242char *myname;243244245#ifdef TIOCGWINSZ246/****************************************************************************247248get_columns249250Determines the number of columns of /dev/tty. Returns the number of251columns, or -1 if error. May return 0 if columns unknown.252Requires include files <fcntl.h> and <sys/ioctl.h>.253by Glenn Chappell & Ian Chai 14 Apr 1993254255****************************************************************************/256257int get_columns()258{259struct winsize ws;260int fd,result;261262if ((fd = open("/dev/tty",O_WRONLY))<0) return -1;263result = ioctl(fd,TIOCGWINSZ,&ws);264close(fd);265return result?-1:ws.ws_col;266}267#endif /* ifdef TIOCGWINSZ */268269270/****************************************************************************271272myalloc273274Calls malloc. If malloc returns error, prints error message and275quits.276277****************************************************************************/278279#ifdef __STDC__280char *myalloc(size_t size)281#else282char *myalloc(size)283int size;284#endif285{286char *ptr;287#ifndef __STDC__288extern void *malloc();289#endif290291if ((ptr = (char*)malloc(size))==NULL) {292fprintf(stderr,"%s: Out of memory\n",myname);293exit(1);294}295else {296return ptr;297}298}299300301/****************************************************************************302303hasdirsep304305Returns true if s1 contains a DIRSEP or DIRSEP2 character.306307****************************************************************************/308309int hasdirsep(s1)310char *s1;311{312if (strchr(s1, DIRSEP)) return 1;313else if (strchr(s1, DIRSEP2)) return 1;314else return 0;315}316317/****************************************************************************318319suffixcmp320321Returns true if s2 is a suffix of s1; uses case-blind comparison.322323****************************************************************************/324325int suffixcmp(s1, s2)326char *s1;327char *s2;328{329int len1, len2;330331len1 = MYSTRLEN(s1);332len2 = MYSTRLEN(s2);333if (len2 > len1) return 0;334s1 += len1 - len2;335while (*s1) {336if (tolower(*s1) != tolower(*s2)) return 0;337s1++;338s2++;339}340return 1;341}342343/****************************************************************************344345skiptoeol346347Skips to the end of a line, given a stream. Handles \r, \n, or \r\n.348349****************************************************************************/350351void skiptoeol(fp)352ZFILE *fp;353{354int dummy;355356while (dummy=Zgetc(fp),dummy!=EOF) {357if (dummy == '\n') return;358if (dummy == '\r') {359dummy = Zgetc(fp);360if (dummy != EOF && dummy != '\n') Zungetc(dummy,fp);361return;362}363}364}365366367/****************************************************************************368369myfgets370371Local version of fgets. Handles \r, \n, and \r\n terminators.372373****************************************************************************/374375char *myfgets(line,maxlen,fp)376char *line;377int maxlen;378ZFILE *fp;379{380int c = 0;381char *p;382383p = line;384while((c=Zgetc(fp))!=EOF&&maxlen) {385*p++ = c;386maxlen--;387if (c=='\n') break;388if (c=='\r') {389c = Zgetc(fp);390if (c != EOF && c != '\n') Zungetc(c,fp);391*(p-1) = '\n';392break;393}394}395*p = 0;396return (c==EOF) ? NULL : line;397}398399400/****************************************************************************401402usageerr403404Prints "Usage: ...." line to the given stream.405406****************************************************************************/407408void printusage(out)409FILE *out;410{411fprintf(out,412"Usage: %s [ -cklnoprstvxDELNRSWX ] [ -d fontdirectory ]\n",413myname);414fprintf(out,415" [ -f fontfile ] [ -m smushmode ] [ -w outputwidth ]\n");416fprintf(out,417" [ -C controlfile ] [ -I infocode ] [ message ]\n");418}419420421/****************************************************************************422423printinfo424425Prints version and copyright message, or utility information.426427****************************************************************************/428429void printinfo(infonum)430int infonum;431{432switch (infonum) {433case 0: /* Copyright message */434printf("FIGlet Copyright (C) 1991-2012 Glenn Chappell, Ian Chai, ");435printf("John Cowan,\nChristiaan Keet and Claudio Matsuoka\n");436printf("Internet: <[email protected]> ");437printf("Version: %s, date: %s\n\n",VERSION,DATE);438printf("FIGlet, along with the various FIGlet fonts");439printf(" and documentation, may be\n");440printf("freely copied and distributed.\n\n");441printf("If you use FIGlet, please send an");442printf(" e-mail message to <[email protected]>.\n\n");443printf("The latest version of FIGlet is available from the");444printf(" web site,\n\thttp://www.figlet.org/\n\n");445printusage(stdout);446break;447case 1: /* Version (integer) */448printf("%d\n",VERSION_INT);449break;450case 2: /* Font directory */451printf("%s\n",fontdirname);452break;453case 3: /* Font */454printf("%s\n",fontname);455break;456case 4: /* Outputwidth */457printf("%d\n",outputwidth);458break;459case 5: /* Font formats */460printf("%s", FONTFILEMAGICNUMBER);461#ifdef TLF_FONTS462printf(" %s", TOILETFILEMAGICNUMBER);463#endif464printf("\n");465}466}467468469/****************************************************************************470471readmagic472473Reads a four-character magic string from a stream.474475****************************************************************************/476void readmagic(fp,magic)477ZFILE *fp;478char *magic;479{480int i;481482for (i=0;i<4;i++) {483magic[i] = Zgetc(fp);484}485magic[4] = 0;486}487488/****************************************************************************489490skipws491492Skips whitespace characters from a stream.493494****************************************************************************/495void skipws(fp)496ZFILE *fp;497{498int c;499while (c=Zgetc(fp),isascii(c)&&isspace(c)) ;500Zungetc(c,fp);501}502503/****************************************************************************504505readnum506507Reads a number from a stream. Accepts "0" prefix for octal and508"0x" or "0X" for hexadecimal. Ignores leading whitespace.509510****************************************************************************/511void readnum(fp,nump)512ZFILE *fp;513inchr *nump;514{515int acc = 0;516char *p;517int c;518int base;519int sign = 1;520char digits[] = "0123456789ABCDEF";521522skipws(fp);523c = Zgetc(fp);524if (c=='-') {525sign = -1;526}527else {528Zungetc(c,fp);529}530c = Zgetc(fp);531if (c=='0') {532c = Zgetc(fp);533if (c=='x'||c=='X') {534base = 16;535}536else {537base = 8;538Zungetc(c,fp);539}540}541else {542base = 10;543Zungetc(c,fp);544}545546while((c=Zgetc(fp))!=EOF) {547c=toupper(c);548p=strchr(digits,c);549if (!p) {550Zungetc(c,fp);551*nump = acc * sign;552return;553}554acc = acc*base+(p-digits);555}556*nump = acc * sign;557}558559/****************************************************************************560561readTchar562563Reads a control file "T" command character specification.564565Character is a single byte, an escape sequence, or566an escaped numeric.567568****************************************************************************/569570inchr readTchar(fp)571ZFILE *fp;572{573inchr thechar;574char next;575576thechar=Zgetc(fp);577if (thechar=='\n' || thechar=='\r') { /* Handle badly-formatted file */578Zungetc(thechar,fp);579return '\0';580}581if (thechar!='\\') return thechar;582next=Zgetc(fp);583switch(next) {584case 'a':585return 7;586case 'b':587return 8;588case 'e':589return 27;590case 'f':591return 12;592case 'n':593return 10;594case 'r':595return 13;596case 't':597return 9;598case 'v':599return 11;600default:601if (next=='-' || next=='x' || (next>='0' && next<='9')) {602Zungetc(next,fp);603readnum(fp,&thechar);604return thechar;605}606return next;607}608}609610/****************************************************************************611612charsetname613614Get a Tchar representing a charset name, or 0 if none available.615Called in getcharset().616617****************************************************************************/618619inchr charsetname(fp)620ZFILE *fp;621{622inchr result;623624result = readTchar(fp);625if (result == '\n' || result == '\r') {626result = 0;627Zungetc(result,fp);628}629return result;630}631632/****************************************************************************633634charset635636Processes "g[0123]" character set specifier637Called in readcontrol().638639****************************************************************************/640641void charset(n, controlfile)642int n;643ZFILE *controlfile;644{645int ch;646647skipws(controlfile);648if (Zgetc(controlfile) != '9') {649skiptoeol(controlfile);650return;651}652ch = Zgetc(controlfile);653if (ch == '6') {654gn[n] = 65536L * charsetname(controlfile) + 0x80;655gndbl[n] = 0;656skiptoeol(controlfile);657return;658}659if (ch != '4') {660skiptoeol(controlfile);661return;662}663ch = Zgetc(controlfile);664if (ch == 'x') {665if (Zgetc(controlfile) != '9') {666skiptoeol(controlfile);667return;668}669if (Zgetc(controlfile) != '4') {670skiptoeol(controlfile);671return;672}673skipws(controlfile);674gn[n] = 65536L * charsetname(controlfile);675gndbl[n] = 1;676skiptoeol(controlfile);677return;678}679Zungetc(ch, controlfile);680skipws(controlfile);681gn[n] = 65536L * charsetname(controlfile);682gndbl[n] = 0;683return;684}685686/****************************************************************************687688FIGopen689690Given a FIGlet font or control file name and suffix, return the file691or NULL if not found692693****************************************************************************/694695ZFILE *FIGopen(name,suffix)696char *name;697char *suffix;698{699char *fontpath;700ZFILE *fontfile;701struct stat st;702int namelen;703704namelen = MYSTRLEN(fontdirname);705fontpath = (char*)alloca(sizeof(char)*706(namelen+MYSTRLEN(name)+MYSTRLEN(suffix)+2));707fontfile = NULL;708if (!hasdirsep(name)) { /* not a full path name */709strcpy(fontpath,fontdirname);710fontpath[namelen] = DIRSEP;711fontpath[namelen+1] = '\0';712strcat(fontpath,name);713strcat(fontpath,suffix);714if(stat(fontpath,&st)==0) goto ok;715}716/* just append suffix */717strcpy(fontpath,name);718strcat(fontpath,suffix);719if(stat(fontpath,&st)==0) goto ok;720721return NULL;722723ok:724fontfile = Zopen(fontpath,"rb");725return fontfile;726}727728/****************************************************************************729730readcontrol731732Allocates memory and reads in the given control file.733Called in readcontrolfiles().734735****************************************************************************/736737void readcontrol(controlname)738char *controlname;739{740inchr firstch,lastch;741char dashcheck;742inchr offset;743int command;744ZFILE *controlfile;745746controlfile = FIGopen(controlname,CONTROLFILESUFFIX);747748if (controlfile==NULL) {749fprintf(stderr,"%s: %s: Unable to open control file\n",myname,750controlname);751exit(1);752}753754(*commandlistend) = (comnode*)myalloc(sizeof(comnode));755(*commandlistend)->thecommand = 0; /* Begin with a freeze command */756commandlistend = &(*commandlistend)->next;757(*commandlistend) = NULL;758759while(command=Zgetc(controlfile),command!=EOF) {760switch (command) {761case 't': /* Translate */762skipws(controlfile);763firstch=readTchar(controlfile);764if ((dashcheck=Zgetc(controlfile))=='-') {765lastch=readTchar(controlfile);766}767else {768Zungetc(dashcheck,controlfile);769lastch=firstch;770}771skipws(controlfile);772offset=readTchar(controlfile)-firstch;773skiptoeol(controlfile);774(*commandlistend) = (comnode*)myalloc(sizeof(comnode));775(*commandlistend)->thecommand = 1;776(*commandlistend)->rangelo = firstch;777(*commandlistend)->rangehi = lastch;778(*commandlistend)->offset = offset;779commandlistend = &(*commandlistend)->next;780(*commandlistend) = NULL;781break;782case '0': case '1': case '2': case '3': case '4':783case '5': case '6': case '7': case '8': case '9':784case '-':785/* Mapping table entry */786Zungetc(command,controlfile);787readnum(controlfile,&firstch);788skipws(controlfile);789readnum(controlfile,&lastch);790offset=lastch-firstch;791lastch=firstch;792skiptoeol(controlfile);793(*commandlistend) = (comnode*)myalloc(sizeof(comnode));794(*commandlistend)->thecommand = 1;795(*commandlistend)->rangelo = firstch;796(*commandlistend)->rangehi = lastch;797(*commandlistend)->offset = offset;798commandlistend = &(*commandlistend)->next;799(*commandlistend) = NULL;800break;801case 'f': /* freeze */802skiptoeol(controlfile);803(*commandlistend) = (comnode*)myalloc(sizeof(comnode));804(*commandlistend)->thecommand = 0;805commandlistend = &(*commandlistend)->next;806(*commandlistend) = NULL;807break;808case 'b': /* DBCS input mode */809multibyte = 1;810break;811case 'u': /* UTF-8 input mode */812multibyte = 2;813break;814case 'h': /* HZ input mode */815multibyte = 3;816break;817case 'j': /* Shift-JIS input mode */818multibyte = 4;819break;820case 'g': /* ISO 2022 character set choices */821multibyte = 0;822skipws(controlfile);823command=Zgetc(controlfile);824switch (command) {825case '0': /* define G0 charset */826charset(0, controlfile);827break;828case '1': /* set G1 charset */829charset(1, controlfile);830break;831case '2': /* set G2 charset */832charset(2, controlfile);833break;834case '3': /* set G3 charset */835charset(3, controlfile);836break;837case 'l': case 'L': /* define left half */838skipws(controlfile);839gl = Zgetc(controlfile) - '0';840skiptoeol(controlfile);841break;842case 'r': case 'R': /* define right half */843skipws(controlfile);844gr = Zgetc(controlfile) - '0';845skiptoeol(controlfile);846break;847default: /* meaningless "g" command */848skiptoeol(controlfile);849}850case '\r': case '\n': /* blank line */851break;852default: /* Includes '#' */853skiptoeol(controlfile);854}855}856Zclose(controlfile);857}858859860/****************************************************************************861862readcontrolfiles863864Reads in the controlfiles names in cfilelist. Uses readcontrol.865Called in main().866867****************************************************************************/868869void readcontrolfiles()870{871cfnamenode *cfnptr;872873for (cfnptr=cfilelist;cfnptr!=NULL;cfnptr=cfnptr->next) {874readcontrol(cfnptr->thename);875}876}877878879/****************************************************************************880881clearcfilelist882883Clears the control file list. Assumes thename does not need freeing.884885****************************************************************************/886887void clearcfilelist()888{889cfnamenode *cfnptr1,*cfnptr2;890891cfnptr1 = cfilelist;892while (cfnptr1 != NULL) {893cfnptr2 = cfnptr1->next;894free(cfnptr1);895cfnptr1 = cfnptr2;896}897cfilelist = NULL;898cfilelistend = &cfilelist;899}900901902/****************************************************************************903904getparams905906Handles all command-line parameters. Puts all parameters within907bounds.908909****************************************************************************/910911void getparams()912{913extern char *optarg;914extern int optind;915int c; /* "Should" be a char -- need int for "!= -1" test*/916int columns,infoprint;917char *controlname,*env;918919if ((myname = strrchr(Myargv[0],DIRSEP))!=NULL) {920myname++;921}922else {923myname = Myargv[0];924}925fontdirname = DEFAULTFONTDIR;926env = getenv("FIGLET_FONTDIR");927if (env!=NULL) {928fontdirname = env;929}930fontname = DEFAULTFONTFILE;931cfilelist = NULL;932cfilelistend = &cfilelist;933commandlist = NULL;934commandlistend = &commandlist;935smushoverride = SMO_NO;936deutschflag = 0;937justification = -1;938right2left = -1;939paragraphflag = 0;940infoprint = -1;941cmdinput = 0;942outputwidth = DEFAULTCOLUMNS;943gn[1] = 0x80;944gr = 1;945while ((c = getopt(Myargc,Myargv,"ADEXLRI:xlcrpntvm:w:d:f:C:NFskSWo"))!= -1) {946/* Note: -F is not a legal option -- prints a special err message. */947switch (c) {948case 'A':949cmdinput = 1;950break;951case 'D':952deutschflag = 1;953break;954case 'E':955deutschflag = 0;956break;957case 'X':958right2left = -1;959break;960case 'L':961right2left = 0;962break;963case 'R':964right2left = 1;965break;966case 'x':967justification = -1;968break;969case 'l':970justification = 0;971break;972case 'c':973justification = 1;974break;975case 'r':976justification = 2;977break;978case 'p':979paragraphflag = 1;980break;981case 'n':982paragraphflag = 0;983break;984case 's':985smushoverride = SMO_NO;986break;987case 'k':988smushmode = SM_KERN;989smushoverride = SMO_YES;990break;991case 'S':992smushmode = SM_SMUSH;993smushoverride = SMO_FORCE;994break;995case 'o':996smushmode = SM_SMUSH;997smushoverride = SMO_YES;998break;999case 'W':1000smushmode = 0;1001smushoverride = SMO_YES;1002break;1003case 't':1004#ifdef TIOCGWINSZ1005columns = get_columns();1006if (columns>0) {1007outputwidth = columns;1008}1009#else /* ifdef TIOCGWINSZ */1010fprintf(stderr,1011"%s: \"-t\" is disabled, since ioctl is not fully implemented.\n",1012myname);1013#endif /* ifdef TIOCGWINSZ */1014break;1015case 'v':1016infoprint = 0;1017break;1018case 'I':1019infoprint = atoi(optarg);1020break;1021case 'm':1022smushmode = atoi(optarg);1023if (smushmode < -1) {1024smushoverride = SMO_NO;1025break;1026}1027if (smushmode == 0) smushmode = SM_KERN;1028else if (smushmode == -1) smushmode = 0;1029else smushmode = (smushmode & 63) | SM_SMUSH;1030smushoverride = SMO_YES;1031break;1032case 'w':1033columns = atoi(optarg);1034if (columns>0) {1035outputwidth = columns;1036}1037break;1038case 'd':1039fontdirname = optarg;1040break;1041case 'f':1042fontname = optarg;1043if (suffixcmp(fontname,FONTFILESUFFIX)) {1044fontname[MYSTRLEN(fontname)-FSUFFIXLEN] = '\0';1045}1046#ifdef TLF_FONTS1047else if (suffixcmp(fontname,TOILETFILESUFFIX)) {1048fontname[MYSTRLEN(fontname)-TSUFFIXLEN] = '\0';1049}1050#endif1051break;1052case 'C':1053controlname = optarg;1054if (suffixcmp(controlname, CONTROLFILESUFFIX)) {1055controlname[MYSTRLEN(controlname)-CSUFFIXLEN] = '\0';1056}1057(*cfilelistend) = (cfnamenode*)myalloc(sizeof(cfnamenode));1058(*cfilelistend)->thename = controlname;1059cfilelistend = &(*cfilelistend)->next;1060(*cfilelistend) = NULL;1061break;1062case 'N':1063clearcfilelist();1064multibyte = 0;1065gn[0] = 0;1066gn[1] = 0x80;1067gn[2] = gn[3] = 0;1068gndbl[0] = gndbl[1] = gndbl[2] = gndbl[3] = 0;1069gl = 0;1070gr = 1;1071break;1072case 'F': /* Not a legal option */1073fprintf(stderr,"%s: illegal option -- F\n",myname);1074printusage(stderr);1075fprintf(stderr,"\nBecause of numerous incompatibilities, the");1076fprintf(stderr," \"-F\" option has been\n");1077fprintf(stderr,"removed. It has been replaced by the \"figlist\"");1078fprintf(stderr," program, which is now\n");1079fprintf(stderr,"included in the basic FIGlet package. \"figlist\"");1080fprintf(stderr," is also available\n");1081fprintf(stderr,"from http://www.figlet.org/");1082fprintf(stderr,"under UNIX utilities.\n");1083exit(1);1084break;1085default:1086printusage(stderr);1087exit(1);1088}1089}1090if (optind!=Myargc) cmdinput = 1; /* force cmdinput if more arguments */1091outlinelenlimit = outputwidth-1;1092if (infoprint>=0) {1093printinfo(infoprint);1094exit(0);1095}1096}109710981099/****************************************************************************11001101clearline11021103Clears both the input (inchrline) and output (outputline) storage.11041105****************************************************************************/11061107void clearline()1108{1109int i;11101111for (i=0;i<charheight;i++) {1112outputline[i][0] = '\0';1113}1114outlinelen = 0;1115inchrlinelen = 0;1116}111711181119/****************************************************************************11201121readfontchar11221123Reads a font character from the font file, and places it in a1124newly-allocated entry in the list.11251126****************************************************************************/11271128void readfontchar(file,theord)1129ZFILE *file;1130inchr theord;1131{1132int row,k;1133char templine[MAXLEN+1];1134outchr endchar, outline[MAXLEN+1];1135fcharnode *fclsave;11361137fclsave = fcharlist;1138fcharlist = (fcharnode*)myalloc(sizeof(fcharnode));1139fcharlist->ord = theord;1140fcharlist->thechar = (outchr**)myalloc(sizeof(outchr*)*charheight);1141fcharlist->next = fclsave;11421143outline[0] = 0;11441145for (row=0;row<charheight;row++) {1146if (myfgets(templine,MAXLEN,file)==NULL) {1147templine[0] = '\0';1148}1149#ifdef TLF_FONTS1150utf8_to_wchar(templine,MAXLEN,outline,MAXLEN,0);1151#else1152strcpy(outline,templine);1153#endif1154k = STRLEN(outline)-1;1155while (k>=0 && ISSPACE(outline[k])) { /* remove trailing spaces */1156k--;1157}1158if (k>=0) {1159endchar = outline[k]; /* remove endmarks */1160while (k>=0 && outline[k]==endchar) {1161k--;1162}1163}1164outline[k+1] = '\0';1165fcharlist->thechar[row] = (outchr*)myalloc(sizeof(outchr)*(STRLEN(outline)+1));1166STRCPY(fcharlist->thechar[row],outline);1167}1168}116911701171/****************************************************************************11721173readfont11741175Allocates memory, initializes variables, and reads in the font.1176Called near beginning of main().11771178****************************************************************************/11791180void readfont()1181{1182int i,row,numsread;1183inchr theord;1184int maxlen,cmtlines,ffright2left;1185int smush,smush2;1186char fileline[MAXLEN+1],magicnum[5];1187ZFILE *fontfile;11881189fontfile = FIGopen(fontname,FONTFILESUFFIX);1190#ifdef TLF_FONTS1191if (fontfile==NULL) {1192fontfile = FIGopen(fontname,TOILETFILESUFFIX);1193if(fontfile) toiletfont = 1;1194}1195#endif11961197if (fontfile==NULL) {1198fprintf(stderr,"%s: %s: Unable to open font file\n",myname,fontname);1199exit(1);1200}12011202readmagic(fontfile,magicnum);1203if (myfgets(fileline,MAXLEN,fontfile)==NULL) {1204fileline[0] = '\0';1205}1206if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) {1207skiptoeol(fontfile);1208}1209numsread = sscanf(fileline,"%*c%c %d %*d %d %d %d %d %d",1210&hardblank,&charheight,&maxlen,&smush,&cmtlines,1211&ffright2left,&smush2);12121213if (maxlen > MAXLEN) {1214fprintf(stderr,"%s: %s: character is too wide\n",myname,fontname);1215exit(1);1216}1217#ifdef TLF_FONTS1218if ((!toiletfont && strcmp(magicnum,FONTFILEMAGICNUMBER)) ||1219(toiletfont && strcmp(magicnum,TOILETFILEMAGICNUMBER)) || numsread<5) {1220#else1221if (strcmp(magicnum,FONTFILEMAGICNUMBER) || numsread<5) {1222#endif1223fprintf(stderr,"%s: %s: Not a FIGlet 2 font file\n",myname,fontname);1224exit(1);1225}1226for (i=1;i<=cmtlines;i++) {1227skiptoeol(fontfile);1228}12291230if (numsread<6) {1231ffright2left = 0;1232}12331234if (numsread<7) { /* if no smush2, decode smush into smush2 */1235if (smush == 0) smush2 = SM_KERN;1236else if (smush < 0) smush2 = 0;1237else smush2 = (smush & 31) | SM_SMUSH;1238}12391240if (charheight<1) {1241charheight = 1;1242}12431244if (maxlen<1) {1245maxlen = 1;1246}12471248maxlen += 100; /* Give ourselves some extra room */12491250if (smushoverride == SMO_NO)1251smushmode = smush2;1252else if (smushoverride == SMO_FORCE)1253smushmode |= smush2;12541255if (right2left<0) {1256right2left = ffright2left;1257}12581259if (justification<0) {1260justification = 2*right2left;1261}12621263/* Allocate "missing" character */1264fcharlist = (fcharnode*)myalloc(sizeof(fcharnode));1265fcharlist->ord = 0;1266fcharlist->thechar = (outchr**)myalloc(sizeof(outchr*)*charheight);1267fcharlist->next = NULL;1268for (row=0;row<charheight;row++) {1269fcharlist->thechar[row] = (outchr*)myalloc(sizeof(outchr));1270fcharlist->thechar[row][0] = '\0';1271}1272for (theord=' ';theord<='~';theord++) {1273readfontchar(fontfile,theord);1274}1275for (theord=0;theord<=6;theord++) {1276readfontchar(fontfile,deutsch[theord]);1277}1278while (myfgets(fileline,maxlen+1,fontfile)==NULL?0:1279sscanf(fileline,"%li",&theord)==1) {1280readfontchar(fontfile,theord);1281}1282Zclose(fontfile);1283}128412851286/****************************************************************************12871288linealloc12891290Allocates & clears outputline, inchrline. Sets inchrlinelenlimit.1291Called near beginning of main().12921293****************************************************************************/12941295void linealloc()1296{1297int row;12981299outputline = (outchr**)myalloc(sizeof(outchr*)*charheight);1300for (row=0;row<charheight;row++) {1301outputline[row] = (outchr*)myalloc(sizeof(outchr)*(outlinelenlimit+1));1302}1303inchrlinelenlimit = outputwidth*4+100;1304inchrline = (inchr*)myalloc(sizeof(inchr)*(inchrlinelenlimit+1));1305clearline();1306}130713081309/****************************************************************************13101311getletter13121313Sets currchar to point to the font entry for the given character.1314Sets currcharwidth to the width of this character.13151316****************************************************************************/13171318void getletter(c)1319inchr c;1320{1321fcharnode *charptr;13221323for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=c;1324charptr=charptr->next) ;1325if (charptr!=NULL) {1326currchar = charptr->thechar;1327}1328else {1329for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=0;1330charptr=charptr->next) ;1331currchar = charptr->thechar;1332}1333previouscharwidth = currcharwidth;1334currcharwidth = STRLEN(currchar[0]);1335}133613371338/****************************************************************************13391340smushem13411342Given 2 characters, attempts to smush them into 1, according to1343smushmode. Returns smushed character or '\0' if no smushing can be1344done.13451346smushmode values are sum of following (all values smush blanks):13471: Smush equal chars (not hardblanks)13482: Smush '_' with any char in hierarchy below13494: hierarchy: "|", "/\", "[]", "{}", "()", "<>"1350Each class in hier. can be replaced by later class.13518: [ + ] -> |, { + } -> |, ( + ) -> |135216: / + \ -> X, > + < -> X (only in that order)135332: hardblank + hardblank -> hardblank13541355****************************************************************************/13561357outchr smushem(lch,rch)1358outchr lch,rch;1359{1360if (lch==' ') return rch;1361if (rch==' ') return lch;13621363if (previouscharwidth<2 || currcharwidth<2) return '\0';1364/* Disallows overlapping if the previous character */1365/* or the current character has a width of 1 or zero. */13661367if ((smushmode & SM_SMUSH) == 0) return '\0'; /* kerning */13681369if ((smushmode & 63) == 0) {1370/* This is smushing by universal overlapping. */1371if (lch==' ') return rch;1372if (rch==' ') return lch;1373if (lch==hardblank) return rch;1374if (rch==hardblank) return lch;1375/* Above four lines ensure overlapping preference to */1376/* visible characters. */1377if (right2left==1) return lch;1378/* Above line ensures that the dominant (foreground) */1379/* fig-character for overlapping is the latter in the */1380/* user's text, not necessarily the rightmost character. */1381return rch;1382/* Occurs in the absence of above exceptions. */1383}13841385if (smushmode & SM_HARDBLANK) {1386if (lch==hardblank && rch==hardblank) return lch;1387}13881389if (lch==hardblank || rch==hardblank) return '\0';13901391if (smushmode & SM_EQUAL) {1392if (lch==rch) return lch;1393}13941395if (smushmode & SM_LOWLINE) {1396if (lch=='_' && strchr("|/\\[]{}()<>",rch)) return rch;1397if (rch=='_' && strchr("|/\\[]{}()<>",lch)) return lch;1398}13991400if (smushmode & SM_HIERARCHY) {1401if (lch=='|' && strchr("/\\[]{}()<>",rch)) return rch;1402if (rch=='|' && strchr("/\\[]{}()<>",lch)) return lch;1403if (strchr("/\\",lch) && strchr("[]{}()<>",rch)) return rch;1404if (strchr("/\\",rch) && strchr("[]{}()<>",lch)) return lch;1405if (strchr("[]",lch) && strchr("{}()<>",rch)) return rch;1406if (strchr("[]",rch) && strchr("{}()<>",lch)) return lch;1407if (strchr("{}",lch) && strchr("()<>",rch)) return rch;1408if (strchr("{}",rch) && strchr("()<>",lch)) return lch;1409if (strchr("()",lch) && strchr("<>",rch)) return rch;1410if (strchr("()",rch) && strchr("<>",lch)) return lch;1411}14121413if (smushmode & SM_PAIR) {1414if (lch=='[' && rch==']') return '|';1415if (rch=='[' && lch==']') return '|';1416if (lch=='{' && rch=='}') return '|';1417if (rch=='{' && lch=='}') return '|';1418if (lch=='(' && rch==')') return '|';1419if (rch=='(' && lch==')') return '|';1420}14211422if (smushmode & SM_BIGX) {1423if (lch=='/' && rch=='\\') return '|';1424if (rch=='/' && lch=='\\') return 'Y';1425if (lch=='>' && rch=='<') return 'X';1426/* Don't want the reverse of above to give 'X'. */1427}14281429return '\0';1430}143114321433/****************************************************************************14341435smushamt14361437Returns the maximum amount that the current character can be smushed1438into the current line.14391440****************************************************************************/14411442int smushamt()1443{1444int maxsmush,amt;1445int row,linebd,charbd;1446outchr ch1,ch2;14471448if ((smushmode & (SM_SMUSH | SM_KERN)) == 0) {1449return 0;1450}1451maxsmush = currcharwidth;1452for (row=0;row<charheight;row++) {1453if (right2left) {1454if (maxsmush>STRLEN(outputline[row])) {1455maxsmush=STRLEN(outputline[row]);1456}1457for (charbd=STRLEN(currchar[row]);1458ch1=currchar[row][charbd],(charbd>0&&(!ch1||ch1==' '));charbd--) ;1459for (linebd=0;ch2=outputline[row][linebd],ch2==' ';linebd++) ;1460amt = linebd+currcharwidth-1-charbd;1461}1462else {1463for (linebd=STRLEN(outputline[row]);1464ch1 = outputline[row][linebd],(linebd>0&&(!ch1||ch1==' '));linebd--) ;1465for (charbd=0;ch2=currchar[row][charbd],ch2==' ';charbd++) ;1466amt = charbd+outlinelen-1-linebd;1467}1468if (!ch1||ch1==' ') {1469amt++;1470}1471else if (ch2) {1472if (smushem(ch1,ch2)!='\0') {1473amt++;1474}1475}1476if (amt<maxsmush) {1477maxsmush = amt;1478}1479}1480return maxsmush;1481}148214831484/****************************************************************************14851486addchar14871488Attempts to add the given character onto the end of the current line.1489Returns 1 if this can be done, 0 otherwise.14901491****************************************************************************/14921493int addchar(c)1494inchr c;1495{1496int smushamount,row,k,column;1497outchr *templine;14981499getletter(c);1500smushamount = smushamt();1501if (outlinelen+currcharwidth-smushamount>outlinelenlimit1502||inchrlinelen+1>inchrlinelenlimit) {1503return 0;1504}15051506templine = (outchr*)myalloc(sizeof(outchr)*(outlinelenlimit+1));1507for (row=0;row<charheight;row++) {1508if (right2left) {1509STRCPY(templine,currchar[row]);1510for (k=0;k<smushamount;k++) {1511templine[currcharwidth-smushamount+k] =1512smushem(templine[currcharwidth-smushamount+k],outputline[row][k]);1513}1514STRCAT(templine,outputline[row]+smushamount);1515STRCPY(outputline[row],templine);1516}1517else {1518for (k=0;k<smushamount;k++) {1519column = outlinelen-smushamount+k;1520if (column < 0) {1521column = 0;1522}1523outputline[row][column] =1524smushem(outputline[row][column],currchar[row][k]);1525}1526STRCAT(outputline[row],currchar[row]+smushamount);1527}1528}1529free(templine);1530outlinelen = STRLEN(outputline[0]);1531inchrline[inchrlinelen++] = c;1532return 1;1533}153415351536/****************************************************************************15371538putstring15391540Prints out the given null-terminated string, substituting blanks1541for hardblanks. If outputwidth is 1, prints the entire string;1542otherwise prints at most outputwidth-1 characters. Prints a newline1543at the end of the string. The string is left-justified, centered or1544right-justified (taking outputwidth as the screen width) if1545justification is 0, 1 or 2, respectively.15461547****************************************************************************/15481549void putstring(string)1550outchr *string;1551{1552int i,len;1553char c[10];1554#ifdef TLF_FONTS1555size_t size;1556wchar_t wc[2];1557#endif15581559len = STRLEN(string);1560if (outputwidth>1) {1561if (len>outputwidth-1) {1562len = outputwidth-1;1563}1564if (justification>0) {1565for (i=1;(3-justification)*i+len+justification-2<outputwidth;i++) {1566putchar(' ');1567}1568}1569}1570for (i=0;i<len;i++) {1571#ifdef TLF_FONTS1572wc[0] = string[i];1573wc[1] = 0;1574size = wchar_to_utf8(wc,1,c,10,0);1575if(size==1) {1576if(c[0]==hardblank) {1577c[0] = ' ';1578}1579}1580c[size] = 0;1581printf("%s",c);1582#else1583putchar(string[i]==hardblank?' ':string[i]);1584#endif1585}1586putchar('\n');1587}158815891590/****************************************************************************15911592printline15931594Prints outputline using putstring, then clears the current line.15951596****************************************************************************/15971598void printline()1599{1600int i;16011602for (i=0;i<charheight;i++) {1603putstring(outputline[i]);1604}1605clearline();1606}160716081609/****************************************************************************16101611splitline16121613Splits inchrline at the last word break (bunch of consecutive blanks).1614Makes a new line out of the first part and prints it using1615printline. Makes a new line out of the second part and returns.16161617****************************************************************************/16181619void splitline()1620{1621int i,gotspace,lastspace,len1,len2;1622inchr *part1,*part2;16231624part1 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));1625part2 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));1626gotspace = 0;1627lastspace = inchrlinelen-1;1628for (i=inchrlinelen-1;i>=0;i--) {1629if (!gotspace && inchrline[i]==' ') {1630gotspace = 1;1631lastspace = i;1632}1633if (gotspace && inchrline[i]!=' ') {1634break;1635}1636}1637len1 = i+1;1638len2 = inchrlinelen-lastspace-1;1639for (i=0;i<len1;i++) {1640part1[i] = inchrline[i];1641}1642for (i=0;i<len2;i++) {1643part2[i] = inchrline[lastspace+1+i];1644}1645clearline();1646for (i=0;i<len1;i++) {1647addchar(part1[i]);1648}1649printline();1650for (i=0;i<len2;i++) {1651addchar(part2[i]);1652}1653free(part1);1654free(part2);1655}165616571658/****************************************************************************16591660handlemapping16611662Given an input character (type inchr), executes re-mapping commands1663read from control files. Returns re-mapped character (inchr).16641665****************************************************************************/16661667inchr handlemapping(c)1668inchr c;1669{1670comnode *cmptr;16711672cmptr=commandlist;1673while (cmptr!=NULL) {1674if (cmptr->thecommand ?1675(c >= cmptr->rangelo && c <= cmptr->rangehi) : 0) {1676c += cmptr->offset;1677while(cmptr!=NULL ? cmptr->thecommand : 0) {1678cmptr=cmptr->next;1679}1680}1681else {1682cmptr=cmptr->next;1683}1684}1685return c;1686}16871688/****************************************************************************16891690Agetchar16911692Replacement to getchar().1693Acts exactly like getchar if -A is NOT specified,1694else obtains input from All remaining command line words.16951696****************************************************************************/16971698int Agetchar()1699{1700extern int optind; /* current argv[] element under study */1701static int AgetMode = 0; /* >= 0 for displacement into argv[n], <0 EOF */1702char *arg; /* pointer to active character */1703int c; /* current character */17041705if ( ! cmdinput ) /* is -A active? */1706return( getchar() ); /* no: return stdin character */17071708if ( AgetMode < 0 || optind >= Myargc ) /* EOF is sticky: */1709return( EOF ); /* **ensure it now and forever more */17101711/* find next character */1712arg = Myargv[optind]; /* pointer to active arg */1713c = arg[AgetMode++]&0xFF; /* get appropriate char of arg */17141715if ( ! c ) /* at '\0' that terminates word? */1716{ /* at end of word: return ' ' if normal word, '\n' if empty */1717c = ' '; /* suppose normal word and return blank */1718if ( AgetMode == 1 ) /* if ran out in very 1st char, force \n */1719c = '\n'; /* (allows "hello '' world" to do \n at '') */1720AgetMode = 0; /* return to char 0 in NEXT word */1721if ( ++optind >= Myargc ) /* run up word count and check if at "EOF" */1722{ /* just ran out of arguments */1723c = EOF; /* return EOF */1724AgetMode = -1; /* ensure all future returns return EOF */1725}1726}17271728return( c ); /* return appropriate character */17291730} /* end: Agetchar() */173117321733/****************************************************************************17341735iso202217361737Called by getinchr. Interprets ISO 2022 sequences17381739******************************************************************************/17401741inchr iso2022()1742{1743inchr ch;1744inchr ch2;1745int save_gl;1746int save_gr;17471748ch = Agetchar();1749if (ch == EOF) return ch;1750if (ch == 27) ch = Agetchar() + 0x100; /* ESC x */1751if (ch == 0x100 + '$') ch = Agetchar() + 0x200; /* ESC $ x */1752switch (ch) {1753case 14: /* invoke G1 into GL */1754gl = 1;1755return iso2022();1756case 15: /* invoke G0 into GL */1757gl = 0;1758return iso2022();1759case 142: case 'N' + 0x100: /* invoke G2 into GL for next char */1760save_gl = gl; save_gr = gr;1761gl = gr = 2;1762ch = iso2022();1763gl = save_gl; gr = save_gr;1764return ch;1765case 143: case 'O' + 0x100: /* invoke G3 into GL for next char */1766save_gl = gl; save_gr = gr;1767gl = gr = 3;1768ch = iso2022();1769gl = save_gl; gr = save_gr;1770return ch;1771case 'n' + 0x100: /* invoke G2 into GL */1772gl = 2;1773return iso2022();1774case 'o' + 0x100: /* invoke G3 into GL */1775gl = 3;1776return iso2022();1777case '~' + 0x100: /* invoke G1 into GR */1778gr = 1;1779return iso2022();1780case '}' + 0x100: /* invoke G2 into GR */1781gr = 2;1782return iso2022();1783case '|' + 0x100: /* invoke G3 into GR */1784gr = 3;1785return iso2022();1786case '(' + 0x100: /* set G0 to 94-char set */1787ch = Agetchar();1788if (ch == 'B') ch = 0; /* ASCII */1789gn[0] = ch << 16;1790gndbl[0] = 0;1791return iso2022();1792case ')' + 0x100: /* set G1 to 94-char set */1793ch = Agetchar();1794if (ch == 'B') ch = 0;1795gn[1] = ch << 16;1796gndbl[1] = 0;1797return iso2022();1798case '*' + 0x100: /* set G2 to 94-char set */1799ch = Agetchar();1800if (ch == 'B') ch = 0;1801gn[2] = ch << 16;1802gndbl[2] = 0;1803return iso2022();1804case '+' + 0x100: /* set G3 to 94-char set */1805ch = Agetchar();1806if (ch == 'B') ch = 0;1807gn[3] = ch << 16;1808gndbl[3] = 0;1809return iso2022();1810case '-' + 0x100: /* set G1 to 96-char set */1811ch = Agetchar();1812if (ch == 'A') ch = 0; /* Latin-1 top half */1813gn[1] = (ch << 16) | 0x80;1814gndbl[1] = 0;1815return iso2022();1816case '.' + 0x100: /* set G2 to 96-char set */1817ch = Agetchar();1818if (ch == 'A') ch = 0;1819gn[2] = (ch << 16) | 0x80;1820gndbl[2] = 0;1821return iso2022();1822case '/' + 0x100: /* set G3 to 96-char set */1823ch = Agetchar();1824if (ch == 'A') ch = 0;1825gn[3] = (ch << 16) | 0x80;1826gndbl[3] = 0;1827return iso2022();1828case '(' + 0x200: /* set G0 to 94 x 94 char set */1829ch = Agetchar();1830gn[0] = ch << 16;1831gndbl[0] = 1;1832return iso2022();1833case ')' + 0x200: /* set G1 to 94 x 94 char set */1834ch = Agetchar();1835gn[1] = ch << 16;1836gndbl[1] = 1;1837return iso2022();1838case '*' + 0x200: /* set G2 to 94 x 94 char set */1839ch = Agetchar();1840gn[2] = ch << 16;1841gndbl[2] = 1;1842return iso2022();1843case '+' + 0x200: /* set G3 to 94 x 94 char set */1844ch = Agetchar();1845gn[3] = ch << 16;1846gndbl[3] = 1;1847return iso2022();1848default:1849if (ch & 0x200) { /* set G0 to 94 x 94 char set (deprecated) */1850gn[0] = (ch & ~0x200) << 16;1851gndbl[0] = 1;1852return iso2022();1853}1854}18551856if (ch >= 0x21 && ch <= 0x7E) { /* process GL */1857if (gndbl[gl]) {1858ch2 = Agetchar();1859return gn[gl] | (ch << 8) | ch2;1860}1861else return gn[gl] | ch;1862}1863else if (ch >= 0xA0 && ch <= 0xFF) { /* process GR */1864if (gndbl[gr]) {1865ch2 = Agetchar();1866return gn[gr] | (ch << 8) | ch2;1867}1868else return gn[gr] | (ch & ~0x80);1869}1870else return ch;1871}18721873/****************************************************************************18741875ungetinchr18761877Called by main. Pushes back an "inchr" to be read by getinchr1878on the next call.18791880******************************************************************************/1881inchr getinchr_buffer;1882int getinchr_flag;18831884inchr ungetinchr(c)1885inchr c;1886{1887getinchr_buffer = c;1888getinchr_flag = 1;1889return c;1890}18911892/*****************************************************************************18931894getinchr18951896Called by main. Processes multibyte characters. Invokes Agetchar.1897If multibyte = 0, ISO 2022 mode (see iso2022 routine).1898If multibyte = 1, double-byte mode (0x00-0x7f bytes are characters,18990x80-0xFF bytes are first byte of a double-byte character).1900If multibyte = 2, Unicode UTF-8 mode (0x00-0x7F bytes are characters,19010x80-0xBF bytes are nonfirst byte of a multibyte character,19020xC0-0xFD bytes are first byte of a multibyte character,19030xFE-0xFF bytes are errors (all errors return code 0x0080)).1904If multibyte = 3, HZ mode ("~{" starts double-byte mode, "}~" ends it,1905"~~" is a tilde, "~x" for all other x is ignored).1906If multibyte = 4, Shift-JIS mode (0x80-0x9F and 0xE0-0xEF are first byte1907of a double-byte character, all other bytes are characters).190819091910*****************************************************************************/19111912inchr getinchr()1913{1914int ch, ch2, ch3, ch4, ch5, ch6;19151916if (getinchr_flag) {1917getinchr_flag = 0;1918return getinchr_buffer;1919}19201921switch(multibyte) {1922case 0: /* single-byte */1923return iso2022();1924case 1: /* DBCS */1925ch = Agetchar();1926if ((ch >= 0x80 && ch <= 0x9F) ||1927(ch >= 0xE0 && ch <= 0xEF)) {1928ch = (ch << 8) + Agetchar();1929}1930return ch;1931case 2: /* UTF-8 */1932ch = Agetchar();1933if (ch < 0x80) return ch; /* handles EOF, too */1934if (ch < 0xC0 || ch > 0xFD)1935return 0x0080; /* illegal first character */1936ch2 = Agetchar() & 0x3F;1937if (ch < 0xE0) return ((ch & 0x1F) << 6) + ch2;1938ch3 = Agetchar() & 0x3F;1939if (ch < 0xF0)1940return ((ch & 0x0F) << 12) + (ch2 << 6) + ch3;1941ch4 = Agetchar() & 0x3F;1942if (ch < 0xF8)1943return ((ch & 0x07) << 18) + (ch2 << 12) + (ch3 << 6) + ch4;1944ch5 = Agetchar() & 0x3F;1945if (ch < 0xFC)1946return ((ch & 0x03) << 24) + (ch2 << 18) + (ch3 << 12) +1947(ch4 << 6) + ch5;1948ch6 = Agetchar() & 0x3F;1949return ((ch & 0x01) << 30) + (ch2 << 24) + (ch3 << 18) +1950(ch4 << 12) + (ch5 << 6) + ch6;1951case 3: /* HZ */1952ch = Agetchar();1953if (ch == EOF) return ch;1954if (hzmode) {1955ch = (ch << 8) + Agetchar();1956if (ch == ('}' << 8) + '~') {1957hzmode = 0;1958return getinchr();1959}1960return ch;1961}1962else if (ch == '~') {1963ch = Agetchar();1964if (ch == '{') {1965hzmode = 1;1966return getinchr();1967}1968else if (ch == '~') {1969return ch;1970}1971else {1972return getinchr();1973}1974}1975else return ch;1976case 4: /* Shift-JIS */1977ch = Agetchar();1978if ((ch >= 0x80 && ch <= 0x9F) ||1979(ch >= 0xE0 && ch <= 0xEF)) {1980ch = (ch << 8) + Agetchar();1981}1982return ch;1983default:1984return 0x80;1985}1986}19871988/****************************************************************************19891990main19911992The main program, of course.1993Reads characters 1 by 1 from stdin, and makes lines out of them using1994addchar. Handles line breaking, (which accounts for most of the1995complexity in this function).19961997****************************************************************************/19981999int main(argc,argv)2000int argc;2001char *argv[];2002{2003inchr c,c2;2004int i;2005int last_was_eol_flag;2006/*---------------------------------------------------------------------------2007wordbreakmode:2008-1: /^$/ and blanks are to be absorbed (when line break was forced2009by a blank or character larger than outlinelenlimit)20100: /^ *$/ and blanks are not to be absorbed20111: /[^ ]$/ no word break yet20122: /[^ ] *$/20133: /[^ ]$/ had a word break2014---------------------------------------------------------------------------*/2015int wordbreakmode;2016int char_not_added;20172018Myargc = argc;2019Myargv = argv;2020getparams();2021readcontrolfiles();2022readfont();2023linealloc();20242025wordbreakmode = 0;2026last_was_eol_flag = 0;20272028#ifdef TLF_FONTS2029toiletfont = 0;2030#endif20312032while ((c = getinchr())!=EOF) {20332034if (c=='\n'&¶graphflag&&!last_was_eol_flag) {2035ungetinchr(c2 = getinchr());2036c = ((isascii(c2)&&isspace(c2))?'\n':' ');2037}2038last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' ');20392040if (deutschflag) {2041if (c>='[' && c<=']') {2042c = deutsch[c-'['];2043}2044else if (c >='{' && c <= '~') {2045c = deutsch[c-'{'+3];2046}2047}20482049c = handlemapping(c);20502051if (isascii(c)&&isspace(c)) {2052c = (c=='\t'||c==' ') ? ' ' : '\n';2053}20542055if ((c>'\0' && c<' ' && c!='\n') || c==127) continue;20562057/*2058Note: The following code is complex and thoroughly tested.2059Be careful when modifying!2060*/20612062do {2063char_not_added = 0;20642065if (wordbreakmode== -1) {2066if (c==' ') {2067break;2068}2069else if (c=='\n') {2070wordbreakmode = 0;2071break;2072}2073wordbreakmode = 0;2074}20752076if (c=='\n') {2077printline();2078wordbreakmode = 0;2079}20802081else if (addchar(c)) {2082if (c!=' ') {2083wordbreakmode = (wordbreakmode>=2)?3:1;2084}2085else {2086wordbreakmode = (wordbreakmode>0)?2:0;2087}2088}20892090else if (outlinelen==0) {2091for (i=0;i<charheight;i++) {2092if (right2left && outputwidth>1) {2093putstring(currchar[i]+STRLEN(currchar[i])-outlinelenlimit);2094}2095else {2096putstring(currchar[i]);2097}2098}2099wordbreakmode = -1;2100}21012102else if (c==' ') {2103if (wordbreakmode==2) {2104splitline();2105}2106else {2107printline();2108}2109wordbreakmode = -1;2110}21112112else {2113if (wordbreakmode>=2) {2114splitline();2115}2116else {2117printline();2118}2119wordbreakmode = (wordbreakmode==3)?1:0;2120char_not_added = 1;2121}21222123} while (char_not_added);2124}21252126if (outlinelen!=0) {2127printline();2128}2129return 0;2130}213121322133