Changeset View
Changeset View
Standalone View
Standalone View
externals/figlet/figlet.c
- This file was added.
| /**************************************************************************** | |||||
| FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai | |||||
| FIGlet Copyright 1996, 1997, 1998, 1999, 2000, 2001 John Cowan | |||||
| FIGlet Copyright 2002 Christiaan Keet | |||||
| FIGlet Copyright 2011, 2012 Claudio Matsuoka | |||||
| Portions written by Paul Burton and Christiaan Keet | |||||
| Internet: <info@figlet.org> | |||||
| FIGlet, along with the various FIGlet fonts and documentation, is | |||||
| copyrighted under the provisions of the New BSD License (3-clause) | |||||
| (as listed in the file "LICENSE" which is included in this package) | |||||
| ****************************************************************************/ | |||||
| #define DATE "31 May 2012" | |||||
| #define VERSION "2.2.5" | |||||
| #define VERSION_INT 20205 | |||||
| /* FIGlet (Frank, Ian & Glenn's Letters) */ | |||||
| /* by Glenn Chappell */ | |||||
| /* Apr 1991 */ | |||||
| /* Automatic file addition by Ian Chai May 1991 */ | |||||
| /* Punctuation and numbers addition by Ian Chai Jan 1993 */ | |||||
| /* Full ASCII by Glenn Chappell Feb 1993 */ | |||||
| /* Line-breaking, general rewrite by Glenn Chappell Mar 1993 */ | |||||
| /* Hard blanks by Glenn Chappell Apr 1993 */ | |||||
| /* Release 2.0 5 Aug 1993 */ | |||||
| /* Right-to-left printing, extended char set by Glenn Chappell Dec 1993 */ | |||||
| /* Control files by Glenn Chappell Feb 1994 */ | |||||
| /* Release 2.1 12 Aug 1994 */ | |||||
| /* Release 2.1.1 25 Aug 1994 */ | |||||
| /* Release 2.1.2 by Gilbert (Mad Programmer) Healton: Add -A command line | |||||
| option. Sept 8, 1996 */ | |||||
| /* Release 2.2 by John Cowan: multibyte inputs, compressed fonts, | |||||
| mapping tables, kerning/smushing options. */ | |||||
| /* Release 2.2.1 by Christiaan Keet: minor updates including readmes | |||||
| FAQs and comments. 13 July 2002. The new official FIGlet website is | |||||
| http://www.figlet.org/ */ | |||||
| /* Release 2.2.2 by Christiaan Keet: License changed from "Artistic License" | |||||
| to "Academic Free License" as agreed by FIGlet authors. 05 July 2005 */ | |||||
| /* Release 2.2.3 by Claudio Matsuoka, 12 Jan 2011: BSD license, fixes */ | |||||
| /* Release 2.2.4 by Claudio Matsuoka, 26 Jan 2011: tlf2 font support */ | |||||
| /* Release 2.2.5 by Claudio Matsuoka, 31 May 2012: flc licensing, minor fixes */ | |||||
| /*--------------------------------------------------------------------------- | |||||
| DEFAULTFONTDIR and DEFAULTFONTFILE should be defined in the Makefile. | |||||
| DEFAULTFONTDIR is the full path name of the directory in which FIGlet | |||||
| will search first for fonts (the ".flf" files). | |||||
| DEFAULTFONTFILE is the filename of the font to be used if no other | |||||
| is specified (standard.flf is recommended, but any other can be | |||||
| used). This file should reside in the directory specified by | |||||
| DEFAULTFONTDIR. | |||||
| ---------------------------------------------------------------------------*/ | |||||
| #ifndef DEFAULTFONTDIR | |||||
| #define DEFAULTFONTDIR "fonts" | |||||
| #endif | |||||
| #ifndef DEFAULTFONTFILE | |||||
| #define DEFAULTFONTFILE "standard.flf" | |||||
| #endif | |||||
| #include <stdio.h> | |||||
| #ifdef __STDC__ | |||||
| #include <stdlib.h> | |||||
| #endif | |||||
| #include <string.h> | |||||
| #include <ctype.h> | |||||
| #include <sys/stat.h> | |||||
| #include <fcntl.h> /* Needed for get_columns */ | |||||
| #if defined(unix) || defined(__unix__) || defined(__APPLE__) | |||||
| #include <unistd.h> | |||||
| #include <sys/ioctl.h> /* Needed for get_columns */ | |||||
| #endif | |||||
| #ifdef TLF_FONTS | |||||
| #include <wchar.h> | |||||
| #include <wctype.h> | |||||
| #include "utf8.h" | |||||
| #endif | |||||
| #include "zipio.h" /* Package for reading compressed files */ | |||||
| #define MYSTRLEN(x) ((int)strlen(x)) /* Eliminate ANSI problem */ | |||||
| #define DIRSEP '/' | |||||
| #define DIRSEP2 '\\' | |||||
| /* Leave alone for Unix and MS-DOS/Windows! | |||||
| Note: '/' also used in filename in get_columns(). */ | |||||
| #define FONTFILESUFFIX ".flf" | |||||
| #define FONTFILEMAGICNUMBER "flf2" | |||||
| #define FSUFFIXLEN MYSTRLEN(FONTFILESUFFIX) | |||||
| #define CONTROLFILESUFFIX ".flc" | |||||
| #define CONTROLFILEMAGICNUMBER "flc2" /* no longer used in 2.2 */ | |||||
| #define CSUFFIXLEN MYSTRLEN(CONTROLFILESUFFIX) | |||||
| #define DEFAULTCOLUMNS 80 | |||||
| #define MAXLEN 255 /* Maximum character width */ | |||||
| /* Add support for Sam Hocevar's TOIlet fonts */ | |||||
| #ifdef TLF_FONTS | |||||
| #define TOILETFILESUFFIX ".tlf" | |||||
| #define TOILETFILEMAGICNUMBER "tlf2" | |||||
| #define TSUFFIXLEN MYSTRLEN(TOILETFILESUFFIX) | |||||
| int toiletfont; /* true if font is a TOIlet TLF font */ | |||||
| #endif | |||||
| /**************************************************************************** | |||||
| Globals dealing with chars that are read | |||||
| ****************************************************************************/ | |||||
| typedef long inchr; /* "char" read from stdin */ | |||||
| inchr *inchrline; /* Alloc'd inchr inchrline[inchrlinelenlimit+1]; */ | |||||
| /* Note: not null-terminated. */ | |||||
| int inchrlinelen,inchrlinelenlimit; | |||||
| inchr deutsch[7] = {196, 214, 220, 228, 246, 252, 223}; | |||||
| /* Latin-1 codes for German letters, respectively: | |||||
| LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut | |||||
| LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut | |||||
| LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut | |||||
| LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut | |||||
| LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut | |||||
| LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut | |||||
| LATIN SMALL LETTER SHARP S = ess-zed | |||||
| */ | |||||
| int hzmode; /* true if reading double-bytes in HZ mode */ | |||||
| int gndbl[4]; /* gndbl[n] is true if Gn is double-byte */ | |||||
| inchr gn[4]; /* Gn character sets: ASCII, Latin-1, none, none */ | |||||
| int gl; /* 0-3 specifies left-half Gn character set */ | |||||
| int gr; /* 0-3 specifies right-half Gn character set */ | |||||
| int Myargc; /* to avoid passing around argc and argv */ | |||||
| char **Myargv; | |||||
| /**************************************************************************** | |||||
| Globals dealing with chars that are written | |||||
| ****************************************************************************/ | |||||
| #ifdef TLF_FONTS | |||||
| typedef wchar_t outchr; /* "char" written to stdout */ | |||||
| #define STRLEN(x) wcslen(x) | |||||
| #define STRCPY(x,y) wcscpy((x),(y)) | |||||
| #define STRCAT(x,y) wcscat((x),(y)) | |||||
| #define ISSPACE(x) iswspace(x) | |||||
| #else | |||||
| typedef char outchr; /* "char" written to stdout */ | |||||
| #define STRLEN(x) MYSTRLEN(x) | |||||
| #define STRCPY(x,y) strcpy((x),(y)) | |||||
| #define STRCAT(x,y) strcat((x),(y)) | |||||
| #define ISSPACE(x) isspace(x) | |||||
| #endif | |||||
| typedef struct fc { | |||||
| inchr ord; | |||||
| outchr **thechar; /* Alloc'd char thechar[charheight][]; */ | |||||
| struct fc *next; | |||||
| } fcharnode; | |||||
| fcharnode *fcharlist; | |||||
| outchr **currchar; | |||||
| int currcharwidth; | |||||
| int previouscharwidth; | |||||
| outchr **outputline; /* Alloc'd char outputline[charheight][outlinelenlimit+1]; */ | |||||
| int outlinelen; | |||||
| /**************************************************************************** | |||||
| Globals dealing with command file storage | |||||
| ****************************************************************************/ | |||||
| typedef struct cfn { | |||||
| char *thename; | |||||
| struct cfn *next; | |||||
| } cfnamenode; | |||||
| cfnamenode *cfilelist,**cfilelistend; | |||||
| typedef struct cm { | |||||
| int thecommand; | |||||
| inchr rangelo; | |||||
| inchr rangehi; | |||||
| inchr offset; | |||||
| struct cm *next; | |||||
| } comnode; | |||||
| comnode *commandlist,**commandlistend; | |||||
| /**************************************************************************** | |||||
| Globals affected by command line options | |||||
| ****************************************************************************/ | |||||
| int deutschflag,justification,paragraphflag,right2left,multibyte; | |||||
| int cmdinput; | |||||
| #define SM_SMUSH 128 | |||||
| #define SM_KERN 64 | |||||
| #define SM_EQUAL 1 | |||||
| #define SM_LOWLINE 2 | |||||
| #define SM_HIERARCHY 4 | |||||
| #define SM_PAIR 8 | |||||
| #define SM_BIGX 16 | |||||
| #define SM_HARDBLANK 32 | |||||
| int smushmode; | |||||
| #define SMO_NO 0 /* no command-line smushmode */ | |||||
| #define SMO_YES 1 /* use command-line smushmode, ignore font smushmode */ | |||||
| #define SMO_FORCE 2 /* logically OR command-line and font smushmodes */ | |||||
| int smushoverride; | |||||
| int outputwidth; | |||||
| int outlinelenlimit; | |||||
| char *fontdirname,*fontname; | |||||
| /**************************************************************************** | |||||
| Globals read from font file | |||||
| ****************************************************************************/ | |||||
| char hardblank; | |||||
| int charheight; | |||||
| /**************************************************************************** | |||||
| Name of program, used in error messages | |||||
| ****************************************************************************/ | |||||
| char *myname; | |||||
| #ifdef TIOCGWINSZ | |||||
| /**************************************************************************** | |||||
| get_columns | |||||
| Determines the number of columns of /dev/tty. Returns the number of | |||||
| columns, or -1 if error. May return 0 if columns unknown. | |||||
| Requires include files <fcntl.h> and <sys/ioctl.h>. | |||||
| by Glenn Chappell & Ian Chai 14 Apr 1993 | |||||
| ****************************************************************************/ | |||||
| int get_columns() | |||||
| { | |||||
| struct winsize ws; | |||||
| int fd,result; | |||||
| if ((fd = open("/dev/tty",O_WRONLY))<0) return -1; | |||||
| result = ioctl(fd,TIOCGWINSZ,&ws); | |||||
| close(fd); | |||||
| return result?-1:ws.ws_col; | |||||
| } | |||||
| #endif /* ifdef TIOCGWINSZ */ | |||||
| /**************************************************************************** | |||||
| myalloc | |||||
| Calls malloc. If malloc returns error, prints error message and | |||||
| quits. | |||||
| ****************************************************************************/ | |||||
| #ifdef __STDC__ | |||||
| char *myalloc(size_t size) | |||||
| #else | |||||
| char *myalloc(size) | |||||
| int size; | |||||
| #endif | |||||
| { | |||||
| char *ptr; | |||||
| #ifndef __STDC__ | |||||
| extern void *malloc(); | |||||
| #endif | |||||
| if ((ptr = (char*)malloc(size))==NULL) { | |||||
| fprintf(stderr,"%s: Out of memory\n",myname); | |||||
| exit(1); | |||||
| } | |||||
| else { | |||||
| return ptr; | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| hasdirsep | |||||
| Returns true if s1 contains a DIRSEP or DIRSEP2 character. | |||||
| ****************************************************************************/ | |||||
| int hasdirsep(s1) | |||||
| char *s1; | |||||
| { | |||||
| if (strchr(s1, DIRSEP)) return 1; | |||||
| else if (strchr(s1, DIRSEP2)) return 1; | |||||
| else return 0; | |||||
| } | |||||
| /**************************************************************************** | |||||
| suffixcmp | |||||
| Returns true if s2 is a suffix of s1; uses case-blind comparison. | |||||
| ****************************************************************************/ | |||||
| int suffixcmp(s1, s2) | |||||
| char *s1; | |||||
| char *s2; | |||||
| { | |||||
| int len1, len2; | |||||
| len1 = MYSTRLEN(s1); | |||||
| len2 = MYSTRLEN(s2); | |||||
| if (len2 > len1) return 0; | |||||
| s1 += len1 - len2; | |||||
| while (*s1) { | |||||
| if (tolower(*s1) != tolower(*s2)) return 0; | |||||
| s1++; | |||||
| s2++; | |||||
| } | |||||
| return 1; | |||||
| } | |||||
| /**************************************************************************** | |||||
| skiptoeol | |||||
| Skips to the end of a line, given a stream. Handles \r, \n, or \r\n. | |||||
| ****************************************************************************/ | |||||
| void skiptoeol(fp) | |||||
| ZFILE *fp; | |||||
| { | |||||
| int dummy; | |||||
| while (dummy=Zgetc(fp),dummy!=EOF) { | |||||
| if (dummy == '\n') return; | |||||
| if (dummy == '\r') { | |||||
| dummy = Zgetc(fp); | |||||
| if (dummy != EOF && dummy != '\n') Zungetc(dummy,fp); | |||||
| return; | |||||
| } | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| myfgets | |||||
| Local version of fgets. Handles \r, \n, and \r\n terminators. | |||||
| ****************************************************************************/ | |||||
| char *myfgets(line,maxlen,fp) | |||||
| char *line; | |||||
| int maxlen; | |||||
| ZFILE *fp; | |||||
| { | |||||
| int c = 0; | |||||
| char *p; | |||||
| p = line; | |||||
| while((c=Zgetc(fp))!=EOF&&maxlen) { | |||||
| *p++ = c; | |||||
| maxlen--; | |||||
| if (c=='\n') break; | |||||
| if (c=='\r') { | |||||
| c = Zgetc(fp); | |||||
| if (c != EOF && c != '\n') Zungetc(c,fp); | |||||
| *(p-1) = '\n'; | |||||
| break; | |||||
| } | |||||
| } | |||||
| *p = 0; | |||||
| return (c==EOF) ? NULL : line; | |||||
| } | |||||
| /**************************************************************************** | |||||
| usageerr | |||||
| Prints "Usage: ...." line to the given stream. | |||||
| ****************************************************************************/ | |||||
| void printusage(out) | |||||
| FILE *out; | |||||
| { | |||||
| fprintf(out, | |||||
| "Usage: %s [ -cklnoprstvxDELNRSWX ] [ -d fontdirectory ]\n", | |||||
| myname); | |||||
| fprintf(out, | |||||
| " [ -f fontfile ] [ -m smushmode ] [ -w outputwidth ]\n"); | |||||
| fprintf(out, | |||||
| " [ -C controlfile ] [ -I infocode ] [ message ]\n"); | |||||
| } | |||||
| /**************************************************************************** | |||||
| printinfo | |||||
| Prints version and copyright message, or utility information. | |||||
| ****************************************************************************/ | |||||
| void printinfo(infonum) | |||||
| int infonum; | |||||
| { | |||||
| switch (infonum) { | |||||
| case 0: /* Copyright message */ | |||||
| printf("FIGlet Copyright (C) 1991-2012 Glenn Chappell, Ian Chai, "); | |||||
| printf("John Cowan,\nChristiaan Keet and Claudio Matsuoka\n"); | |||||
| printf("Internet: <info@figlet.org> "); | |||||
| printf("Version: %s, date: %s\n\n",VERSION,DATE); | |||||
| printf("FIGlet, along with the various FIGlet fonts"); | |||||
| printf(" and documentation, may be\n"); | |||||
| printf("freely copied and distributed.\n\n"); | |||||
| printf("If you use FIGlet, please send an"); | |||||
| printf(" e-mail message to <info@figlet.org>.\n\n"); | |||||
| printf("The latest version of FIGlet is available from the"); | |||||
| printf(" web site,\n\thttp://www.figlet.org/\n\n"); | |||||
| printusage(stdout); | |||||
| break; | |||||
| case 1: /* Version (integer) */ | |||||
| printf("%d\n",VERSION_INT); | |||||
| break; | |||||
| case 2: /* Font directory */ | |||||
| printf("%s\n",fontdirname); | |||||
| break; | |||||
| case 3: /* Font */ | |||||
| printf("%s\n",fontname); | |||||
| break; | |||||
| case 4: /* Outputwidth */ | |||||
| printf("%d\n",outputwidth); | |||||
| break; | |||||
| case 5: /* Font formats */ | |||||
| printf("%s", FONTFILEMAGICNUMBER); | |||||
| #ifdef TLF_FONTS | |||||
| printf(" %s", TOILETFILEMAGICNUMBER); | |||||
| #endif | |||||
| printf("\n"); | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| readmagic | |||||
| Reads a four-character magic string from a stream. | |||||
| ****************************************************************************/ | |||||
| void readmagic(fp,magic) | |||||
| ZFILE *fp; | |||||
| char *magic; | |||||
| { | |||||
| int i; | |||||
| for (i=0;i<4;i++) { | |||||
| magic[i] = Zgetc(fp); | |||||
| } | |||||
| magic[4] = 0; | |||||
| } | |||||
| /**************************************************************************** | |||||
| skipws | |||||
| Skips whitespace characters from a stream. | |||||
| ****************************************************************************/ | |||||
| void skipws(fp) | |||||
| ZFILE *fp; | |||||
| { | |||||
| int c; | |||||
| while (c=Zgetc(fp),isascii(c)&&isspace(c)) ; | |||||
| Zungetc(c,fp); | |||||
| } | |||||
| /**************************************************************************** | |||||
| readnum | |||||
| Reads a number from a stream. Accepts "0" prefix for octal and | |||||
| "0x" or "0X" for hexadecimal. Ignores leading whitespace. | |||||
| ****************************************************************************/ | |||||
| void readnum(fp,nump) | |||||
| ZFILE *fp; | |||||
| inchr *nump; | |||||
| { | |||||
| int acc = 0; | |||||
| char *p; | |||||
| int c; | |||||
| int base; | |||||
| int sign = 1; | |||||
| char digits[] = "0123456789ABCDEF"; | |||||
| skipws(fp); | |||||
| c = Zgetc(fp); | |||||
| if (c=='-') { | |||||
| sign = -1; | |||||
| } | |||||
| else { | |||||
| Zungetc(c,fp); | |||||
| } | |||||
| c = Zgetc(fp); | |||||
| if (c=='0') { | |||||
| c = Zgetc(fp); | |||||
| if (c=='x'||c=='X') { | |||||
| base = 16; | |||||
| } | |||||
| else { | |||||
| base = 8; | |||||
| Zungetc(c,fp); | |||||
| } | |||||
| } | |||||
| else { | |||||
| base = 10; | |||||
| Zungetc(c,fp); | |||||
| } | |||||
| while((c=Zgetc(fp))!=EOF) { | |||||
| c=toupper(c); | |||||
| p=strchr(digits,c); | |||||
| if (!p) { | |||||
| Zungetc(c,fp); | |||||
| *nump = acc * sign; | |||||
| return; | |||||
| } | |||||
| acc = acc*base+(p-digits); | |||||
| } | |||||
| *nump = acc * sign; | |||||
| } | |||||
| /**************************************************************************** | |||||
| readTchar | |||||
| Reads a control file "T" command character specification. | |||||
| Character is a single byte, an escape sequence, or | |||||
| an escaped numeric. | |||||
| ****************************************************************************/ | |||||
| inchr readTchar(fp) | |||||
| ZFILE *fp; | |||||
| { | |||||
| inchr thechar; | |||||
| char next; | |||||
| thechar=Zgetc(fp); | |||||
| if (thechar=='\n' || thechar=='\r') { /* Handle badly-formatted file */ | |||||
| Zungetc(thechar,fp); | |||||
| return '\0'; | |||||
| } | |||||
| if (thechar!='\\') return thechar; | |||||
| next=Zgetc(fp); | |||||
| switch(next) { | |||||
| case 'a': | |||||
| return 7; | |||||
| case 'b': | |||||
| return 8; | |||||
| case 'e': | |||||
| return 27; | |||||
| case 'f': | |||||
| return 12; | |||||
| case 'n': | |||||
| return 10; | |||||
| case 'r': | |||||
| return 13; | |||||
| case 't': | |||||
| return 9; | |||||
| case 'v': | |||||
| return 11; | |||||
| default: | |||||
| if (next=='-' || next=='x' || (next>='0' && next<='9')) { | |||||
| Zungetc(next,fp); | |||||
| readnum(fp,&thechar); | |||||
| return thechar; | |||||
| } | |||||
| return next; | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| charsetname | |||||
| Get a Tchar representing a charset name, or 0 if none available. | |||||
| Called in getcharset(). | |||||
| ****************************************************************************/ | |||||
| inchr charsetname(fp) | |||||
| ZFILE *fp; | |||||
| { | |||||
| inchr result; | |||||
| result = readTchar(fp); | |||||
| if (result == '\n' || result == '\r') { | |||||
| result = 0; | |||||
| Zungetc(result,fp); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| /**************************************************************************** | |||||
| charset | |||||
| Processes "g[0123]" character set specifier | |||||
| Called in readcontrol(). | |||||
| ****************************************************************************/ | |||||
| void charset(n, controlfile) | |||||
| int n; | |||||
| ZFILE *controlfile; | |||||
| { | |||||
| int ch; | |||||
| skipws(controlfile); | |||||
| if (Zgetc(controlfile) != '9') { | |||||
| skiptoeol(controlfile); | |||||
| return; | |||||
| } | |||||
| ch = Zgetc(controlfile); | |||||
| if (ch == '6') { | |||||
| gn[n] = 65536L * charsetname(controlfile) + 0x80; | |||||
| gndbl[n] = 0; | |||||
| skiptoeol(controlfile); | |||||
| return; | |||||
| } | |||||
| if (ch != '4') { | |||||
| skiptoeol(controlfile); | |||||
| return; | |||||
| } | |||||
| ch = Zgetc(controlfile); | |||||
| if (ch == 'x') { | |||||
| if (Zgetc(controlfile) != '9') { | |||||
| skiptoeol(controlfile); | |||||
| return; | |||||
| } | |||||
| if (Zgetc(controlfile) != '4') { | |||||
| skiptoeol(controlfile); | |||||
| return; | |||||
| } | |||||
| skipws(controlfile); | |||||
| gn[n] = 65536L * charsetname(controlfile); | |||||
| gndbl[n] = 1; | |||||
| skiptoeol(controlfile); | |||||
| return; | |||||
| } | |||||
| Zungetc(ch, controlfile); | |||||
| skipws(controlfile); | |||||
| gn[n] = 65536L * charsetname(controlfile); | |||||
| gndbl[n] = 0; | |||||
| return; | |||||
| } | |||||
| /**************************************************************************** | |||||
| FIGopen | |||||
| Given a FIGlet font or control file name and suffix, return the file | |||||
| or NULL if not found | |||||
| ****************************************************************************/ | |||||
| ZFILE *FIGopen(name,suffix) | |||||
| char *name; | |||||
| char *suffix; | |||||
| { | |||||
| char *fontpath; | |||||
| ZFILE *fontfile; | |||||
| struct stat st; | |||||
| int namelen; | |||||
| namelen = MYSTRLEN(fontdirname); | |||||
| fontpath = (char*)alloca(sizeof(char)* | |||||
| (namelen+MYSTRLEN(name)+MYSTRLEN(suffix)+2)); | |||||
| fontfile = NULL; | |||||
| if (!hasdirsep(name)) { /* not a full path name */ | |||||
| strcpy(fontpath,fontdirname); | |||||
| fontpath[namelen] = DIRSEP; | |||||
| fontpath[namelen+1] = '\0'; | |||||
| strcat(fontpath,name); | |||||
| strcat(fontpath,suffix); | |||||
| if(stat(fontpath,&st)==0) goto ok; | |||||
| } | |||||
| /* just append suffix */ | |||||
| strcpy(fontpath,name); | |||||
| strcat(fontpath,suffix); | |||||
| if(stat(fontpath,&st)==0) goto ok; | |||||
| return NULL; | |||||
| ok: | |||||
| fontfile = Zopen(fontpath,"rb"); | |||||
| return fontfile; | |||||
| } | |||||
| /**************************************************************************** | |||||
| readcontrol | |||||
| Allocates memory and reads in the given control file. | |||||
| Called in readcontrolfiles(). | |||||
| ****************************************************************************/ | |||||
| void readcontrol(controlname) | |||||
| char *controlname; | |||||
| { | |||||
| inchr firstch,lastch; | |||||
| char dashcheck; | |||||
| inchr offset; | |||||
| int command; | |||||
| ZFILE *controlfile; | |||||
| controlfile = FIGopen(controlname,CONTROLFILESUFFIX); | |||||
| if (controlfile==NULL) { | |||||
| fprintf(stderr,"%s: %s: Unable to open control file\n",myname, | |||||
| controlname); | |||||
| exit(1); | |||||
| } | |||||
| (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); | |||||
| (*commandlistend)->thecommand = 0; /* Begin with a freeze command */ | |||||
| commandlistend = &(*commandlistend)->next; | |||||
| (*commandlistend) = NULL; | |||||
| while(command=Zgetc(controlfile),command!=EOF) { | |||||
| switch (command) { | |||||
| case 't': /* Translate */ | |||||
| skipws(controlfile); | |||||
| firstch=readTchar(controlfile); | |||||
| if ((dashcheck=Zgetc(controlfile))=='-') { | |||||
| lastch=readTchar(controlfile); | |||||
| } | |||||
| else { | |||||
| Zungetc(dashcheck,controlfile); | |||||
| lastch=firstch; | |||||
| } | |||||
| skipws(controlfile); | |||||
| offset=readTchar(controlfile)-firstch; | |||||
| skiptoeol(controlfile); | |||||
| (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); | |||||
| (*commandlistend)->thecommand = 1; | |||||
| (*commandlistend)->rangelo = firstch; | |||||
| (*commandlistend)->rangehi = lastch; | |||||
| (*commandlistend)->offset = offset; | |||||
| commandlistend = &(*commandlistend)->next; | |||||
| (*commandlistend) = NULL; | |||||
| break; | |||||
| case '0': case '1': case '2': case '3': case '4': | |||||
| case '5': case '6': case '7': case '8': case '9': | |||||
| case '-': | |||||
| /* Mapping table entry */ | |||||
| Zungetc(command,controlfile); | |||||
| readnum(controlfile,&firstch); | |||||
| skipws(controlfile); | |||||
| readnum(controlfile,&lastch); | |||||
| offset=lastch-firstch; | |||||
| lastch=firstch; | |||||
| skiptoeol(controlfile); | |||||
| (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); | |||||
| (*commandlistend)->thecommand = 1; | |||||
| (*commandlistend)->rangelo = firstch; | |||||
| (*commandlistend)->rangehi = lastch; | |||||
| (*commandlistend)->offset = offset; | |||||
| commandlistend = &(*commandlistend)->next; | |||||
| (*commandlistend) = NULL; | |||||
| break; | |||||
| case 'f': /* freeze */ | |||||
| skiptoeol(controlfile); | |||||
| (*commandlistend) = (comnode*)myalloc(sizeof(comnode)); | |||||
| (*commandlistend)->thecommand = 0; | |||||
| commandlistend = &(*commandlistend)->next; | |||||
| (*commandlistend) = NULL; | |||||
| break; | |||||
| case 'b': /* DBCS input mode */ | |||||
| multibyte = 1; | |||||
| break; | |||||
| case 'u': /* UTF-8 input mode */ | |||||
| multibyte = 2; | |||||
| break; | |||||
| case 'h': /* HZ input mode */ | |||||
| multibyte = 3; | |||||
| break; | |||||
| case 'j': /* Shift-JIS input mode */ | |||||
| multibyte = 4; | |||||
| break; | |||||
| case 'g': /* ISO 2022 character set choices */ | |||||
| multibyte = 0; | |||||
| skipws(controlfile); | |||||
| command=Zgetc(controlfile); | |||||
| switch (command) { | |||||
| case '0': /* define G0 charset */ | |||||
| charset(0, controlfile); | |||||
| break; | |||||
| case '1': /* set G1 charset */ | |||||
| charset(1, controlfile); | |||||
| break; | |||||
| case '2': /* set G2 charset */ | |||||
| charset(2, controlfile); | |||||
| break; | |||||
| case '3': /* set G3 charset */ | |||||
| charset(3, controlfile); | |||||
| break; | |||||
| case 'l': case 'L': /* define left half */ | |||||
| skipws(controlfile); | |||||
| gl = Zgetc(controlfile) - '0'; | |||||
| skiptoeol(controlfile); | |||||
| break; | |||||
| case 'r': case 'R': /* define right half */ | |||||
| skipws(controlfile); | |||||
| gr = Zgetc(controlfile) - '0'; | |||||
| skiptoeol(controlfile); | |||||
| break; | |||||
| default: /* meaningless "g" command */ | |||||
| skiptoeol(controlfile); | |||||
| } | |||||
| case '\r': case '\n': /* blank line */ | |||||
| break; | |||||
| default: /* Includes '#' */ | |||||
| skiptoeol(controlfile); | |||||
| } | |||||
| } | |||||
| Zclose(controlfile); | |||||
| } | |||||
| /**************************************************************************** | |||||
| readcontrolfiles | |||||
| Reads in the controlfiles names in cfilelist. Uses readcontrol. | |||||
| Called in main(). | |||||
| ****************************************************************************/ | |||||
| void readcontrolfiles() | |||||
| { | |||||
| cfnamenode *cfnptr; | |||||
| for (cfnptr=cfilelist;cfnptr!=NULL;cfnptr=cfnptr->next) { | |||||
| readcontrol(cfnptr->thename); | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| clearcfilelist | |||||
| Clears the control file list. Assumes thename does not need freeing. | |||||
| ****************************************************************************/ | |||||
| void clearcfilelist() | |||||
| { | |||||
| cfnamenode *cfnptr1,*cfnptr2; | |||||
| cfnptr1 = cfilelist; | |||||
| while (cfnptr1 != NULL) { | |||||
| cfnptr2 = cfnptr1->next; | |||||
| free(cfnptr1); | |||||
| cfnptr1 = cfnptr2; | |||||
| } | |||||
| cfilelist = NULL; | |||||
| cfilelistend = &cfilelist; | |||||
| } | |||||
| /**************************************************************************** | |||||
| getparams | |||||
| Handles all command-line parameters. Puts all parameters within | |||||
| bounds. | |||||
| ****************************************************************************/ | |||||
| void getparams() | |||||
| { | |||||
| extern char *optarg; | |||||
| extern int optind; | |||||
| int c; /* "Should" be a char -- need int for "!= -1" test*/ | |||||
| int columns,infoprint; | |||||
| char *controlname,*env; | |||||
| if ((myname = strrchr(Myargv[0],DIRSEP))!=NULL) { | |||||
| myname++; | |||||
| } | |||||
| else { | |||||
| myname = Myargv[0]; | |||||
| } | |||||
| fontdirname = DEFAULTFONTDIR; | |||||
| env = getenv("FIGLET_FONTDIR"); | |||||
| if (env!=NULL) { | |||||
| fontdirname = env; | |||||
| } | |||||
| fontname = DEFAULTFONTFILE; | |||||
| cfilelist = NULL; | |||||
| cfilelistend = &cfilelist; | |||||
| commandlist = NULL; | |||||
| commandlistend = &commandlist; | |||||
| smushoverride = SMO_NO; | |||||
| deutschflag = 0; | |||||
| justification = -1; | |||||
| right2left = -1; | |||||
| paragraphflag = 0; | |||||
| infoprint = -1; | |||||
| cmdinput = 0; | |||||
| outputwidth = DEFAULTCOLUMNS; | |||||
| gn[1] = 0x80; | |||||
| gr = 1; | |||||
| while ((c = getopt(Myargc,Myargv,"ADEXLRI:xlcrpntvm:w:d:f:C:NFskSWo"))!= -1) { | |||||
| /* Note: -F is not a legal option -- prints a special err message. */ | |||||
| switch (c) { | |||||
| case 'A': | |||||
| cmdinput = 1; | |||||
| break; | |||||
| case 'D': | |||||
| deutschflag = 1; | |||||
| break; | |||||
| case 'E': | |||||
| deutschflag = 0; | |||||
| break; | |||||
| case 'X': | |||||
| right2left = -1; | |||||
| break; | |||||
| case 'L': | |||||
| right2left = 0; | |||||
| break; | |||||
| case 'R': | |||||
| right2left = 1; | |||||
| break; | |||||
| case 'x': | |||||
| justification = -1; | |||||
| break; | |||||
| case 'l': | |||||
| justification = 0; | |||||
| break; | |||||
| case 'c': | |||||
| justification = 1; | |||||
| break; | |||||
| case 'r': | |||||
| justification = 2; | |||||
| break; | |||||
| case 'p': | |||||
| paragraphflag = 1; | |||||
| break; | |||||
| case 'n': | |||||
| paragraphflag = 0; | |||||
| break; | |||||
| case 's': | |||||
| smushoverride = SMO_NO; | |||||
| break; | |||||
| case 'k': | |||||
| smushmode = SM_KERN; | |||||
| smushoverride = SMO_YES; | |||||
| break; | |||||
| case 'S': | |||||
| smushmode = SM_SMUSH; | |||||
| smushoverride = SMO_FORCE; | |||||
| break; | |||||
| case 'o': | |||||
| smushmode = SM_SMUSH; | |||||
| smushoverride = SMO_YES; | |||||
| break; | |||||
| case 'W': | |||||
| smushmode = 0; | |||||
| smushoverride = SMO_YES; | |||||
| break; | |||||
| case 't': | |||||
| #ifdef TIOCGWINSZ | |||||
| columns = get_columns(); | |||||
| if (columns>0) { | |||||
| outputwidth = columns; | |||||
| } | |||||
| #else /* ifdef TIOCGWINSZ */ | |||||
| fprintf(stderr, | |||||
| "%s: \"-t\" is disabled, since ioctl is not fully implemented.\n", | |||||
| myname); | |||||
| #endif /* ifdef TIOCGWINSZ */ | |||||
| break; | |||||
| case 'v': | |||||
| infoprint = 0; | |||||
| break; | |||||
| case 'I': | |||||
| infoprint = atoi(optarg); | |||||
| break; | |||||
| case 'm': | |||||
| smushmode = atoi(optarg); | |||||
| if (smushmode < -1) { | |||||
| smushoverride = SMO_NO; | |||||
| break; | |||||
| } | |||||
| if (smushmode == 0) smushmode = SM_KERN; | |||||
| else if (smushmode == -1) smushmode = 0; | |||||
| else smushmode = (smushmode & 63) | SM_SMUSH; | |||||
| smushoverride = SMO_YES; | |||||
| break; | |||||
| case 'w': | |||||
| columns = atoi(optarg); | |||||
| if (columns>0) { | |||||
| outputwidth = columns; | |||||
| } | |||||
| break; | |||||
| case 'd': | |||||
| fontdirname = optarg; | |||||
| break; | |||||
| case 'f': | |||||
| fontname = optarg; | |||||
| if (suffixcmp(fontname,FONTFILESUFFIX)) { | |||||
| fontname[MYSTRLEN(fontname)-FSUFFIXLEN] = '\0'; | |||||
| } | |||||
| #ifdef TLF_FONTS | |||||
| else if (suffixcmp(fontname,TOILETFILESUFFIX)) { | |||||
| fontname[MYSTRLEN(fontname)-TSUFFIXLEN] = '\0'; | |||||
| } | |||||
| #endif | |||||
| break; | |||||
| case 'C': | |||||
| controlname = optarg; | |||||
| if (suffixcmp(controlname, CONTROLFILESUFFIX)) { | |||||
| controlname[MYSTRLEN(controlname)-CSUFFIXLEN] = '\0'; | |||||
| } | |||||
| (*cfilelistend) = (cfnamenode*)myalloc(sizeof(cfnamenode)); | |||||
| (*cfilelistend)->thename = controlname; | |||||
| cfilelistend = &(*cfilelistend)->next; | |||||
| (*cfilelistend) = NULL; | |||||
| break; | |||||
| case 'N': | |||||
| clearcfilelist(); | |||||
| multibyte = 0; | |||||
| gn[0] = 0; | |||||
| gn[1] = 0x80; | |||||
| gn[2] = gn[3] = 0; | |||||
| gndbl[0] = gndbl[1] = gndbl[2] = gndbl[3] = 0; | |||||
| gl = 0; | |||||
| gr = 1; | |||||
| break; | |||||
| case 'F': /* Not a legal option */ | |||||
| fprintf(stderr,"%s: illegal option -- F\n",myname); | |||||
| printusage(stderr); | |||||
| fprintf(stderr,"\nBecause of numerous incompatibilities, the"); | |||||
| fprintf(stderr," \"-F\" option has been\n"); | |||||
| fprintf(stderr,"removed. It has been replaced by the \"figlist\""); | |||||
| fprintf(stderr," program, which is now\n"); | |||||
| fprintf(stderr,"included in the basic FIGlet package. \"figlist\""); | |||||
| fprintf(stderr," is also available\n"); | |||||
| fprintf(stderr,"from http://www.figlet.org/"); | |||||
| fprintf(stderr,"under UNIX utilities.\n"); | |||||
| exit(1); | |||||
| break; | |||||
| default: | |||||
| printusage(stderr); | |||||
| exit(1); | |||||
| } | |||||
| } | |||||
| if (optind!=Myargc) cmdinput = 1; /* force cmdinput if more arguments */ | |||||
| outlinelenlimit = outputwidth-1; | |||||
| if (infoprint>=0) { | |||||
| printinfo(infoprint); | |||||
| exit(0); | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| clearline | |||||
| Clears both the input (inchrline) and output (outputline) storage. | |||||
| ****************************************************************************/ | |||||
| void clearline() | |||||
| { | |||||
| int i; | |||||
| for (i=0;i<charheight;i++) { | |||||
| outputline[i][0] = '\0'; | |||||
| } | |||||
| outlinelen = 0; | |||||
| inchrlinelen = 0; | |||||
| } | |||||
| /**************************************************************************** | |||||
| readfontchar | |||||
| Reads a font character from the font file, and places it in a | |||||
| newly-allocated entry in the list. | |||||
| ****************************************************************************/ | |||||
| void readfontchar(file,theord) | |||||
| ZFILE *file; | |||||
| inchr theord; | |||||
| { | |||||
| int row,k; | |||||
| char templine[MAXLEN+1]; | |||||
| outchr endchar, outline[MAXLEN+1]; | |||||
| fcharnode *fclsave; | |||||
| fclsave = fcharlist; | |||||
| fcharlist = (fcharnode*)myalloc(sizeof(fcharnode)); | |||||
| fcharlist->ord = theord; | |||||
| fcharlist->thechar = (outchr**)myalloc(sizeof(outchr*)*charheight); | |||||
| fcharlist->next = fclsave; | |||||
| outline[0] = 0; | |||||
| for (row=0;row<charheight;row++) { | |||||
| if (myfgets(templine,MAXLEN,file)==NULL) { | |||||
| templine[0] = '\0'; | |||||
| } | |||||
| #ifdef TLF_FONTS | |||||
| utf8_to_wchar(templine,MAXLEN,outline,MAXLEN,0); | |||||
| #else | |||||
| strcpy(outline,templine); | |||||
| #endif | |||||
| k = STRLEN(outline)-1; | |||||
| while (k>=0 && ISSPACE(outline[k])) { /* remove trailing spaces */ | |||||
| k--; | |||||
| } | |||||
| if (k>=0) { | |||||
| endchar = outline[k]; /* remove endmarks */ | |||||
| while (k>=0 && outline[k]==endchar) { | |||||
| k--; | |||||
| } | |||||
| } | |||||
| outline[k+1] = '\0'; | |||||
| fcharlist->thechar[row] = (outchr*)myalloc(sizeof(outchr)*(STRLEN(outline)+1)); | |||||
| STRCPY(fcharlist->thechar[row],outline); | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| readfont | |||||
| Allocates memory, initializes variables, and reads in the font. | |||||
| Called near beginning of main(). | |||||
| ****************************************************************************/ | |||||
| void readfont() | |||||
| { | |||||
| int i,row,numsread; | |||||
| inchr theord; | |||||
| int maxlen,cmtlines,ffright2left; | |||||
| int smush,smush2; | |||||
| char fileline[MAXLEN+1],magicnum[5]; | |||||
| ZFILE *fontfile; | |||||
| fontfile = FIGopen(fontname,FONTFILESUFFIX); | |||||
| #ifdef TLF_FONTS | |||||
| if (fontfile==NULL) { | |||||
| fontfile = FIGopen(fontname,TOILETFILESUFFIX); | |||||
| if(fontfile) toiletfont = 1; | |||||
| } | |||||
| #endif | |||||
| if (fontfile==NULL) { | |||||
| fprintf(stderr,"%s: %s: Unable to open font file\n",myname,fontname); | |||||
| exit(1); | |||||
| } | |||||
| readmagic(fontfile,magicnum); | |||||
| if (myfgets(fileline,MAXLEN,fontfile)==NULL) { | |||||
| fileline[0] = '\0'; | |||||
| } | |||||
| if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) { | |||||
| skiptoeol(fontfile); | |||||
| } | |||||
| numsread = sscanf(fileline,"%*c%c %d %*d %d %d %d %d %d", | |||||
| &hardblank,&charheight,&maxlen,&smush,&cmtlines, | |||||
| &ffright2left,&smush2); | |||||
| if (maxlen > MAXLEN) { | |||||
| fprintf(stderr,"%s: %s: character is too wide\n",myname,fontname); | |||||
| exit(1); | |||||
| } | |||||
| #ifdef TLF_FONTS | |||||
| if ((!toiletfont && strcmp(magicnum,FONTFILEMAGICNUMBER)) || | |||||
| (toiletfont && strcmp(magicnum,TOILETFILEMAGICNUMBER)) || numsread<5) { | |||||
| #else | |||||
| if (strcmp(magicnum,FONTFILEMAGICNUMBER) || numsread<5) { | |||||
| #endif | |||||
| fprintf(stderr,"%s: %s: Not a FIGlet 2 font file\n",myname,fontname); | |||||
| exit(1); | |||||
| } | |||||
| for (i=1;i<=cmtlines;i++) { | |||||
| skiptoeol(fontfile); | |||||
| } | |||||
| if (numsread<6) { | |||||
| ffright2left = 0; | |||||
| } | |||||
| if (numsread<7) { /* if no smush2, decode smush into smush2 */ | |||||
| if (smush == 0) smush2 = SM_KERN; | |||||
| else if (smush < 0) smush2 = 0; | |||||
| else smush2 = (smush & 31) | SM_SMUSH; | |||||
| } | |||||
| if (charheight<1) { | |||||
| charheight = 1; | |||||
| } | |||||
| if (maxlen<1) { | |||||
| maxlen = 1; | |||||
| } | |||||
| maxlen += 100; /* Give ourselves some extra room */ | |||||
| if (smushoverride == SMO_NO) | |||||
| smushmode = smush2; | |||||
| else if (smushoverride == SMO_FORCE) | |||||
| smushmode |= smush2; | |||||
| if (right2left<0) { | |||||
| right2left = ffright2left; | |||||
| } | |||||
| if (justification<0) { | |||||
| justification = 2*right2left; | |||||
| } | |||||
| /* Allocate "missing" character */ | |||||
| fcharlist = (fcharnode*)myalloc(sizeof(fcharnode)); | |||||
| fcharlist->ord = 0; | |||||
| fcharlist->thechar = (outchr**)myalloc(sizeof(outchr*)*charheight); | |||||
| fcharlist->next = NULL; | |||||
| for (row=0;row<charheight;row++) { | |||||
| fcharlist->thechar[row] = (outchr*)myalloc(sizeof(outchr)); | |||||
| fcharlist->thechar[row][0] = '\0'; | |||||
| } | |||||
| for (theord=' ';theord<='~';theord++) { | |||||
| readfontchar(fontfile,theord); | |||||
| } | |||||
| for (theord=0;theord<=6;theord++) { | |||||
| readfontchar(fontfile,deutsch[theord]); | |||||
| } | |||||
| while (myfgets(fileline,maxlen+1,fontfile)==NULL?0: | |||||
| sscanf(fileline,"%li",&theord)==1) { | |||||
| readfontchar(fontfile,theord); | |||||
| } | |||||
| Zclose(fontfile); | |||||
| } | |||||
| /**************************************************************************** | |||||
| linealloc | |||||
| Allocates & clears outputline, inchrline. Sets inchrlinelenlimit. | |||||
| Called near beginning of main(). | |||||
| ****************************************************************************/ | |||||
| void linealloc() | |||||
| { | |||||
| int row; | |||||
| outputline = (outchr**)myalloc(sizeof(outchr*)*charheight); | |||||
| for (row=0;row<charheight;row++) { | |||||
| outputline[row] = (outchr*)myalloc(sizeof(outchr)*(outlinelenlimit+1)); | |||||
| } | |||||
| inchrlinelenlimit = outputwidth*4+100; | |||||
| inchrline = (inchr*)myalloc(sizeof(inchr)*(inchrlinelenlimit+1)); | |||||
| clearline(); | |||||
| } | |||||
| /**************************************************************************** | |||||
| getletter | |||||
| Sets currchar to point to the font entry for the given character. | |||||
| Sets currcharwidth to the width of this character. | |||||
| ****************************************************************************/ | |||||
| void getletter(c) | |||||
| inchr c; | |||||
| { | |||||
| fcharnode *charptr; | |||||
| for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=c; | |||||
| charptr=charptr->next) ; | |||||
| if (charptr!=NULL) { | |||||
| currchar = charptr->thechar; | |||||
| } | |||||
| else { | |||||
| for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=0; | |||||
| charptr=charptr->next) ; | |||||
| currchar = charptr->thechar; | |||||
| } | |||||
| previouscharwidth = currcharwidth; | |||||
| currcharwidth = STRLEN(currchar[0]); | |||||
| } | |||||
| /**************************************************************************** | |||||
| smushem | |||||
| Given 2 characters, attempts to smush them into 1, according to | |||||
| smushmode. Returns smushed character or '\0' if no smushing can be | |||||
| done. | |||||
| smushmode values are sum of following (all values smush blanks): | |||||
| 1: Smush equal chars (not hardblanks) | |||||
| 2: Smush '_' with any char in hierarchy below | |||||
| 4: hierarchy: "|", "/\", "[]", "{}", "()", "<>" | |||||
| Each class in hier. can be replaced by later class. | |||||
| 8: [ + ] -> |, { + } -> |, ( + ) -> | | |||||
| 16: / + \ -> X, > + < -> X (only in that order) | |||||
| 32: hardblank + hardblank -> hardblank | |||||
| ****************************************************************************/ | |||||
| outchr smushem(lch,rch) | |||||
| outchr lch,rch; | |||||
| { | |||||
| if (lch==' ') return rch; | |||||
| if (rch==' ') return lch; | |||||
| if (previouscharwidth<2 || currcharwidth<2) return '\0'; | |||||
| /* Disallows overlapping if the previous character */ | |||||
| /* or the current character has a width of 1 or zero. */ | |||||
| if ((smushmode & SM_SMUSH) == 0) return '\0'; /* kerning */ | |||||
| if ((smushmode & 63) == 0) { | |||||
| /* This is smushing by universal overlapping. */ | |||||
| if (lch==' ') return rch; | |||||
| if (rch==' ') return lch; | |||||
| if (lch==hardblank) return rch; | |||||
| if (rch==hardblank) return lch; | |||||
| /* Above four lines ensure overlapping preference to */ | |||||
| /* visible characters. */ | |||||
| if (right2left==1) return lch; | |||||
| /* Above line ensures that the dominant (foreground) */ | |||||
| /* fig-character for overlapping is the latter in the */ | |||||
| /* user's text, not necessarily the rightmost character. */ | |||||
| return rch; | |||||
| /* Occurs in the absence of above exceptions. */ | |||||
| } | |||||
| if (smushmode & SM_HARDBLANK) { | |||||
| if (lch==hardblank && rch==hardblank) return lch; | |||||
| } | |||||
| if (lch==hardblank || rch==hardblank) return '\0'; | |||||
| if (smushmode & SM_EQUAL) { | |||||
| if (lch==rch) return lch; | |||||
| } | |||||
| if (smushmode & SM_LOWLINE) { | |||||
| if (lch=='_' && strchr("|/\\[]{}()<>",rch)) return rch; | |||||
| if (rch=='_' && strchr("|/\\[]{}()<>",lch)) return lch; | |||||
| } | |||||
| if (smushmode & SM_HIERARCHY) { | |||||
| if (lch=='|' && strchr("/\\[]{}()<>",rch)) return rch; | |||||
| if (rch=='|' && strchr("/\\[]{}()<>",lch)) return lch; | |||||
| if (strchr("/\\",lch) && strchr("[]{}()<>",rch)) return rch; | |||||
| if (strchr("/\\",rch) && strchr("[]{}()<>",lch)) return lch; | |||||
| if (strchr("[]",lch) && strchr("{}()<>",rch)) return rch; | |||||
| if (strchr("[]",rch) && strchr("{}()<>",lch)) return lch; | |||||
| if (strchr("{}",lch) && strchr("()<>",rch)) return rch; | |||||
| if (strchr("{}",rch) && strchr("()<>",lch)) return lch; | |||||
| if (strchr("()",lch) && strchr("<>",rch)) return rch; | |||||
| if (strchr("()",rch) && strchr("<>",lch)) return lch; | |||||
| } | |||||
| if (smushmode & SM_PAIR) { | |||||
| if (lch=='[' && rch==']') return '|'; | |||||
| if (rch=='[' && lch==']') return '|'; | |||||
| if (lch=='{' && rch=='}') return '|'; | |||||
| if (rch=='{' && lch=='}') return '|'; | |||||
| if (lch=='(' && rch==')') return '|'; | |||||
| if (rch=='(' && lch==')') return '|'; | |||||
| } | |||||
| if (smushmode & SM_BIGX) { | |||||
| if (lch=='/' && rch=='\\') return '|'; | |||||
| if (rch=='/' && lch=='\\') return 'Y'; | |||||
| if (lch=='>' && rch=='<') return 'X'; | |||||
| /* Don't want the reverse of above to give 'X'. */ | |||||
| } | |||||
| return '\0'; | |||||
| } | |||||
| /**************************************************************************** | |||||
| smushamt | |||||
| Returns the maximum amount that the current character can be smushed | |||||
| into the current line. | |||||
| ****************************************************************************/ | |||||
| int smushamt() | |||||
| { | |||||
| int maxsmush,amt; | |||||
| int row,linebd,charbd; | |||||
| outchr ch1,ch2; | |||||
| if ((smushmode & (SM_SMUSH | SM_KERN)) == 0) { | |||||
| return 0; | |||||
| } | |||||
| maxsmush = currcharwidth; | |||||
| for (row=0;row<charheight;row++) { | |||||
| if (right2left) { | |||||
| if (maxsmush>STRLEN(outputline[row])) { | |||||
| maxsmush=STRLEN(outputline[row]); | |||||
| } | |||||
| for (charbd=STRLEN(currchar[row]); | |||||
| ch1=currchar[row][charbd],(charbd>0&&(!ch1||ch1==' '));charbd--) ; | |||||
| for (linebd=0;ch2=outputline[row][linebd],ch2==' ';linebd++) ; | |||||
| amt = linebd+currcharwidth-1-charbd; | |||||
| } | |||||
| else { | |||||
| for (linebd=STRLEN(outputline[row]); | |||||
| ch1 = outputline[row][linebd],(linebd>0&&(!ch1||ch1==' '));linebd--) ; | |||||
| for (charbd=0;ch2=currchar[row][charbd],ch2==' ';charbd++) ; | |||||
| amt = charbd+outlinelen-1-linebd; | |||||
| } | |||||
| if (!ch1||ch1==' ') { | |||||
| amt++; | |||||
| } | |||||
| else if (ch2) { | |||||
| if (smushem(ch1,ch2)!='\0') { | |||||
| amt++; | |||||
| } | |||||
| } | |||||
| if (amt<maxsmush) { | |||||
| maxsmush = amt; | |||||
| } | |||||
| } | |||||
| return maxsmush; | |||||
| } | |||||
| /**************************************************************************** | |||||
| addchar | |||||
| Attempts to add the given character onto the end of the current line. | |||||
| Returns 1 if this can be done, 0 otherwise. | |||||
| ****************************************************************************/ | |||||
| int addchar(c) | |||||
| inchr c; | |||||
| { | |||||
| int smushamount,row,k,column; | |||||
| outchr *templine; | |||||
| getletter(c); | |||||
| smushamount = smushamt(); | |||||
| if (outlinelen+currcharwidth-smushamount>outlinelenlimit | |||||
| ||inchrlinelen+1>inchrlinelenlimit) { | |||||
| return 0; | |||||
| } | |||||
| templine = (outchr*)myalloc(sizeof(outchr)*(outlinelenlimit+1)); | |||||
| for (row=0;row<charheight;row++) { | |||||
| if (right2left) { | |||||
| STRCPY(templine,currchar[row]); | |||||
| for (k=0;k<smushamount;k++) { | |||||
| templine[currcharwidth-smushamount+k] = | |||||
| smushem(templine[currcharwidth-smushamount+k],outputline[row][k]); | |||||
| } | |||||
| STRCAT(templine,outputline[row]+smushamount); | |||||
| STRCPY(outputline[row],templine); | |||||
| } | |||||
| else { | |||||
| for (k=0;k<smushamount;k++) { | |||||
| column = outlinelen-smushamount+k; | |||||
| if (column < 0) { | |||||
| column = 0; | |||||
| } | |||||
| outputline[row][column] = | |||||
| smushem(outputline[row][column],currchar[row][k]); | |||||
| } | |||||
| STRCAT(outputline[row],currchar[row]+smushamount); | |||||
| } | |||||
| } | |||||
| free(templine); | |||||
| outlinelen = STRLEN(outputline[0]); | |||||
| inchrline[inchrlinelen++] = c; | |||||
| return 1; | |||||
| } | |||||
| /**************************************************************************** | |||||
| putstring | |||||
| Prints out the given null-terminated string, substituting blanks | |||||
| for hardblanks. If outputwidth is 1, prints the entire string; | |||||
| otherwise prints at most outputwidth-1 characters. Prints a newline | |||||
| at the end of the string. The string is left-justified, centered or | |||||
| right-justified (taking outputwidth as the screen width) if | |||||
| justification is 0, 1 or 2, respectively. | |||||
| ****************************************************************************/ | |||||
| void putstring(string) | |||||
| outchr *string; | |||||
| { | |||||
| int i,len; | |||||
| char c[10]; | |||||
| #ifdef TLF_FONTS | |||||
| size_t size; | |||||
| wchar_t wc[2]; | |||||
| #endif | |||||
| len = STRLEN(string); | |||||
| if (outputwidth>1) { | |||||
| if (len>outputwidth-1) { | |||||
| len = outputwidth-1; | |||||
| } | |||||
| if (justification>0) { | |||||
| for (i=1;(3-justification)*i+len+justification-2<outputwidth;i++) { | |||||
| putchar(' '); | |||||
| } | |||||
| } | |||||
| } | |||||
| for (i=0;i<len;i++) { | |||||
| #ifdef TLF_FONTS | |||||
| wc[0] = string[i]; | |||||
| wc[1] = 0; | |||||
| size = wchar_to_utf8(wc,1,c,10,0); | |||||
| if(size==1) { | |||||
| if(c[0]==hardblank) { | |||||
| c[0] = ' '; | |||||
| } | |||||
| } | |||||
| c[size] = 0; | |||||
| printf("%s",c); | |||||
| #else | |||||
| putchar(string[i]==hardblank?' ':string[i]); | |||||
| #endif | |||||
| } | |||||
| putchar('\n'); | |||||
| } | |||||
| /**************************************************************************** | |||||
| printline | |||||
| Prints outputline using putstring, then clears the current line. | |||||
| ****************************************************************************/ | |||||
| void printline() | |||||
| { | |||||
| int i; | |||||
| for (i=0;i<charheight;i++) { | |||||
| putstring(outputline[i]); | |||||
| } | |||||
| clearline(); | |||||
| } | |||||
| /**************************************************************************** | |||||
| splitline | |||||
| Splits inchrline at the last word break (bunch of consecutive blanks). | |||||
| Makes a new line out of the first part and prints it using | |||||
| printline. Makes a new line out of the second part and returns. | |||||
| ****************************************************************************/ | |||||
| void splitline() | |||||
| { | |||||
| int i,gotspace,lastspace,len1,len2; | |||||
| inchr *part1,*part2; | |||||
| part1 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1)); | |||||
| part2 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1)); | |||||
| gotspace = 0; | |||||
| lastspace = inchrlinelen-1; | |||||
| for (i=inchrlinelen-1;i>=0;i--) { | |||||
| if (!gotspace && inchrline[i]==' ') { | |||||
| gotspace = 1; | |||||
| lastspace = i; | |||||
| } | |||||
| if (gotspace && inchrline[i]!=' ') { | |||||
| break; | |||||
| } | |||||
| } | |||||
| len1 = i+1; | |||||
| len2 = inchrlinelen-lastspace-1; | |||||
| for (i=0;i<len1;i++) { | |||||
| part1[i] = inchrline[i]; | |||||
| } | |||||
| for (i=0;i<len2;i++) { | |||||
| part2[i] = inchrline[lastspace+1+i]; | |||||
| } | |||||
| clearline(); | |||||
| for (i=0;i<len1;i++) { | |||||
| addchar(part1[i]); | |||||
| } | |||||
| printline(); | |||||
| for (i=0;i<len2;i++) { | |||||
| addchar(part2[i]); | |||||
| } | |||||
| free(part1); | |||||
| free(part2); | |||||
| } | |||||
| /**************************************************************************** | |||||
| handlemapping | |||||
| Given an input character (type inchr), executes re-mapping commands | |||||
| read from control files. Returns re-mapped character (inchr). | |||||
| ****************************************************************************/ | |||||
| inchr handlemapping(c) | |||||
| inchr c; | |||||
| { | |||||
| comnode *cmptr; | |||||
| cmptr=commandlist; | |||||
| while (cmptr!=NULL) { | |||||
| if (cmptr->thecommand ? | |||||
| (c >= cmptr->rangelo && c <= cmptr->rangehi) : 0) { | |||||
| c += cmptr->offset; | |||||
| while(cmptr!=NULL ? cmptr->thecommand : 0) { | |||||
| cmptr=cmptr->next; | |||||
| } | |||||
| } | |||||
| else { | |||||
| cmptr=cmptr->next; | |||||
| } | |||||
| } | |||||
| return c; | |||||
| } | |||||
| /**************************************************************************** | |||||
| Agetchar | |||||
| Replacement to getchar(). | |||||
| Acts exactly like getchar if -A is NOT specified, | |||||
| else obtains input from All remaining command line words. | |||||
| ****************************************************************************/ | |||||
| int Agetchar() | |||||
| { | |||||
| extern int optind; /* current argv[] element under study */ | |||||
| static int AgetMode = 0; /* >= 0 for displacement into argv[n], <0 EOF */ | |||||
| char *arg; /* pointer to active character */ | |||||
| int c; /* current character */ | |||||
| if ( ! cmdinput ) /* is -A active? */ | |||||
| return( getchar() ); /* no: return stdin character */ | |||||
| if ( AgetMode < 0 || optind >= Myargc ) /* EOF is sticky: */ | |||||
| return( EOF ); /* **ensure it now and forever more */ | |||||
| /* find next character */ | |||||
| arg = Myargv[optind]; /* pointer to active arg */ | |||||
| c = arg[AgetMode++]&0xFF; /* get appropriate char of arg */ | |||||
| if ( ! c ) /* at '\0' that terminates word? */ | |||||
| { /* at end of word: return ' ' if normal word, '\n' if empty */ | |||||
| c = ' '; /* suppose normal word and return blank */ | |||||
| if ( AgetMode == 1 ) /* if ran out in very 1st char, force \n */ | |||||
| c = '\n'; /* (allows "hello '' world" to do \n at '') */ | |||||
| AgetMode = 0; /* return to char 0 in NEXT word */ | |||||
| if ( ++optind >= Myargc ) /* run up word count and check if at "EOF" */ | |||||
| { /* just ran out of arguments */ | |||||
| c = EOF; /* return EOF */ | |||||
| AgetMode = -1; /* ensure all future returns return EOF */ | |||||
| } | |||||
| } | |||||
| return( c ); /* return appropriate character */ | |||||
| } /* end: Agetchar() */ | |||||
| /**************************************************************************** | |||||
| iso2022 | |||||
| Called by getinchr. Interprets ISO 2022 sequences | |||||
| ******************************************************************************/ | |||||
| inchr iso2022() | |||||
| { | |||||
| inchr ch; | |||||
| inchr ch2; | |||||
| int save_gl; | |||||
| int save_gr; | |||||
| ch = Agetchar(); | |||||
| if (ch == EOF) return ch; | |||||
| if (ch == 27) ch = Agetchar() + 0x100; /* ESC x */ | |||||
| if (ch == 0x100 + '$') ch = Agetchar() + 0x200; /* ESC $ x */ | |||||
| switch (ch) { | |||||
| case 14: /* invoke G1 into GL */ | |||||
| gl = 1; | |||||
| return iso2022(); | |||||
| case 15: /* invoke G0 into GL */ | |||||
| gl = 0; | |||||
| return iso2022(); | |||||
| case 142: case 'N' + 0x100: /* invoke G2 into GL for next char */ | |||||
| save_gl = gl; save_gr = gr; | |||||
| gl = gr = 2; | |||||
| ch = iso2022(); | |||||
| gl = save_gl; gr = save_gr; | |||||
| return ch; | |||||
| case 143: case 'O' + 0x100: /* invoke G3 into GL for next char */ | |||||
| save_gl = gl; save_gr = gr; | |||||
| gl = gr = 3; | |||||
| ch = iso2022(); | |||||
| gl = save_gl; gr = save_gr; | |||||
| return ch; | |||||
| case 'n' + 0x100: /* invoke G2 into GL */ | |||||
| gl = 2; | |||||
| return iso2022(); | |||||
| case 'o' + 0x100: /* invoke G3 into GL */ | |||||
| gl = 3; | |||||
| return iso2022(); | |||||
| case '~' + 0x100: /* invoke G1 into GR */ | |||||
| gr = 1; | |||||
| return iso2022(); | |||||
| case '}' + 0x100: /* invoke G2 into GR */ | |||||
| gr = 2; | |||||
| return iso2022(); | |||||
| case '|' + 0x100: /* invoke G3 into GR */ | |||||
| gr = 3; | |||||
| return iso2022(); | |||||
| case '(' + 0x100: /* set G0 to 94-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'B') ch = 0; /* ASCII */ | |||||
| gn[0] = ch << 16; | |||||
| gndbl[0] = 0; | |||||
| return iso2022(); | |||||
| case ')' + 0x100: /* set G1 to 94-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'B') ch = 0; | |||||
| gn[1] = ch << 16; | |||||
| gndbl[1] = 0; | |||||
| return iso2022(); | |||||
| case '*' + 0x100: /* set G2 to 94-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'B') ch = 0; | |||||
| gn[2] = ch << 16; | |||||
| gndbl[2] = 0; | |||||
| return iso2022(); | |||||
| case '+' + 0x100: /* set G3 to 94-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'B') ch = 0; | |||||
| gn[3] = ch << 16; | |||||
| gndbl[3] = 0; | |||||
| return iso2022(); | |||||
| case '-' + 0x100: /* set G1 to 96-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'A') ch = 0; /* Latin-1 top half */ | |||||
| gn[1] = (ch << 16) | 0x80; | |||||
| gndbl[1] = 0; | |||||
| return iso2022(); | |||||
| case '.' + 0x100: /* set G2 to 96-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'A') ch = 0; | |||||
| gn[2] = (ch << 16) | 0x80; | |||||
| gndbl[2] = 0; | |||||
| return iso2022(); | |||||
| case '/' + 0x100: /* set G3 to 96-char set */ | |||||
| ch = Agetchar(); | |||||
| if (ch == 'A') ch = 0; | |||||
| gn[3] = (ch << 16) | 0x80; | |||||
| gndbl[3] = 0; | |||||
| return iso2022(); | |||||
| case '(' + 0x200: /* set G0 to 94 x 94 char set */ | |||||
| ch = Agetchar(); | |||||
| gn[0] = ch << 16; | |||||
| gndbl[0] = 1; | |||||
| return iso2022(); | |||||
| case ')' + 0x200: /* set G1 to 94 x 94 char set */ | |||||
| ch = Agetchar(); | |||||
| gn[1] = ch << 16; | |||||
| gndbl[1] = 1; | |||||
| return iso2022(); | |||||
| case '*' + 0x200: /* set G2 to 94 x 94 char set */ | |||||
| ch = Agetchar(); | |||||
| gn[2] = ch << 16; | |||||
| gndbl[2] = 1; | |||||
| return iso2022(); | |||||
| case '+' + 0x200: /* set G3 to 94 x 94 char set */ | |||||
| ch = Agetchar(); | |||||
| gn[3] = ch << 16; | |||||
| gndbl[3] = 1; | |||||
| return iso2022(); | |||||
| default: | |||||
| if (ch & 0x200) { /* set G0 to 94 x 94 char set (deprecated) */ | |||||
| gn[0] = (ch & ~0x200) << 16; | |||||
| gndbl[0] = 1; | |||||
| return iso2022(); | |||||
| } | |||||
| } | |||||
| if (ch >= 0x21 && ch <= 0x7E) { /* process GL */ | |||||
| if (gndbl[gl]) { | |||||
| ch2 = Agetchar(); | |||||
| return gn[gl] | (ch << 8) | ch2; | |||||
| } | |||||
| else return gn[gl] | ch; | |||||
| } | |||||
| else if (ch >= 0xA0 && ch <= 0xFF) { /* process GR */ | |||||
| if (gndbl[gr]) { | |||||
| ch2 = Agetchar(); | |||||
| return gn[gr] | (ch << 8) | ch2; | |||||
| } | |||||
| else return gn[gr] | (ch & ~0x80); | |||||
| } | |||||
| else return ch; | |||||
| } | |||||
| /**************************************************************************** | |||||
| ungetinchr | |||||
| Called by main. Pushes back an "inchr" to be read by getinchr | |||||
| on the next call. | |||||
| ******************************************************************************/ | |||||
| inchr getinchr_buffer; | |||||
| int getinchr_flag; | |||||
| inchr ungetinchr(c) | |||||
| inchr c; | |||||
| { | |||||
| getinchr_buffer = c; | |||||
| getinchr_flag = 1; | |||||
| return c; | |||||
| } | |||||
| /***************************************************************************** | |||||
| getinchr | |||||
| Called by main. Processes multibyte characters. Invokes Agetchar. | |||||
| If multibyte = 0, ISO 2022 mode (see iso2022 routine). | |||||
| If multibyte = 1, double-byte mode (0x00-0x7f bytes are characters, | |||||
| 0x80-0xFF bytes are first byte of a double-byte character). | |||||
| If multibyte = 2, Unicode UTF-8 mode (0x00-0x7F bytes are characters, | |||||
| 0x80-0xBF bytes are nonfirst byte of a multibyte character, | |||||
| 0xC0-0xFD bytes are first byte of a multibyte character, | |||||
| 0xFE-0xFF bytes are errors (all errors return code 0x0080)). | |||||
| If multibyte = 3, HZ mode ("~{" starts double-byte mode, "}~" ends it, | |||||
| "~~" is a tilde, "~x" for all other x is ignored). | |||||
| If multibyte = 4, Shift-JIS mode (0x80-0x9F and 0xE0-0xEF are first byte | |||||
| of a double-byte character, all other bytes are characters). | |||||
| *****************************************************************************/ | |||||
| inchr getinchr() | |||||
| { | |||||
| int ch, ch2, ch3, ch4, ch5, ch6; | |||||
| if (getinchr_flag) { | |||||
| getinchr_flag = 0; | |||||
| return getinchr_buffer; | |||||
| } | |||||
| switch(multibyte) { | |||||
| case 0: /* single-byte */ | |||||
| return iso2022(); | |||||
| case 1: /* DBCS */ | |||||
| ch = Agetchar(); | |||||
| if ((ch >= 0x80 && ch <= 0x9F) || | |||||
| (ch >= 0xE0 && ch <= 0xEF)) { | |||||
| ch = (ch << 8) + Agetchar(); | |||||
| } | |||||
| return ch; | |||||
| case 2: /* UTF-8 */ | |||||
| ch = Agetchar(); | |||||
| if (ch < 0x80) return ch; /* handles EOF, too */ | |||||
| if (ch < 0xC0 || ch > 0xFD) | |||||
| return 0x0080; /* illegal first character */ | |||||
| ch2 = Agetchar() & 0x3F; | |||||
| if (ch < 0xE0) return ((ch & 0x1F) << 6) + ch2; | |||||
| ch3 = Agetchar() & 0x3F; | |||||
| if (ch < 0xF0) | |||||
| return ((ch & 0x0F) << 12) + (ch2 << 6) + ch3; | |||||
| ch4 = Agetchar() & 0x3F; | |||||
| if (ch < 0xF8) | |||||
| return ((ch & 0x07) << 18) + (ch2 << 12) + (ch3 << 6) + ch4; | |||||
| ch5 = Agetchar() & 0x3F; | |||||
| if (ch < 0xFC) | |||||
| return ((ch & 0x03) << 24) + (ch2 << 18) + (ch3 << 12) + | |||||
| (ch4 << 6) + ch5; | |||||
| ch6 = Agetchar() & 0x3F; | |||||
| return ((ch & 0x01) << 30) + (ch2 << 24) + (ch3 << 18) + | |||||
| (ch4 << 12) + (ch5 << 6) + ch6; | |||||
| case 3: /* HZ */ | |||||
| ch = Agetchar(); | |||||
| if (ch == EOF) return ch; | |||||
| if (hzmode) { | |||||
| ch = (ch << 8) + Agetchar(); | |||||
| if (ch == ('}' << 8) + '~') { | |||||
| hzmode = 0; | |||||
| return getinchr(); | |||||
| } | |||||
| return ch; | |||||
| } | |||||
| else if (ch == '~') { | |||||
| ch = Agetchar(); | |||||
| if (ch == '{') { | |||||
| hzmode = 1; | |||||
| return getinchr(); | |||||
| } | |||||
| else if (ch == '~') { | |||||
| return ch; | |||||
| } | |||||
| else { | |||||
| return getinchr(); | |||||
| } | |||||
| } | |||||
| else return ch; | |||||
| case 4: /* Shift-JIS */ | |||||
| ch = Agetchar(); | |||||
| if ((ch >= 0x80 && ch <= 0x9F) || | |||||
| (ch >= 0xE0 && ch <= 0xEF)) { | |||||
| ch = (ch << 8) + Agetchar(); | |||||
| } | |||||
| return ch; | |||||
| default: | |||||
| return 0x80; | |||||
| } | |||||
| } | |||||
| /**************************************************************************** | |||||
| main | |||||
| The main program, of course. | |||||
| Reads characters 1 by 1 from stdin, and makes lines out of them using | |||||
| addchar. Handles line breaking, (which accounts for most of the | |||||
| complexity in this function). | |||||
| ****************************************************************************/ | |||||
| int main(argc,argv) | |||||
| int argc; | |||||
| char *argv[]; | |||||
| { | |||||
| inchr c,c2; | |||||
| int i; | |||||
| int last_was_eol_flag; | |||||
| /*--------------------------------------------------------------------------- | |||||
| wordbreakmode: | |||||
| -1: /^$/ and blanks are to be absorbed (when line break was forced | |||||
| by a blank or character larger than outlinelenlimit) | |||||
| 0: /^ *$/ and blanks are not to be absorbed | |||||
| 1: /[^ ]$/ no word break yet | |||||
| 2: /[^ ] *$/ | |||||
| 3: /[^ ]$/ had a word break | |||||
| ---------------------------------------------------------------------------*/ | |||||
| int wordbreakmode; | |||||
| int char_not_added; | |||||
| Myargc = argc; | |||||
| Myargv = argv; | |||||
| getparams(); | |||||
| readcontrolfiles(); | |||||
| readfont(); | |||||
| linealloc(); | |||||
| wordbreakmode = 0; | |||||
| last_was_eol_flag = 0; | |||||
| #ifdef TLF_FONTS | |||||
| toiletfont = 0; | |||||
| #endif | |||||
| while ((c = getinchr())!=EOF) { | |||||
| if (c=='\n'&¶graphflag&&!last_was_eol_flag) { | |||||
| ungetinchr(c2 = getinchr()); | |||||
| c = ((isascii(c2)&&isspace(c2))?'\n':' '); | |||||
| } | |||||
| last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' '); | |||||
| if (deutschflag) { | |||||
| if (c>='[' && c<=']') { | |||||
| c = deutsch[c-'[']; | |||||
| } | |||||
| else if (c >='{' && c <= '~') { | |||||
| c = deutsch[c-'{'+3]; | |||||
| } | |||||
| } | |||||
| c = handlemapping(c); | |||||
| if (isascii(c)&&isspace(c)) { | |||||
| c = (c=='\t'||c==' ') ? ' ' : '\n'; | |||||
| } | |||||
| if ((c>'\0' && c<' ' && c!='\n') || c==127) continue; | |||||
| /* | |||||
| Note: The following code is complex and thoroughly tested. | |||||
| Be careful when modifying! | |||||
| */ | |||||
| do { | |||||
| char_not_added = 0; | |||||
| if (wordbreakmode== -1) { | |||||
| if (c==' ') { | |||||
| break; | |||||
| } | |||||
| else if (c=='\n') { | |||||
| wordbreakmode = 0; | |||||
| break; | |||||
| } | |||||
| wordbreakmode = 0; | |||||
| } | |||||
| if (c=='\n') { | |||||
| printline(); | |||||
| wordbreakmode = 0; | |||||
| } | |||||
| else if (addchar(c)) { | |||||
| if (c!=' ') { | |||||
| wordbreakmode = (wordbreakmode>=2)?3:1; | |||||
| } | |||||
| else { | |||||
| wordbreakmode = (wordbreakmode>0)?2:0; | |||||
| } | |||||
| } | |||||
| else if (outlinelen==0) { | |||||
| for (i=0;i<charheight;i++) { | |||||
| if (right2left && outputwidth>1) { | |||||
| putstring(currchar[i]+STRLEN(currchar[i])-outlinelenlimit); | |||||
| } | |||||
| else { | |||||
| putstring(currchar[i]); | |||||
| } | |||||
| } | |||||
| wordbreakmode = -1; | |||||
| } | |||||
| else if (c==' ') { | |||||
| if (wordbreakmode==2) { | |||||
| splitline(); | |||||
| } | |||||
| else { | |||||
| printline(); | |||||
| } | |||||
| wordbreakmode = -1; | |||||
| } | |||||
| else { | |||||
| if (wordbreakmode>=2) { | |||||
| splitline(); | |||||
| } | |||||
| else { | |||||
| printline(); | |||||
| } | |||||
| wordbreakmode = (wordbreakmode==3)?1:0; | |||||
| char_not_added = 1; | |||||
| } | |||||
| } while (char_not_added); | |||||
| } | |||||
| if (outlinelen!=0) { | |||||
| printline(); | |||||
| } | |||||
| return 0; | |||||
| } | |||||