Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/externals/figlet/figlet.c
12240 views
1
/****************************************************************************
2
3
FIGlet Copyright 1991, 1993, 1994 Glenn Chappell and Ian Chai
4
FIGlet Copyright 1996, 1997, 1998, 1999, 2000, 2001 John Cowan
5
FIGlet Copyright 2002 Christiaan Keet
6
FIGlet Copyright 2011, 2012 Claudio Matsuoka
7
Portions written by Paul Burton and Christiaan Keet
8
Internet: <[email protected]>
9
FIGlet, along with the various FIGlet fonts and documentation, is
10
copyrighted under the provisions of the New BSD License (3-clause)
11
(as listed in the file "LICENSE" which is included in this package)
12
****************************************************************************/
13
14
#define DATE "31 May 2012"
15
#define VERSION "2.2.5"
16
#define VERSION_INT 20205
17
18
/* FIGlet (Frank, Ian & Glenn's Letters) */
19
/* by Glenn Chappell */
20
/* Apr 1991 */
21
/* Automatic file addition by Ian Chai May 1991 */
22
/* Punctuation and numbers addition by Ian Chai Jan 1993 */
23
/* Full ASCII by Glenn Chappell Feb 1993 */
24
/* Line-breaking, general rewrite by Glenn Chappell Mar 1993 */
25
/* Hard blanks by Glenn Chappell Apr 1993 */
26
/* Release 2.0 5 Aug 1993 */
27
/* Right-to-left printing, extended char set by Glenn Chappell Dec 1993 */
28
/* Control files by Glenn Chappell Feb 1994 */
29
/* Release 2.1 12 Aug 1994 */
30
/* Release 2.1.1 25 Aug 1994 */
31
/* Release 2.1.2 by Gilbert (Mad Programmer) Healton: Add -A command line
32
option. Sept 8, 1996 */
33
/* Release 2.2 by John Cowan: multibyte inputs, compressed fonts,
34
mapping tables, kerning/smushing options. */
35
/* Release 2.2.1 by Christiaan Keet: minor updates including readmes
36
FAQs and comments. 13 July 2002. The new official FIGlet website is
37
http://www.figlet.org/ */
38
/* Release 2.2.2 by Christiaan Keet: License changed from "Artistic License"
39
to "Academic Free License" as agreed by FIGlet authors. 05 July 2005 */
40
/* Release 2.2.3 by Claudio Matsuoka, 12 Jan 2011: BSD license, fixes */
41
/* Release 2.2.4 by Claudio Matsuoka, 26 Jan 2011: tlf2 font support */
42
/* Release 2.2.5 by Claudio Matsuoka, 31 May 2012: flc licensing, minor fixes */
43
44
/*---------------------------------------------------------------------------
45
DEFAULTFONTDIR and DEFAULTFONTFILE should be defined in the Makefile.
46
DEFAULTFONTDIR is the full path name of the directory in which FIGlet
47
will search first for fonts (the ".flf" files).
48
DEFAULTFONTFILE is the filename of the font to be used if no other
49
is specified (standard.flf is recommended, but any other can be
50
used). This file should reside in the directory specified by
51
DEFAULTFONTDIR.
52
---------------------------------------------------------------------------*/
53
#ifndef DEFAULTFONTDIR
54
#define DEFAULTFONTDIR "fonts"
55
#endif
56
#ifndef DEFAULTFONTFILE
57
#define DEFAULTFONTFILE "standard.flf"
58
#endif
59
60
#include <stdio.h>
61
#ifdef __STDC__
62
#include <stdlib.h>
63
#endif
64
#include <string.h>
65
#include <ctype.h>
66
#include <sys/stat.h>
67
#include <fcntl.h> /* Needed for get_columns */
68
69
#if defined(unix) || defined(__unix__) || defined(__APPLE__)
70
#include <unistd.h>
71
#include <sys/ioctl.h> /* Needed for get_columns */
72
#endif
73
74
#ifdef TLF_FONTS
75
#include <wchar.h>
76
#include <wctype.h>
77
#include "utf8.h"
78
#endif
79
80
#include "zipio.h" /* Package for reading compressed files */
81
82
#define MYSTRLEN(x) ((int)strlen(x)) /* Eliminate ANSI problem */
83
84
#define DIRSEP '/'
85
#define DIRSEP2 '\\'
86
/* Leave alone for Unix and MS-DOS/Windows!
87
Note: '/' also used in filename in get_columns(). */
88
89
#define FONTFILESUFFIX ".flf"
90
#define FONTFILEMAGICNUMBER "flf2"
91
#define FSUFFIXLEN MYSTRLEN(FONTFILESUFFIX)
92
#define CONTROLFILESUFFIX ".flc"
93
#define CONTROLFILEMAGICNUMBER "flc2" /* no longer used in 2.2 */
94
#define CSUFFIXLEN MYSTRLEN(CONTROLFILESUFFIX)
95
#define DEFAULTCOLUMNS 80
96
#define MAXLEN 255 /* Maximum character width */
97
98
/* Add support for Sam Hocevar's TOIlet fonts */
99
#ifdef TLF_FONTS
100
#define TOILETFILESUFFIX ".tlf"
101
#define TOILETFILEMAGICNUMBER "tlf2"
102
#define TSUFFIXLEN MYSTRLEN(TOILETFILESUFFIX)
103
104
int toiletfont; /* true if font is a TOIlet TLF font */
105
#endif
106
107
108
/****************************************************************************
109
110
Globals dealing with chars that are read
111
112
****************************************************************************/
113
114
typedef long inchr; /* "char" read from stdin */
115
116
inchr *inchrline; /* Alloc'd inchr inchrline[inchrlinelenlimit+1]; */
117
/* Note: not null-terminated. */
118
int inchrlinelen,inchrlinelenlimit;
119
inchr deutsch[7] = {196, 214, 220, 228, 246, 252, 223};
120
/* Latin-1 codes for German letters, respectively:
121
LATIN CAPITAL LETTER A WITH DIAERESIS = A-umlaut
122
LATIN CAPITAL LETTER O WITH DIAERESIS = O-umlaut
123
LATIN CAPITAL LETTER U WITH DIAERESIS = U-umlaut
124
LATIN SMALL LETTER A WITH DIAERESIS = a-umlaut
125
LATIN SMALL LETTER O WITH DIAERESIS = o-umlaut
126
LATIN SMALL LETTER U WITH DIAERESIS = u-umlaut
127
LATIN SMALL LETTER SHARP S = ess-zed
128
*/
129
130
int hzmode; /* true if reading double-bytes in HZ mode */
131
int gndbl[4]; /* gndbl[n] is true if Gn is double-byte */
132
inchr gn[4]; /* Gn character sets: ASCII, Latin-1, none, none */
133
int gl; /* 0-3 specifies left-half Gn character set */
134
int gr; /* 0-3 specifies right-half Gn character set */
135
136
int Myargc; /* to avoid passing around argc and argv */
137
char **Myargv;
138
139
/****************************************************************************
140
141
Globals dealing with chars that are written
142
143
****************************************************************************/
144
145
#ifdef TLF_FONTS
146
typedef wchar_t outchr; /* "char" written to stdout */
147
#define STRLEN(x) wcslen(x)
148
#define STRCPY(x,y) wcscpy((x),(y))
149
#define STRCAT(x,y) wcscat((x),(y))
150
#define ISSPACE(x) iswspace(x)
151
#else
152
typedef char outchr; /* "char" written to stdout */
153
#define STRLEN(x) MYSTRLEN(x)
154
#define STRCPY(x,y) strcpy((x),(y))
155
#define STRCAT(x,y) strcat((x),(y))
156
#define ISSPACE(x) isspace(x)
157
#endif
158
159
typedef struct fc {
160
inchr ord;
161
outchr **thechar; /* Alloc'd char thechar[charheight][]; */
162
struct fc *next;
163
} fcharnode;
164
165
fcharnode *fcharlist;
166
outchr **currchar;
167
int currcharwidth;
168
int previouscharwidth;
169
outchr **outputline; /* Alloc'd char outputline[charheight][outlinelenlimit+1]; */
170
int outlinelen;
171
172
173
/****************************************************************************
174
175
Globals dealing with command file storage
176
177
****************************************************************************/
178
179
typedef struct cfn {
180
char *thename;
181
struct cfn *next;
182
} cfnamenode;
183
184
cfnamenode *cfilelist,**cfilelistend;
185
186
typedef struct cm {
187
int thecommand;
188
inchr rangelo;
189
inchr rangehi;
190
inchr offset;
191
struct cm *next;
192
} comnode;
193
194
comnode *commandlist,**commandlistend;
195
196
/****************************************************************************
197
198
Globals affected by command line options
199
200
****************************************************************************/
201
202
int deutschflag,justification,paragraphflag,right2left,multibyte;
203
int cmdinput;
204
205
#define SM_SMUSH 128
206
#define SM_KERN 64
207
#define SM_EQUAL 1
208
#define SM_LOWLINE 2
209
#define SM_HIERARCHY 4
210
#define SM_PAIR 8
211
#define SM_BIGX 16
212
#define SM_HARDBLANK 32
213
214
int smushmode;
215
216
#define SMO_NO 0 /* no command-line smushmode */
217
#define SMO_YES 1 /* use command-line smushmode, ignore font smushmode */
218
#define SMO_FORCE 2 /* logically OR command-line and font smushmodes */
219
220
int smushoverride;
221
222
int outputwidth;
223
int outlinelenlimit;
224
char *fontdirname,*fontname;
225
226
227
/****************************************************************************
228
229
Globals read from font file
230
231
****************************************************************************/
232
233
char hardblank;
234
int charheight;
235
236
237
/****************************************************************************
238
239
Name of program, used in error messages
240
241
****************************************************************************/
242
243
char *myname;
244
245
246
#ifdef TIOCGWINSZ
247
/****************************************************************************
248
249
get_columns
250
251
Determines the number of columns of /dev/tty. Returns the number of
252
columns, or -1 if error. May return 0 if columns unknown.
253
Requires include files <fcntl.h> and <sys/ioctl.h>.
254
by Glenn Chappell & Ian Chai 14 Apr 1993
255
256
****************************************************************************/
257
258
int get_columns()
259
{
260
struct winsize ws;
261
int fd,result;
262
263
if ((fd = open("/dev/tty",O_WRONLY))<0) return -1;
264
result = ioctl(fd,TIOCGWINSZ,&ws);
265
close(fd);
266
return result?-1:ws.ws_col;
267
}
268
#endif /* ifdef TIOCGWINSZ */
269
270
271
/****************************************************************************
272
273
myalloc
274
275
Calls malloc. If malloc returns error, prints error message and
276
quits.
277
278
****************************************************************************/
279
280
#ifdef __STDC__
281
char *myalloc(size_t size)
282
#else
283
char *myalloc(size)
284
int size;
285
#endif
286
{
287
char *ptr;
288
#ifndef __STDC__
289
extern void *malloc();
290
#endif
291
292
if ((ptr = (char*)malloc(size))==NULL) {
293
fprintf(stderr,"%s: Out of memory\n",myname);
294
exit(1);
295
}
296
else {
297
return ptr;
298
}
299
}
300
301
302
/****************************************************************************
303
304
hasdirsep
305
306
Returns true if s1 contains a DIRSEP or DIRSEP2 character.
307
308
****************************************************************************/
309
310
int hasdirsep(s1)
311
char *s1;
312
{
313
if (strchr(s1, DIRSEP)) return 1;
314
else if (strchr(s1, DIRSEP2)) return 1;
315
else return 0;
316
}
317
318
/****************************************************************************
319
320
suffixcmp
321
322
Returns true if s2 is a suffix of s1; uses case-blind comparison.
323
324
****************************************************************************/
325
326
int suffixcmp(s1, s2)
327
char *s1;
328
char *s2;
329
{
330
int len1, len2;
331
332
len1 = MYSTRLEN(s1);
333
len2 = MYSTRLEN(s2);
334
if (len2 > len1) return 0;
335
s1 += len1 - len2;
336
while (*s1) {
337
if (tolower(*s1) != tolower(*s2)) return 0;
338
s1++;
339
s2++;
340
}
341
return 1;
342
}
343
344
/****************************************************************************
345
346
skiptoeol
347
348
Skips to the end of a line, given a stream. Handles \r, \n, or \r\n.
349
350
****************************************************************************/
351
352
void skiptoeol(fp)
353
ZFILE *fp;
354
{
355
int dummy;
356
357
while (dummy=Zgetc(fp),dummy!=EOF) {
358
if (dummy == '\n') return;
359
if (dummy == '\r') {
360
dummy = Zgetc(fp);
361
if (dummy != EOF && dummy != '\n') Zungetc(dummy,fp);
362
return;
363
}
364
}
365
}
366
367
368
/****************************************************************************
369
370
myfgets
371
372
Local version of fgets. Handles \r, \n, and \r\n terminators.
373
374
****************************************************************************/
375
376
char *myfgets(line,maxlen,fp)
377
char *line;
378
int maxlen;
379
ZFILE *fp;
380
{
381
int c = 0;
382
char *p;
383
384
p = line;
385
while((c=Zgetc(fp))!=EOF&&maxlen) {
386
*p++ = c;
387
maxlen--;
388
if (c=='\n') break;
389
if (c=='\r') {
390
c = Zgetc(fp);
391
if (c != EOF && c != '\n') Zungetc(c,fp);
392
*(p-1) = '\n';
393
break;
394
}
395
}
396
*p = 0;
397
return (c==EOF) ? NULL : line;
398
}
399
400
401
/****************************************************************************
402
403
usageerr
404
405
Prints "Usage: ...." line to the given stream.
406
407
****************************************************************************/
408
409
void printusage(out)
410
FILE *out;
411
{
412
fprintf(out,
413
"Usage: %s [ -cklnoprstvxDELNRSWX ] [ -d fontdirectory ]\n",
414
myname);
415
fprintf(out,
416
" [ -f fontfile ] [ -m smushmode ] [ -w outputwidth ]\n");
417
fprintf(out,
418
" [ -C controlfile ] [ -I infocode ] [ message ]\n");
419
}
420
421
422
/****************************************************************************
423
424
printinfo
425
426
Prints version and copyright message, or utility information.
427
428
****************************************************************************/
429
430
void printinfo(infonum)
431
int infonum;
432
{
433
switch (infonum) {
434
case 0: /* Copyright message */
435
printf("FIGlet Copyright (C) 1991-2012 Glenn Chappell, Ian Chai, ");
436
printf("John Cowan,\nChristiaan Keet and Claudio Matsuoka\n");
437
printf("Internet: <[email protected]> ");
438
printf("Version: %s, date: %s\n\n",VERSION,DATE);
439
printf("FIGlet, along with the various FIGlet fonts");
440
printf(" and documentation, may be\n");
441
printf("freely copied and distributed.\n\n");
442
printf("If you use FIGlet, please send an");
443
printf(" e-mail message to <[email protected]>.\n\n");
444
printf("The latest version of FIGlet is available from the");
445
printf(" web site,\n\thttp://www.figlet.org/\n\n");
446
printusage(stdout);
447
break;
448
case 1: /* Version (integer) */
449
printf("%d\n",VERSION_INT);
450
break;
451
case 2: /* Font directory */
452
printf("%s\n",fontdirname);
453
break;
454
case 3: /* Font */
455
printf("%s\n",fontname);
456
break;
457
case 4: /* Outputwidth */
458
printf("%d\n",outputwidth);
459
break;
460
case 5: /* Font formats */
461
printf("%s", FONTFILEMAGICNUMBER);
462
#ifdef TLF_FONTS
463
printf(" %s", TOILETFILEMAGICNUMBER);
464
#endif
465
printf("\n");
466
}
467
}
468
469
470
/****************************************************************************
471
472
readmagic
473
474
Reads a four-character magic string from a stream.
475
476
****************************************************************************/
477
void readmagic(fp,magic)
478
ZFILE *fp;
479
char *magic;
480
{
481
int i;
482
483
for (i=0;i<4;i++) {
484
magic[i] = Zgetc(fp);
485
}
486
magic[4] = 0;
487
}
488
489
/****************************************************************************
490
491
skipws
492
493
Skips whitespace characters from a stream.
494
495
****************************************************************************/
496
void skipws(fp)
497
ZFILE *fp;
498
{
499
int c;
500
while (c=Zgetc(fp),isascii(c)&&isspace(c)) ;
501
Zungetc(c,fp);
502
}
503
504
/****************************************************************************
505
506
readnum
507
508
Reads a number from a stream. Accepts "0" prefix for octal and
509
"0x" or "0X" for hexadecimal. Ignores leading whitespace.
510
511
****************************************************************************/
512
void readnum(fp,nump)
513
ZFILE *fp;
514
inchr *nump;
515
{
516
int acc = 0;
517
char *p;
518
int c;
519
int base;
520
int sign = 1;
521
char digits[] = "0123456789ABCDEF";
522
523
skipws(fp);
524
c = Zgetc(fp);
525
if (c=='-') {
526
sign = -1;
527
}
528
else {
529
Zungetc(c,fp);
530
}
531
c = Zgetc(fp);
532
if (c=='0') {
533
c = Zgetc(fp);
534
if (c=='x'||c=='X') {
535
base = 16;
536
}
537
else {
538
base = 8;
539
Zungetc(c,fp);
540
}
541
}
542
else {
543
base = 10;
544
Zungetc(c,fp);
545
}
546
547
while((c=Zgetc(fp))!=EOF) {
548
c=toupper(c);
549
p=strchr(digits,c);
550
if (!p) {
551
Zungetc(c,fp);
552
*nump = acc * sign;
553
return;
554
}
555
acc = acc*base+(p-digits);
556
}
557
*nump = acc * sign;
558
}
559
560
/****************************************************************************
561
562
readTchar
563
564
Reads a control file "T" command character specification.
565
566
Character is a single byte, an escape sequence, or
567
an escaped numeric.
568
569
****************************************************************************/
570
571
inchr readTchar(fp)
572
ZFILE *fp;
573
{
574
inchr thechar;
575
char next;
576
577
thechar=Zgetc(fp);
578
if (thechar=='\n' || thechar=='\r') { /* Handle badly-formatted file */
579
Zungetc(thechar,fp);
580
return '\0';
581
}
582
if (thechar!='\\') return thechar;
583
next=Zgetc(fp);
584
switch(next) {
585
case 'a':
586
return 7;
587
case 'b':
588
return 8;
589
case 'e':
590
return 27;
591
case 'f':
592
return 12;
593
case 'n':
594
return 10;
595
case 'r':
596
return 13;
597
case 't':
598
return 9;
599
case 'v':
600
return 11;
601
default:
602
if (next=='-' || next=='x' || (next>='0' && next<='9')) {
603
Zungetc(next,fp);
604
readnum(fp,&thechar);
605
return thechar;
606
}
607
return next;
608
}
609
}
610
611
/****************************************************************************
612
613
charsetname
614
615
Get a Tchar representing a charset name, or 0 if none available.
616
Called in getcharset().
617
618
****************************************************************************/
619
620
inchr charsetname(fp)
621
ZFILE *fp;
622
{
623
inchr result;
624
625
result = readTchar(fp);
626
if (result == '\n' || result == '\r') {
627
result = 0;
628
Zungetc(result,fp);
629
}
630
return result;
631
}
632
633
/****************************************************************************
634
635
charset
636
637
Processes "g[0123]" character set specifier
638
Called in readcontrol().
639
640
****************************************************************************/
641
642
void charset(n, controlfile)
643
int n;
644
ZFILE *controlfile;
645
{
646
int ch;
647
648
skipws(controlfile);
649
if (Zgetc(controlfile) != '9') {
650
skiptoeol(controlfile);
651
return;
652
}
653
ch = Zgetc(controlfile);
654
if (ch == '6') {
655
gn[n] = 65536L * charsetname(controlfile) + 0x80;
656
gndbl[n] = 0;
657
skiptoeol(controlfile);
658
return;
659
}
660
if (ch != '4') {
661
skiptoeol(controlfile);
662
return;
663
}
664
ch = Zgetc(controlfile);
665
if (ch == 'x') {
666
if (Zgetc(controlfile) != '9') {
667
skiptoeol(controlfile);
668
return;
669
}
670
if (Zgetc(controlfile) != '4') {
671
skiptoeol(controlfile);
672
return;
673
}
674
skipws(controlfile);
675
gn[n] = 65536L * charsetname(controlfile);
676
gndbl[n] = 1;
677
skiptoeol(controlfile);
678
return;
679
}
680
Zungetc(ch, controlfile);
681
skipws(controlfile);
682
gn[n] = 65536L * charsetname(controlfile);
683
gndbl[n] = 0;
684
return;
685
}
686
687
/****************************************************************************
688
689
FIGopen
690
691
Given a FIGlet font or control file name and suffix, return the file
692
or NULL if not found
693
694
****************************************************************************/
695
696
ZFILE *FIGopen(name,suffix)
697
char *name;
698
char *suffix;
699
{
700
char *fontpath;
701
ZFILE *fontfile;
702
struct stat st;
703
int namelen;
704
705
namelen = MYSTRLEN(fontdirname);
706
fontpath = (char*)alloca(sizeof(char)*
707
(namelen+MYSTRLEN(name)+MYSTRLEN(suffix)+2));
708
fontfile = NULL;
709
if (!hasdirsep(name)) { /* not a full path name */
710
strcpy(fontpath,fontdirname);
711
fontpath[namelen] = DIRSEP;
712
fontpath[namelen+1] = '\0';
713
strcat(fontpath,name);
714
strcat(fontpath,suffix);
715
if(stat(fontpath,&st)==0) goto ok;
716
}
717
/* just append suffix */
718
strcpy(fontpath,name);
719
strcat(fontpath,suffix);
720
if(stat(fontpath,&st)==0) goto ok;
721
722
return NULL;
723
724
ok:
725
fontfile = Zopen(fontpath,"rb");
726
return fontfile;
727
}
728
729
/****************************************************************************
730
731
readcontrol
732
733
Allocates memory and reads in the given control file.
734
Called in readcontrolfiles().
735
736
****************************************************************************/
737
738
void readcontrol(controlname)
739
char *controlname;
740
{
741
inchr firstch,lastch;
742
char dashcheck;
743
inchr offset;
744
int command;
745
ZFILE *controlfile;
746
747
controlfile = FIGopen(controlname,CONTROLFILESUFFIX);
748
749
if (controlfile==NULL) {
750
fprintf(stderr,"%s: %s: Unable to open control file\n",myname,
751
controlname);
752
exit(1);
753
}
754
755
(*commandlistend) = (comnode*)myalloc(sizeof(comnode));
756
(*commandlistend)->thecommand = 0; /* Begin with a freeze command */
757
commandlistend = &(*commandlistend)->next;
758
(*commandlistend) = NULL;
759
760
while(command=Zgetc(controlfile),command!=EOF) {
761
switch (command) {
762
case 't': /* Translate */
763
skipws(controlfile);
764
firstch=readTchar(controlfile);
765
if ((dashcheck=Zgetc(controlfile))=='-') {
766
lastch=readTchar(controlfile);
767
}
768
else {
769
Zungetc(dashcheck,controlfile);
770
lastch=firstch;
771
}
772
skipws(controlfile);
773
offset=readTchar(controlfile)-firstch;
774
skiptoeol(controlfile);
775
(*commandlistend) = (comnode*)myalloc(sizeof(comnode));
776
(*commandlistend)->thecommand = 1;
777
(*commandlistend)->rangelo = firstch;
778
(*commandlistend)->rangehi = lastch;
779
(*commandlistend)->offset = offset;
780
commandlistend = &(*commandlistend)->next;
781
(*commandlistend) = NULL;
782
break;
783
case '0': case '1': case '2': case '3': case '4':
784
case '5': case '6': case '7': case '8': case '9':
785
case '-':
786
/* Mapping table entry */
787
Zungetc(command,controlfile);
788
readnum(controlfile,&firstch);
789
skipws(controlfile);
790
readnum(controlfile,&lastch);
791
offset=lastch-firstch;
792
lastch=firstch;
793
skiptoeol(controlfile);
794
(*commandlistend) = (comnode*)myalloc(sizeof(comnode));
795
(*commandlistend)->thecommand = 1;
796
(*commandlistend)->rangelo = firstch;
797
(*commandlistend)->rangehi = lastch;
798
(*commandlistend)->offset = offset;
799
commandlistend = &(*commandlistend)->next;
800
(*commandlistend) = NULL;
801
break;
802
case 'f': /* freeze */
803
skiptoeol(controlfile);
804
(*commandlistend) = (comnode*)myalloc(sizeof(comnode));
805
(*commandlistend)->thecommand = 0;
806
commandlistend = &(*commandlistend)->next;
807
(*commandlistend) = NULL;
808
break;
809
case 'b': /* DBCS input mode */
810
multibyte = 1;
811
break;
812
case 'u': /* UTF-8 input mode */
813
multibyte = 2;
814
break;
815
case 'h': /* HZ input mode */
816
multibyte = 3;
817
break;
818
case 'j': /* Shift-JIS input mode */
819
multibyte = 4;
820
break;
821
case 'g': /* ISO 2022 character set choices */
822
multibyte = 0;
823
skipws(controlfile);
824
command=Zgetc(controlfile);
825
switch (command) {
826
case '0': /* define G0 charset */
827
charset(0, controlfile);
828
break;
829
case '1': /* set G1 charset */
830
charset(1, controlfile);
831
break;
832
case '2': /* set G2 charset */
833
charset(2, controlfile);
834
break;
835
case '3': /* set G3 charset */
836
charset(3, controlfile);
837
break;
838
case 'l': case 'L': /* define left half */
839
skipws(controlfile);
840
gl = Zgetc(controlfile) - '0';
841
skiptoeol(controlfile);
842
break;
843
case 'r': case 'R': /* define right half */
844
skipws(controlfile);
845
gr = Zgetc(controlfile) - '0';
846
skiptoeol(controlfile);
847
break;
848
default: /* meaningless "g" command */
849
skiptoeol(controlfile);
850
}
851
case '\r': case '\n': /* blank line */
852
break;
853
default: /* Includes '#' */
854
skiptoeol(controlfile);
855
}
856
}
857
Zclose(controlfile);
858
}
859
860
861
/****************************************************************************
862
863
readcontrolfiles
864
865
Reads in the controlfiles names in cfilelist. Uses readcontrol.
866
Called in main().
867
868
****************************************************************************/
869
870
void readcontrolfiles()
871
{
872
cfnamenode *cfnptr;
873
874
for (cfnptr=cfilelist;cfnptr!=NULL;cfnptr=cfnptr->next) {
875
readcontrol(cfnptr->thename);
876
}
877
}
878
879
880
/****************************************************************************
881
882
clearcfilelist
883
884
Clears the control file list. Assumes thename does not need freeing.
885
886
****************************************************************************/
887
888
void clearcfilelist()
889
{
890
cfnamenode *cfnptr1,*cfnptr2;
891
892
cfnptr1 = cfilelist;
893
while (cfnptr1 != NULL) {
894
cfnptr2 = cfnptr1->next;
895
free(cfnptr1);
896
cfnptr1 = cfnptr2;
897
}
898
cfilelist = NULL;
899
cfilelistend = &cfilelist;
900
}
901
902
903
/****************************************************************************
904
905
getparams
906
907
Handles all command-line parameters. Puts all parameters within
908
bounds.
909
910
****************************************************************************/
911
912
void getparams()
913
{
914
extern char *optarg;
915
extern int optind;
916
int c; /* "Should" be a char -- need int for "!= -1" test*/
917
int columns,infoprint;
918
char *controlname,*env;
919
920
if ((myname = strrchr(Myargv[0],DIRSEP))!=NULL) {
921
myname++;
922
}
923
else {
924
myname = Myargv[0];
925
}
926
fontdirname = DEFAULTFONTDIR;
927
env = getenv("FIGLET_FONTDIR");
928
if (env!=NULL) {
929
fontdirname = env;
930
}
931
fontname = DEFAULTFONTFILE;
932
cfilelist = NULL;
933
cfilelistend = &cfilelist;
934
commandlist = NULL;
935
commandlistend = &commandlist;
936
smushoverride = SMO_NO;
937
deutschflag = 0;
938
justification = -1;
939
right2left = -1;
940
paragraphflag = 0;
941
infoprint = -1;
942
cmdinput = 0;
943
outputwidth = DEFAULTCOLUMNS;
944
gn[1] = 0x80;
945
gr = 1;
946
while ((c = getopt(Myargc,Myargv,"ADEXLRI:xlcrpntvm:w:d:f:C:NFskSWo"))!= -1) {
947
/* Note: -F is not a legal option -- prints a special err message. */
948
switch (c) {
949
case 'A':
950
cmdinput = 1;
951
break;
952
case 'D':
953
deutschflag = 1;
954
break;
955
case 'E':
956
deutschflag = 0;
957
break;
958
case 'X':
959
right2left = -1;
960
break;
961
case 'L':
962
right2left = 0;
963
break;
964
case 'R':
965
right2left = 1;
966
break;
967
case 'x':
968
justification = -1;
969
break;
970
case 'l':
971
justification = 0;
972
break;
973
case 'c':
974
justification = 1;
975
break;
976
case 'r':
977
justification = 2;
978
break;
979
case 'p':
980
paragraphflag = 1;
981
break;
982
case 'n':
983
paragraphflag = 0;
984
break;
985
case 's':
986
smushoverride = SMO_NO;
987
break;
988
case 'k':
989
smushmode = SM_KERN;
990
smushoverride = SMO_YES;
991
break;
992
case 'S':
993
smushmode = SM_SMUSH;
994
smushoverride = SMO_FORCE;
995
break;
996
case 'o':
997
smushmode = SM_SMUSH;
998
smushoverride = SMO_YES;
999
break;
1000
case 'W':
1001
smushmode = 0;
1002
smushoverride = SMO_YES;
1003
break;
1004
case 't':
1005
#ifdef TIOCGWINSZ
1006
columns = get_columns();
1007
if (columns>0) {
1008
outputwidth = columns;
1009
}
1010
#else /* ifdef TIOCGWINSZ */
1011
fprintf(stderr,
1012
"%s: \"-t\" is disabled, since ioctl is not fully implemented.\n",
1013
myname);
1014
#endif /* ifdef TIOCGWINSZ */
1015
break;
1016
case 'v':
1017
infoprint = 0;
1018
break;
1019
case 'I':
1020
infoprint = atoi(optarg);
1021
break;
1022
case 'm':
1023
smushmode = atoi(optarg);
1024
if (smushmode < -1) {
1025
smushoverride = SMO_NO;
1026
break;
1027
}
1028
if (smushmode == 0) smushmode = SM_KERN;
1029
else if (smushmode == -1) smushmode = 0;
1030
else smushmode = (smushmode & 63) | SM_SMUSH;
1031
smushoverride = SMO_YES;
1032
break;
1033
case 'w':
1034
columns = atoi(optarg);
1035
if (columns>0) {
1036
outputwidth = columns;
1037
}
1038
break;
1039
case 'd':
1040
fontdirname = optarg;
1041
break;
1042
case 'f':
1043
fontname = optarg;
1044
if (suffixcmp(fontname,FONTFILESUFFIX)) {
1045
fontname[MYSTRLEN(fontname)-FSUFFIXLEN] = '\0';
1046
}
1047
#ifdef TLF_FONTS
1048
else if (suffixcmp(fontname,TOILETFILESUFFIX)) {
1049
fontname[MYSTRLEN(fontname)-TSUFFIXLEN] = '\0';
1050
}
1051
#endif
1052
break;
1053
case 'C':
1054
controlname = optarg;
1055
if (suffixcmp(controlname, CONTROLFILESUFFIX)) {
1056
controlname[MYSTRLEN(controlname)-CSUFFIXLEN] = '\0';
1057
}
1058
(*cfilelistend) = (cfnamenode*)myalloc(sizeof(cfnamenode));
1059
(*cfilelistend)->thename = controlname;
1060
cfilelistend = &(*cfilelistend)->next;
1061
(*cfilelistend) = NULL;
1062
break;
1063
case 'N':
1064
clearcfilelist();
1065
multibyte = 0;
1066
gn[0] = 0;
1067
gn[1] = 0x80;
1068
gn[2] = gn[3] = 0;
1069
gndbl[0] = gndbl[1] = gndbl[2] = gndbl[3] = 0;
1070
gl = 0;
1071
gr = 1;
1072
break;
1073
case 'F': /* Not a legal option */
1074
fprintf(stderr,"%s: illegal option -- F\n",myname);
1075
printusage(stderr);
1076
fprintf(stderr,"\nBecause of numerous incompatibilities, the");
1077
fprintf(stderr," \"-F\" option has been\n");
1078
fprintf(stderr,"removed. It has been replaced by the \"figlist\"");
1079
fprintf(stderr," program, which is now\n");
1080
fprintf(stderr,"included in the basic FIGlet package. \"figlist\"");
1081
fprintf(stderr," is also available\n");
1082
fprintf(stderr,"from http://www.figlet.org/");
1083
fprintf(stderr,"under UNIX utilities.\n");
1084
exit(1);
1085
break;
1086
default:
1087
printusage(stderr);
1088
exit(1);
1089
}
1090
}
1091
if (optind!=Myargc) cmdinput = 1; /* force cmdinput if more arguments */
1092
outlinelenlimit = outputwidth-1;
1093
if (infoprint>=0) {
1094
printinfo(infoprint);
1095
exit(0);
1096
}
1097
}
1098
1099
1100
/****************************************************************************
1101
1102
clearline
1103
1104
Clears both the input (inchrline) and output (outputline) storage.
1105
1106
****************************************************************************/
1107
1108
void clearline()
1109
{
1110
int i;
1111
1112
for (i=0;i<charheight;i++) {
1113
outputline[i][0] = '\0';
1114
}
1115
outlinelen = 0;
1116
inchrlinelen = 0;
1117
}
1118
1119
1120
/****************************************************************************
1121
1122
readfontchar
1123
1124
Reads a font character from the font file, and places it in a
1125
newly-allocated entry in the list.
1126
1127
****************************************************************************/
1128
1129
void readfontchar(file,theord)
1130
ZFILE *file;
1131
inchr theord;
1132
{
1133
int row,k;
1134
char templine[MAXLEN+1];
1135
outchr endchar, outline[MAXLEN+1];
1136
fcharnode *fclsave;
1137
1138
fclsave = fcharlist;
1139
fcharlist = (fcharnode*)myalloc(sizeof(fcharnode));
1140
fcharlist->ord = theord;
1141
fcharlist->thechar = (outchr**)myalloc(sizeof(outchr*)*charheight);
1142
fcharlist->next = fclsave;
1143
1144
outline[0] = 0;
1145
1146
for (row=0;row<charheight;row++) {
1147
if (myfgets(templine,MAXLEN,file)==NULL) {
1148
templine[0] = '\0';
1149
}
1150
#ifdef TLF_FONTS
1151
utf8_to_wchar(templine,MAXLEN,outline,MAXLEN,0);
1152
#else
1153
strcpy(outline,templine);
1154
#endif
1155
k = STRLEN(outline)-1;
1156
while (k>=0 && ISSPACE(outline[k])) { /* remove trailing spaces */
1157
k--;
1158
}
1159
if (k>=0) {
1160
endchar = outline[k]; /* remove endmarks */
1161
while (k>=0 && outline[k]==endchar) {
1162
k--;
1163
}
1164
}
1165
outline[k+1] = '\0';
1166
fcharlist->thechar[row] = (outchr*)myalloc(sizeof(outchr)*(STRLEN(outline)+1));
1167
STRCPY(fcharlist->thechar[row],outline);
1168
}
1169
}
1170
1171
1172
/****************************************************************************
1173
1174
readfont
1175
1176
Allocates memory, initializes variables, and reads in the font.
1177
Called near beginning of main().
1178
1179
****************************************************************************/
1180
1181
void readfont()
1182
{
1183
int i,row,numsread;
1184
inchr theord;
1185
int maxlen,cmtlines,ffright2left;
1186
int smush,smush2;
1187
char fileline[MAXLEN+1],magicnum[5];
1188
ZFILE *fontfile;
1189
1190
fontfile = FIGopen(fontname,FONTFILESUFFIX);
1191
#ifdef TLF_FONTS
1192
if (fontfile==NULL) {
1193
fontfile = FIGopen(fontname,TOILETFILESUFFIX);
1194
if(fontfile) toiletfont = 1;
1195
}
1196
#endif
1197
1198
if (fontfile==NULL) {
1199
fprintf(stderr,"%s: %s: Unable to open font file\n",myname,fontname);
1200
exit(1);
1201
}
1202
1203
readmagic(fontfile,magicnum);
1204
if (myfgets(fileline,MAXLEN,fontfile)==NULL) {
1205
fileline[0] = '\0';
1206
}
1207
if (MYSTRLEN(fileline)>0 ? fileline[MYSTRLEN(fileline)-1]!='\n' : 0) {
1208
skiptoeol(fontfile);
1209
}
1210
numsread = sscanf(fileline,"%*c%c %d %*d %d %d %d %d %d",
1211
&hardblank,&charheight,&maxlen,&smush,&cmtlines,
1212
&ffright2left,&smush2);
1213
1214
if (maxlen > MAXLEN) {
1215
fprintf(stderr,"%s: %s: character is too wide\n",myname,fontname);
1216
exit(1);
1217
}
1218
#ifdef TLF_FONTS
1219
if ((!toiletfont && strcmp(magicnum,FONTFILEMAGICNUMBER)) ||
1220
(toiletfont && strcmp(magicnum,TOILETFILEMAGICNUMBER)) || numsread<5) {
1221
#else
1222
if (strcmp(magicnum,FONTFILEMAGICNUMBER) || numsread<5) {
1223
#endif
1224
fprintf(stderr,"%s: %s: Not a FIGlet 2 font file\n",myname,fontname);
1225
exit(1);
1226
}
1227
for (i=1;i<=cmtlines;i++) {
1228
skiptoeol(fontfile);
1229
}
1230
1231
if (numsread<6) {
1232
ffright2left = 0;
1233
}
1234
1235
if (numsread<7) { /* if no smush2, decode smush into smush2 */
1236
if (smush == 0) smush2 = SM_KERN;
1237
else if (smush < 0) smush2 = 0;
1238
else smush2 = (smush & 31) | SM_SMUSH;
1239
}
1240
1241
if (charheight<1) {
1242
charheight = 1;
1243
}
1244
1245
if (maxlen<1) {
1246
maxlen = 1;
1247
}
1248
1249
maxlen += 100; /* Give ourselves some extra room */
1250
1251
if (smushoverride == SMO_NO)
1252
smushmode = smush2;
1253
else if (smushoverride == SMO_FORCE)
1254
smushmode |= smush2;
1255
1256
if (right2left<0) {
1257
right2left = ffright2left;
1258
}
1259
1260
if (justification<0) {
1261
justification = 2*right2left;
1262
}
1263
1264
/* Allocate "missing" character */
1265
fcharlist = (fcharnode*)myalloc(sizeof(fcharnode));
1266
fcharlist->ord = 0;
1267
fcharlist->thechar = (outchr**)myalloc(sizeof(outchr*)*charheight);
1268
fcharlist->next = NULL;
1269
for (row=0;row<charheight;row++) {
1270
fcharlist->thechar[row] = (outchr*)myalloc(sizeof(outchr));
1271
fcharlist->thechar[row][0] = '\0';
1272
}
1273
for (theord=' ';theord<='~';theord++) {
1274
readfontchar(fontfile,theord);
1275
}
1276
for (theord=0;theord<=6;theord++) {
1277
readfontchar(fontfile,deutsch[theord]);
1278
}
1279
while (myfgets(fileline,maxlen+1,fontfile)==NULL?0:
1280
sscanf(fileline,"%li",&theord)==1) {
1281
readfontchar(fontfile,theord);
1282
}
1283
Zclose(fontfile);
1284
}
1285
1286
1287
/****************************************************************************
1288
1289
linealloc
1290
1291
Allocates & clears outputline, inchrline. Sets inchrlinelenlimit.
1292
Called near beginning of main().
1293
1294
****************************************************************************/
1295
1296
void linealloc()
1297
{
1298
int row;
1299
1300
outputline = (outchr**)myalloc(sizeof(outchr*)*charheight);
1301
for (row=0;row<charheight;row++) {
1302
outputline[row] = (outchr*)myalloc(sizeof(outchr)*(outlinelenlimit+1));
1303
}
1304
inchrlinelenlimit = outputwidth*4+100;
1305
inchrline = (inchr*)myalloc(sizeof(inchr)*(inchrlinelenlimit+1));
1306
clearline();
1307
}
1308
1309
1310
/****************************************************************************
1311
1312
getletter
1313
1314
Sets currchar to point to the font entry for the given character.
1315
Sets currcharwidth to the width of this character.
1316
1317
****************************************************************************/
1318
1319
void getletter(c)
1320
inchr c;
1321
{
1322
fcharnode *charptr;
1323
1324
for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=c;
1325
charptr=charptr->next) ;
1326
if (charptr!=NULL) {
1327
currchar = charptr->thechar;
1328
}
1329
else {
1330
for (charptr=fcharlist;charptr==NULL?0:charptr->ord!=0;
1331
charptr=charptr->next) ;
1332
currchar = charptr->thechar;
1333
}
1334
previouscharwidth = currcharwidth;
1335
currcharwidth = STRLEN(currchar[0]);
1336
}
1337
1338
1339
/****************************************************************************
1340
1341
smushem
1342
1343
Given 2 characters, attempts to smush them into 1, according to
1344
smushmode. Returns smushed character or '\0' if no smushing can be
1345
done.
1346
1347
smushmode values are sum of following (all values smush blanks):
1348
1: Smush equal chars (not hardblanks)
1349
2: Smush '_' with any char in hierarchy below
1350
4: hierarchy: "|", "/\", "[]", "{}", "()", "<>"
1351
Each class in hier. can be replaced by later class.
1352
8: [ + ] -> |, { + } -> |, ( + ) -> |
1353
16: / + \ -> X, > + < -> X (only in that order)
1354
32: hardblank + hardblank -> hardblank
1355
1356
****************************************************************************/
1357
1358
outchr smushem(lch,rch)
1359
outchr lch,rch;
1360
{
1361
if (lch==' ') return rch;
1362
if (rch==' ') return lch;
1363
1364
if (previouscharwidth<2 || currcharwidth<2) return '\0';
1365
/* Disallows overlapping if the previous character */
1366
/* or the current character has a width of 1 or zero. */
1367
1368
if ((smushmode & SM_SMUSH) == 0) return '\0'; /* kerning */
1369
1370
if ((smushmode & 63) == 0) {
1371
/* This is smushing by universal overlapping. */
1372
if (lch==' ') return rch;
1373
if (rch==' ') return lch;
1374
if (lch==hardblank) return rch;
1375
if (rch==hardblank) return lch;
1376
/* Above four lines ensure overlapping preference to */
1377
/* visible characters. */
1378
if (right2left==1) return lch;
1379
/* Above line ensures that the dominant (foreground) */
1380
/* fig-character for overlapping is the latter in the */
1381
/* user's text, not necessarily the rightmost character. */
1382
return rch;
1383
/* Occurs in the absence of above exceptions. */
1384
}
1385
1386
if (smushmode & SM_HARDBLANK) {
1387
if (lch==hardblank && rch==hardblank) return lch;
1388
}
1389
1390
if (lch==hardblank || rch==hardblank) return '\0';
1391
1392
if (smushmode & SM_EQUAL) {
1393
if (lch==rch) return lch;
1394
}
1395
1396
if (smushmode & SM_LOWLINE) {
1397
if (lch=='_' && strchr("|/\\[]{}()<>",rch)) return rch;
1398
if (rch=='_' && strchr("|/\\[]{}()<>",lch)) return lch;
1399
}
1400
1401
if (smushmode & SM_HIERARCHY) {
1402
if (lch=='|' && strchr("/\\[]{}()<>",rch)) return rch;
1403
if (rch=='|' && strchr("/\\[]{}()<>",lch)) return lch;
1404
if (strchr("/\\",lch) && strchr("[]{}()<>",rch)) return rch;
1405
if (strchr("/\\",rch) && strchr("[]{}()<>",lch)) return lch;
1406
if (strchr("[]",lch) && strchr("{}()<>",rch)) return rch;
1407
if (strchr("[]",rch) && strchr("{}()<>",lch)) return lch;
1408
if (strchr("{}",lch) && strchr("()<>",rch)) return rch;
1409
if (strchr("{}",rch) && strchr("()<>",lch)) return lch;
1410
if (strchr("()",lch) && strchr("<>",rch)) return rch;
1411
if (strchr("()",rch) && strchr("<>",lch)) return lch;
1412
}
1413
1414
if (smushmode & SM_PAIR) {
1415
if (lch=='[' && rch==']') return '|';
1416
if (rch=='[' && lch==']') return '|';
1417
if (lch=='{' && rch=='}') return '|';
1418
if (rch=='{' && lch=='}') return '|';
1419
if (lch=='(' && rch==')') return '|';
1420
if (rch=='(' && lch==')') return '|';
1421
}
1422
1423
if (smushmode & SM_BIGX) {
1424
if (lch=='/' && rch=='\\') return '|';
1425
if (rch=='/' && lch=='\\') return 'Y';
1426
if (lch=='>' && rch=='<') return 'X';
1427
/* Don't want the reverse of above to give 'X'. */
1428
}
1429
1430
return '\0';
1431
}
1432
1433
1434
/****************************************************************************
1435
1436
smushamt
1437
1438
Returns the maximum amount that the current character can be smushed
1439
into the current line.
1440
1441
****************************************************************************/
1442
1443
int smushamt()
1444
{
1445
int maxsmush,amt;
1446
int row,linebd,charbd;
1447
outchr ch1,ch2;
1448
1449
if ((smushmode & (SM_SMUSH | SM_KERN)) == 0) {
1450
return 0;
1451
}
1452
maxsmush = currcharwidth;
1453
for (row=0;row<charheight;row++) {
1454
if (right2left) {
1455
if (maxsmush>STRLEN(outputline[row])) {
1456
maxsmush=STRLEN(outputline[row]);
1457
}
1458
for (charbd=STRLEN(currchar[row]);
1459
ch1=currchar[row][charbd],(charbd>0&&(!ch1||ch1==' '));charbd--) ;
1460
for (linebd=0;ch2=outputline[row][linebd],ch2==' ';linebd++) ;
1461
amt = linebd+currcharwidth-1-charbd;
1462
}
1463
else {
1464
for (linebd=STRLEN(outputline[row]);
1465
ch1 = outputline[row][linebd],(linebd>0&&(!ch1||ch1==' '));linebd--) ;
1466
for (charbd=0;ch2=currchar[row][charbd],ch2==' ';charbd++) ;
1467
amt = charbd+outlinelen-1-linebd;
1468
}
1469
if (!ch1||ch1==' ') {
1470
amt++;
1471
}
1472
else if (ch2) {
1473
if (smushem(ch1,ch2)!='\0') {
1474
amt++;
1475
}
1476
}
1477
if (amt<maxsmush) {
1478
maxsmush = amt;
1479
}
1480
}
1481
return maxsmush;
1482
}
1483
1484
1485
/****************************************************************************
1486
1487
addchar
1488
1489
Attempts to add the given character onto the end of the current line.
1490
Returns 1 if this can be done, 0 otherwise.
1491
1492
****************************************************************************/
1493
1494
int addchar(c)
1495
inchr c;
1496
{
1497
int smushamount,row,k,column;
1498
outchr *templine;
1499
1500
getletter(c);
1501
smushamount = smushamt();
1502
if (outlinelen+currcharwidth-smushamount>outlinelenlimit
1503
||inchrlinelen+1>inchrlinelenlimit) {
1504
return 0;
1505
}
1506
1507
templine = (outchr*)myalloc(sizeof(outchr)*(outlinelenlimit+1));
1508
for (row=0;row<charheight;row++) {
1509
if (right2left) {
1510
STRCPY(templine,currchar[row]);
1511
for (k=0;k<smushamount;k++) {
1512
templine[currcharwidth-smushamount+k] =
1513
smushem(templine[currcharwidth-smushamount+k],outputline[row][k]);
1514
}
1515
STRCAT(templine,outputline[row]+smushamount);
1516
STRCPY(outputline[row],templine);
1517
}
1518
else {
1519
for (k=0;k<smushamount;k++) {
1520
column = outlinelen-smushamount+k;
1521
if (column < 0) {
1522
column = 0;
1523
}
1524
outputline[row][column] =
1525
smushem(outputline[row][column],currchar[row][k]);
1526
}
1527
STRCAT(outputline[row],currchar[row]+smushamount);
1528
}
1529
}
1530
free(templine);
1531
outlinelen = STRLEN(outputline[0]);
1532
inchrline[inchrlinelen++] = c;
1533
return 1;
1534
}
1535
1536
1537
/****************************************************************************
1538
1539
putstring
1540
1541
Prints out the given null-terminated string, substituting blanks
1542
for hardblanks. If outputwidth is 1, prints the entire string;
1543
otherwise prints at most outputwidth-1 characters. Prints a newline
1544
at the end of the string. The string is left-justified, centered or
1545
right-justified (taking outputwidth as the screen width) if
1546
justification is 0, 1 or 2, respectively.
1547
1548
****************************************************************************/
1549
1550
void putstring(string)
1551
outchr *string;
1552
{
1553
int i,len;
1554
char c[10];
1555
#ifdef TLF_FONTS
1556
size_t size;
1557
wchar_t wc[2];
1558
#endif
1559
1560
len = STRLEN(string);
1561
if (outputwidth>1) {
1562
if (len>outputwidth-1) {
1563
len = outputwidth-1;
1564
}
1565
if (justification>0) {
1566
for (i=1;(3-justification)*i+len+justification-2<outputwidth;i++) {
1567
putchar(' ');
1568
}
1569
}
1570
}
1571
for (i=0;i<len;i++) {
1572
#ifdef TLF_FONTS
1573
wc[0] = string[i];
1574
wc[1] = 0;
1575
size = wchar_to_utf8(wc,1,c,10,0);
1576
if(size==1) {
1577
if(c[0]==hardblank) {
1578
c[0] = ' ';
1579
}
1580
}
1581
c[size] = 0;
1582
printf("%s",c);
1583
#else
1584
putchar(string[i]==hardblank?' ':string[i]);
1585
#endif
1586
}
1587
putchar('\n');
1588
}
1589
1590
1591
/****************************************************************************
1592
1593
printline
1594
1595
Prints outputline using putstring, then clears the current line.
1596
1597
****************************************************************************/
1598
1599
void printline()
1600
{
1601
int i;
1602
1603
for (i=0;i<charheight;i++) {
1604
putstring(outputline[i]);
1605
}
1606
clearline();
1607
}
1608
1609
1610
/****************************************************************************
1611
1612
splitline
1613
1614
Splits inchrline at the last word break (bunch of consecutive blanks).
1615
Makes a new line out of the first part and prints it using
1616
printline. Makes a new line out of the second part and returns.
1617
1618
****************************************************************************/
1619
1620
void splitline()
1621
{
1622
int i,gotspace,lastspace,len1,len2;
1623
inchr *part1,*part2;
1624
1625
part1 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));
1626
part2 = (inchr*)myalloc(sizeof(inchr)*(inchrlinelen+1));
1627
gotspace = 0;
1628
lastspace = inchrlinelen-1;
1629
for (i=inchrlinelen-1;i>=0;i--) {
1630
if (!gotspace && inchrline[i]==' ') {
1631
gotspace = 1;
1632
lastspace = i;
1633
}
1634
if (gotspace && inchrline[i]!=' ') {
1635
break;
1636
}
1637
}
1638
len1 = i+1;
1639
len2 = inchrlinelen-lastspace-1;
1640
for (i=0;i<len1;i++) {
1641
part1[i] = inchrline[i];
1642
}
1643
for (i=0;i<len2;i++) {
1644
part2[i] = inchrline[lastspace+1+i];
1645
}
1646
clearline();
1647
for (i=0;i<len1;i++) {
1648
addchar(part1[i]);
1649
}
1650
printline();
1651
for (i=0;i<len2;i++) {
1652
addchar(part2[i]);
1653
}
1654
free(part1);
1655
free(part2);
1656
}
1657
1658
1659
/****************************************************************************
1660
1661
handlemapping
1662
1663
Given an input character (type inchr), executes re-mapping commands
1664
read from control files. Returns re-mapped character (inchr).
1665
1666
****************************************************************************/
1667
1668
inchr handlemapping(c)
1669
inchr c;
1670
{
1671
comnode *cmptr;
1672
1673
cmptr=commandlist;
1674
while (cmptr!=NULL) {
1675
if (cmptr->thecommand ?
1676
(c >= cmptr->rangelo && c <= cmptr->rangehi) : 0) {
1677
c += cmptr->offset;
1678
while(cmptr!=NULL ? cmptr->thecommand : 0) {
1679
cmptr=cmptr->next;
1680
}
1681
}
1682
else {
1683
cmptr=cmptr->next;
1684
}
1685
}
1686
return c;
1687
}
1688
1689
/****************************************************************************
1690
1691
Agetchar
1692
1693
Replacement to getchar().
1694
Acts exactly like getchar if -A is NOT specified,
1695
else obtains input from All remaining command line words.
1696
1697
****************************************************************************/
1698
1699
int Agetchar()
1700
{
1701
extern int optind; /* current argv[] element under study */
1702
static int AgetMode = 0; /* >= 0 for displacement into argv[n], <0 EOF */
1703
char *arg; /* pointer to active character */
1704
int c; /* current character */
1705
1706
if ( ! cmdinput ) /* is -A active? */
1707
return( getchar() ); /* no: return stdin character */
1708
1709
if ( AgetMode < 0 || optind >= Myargc ) /* EOF is sticky: */
1710
return( EOF ); /* **ensure it now and forever more */
1711
1712
/* find next character */
1713
arg = Myargv[optind]; /* pointer to active arg */
1714
c = arg[AgetMode++]&0xFF; /* get appropriate char of arg */
1715
1716
if ( ! c ) /* at '\0' that terminates word? */
1717
{ /* at end of word: return ' ' if normal word, '\n' if empty */
1718
c = ' '; /* suppose normal word and return blank */
1719
if ( AgetMode == 1 ) /* if ran out in very 1st char, force \n */
1720
c = '\n'; /* (allows "hello '' world" to do \n at '') */
1721
AgetMode = 0; /* return to char 0 in NEXT word */
1722
if ( ++optind >= Myargc ) /* run up word count and check if at "EOF" */
1723
{ /* just ran out of arguments */
1724
c = EOF; /* return EOF */
1725
AgetMode = -1; /* ensure all future returns return EOF */
1726
}
1727
}
1728
1729
return( c ); /* return appropriate character */
1730
1731
} /* end: Agetchar() */
1732
1733
1734
/****************************************************************************
1735
1736
iso2022
1737
1738
Called by getinchr. Interprets ISO 2022 sequences
1739
1740
******************************************************************************/
1741
1742
inchr iso2022()
1743
{
1744
inchr ch;
1745
inchr ch2;
1746
int save_gl;
1747
int save_gr;
1748
1749
ch = Agetchar();
1750
if (ch == EOF) return ch;
1751
if (ch == 27) ch = Agetchar() + 0x100; /* ESC x */
1752
if (ch == 0x100 + '$') ch = Agetchar() + 0x200; /* ESC $ x */
1753
switch (ch) {
1754
case 14: /* invoke G1 into GL */
1755
gl = 1;
1756
return iso2022();
1757
case 15: /* invoke G0 into GL */
1758
gl = 0;
1759
return iso2022();
1760
case 142: case 'N' + 0x100: /* invoke G2 into GL for next char */
1761
save_gl = gl; save_gr = gr;
1762
gl = gr = 2;
1763
ch = iso2022();
1764
gl = save_gl; gr = save_gr;
1765
return ch;
1766
case 143: case 'O' + 0x100: /* invoke G3 into GL for next char */
1767
save_gl = gl; save_gr = gr;
1768
gl = gr = 3;
1769
ch = iso2022();
1770
gl = save_gl; gr = save_gr;
1771
return ch;
1772
case 'n' + 0x100: /* invoke G2 into GL */
1773
gl = 2;
1774
return iso2022();
1775
case 'o' + 0x100: /* invoke G3 into GL */
1776
gl = 3;
1777
return iso2022();
1778
case '~' + 0x100: /* invoke G1 into GR */
1779
gr = 1;
1780
return iso2022();
1781
case '}' + 0x100: /* invoke G2 into GR */
1782
gr = 2;
1783
return iso2022();
1784
case '|' + 0x100: /* invoke G3 into GR */
1785
gr = 3;
1786
return iso2022();
1787
case '(' + 0x100: /* set G0 to 94-char set */
1788
ch = Agetchar();
1789
if (ch == 'B') ch = 0; /* ASCII */
1790
gn[0] = ch << 16;
1791
gndbl[0] = 0;
1792
return iso2022();
1793
case ')' + 0x100: /* set G1 to 94-char set */
1794
ch = Agetchar();
1795
if (ch == 'B') ch = 0;
1796
gn[1] = ch << 16;
1797
gndbl[1] = 0;
1798
return iso2022();
1799
case '*' + 0x100: /* set G2 to 94-char set */
1800
ch = Agetchar();
1801
if (ch == 'B') ch = 0;
1802
gn[2] = ch << 16;
1803
gndbl[2] = 0;
1804
return iso2022();
1805
case '+' + 0x100: /* set G3 to 94-char set */
1806
ch = Agetchar();
1807
if (ch == 'B') ch = 0;
1808
gn[3] = ch << 16;
1809
gndbl[3] = 0;
1810
return iso2022();
1811
case '-' + 0x100: /* set G1 to 96-char set */
1812
ch = Agetchar();
1813
if (ch == 'A') ch = 0; /* Latin-1 top half */
1814
gn[1] = (ch << 16) | 0x80;
1815
gndbl[1] = 0;
1816
return iso2022();
1817
case '.' + 0x100: /* set G2 to 96-char set */
1818
ch = Agetchar();
1819
if (ch == 'A') ch = 0;
1820
gn[2] = (ch << 16) | 0x80;
1821
gndbl[2] = 0;
1822
return iso2022();
1823
case '/' + 0x100: /* set G3 to 96-char set */
1824
ch = Agetchar();
1825
if (ch == 'A') ch = 0;
1826
gn[3] = (ch << 16) | 0x80;
1827
gndbl[3] = 0;
1828
return iso2022();
1829
case '(' + 0x200: /* set G0 to 94 x 94 char set */
1830
ch = Agetchar();
1831
gn[0] = ch << 16;
1832
gndbl[0] = 1;
1833
return iso2022();
1834
case ')' + 0x200: /* set G1 to 94 x 94 char set */
1835
ch = Agetchar();
1836
gn[1] = ch << 16;
1837
gndbl[1] = 1;
1838
return iso2022();
1839
case '*' + 0x200: /* set G2 to 94 x 94 char set */
1840
ch = Agetchar();
1841
gn[2] = ch << 16;
1842
gndbl[2] = 1;
1843
return iso2022();
1844
case '+' + 0x200: /* set G3 to 94 x 94 char set */
1845
ch = Agetchar();
1846
gn[3] = ch << 16;
1847
gndbl[3] = 1;
1848
return iso2022();
1849
default:
1850
if (ch & 0x200) { /* set G0 to 94 x 94 char set (deprecated) */
1851
gn[0] = (ch & ~0x200) << 16;
1852
gndbl[0] = 1;
1853
return iso2022();
1854
}
1855
}
1856
1857
if (ch >= 0x21 && ch <= 0x7E) { /* process GL */
1858
if (gndbl[gl]) {
1859
ch2 = Agetchar();
1860
return gn[gl] | (ch << 8) | ch2;
1861
}
1862
else return gn[gl] | ch;
1863
}
1864
else if (ch >= 0xA0 && ch <= 0xFF) { /* process GR */
1865
if (gndbl[gr]) {
1866
ch2 = Agetchar();
1867
return gn[gr] | (ch << 8) | ch2;
1868
}
1869
else return gn[gr] | (ch & ~0x80);
1870
}
1871
else return ch;
1872
}
1873
1874
/****************************************************************************
1875
1876
ungetinchr
1877
1878
Called by main. Pushes back an "inchr" to be read by getinchr
1879
on the next call.
1880
1881
******************************************************************************/
1882
inchr getinchr_buffer;
1883
int getinchr_flag;
1884
1885
inchr ungetinchr(c)
1886
inchr c;
1887
{
1888
getinchr_buffer = c;
1889
getinchr_flag = 1;
1890
return c;
1891
}
1892
1893
/*****************************************************************************
1894
1895
getinchr
1896
1897
Called by main. Processes multibyte characters. Invokes Agetchar.
1898
If multibyte = 0, ISO 2022 mode (see iso2022 routine).
1899
If multibyte = 1, double-byte mode (0x00-0x7f bytes are characters,
1900
0x80-0xFF bytes are first byte of a double-byte character).
1901
If multibyte = 2, Unicode UTF-8 mode (0x00-0x7F bytes are characters,
1902
0x80-0xBF bytes are nonfirst byte of a multibyte character,
1903
0xC0-0xFD bytes are first byte of a multibyte character,
1904
0xFE-0xFF bytes are errors (all errors return code 0x0080)).
1905
If multibyte = 3, HZ mode ("~{" starts double-byte mode, "}~" ends it,
1906
"~~" is a tilde, "~x" for all other x is ignored).
1907
If multibyte = 4, Shift-JIS mode (0x80-0x9F and 0xE0-0xEF are first byte
1908
of a double-byte character, all other bytes are characters).
1909
1910
1911
*****************************************************************************/
1912
1913
inchr getinchr()
1914
{
1915
int ch, ch2, ch3, ch4, ch5, ch6;
1916
1917
if (getinchr_flag) {
1918
getinchr_flag = 0;
1919
return getinchr_buffer;
1920
}
1921
1922
switch(multibyte) {
1923
case 0: /* single-byte */
1924
return iso2022();
1925
case 1: /* DBCS */
1926
ch = Agetchar();
1927
if ((ch >= 0x80 && ch <= 0x9F) ||
1928
(ch >= 0xE0 && ch <= 0xEF)) {
1929
ch = (ch << 8) + Agetchar();
1930
}
1931
return ch;
1932
case 2: /* UTF-8 */
1933
ch = Agetchar();
1934
if (ch < 0x80) return ch; /* handles EOF, too */
1935
if (ch < 0xC0 || ch > 0xFD)
1936
return 0x0080; /* illegal first character */
1937
ch2 = Agetchar() & 0x3F;
1938
if (ch < 0xE0) return ((ch & 0x1F) << 6) + ch2;
1939
ch3 = Agetchar() & 0x3F;
1940
if (ch < 0xF0)
1941
return ((ch & 0x0F) << 12) + (ch2 << 6) + ch3;
1942
ch4 = Agetchar() & 0x3F;
1943
if (ch < 0xF8)
1944
return ((ch & 0x07) << 18) + (ch2 << 12) + (ch3 << 6) + ch4;
1945
ch5 = Agetchar() & 0x3F;
1946
if (ch < 0xFC)
1947
return ((ch & 0x03) << 24) + (ch2 << 18) + (ch3 << 12) +
1948
(ch4 << 6) + ch5;
1949
ch6 = Agetchar() & 0x3F;
1950
return ((ch & 0x01) << 30) + (ch2 << 24) + (ch3 << 18) +
1951
(ch4 << 12) + (ch5 << 6) + ch6;
1952
case 3: /* HZ */
1953
ch = Agetchar();
1954
if (ch == EOF) return ch;
1955
if (hzmode) {
1956
ch = (ch << 8) + Agetchar();
1957
if (ch == ('}' << 8) + '~') {
1958
hzmode = 0;
1959
return getinchr();
1960
}
1961
return ch;
1962
}
1963
else if (ch == '~') {
1964
ch = Agetchar();
1965
if (ch == '{') {
1966
hzmode = 1;
1967
return getinchr();
1968
}
1969
else if (ch == '~') {
1970
return ch;
1971
}
1972
else {
1973
return getinchr();
1974
}
1975
}
1976
else return ch;
1977
case 4: /* Shift-JIS */
1978
ch = Agetchar();
1979
if ((ch >= 0x80 && ch <= 0x9F) ||
1980
(ch >= 0xE0 && ch <= 0xEF)) {
1981
ch = (ch << 8) + Agetchar();
1982
}
1983
return ch;
1984
default:
1985
return 0x80;
1986
}
1987
}
1988
1989
/****************************************************************************
1990
1991
main
1992
1993
The main program, of course.
1994
Reads characters 1 by 1 from stdin, and makes lines out of them using
1995
addchar. Handles line breaking, (which accounts for most of the
1996
complexity in this function).
1997
1998
****************************************************************************/
1999
2000
int main(argc,argv)
2001
int argc;
2002
char *argv[];
2003
{
2004
inchr c,c2;
2005
int i;
2006
int last_was_eol_flag;
2007
/*---------------------------------------------------------------------------
2008
wordbreakmode:
2009
-1: /^$/ and blanks are to be absorbed (when line break was forced
2010
by a blank or character larger than outlinelenlimit)
2011
0: /^ *$/ and blanks are not to be absorbed
2012
1: /[^ ]$/ no word break yet
2013
2: /[^ ] *$/
2014
3: /[^ ]$/ had a word break
2015
---------------------------------------------------------------------------*/
2016
int wordbreakmode;
2017
int char_not_added;
2018
2019
Myargc = argc;
2020
Myargv = argv;
2021
getparams();
2022
readcontrolfiles();
2023
readfont();
2024
linealloc();
2025
2026
wordbreakmode = 0;
2027
last_was_eol_flag = 0;
2028
2029
#ifdef TLF_FONTS
2030
toiletfont = 0;
2031
#endif
2032
2033
while ((c = getinchr())!=EOF) {
2034
2035
if (c=='\n'&&paragraphflag&&!last_was_eol_flag) {
2036
ungetinchr(c2 = getinchr());
2037
c = ((isascii(c2)&&isspace(c2))?'\n':' ');
2038
}
2039
last_was_eol_flag = (isascii(c)&&isspace(c)&&c!='\t'&&c!=' ');
2040
2041
if (deutschflag) {
2042
if (c>='[' && c<=']') {
2043
c = deutsch[c-'['];
2044
}
2045
else if (c >='{' && c <= '~') {
2046
c = deutsch[c-'{'+3];
2047
}
2048
}
2049
2050
c = handlemapping(c);
2051
2052
if (isascii(c)&&isspace(c)) {
2053
c = (c=='\t'||c==' ') ? ' ' : '\n';
2054
}
2055
2056
if ((c>'\0' && c<' ' && c!='\n') || c==127) continue;
2057
2058
/*
2059
Note: The following code is complex and thoroughly tested.
2060
Be careful when modifying!
2061
*/
2062
2063
do {
2064
char_not_added = 0;
2065
2066
if (wordbreakmode== -1) {
2067
if (c==' ') {
2068
break;
2069
}
2070
else if (c=='\n') {
2071
wordbreakmode = 0;
2072
break;
2073
}
2074
wordbreakmode = 0;
2075
}
2076
2077
if (c=='\n') {
2078
printline();
2079
wordbreakmode = 0;
2080
}
2081
2082
else if (addchar(c)) {
2083
if (c!=' ') {
2084
wordbreakmode = (wordbreakmode>=2)?3:1;
2085
}
2086
else {
2087
wordbreakmode = (wordbreakmode>0)?2:0;
2088
}
2089
}
2090
2091
else if (outlinelen==0) {
2092
for (i=0;i<charheight;i++) {
2093
if (right2left && outputwidth>1) {
2094
putstring(currchar[i]+STRLEN(currchar[i])-outlinelenlimit);
2095
}
2096
else {
2097
putstring(currchar[i]);
2098
}
2099
}
2100
wordbreakmode = -1;
2101
}
2102
2103
else if (c==' ') {
2104
if (wordbreakmode==2) {
2105
splitline();
2106
}
2107
else {
2108
printline();
2109
}
2110
wordbreakmode = -1;
2111
}
2112
2113
else {
2114
if (wordbreakmode>=2) {
2115
splitline();
2116
}
2117
else {
2118
printline();
2119
}
2120
wordbreakmode = (wordbreakmode==3)?1:0;
2121
char_not_added = 1;
2122
}
2123
2124
} while (char_not_added);
2125
}
2126
2127
if (outlinelen!=0) {
2128
printline();
2129
}
2130
return 0;
2131
}
2132
2133