mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-24 15:52:41 +01:00
935ced1edd
Summary: Ref T7785. This prepares for (but does not yet use) a pure PHP implementation of Figlet parsing and rendering. Figlet is somewhat complex, but a parser already exists in PEAR. I'll make sure it's suitable and hook it up in the next diff. Test Plan: N/A, code not reachable Reviewers: chad Reviewed By: chad Maniphest Tasks: T9408, T7785 Differential Revision: https://secure.phabricator.com/D14101
2131 lines
54 KiB
C
2131 lines
54 KiB
C
/****************************************************************************
|
|
|
|
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;
|
|
}
|