4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
40 #pragma ident "%Z%%M% %I% %E% SMI"
42 char *xxxvers
= "@(#)roff:n1.c 2.13";
46 * consume options, initialization, main loop,
47 * input routines, escape function calling
52 #include <sys/types.h>
75 #define MAX_RECURSION_DEPTH 512
78 extern void fdprintf(int, char *, ...);
79 extern char *roff_sprintf(char *, char *, ...);
84 char cfname
[NSO
+1][NS
]; /*file name stack*/
85 int cfline
[NSO
]; /*input line count stack*/
86 char *progname
; /* program name (troff) */
89 char mbbuf1
[MB_LEN_MAX
+ 1];
90 char *mbbuf1p
= mbbuf1
;
96 int debug
= 0; /*debug flag*/
99 static char *sprintn(char *, long, int);
100 static int printn(long, int);
103 main(int argc
, char **argv
)
108 int eileenct
; /*count to test for "Eileen's loop"*/
109 extern void catch(), kcatch();
110 char **oargv
, *getenv();
112 (void)setlocale(LC_ALL
, "");
113 #if !defined(TEXT_DOMAIN)
114 #define TEXT_DOMAIN "SYS_TEST"
116 (void)textdomain(TEXT_DOMAIN
);
118 if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
119 signal(SIGHUP
, catch);
120 if (signal(SIGINT
, catch) == SIG_IGN
) {
121 signal(SIGHUP
, SIG_IGN
);
122 signal(SIGINT
, SIG_IGN
);
123 signal(SIGQUIT
, SIG_IGN
);
125 signal(SIGPIPE
, catch);
126 signal(SIGTERM
, kcatch
);
128 strcpy(cfname
[0], "<standard input>");
137 if ((p
= getenv("TYPESETTER")) != 0)
139 while (--argc
> 0 && (++argv
)[0][0] == '-')
140 switch (argv
[0][1]) {
142 case 'F': /* switch font tables from default */
143 if (argv
[0][2] != '\0') {
144 strcpy(termtab
, &argv
[0][2]);
145 strcpy(fontfile
, &argv
[0][2]);
148 if (argv
[0] != '\0') {
149 strcpy(termtab
, argv
[0]);
150 strcpy(fontfile
, argv
[0]);
152 errprint(gettext("missing the font directory"));
165 errprint(gettext("-q option ignored in troff"));
169 npn
= ctoi(&argv
[0][2]);
171 case 'u': /* set emboldening amount */
172 bdtab
[3] = ctoi(&argv
[0][2]);
173 if (bdtab
[3] < 0 || bdtab
[3] > 50)
177 if (!(stop
= ctoi(&argv
[0][2])))
184 if (&argv
[0][2] != '\0' && strlen(&argv
[0][2]) >= 2 && &argv
[0][3] != '\0')
185 eibuf
= roff_sprintf(ibuf
+strlen(ibuf
), ".nr %c %s\n",
186 argv
[0][2], &argv
[0][3]);
188 errprint(gettext("wrong options"));
193 errprint(gettext("Too many macro packages: %s"),
197 if (argv
[0][2] == '\0') {
198 errprint(gettext("No library provided with -m"));
201 if (getenv("TROFFMACS") != '\0') {
202 if (tryfile(getenv("TROFFMACS"), &argv
[0][2], nmfi
))
205 if (tryfile("/usr/share/lib/tmac/", &argv
[0][2], nmfi
)
206 || tryfile("/usr/share/lib/tmac/tmac.", &argv
[0][2], nmfi
))
209 errprint(gettext("Cannot find library %s\n"),
218 strcpy(devname
, &argv
[0][2]);
245 debug
= ctoi(&argv
[0][2]);
247 errprint("DEBUG not enabled");
251 errprint(gettext("unknown option %s"), argv
[0]);
262 eileenct
= 0; /*reset count for "Eileen's loop"*/
264 copyf
= lgf
= nb
= nflush
= nlflg
= 0;
265 if (ip
&& rbf0(ip
) == 0 && ejf
&& frame
->pframe
<= ejl
) {
268 eject((struct s
*)0);
271 fdprintf(stderr
, "loop: NL=%d, ejf=%d, lss=%d, eileenct=%d\n",
272 numtab
[NL
].val
, ejf
, lss
, eileenct
);
275 errprint(gettext("job looping; check abuse of macros"));
276 ejf
= 0; /*try to break Eileen's loop*/
282 eileenct
= 0; /*reset count for "Eileen's loop"*/
286 if ((j
= cbits(i
)) == XPAR
) {
289 while (cbits(i
) != '\n')
295 if (j
== cc
|| j
== c2
) {
299 while ((j
= cbits(i
= getch())) == ' ' || j
== '\t')
317 tryfile(pat
, fn
, idx
)
321 strcpy(mfiles
[idx
], pat
);
322 strcat(mfiles
[idx
], fn
);
323 if (access(mfiles
[idx
], 4) == -1)
336 signal(SIGTERM
, SIG_IGN
);
343 eibuf
= ibufp
= ibuf
;
360 if ((ibf
= mkstemp(p
)) == -1) {
361 errprint(gettext("cannot create temp file."));
365 for (i
= NTRTAB
; --i
; )
376 extern char *setbrk();
377 extern char *ttyname();
380 if ((ttyp
=ttyname(j
=0)) != 0 || (ttyp
=ttyname(j
=1)) != 0 || (ttyp
=ttyname(j
=2)) != 0)
391 numtab
[PID
].val
= getpid();
394 numtab
[HP
].val
= init
= 0;
399 eibuf
= roff_sprintf(ibuf
+strlen(ibuf
), ".ds .T %s\n", devname
);
400 numtab
[CD
].val
= -1; /* compensation */
404 frame
= stk
= (struct s
*)setbrk(DELTA
);
408 for (i
= 0; i
< NEV
; i
++) {
409 extern tchar corebuf
[];
410 *(struct env
*)&corebuf
[i
* sizeof(env
)/sizeof(tchar
)] = env
;
414 write(ibf
, (char *) & env
, sizeof(env
));
425 tt
= time((time_t *) 0);
427 numtab
[DY
].val
= tm
->tm_mday
;
428 numtab
[DW
].val
= tm
->tm_wday
+ 1;
429 numtab
[YR
].val
= tm
->tm_year
;
430 numtab
[MO
].val
= tm
->tm_mon
+ 1;
445 while (isdigit((unsigned char)*s
))
446 n
= 10 * n
+ *s
++ - '0';
460 mode
= stbuf
.st_mode
;
461 chmod(ttyp
, mode
& ~0122); /* turn off writing for others */
463 if (ttyp
&& *ttyp
&& mode
)
471 errprint(s
, s1
, s2
, s3
, s4
, s5
) /* error message printer */
472 char *s
, *s1
, *s2
, *s3
, *s4
, *s5
;
474 fdprintf(stderr
, "%s: ", progname
);
475 fdprintf(stderr
, s
, s1
, s2
, s3
, s4
, s5
);
476 if (numtab
[CD
].val
> 0)
477 fdprintf(stderr
, gettext("; line %d, file %s"), numtab
[CD
].val
,
479 fdprintf(stderr
, "\n");
490 * Scaled down version of C Library printf.
491 * Only %s %u %d (==%u) %o %c %x %D are recognized.
494 #define putchar(n) (*pfbp++ = (n)) /* NO CHECKING! */
496 static char pfbuf
[NTM
];
497 static char *pfbp
= pfbuf
;
498 int stderr
= 2; /* NOT stdio value */
501 fdprintf(int fd
, char *fmt
, ...)
511 while ((c
= *fmt
++) != '%') {
514 write(stderr
, pfbuf
, pfbp
- pfbuf
);
520 if (obufp
>= &obuf
[OBUFSZ
])
537 } else if (c
== 'u' || c
== 'o' || c
== 'x')
538 printn(va_arg(ap
, long), c
== 'o' ? 8 : (c
== 'x' ? 16 : 10));
540 if (c
> 0177 || c
< 040)
542 putchar(va_arg(ap
, int) & 0177);
543 } else if (c
== 's') {
544 s
= va_arg(ap
, char *);
547 } else if (c
== 'D') {
548 printn(va_arg(ap
, long), 10);
549 } else if (c
== 'O') {
550 printn(va_arg(ap
, long), 8);
557 * Print an unsigned integer in base b.
566 if (n
< 0) { /* shouldn't happen */
572 putchar("0123456789ABCDEF"[(int)(n
%b
)]);
577 /* scaled down version of library roff_sprintf */
578 /* same limits as fdprintf */
579 /* returns pointer to \0 that ends the string */
582 char *roff_sprintf(char *str
, char *fmt
, ...)
591 while ((c
= *fmt
++) != '%') {
606 str
= sprintn(str
, (long)i
, 10);
607 } else if (c
== 'u' || c
== 'o' || c
== 'x')
608 str
= sprintn(str
, va_arg(ap
, long), c
== 'o' ? 8 : (c
== 'x' ? 16 : 10));
610 if (c
> 0177 || c
< 040)
612 *str
++ = va_arg(ap
, int) & 0177;
613 } else if (c
== 's') {
614 s
= va_arg(ap
, char *);
617 } else if (c
== 'D') {
618 str
= sprintn(str
, va_arg(ap
, long), 10);
619 } else if (c
== 'O') {
620 str
= sprintn(str
, va_arg(ap
, unsigned) , 8);
626 * Print an unsigned integer in base b.
628 static char *sprintn(s
, n
, b
)
635 if (n
< 0) { /* shouldn't happen */
640 s
= sprintn(s
, a
, b
);
641 *s
++ = "0123456789ABCDEF"[(int)(n
%b
)];
652 if (a
== 0 || (j
= findmn(a
)) == -1)
656 * Attempt to find endless recursion at runtime. Arbitrary
657 * recursion limit of MAX_RECURSION_DEPTH was chosen as
658 * it is extremely unlikely that a correct nroff/troff
659 * invocation would exceed this value.
666 for (p
= frame
; p
!= stk
; p
= p
->pframe
)
668 if (frame_cnt
> MAX_RECURSION_DEPTH
) {
670 gettext("Exceeded maximum stack size (%d) when "
671 "executing macro %c%c. Stack dump follows"),
673 frame
->mname
& 0177, (frame
->mname
>> BYTE
) & 0177);
680 fdprintf(stderr
, "control: macro %c%c, contab[%d]\n",
681 a
&0177, (a
>>BYTE
)&0177 ? (a
>>BYTE
)&0177 : ' ', j
);
683 if (contab
[j
].f
== 0) {
688 return pushi((filep
)contab
[j
].mx
, a
);
690 return((*contab
[j
].f
)(0));
700 if (((i
= getach()) == 0) || ((j
= getach()) == 0))
708 * table encodes some special characters, to speed up tests
709 * in getchar, viz FLSS, RPT, f, \b, \n, fc, tabch, ldrch
714 000,004,000,000,010,000,000,000, /* fc, ldr */
715 001,002,001,000,001,000,000,000, /* \b, tab, nl, RPT */
716 000,000,000,000,000,000,000,000,
717 000,001,000,000,000,000,000,000, /* FLSS */
718 000,000,000,000,000,000,000,000,
719 000,000,000,000,000,000,000,000,
720 000,000,000,000,000,000,000,000,
721 000,000,000,000,000,000,000,000,
722 000,000,000,000,000,000,000,000,
723 000,000,000,000,000,000,000,000,
724 000,000,000,000,000,000,000,000,
725 000,000,000,000,000,000,000,000,
726 000,000,000,000,000,000,001,000, /* f */
727 000,000,000,000,000,000,000,000,
728 000,000,000,000,000,000,000,000,
729 000,000,000,000,000,000,000,000,
737 tchar
setht(), setslant();
743 fdprintf(stderr
, "getch: ch is %x (%c)\n",
744 ch
, (ch
&0177) < 040 ? 0177 : ch
&0177);
746 if (cbits(i
) == '\n')
755 fdprintf(stderr
,"getch: nlflg is %x\n", nlflg
);
762 fdprintf(stderr
, "getch: getch0 returns %x (%c)\n",
763 i
, (i
&0177) < 040 ? 0177 : i
&0177);
770 * gchtab[] has only 128 entries
771 * if k is out of the range, it should be
772 * handled as gchtab[k] == 0
774 if (!isascii(k
) || gchtab
[k
]==0)
777 if (cbits(i
) == '\n') {
780 numtab
[CD
].val
++; /* line number */
799 if (k
== 'f' && lg
&& !lgf
) {
803 if (k
== fc
|| k
== tabch
|| k
== ldrch
) {
804 if ((i
= setfield(k
)) == 0)
810 i
= makem(-width(' ' | chbits
));
816 k
= cbits(j
= getch0());
821 case 'X': /* \X'...' for copy through */
824 case '\n': /* concealed newline */
826 case 'n': /* number register */
829 case '*': /* string indicator */
832 case '$': /* argument indicator */
838 case '}': /* RIGHT */
841 case '"': /* comment */
842 while (cbits(i
= getch0()) != '\n')
848 case ESC
: /* double backslash */
851 case 'e': /* printable version of current eschar */
854 case ' ': /* unpaddable space */
857 case '\'': /* \(aa */
866 case '-': /* current font minus */
869 case '&': /* filler */
872 case 'c': /* to be continued */
875 case '!': /* transparent indicator */
881 case 'a': /* leader (SOH) */
887 case 'g': /* return format of a number register */
890 case 'N': /* absolute character number */
896 setsfbits(i
, sfbits(j
));
905 case 'p': /* spread */
908 case '(': /* special char name */
909 if ((i
= setch()) == 0)
912 case 's': /* size indicator */
915 case 'H': /* character height */
917 case 'S': /* slant */
919 case 'f': /* font indicator */
922 case 'w': /* width function */
925 case 'v': /* vert mot */
929 case 'h': /* horiz mot */
933 case 'z': /* zero with char */
935 case 'l': /* hor line */
938 case 'L': /* vert line */
941 case 'D': /* drawing function */
944 case 'b': /* bracket */
947 case 'o': /* overstrike */
950 case 'k': /* mark hor place */
951 if ((k
= findr(getsn())) != -1) {
952 numtab
[k
].val
= numtab
[HP
].val
;
955 case '0': /* number space */
956 return(makem(width('0' | chbits
)));
962 case '|': /* narrow space */
963 return(makem((int)(EM
)/6));
964 case '^': /* half narrow space */
965 return(makem((int)(EM
)/12));
967 case 'x': /* extra line space */
971 case 'u': /* half em up */
972 case 'r': /* full em up */
973 case 'd': /* half em down */
982 setxon() /* \X'...' for copy through */
989 if (ismot(c
= getch()))
994 while ((k
= cbits(c
= getch())) != delim
&& k
!= '\n' && i
< xbuf
+NC
-1) {
1008 0, 001, 002, 003, 0, 005, 006, 007, 010, 011, 012};
1026 extern tchar corebuf
[];
1031 if ((++ip
& (BLK
- 1)) == 0) {
1042 if (nx
|| ibufp
>= eibuf
) {
1053 if ((j
= read(ifile
, ibuf
, IBUFSZ
)) <= 0)
1062 i
= *ibufp
++ & 0177;
1064 if (i
>= 040 && i
< 0177)
1067 i
= *ibufp
++ & 0177;
1069 if (i
>= 040 && i
< 0177)
1071 i
= *ibufp
++ & 0377;
1074 if (!multi_locale
) {
1077 } else if ((n
= mbtowc(&twc
, mbbuf1
, MB_CUR_MAX
)) <= 0) {
1078 if (mbbuf1p
>= mbbuf1
+ MB_CUR_MAX
) {
1079 i
&= ~(MBMASK
| CSMASK
);
1094 if ((col_index
= wcwidth(twc
)) < 0)
1097 setcsbits(i
, col_index
);
1102 if (i
>= 040 && i
!= 0177)
1109 if (cbits(i
) == IMP
&& !raw
)
1111 if ((i
== 0 || i
== 0177) && !init
&& !raw
) {
1116 if (copyf
== 0 && (i
& ~BYTEMASK
) == 0)
1119 if (copyf
== 0 && (i
& ~BYTEMASK
) == 0)
1121 if (copyf
== 0 && (i
& ~CHMASK
) == 0)
1132 if (cbits(i
) == eschar
&& !raw
)
1146 while (b
> ob
&& pbp
< &pbbuf
[NC
-3])
1148 if (pbp
>= &pbbuf
[NC
-3]) {
1149 errprint(gettext("pushback overflow"));
1165 while (b
> ob
&& pbp
< &pbbuf
[NC
-3])
1167 if (pbp
>= &pbbuf
[NC
-3]) {
1168 errprint(gettext("cpushback overflow"));
1183 if (nx
|| nmfi
< mflg
) {
1190 goto n0
; /* popf error */
1191 return(1); /* popf ok */
1194 if ((nfo
-= mflg
) && !stdi
)
1197 numtab
[CD
].val
= ifile
= stdi
= mflg
= 0;
1198 strcpy(cfname
[ifi
], "<standard input>");
1205 if (p
[0] == '-' && p
[1] == 0) {
1207 strcpy(cfname
[ifi
], "<standard input>");
1208 } else if ((ifile
= open(p
, 0)) < 0) {
1209 errprint(gettext("cannot open file %s"), p
);
1213 strcpy(cfname
[ifi
],p
);
1225 extern char *ttyname();
1228 numtab
[CD
].val
= cfline
[ifi
]; /*restore line counter*/
1230 if ((ifile
= ifl
[ifi
]) == 0) {
1239 if (lseek(ifile
, (long)(ioff
& ~(IBUFSZ
-1)), 0) == (long) -1
1240 || (i
= read(ifile
, ibuf
, IBUFSZ
)) < 0)
1244 if (ttyname(ifile
) == 0)
1246 if ((ibufp
= ibuf
+ (int)(ioff
& (IBUFSZ
- 1))) > eibuf
)
1260 if (donef
&& (frame
== stk
))
1277 j
= cbits(i
= getch());
1279 if (ismot(i
) || j
== ' ' || j
== '\n' || j
& 0200) {
1282 if (ismot(i
) || j
== ' ' || j
== '\n' || j
& 0200) {
1284 if (ismot(i
) || j
== ' ' || j
== '\n' || j
> 0200) {
1305 strcpy(mfiles
[nmfi
], nextf
);
1324 for (k
= 0; k
< (NS
- 1); k
++) {
1326 if (((j
= cbits(i
= getch())) <= ' ') || (j
> 0176))
1329 if (((j
= cbits(i
= getch())) <= ' ') || (j
> 0176))
1331 if (((j
= cbits(i
= getch())) <= ' ') || (j
== 0177))
1335 nextf
[k
] = j
& BYTEMASK
;
1340 return((int)nextf
[0]);
1352 if (skip() || !getname() || ((i
= open(nextf
, 0)) < 0) || (ifi
>= NSO
)) {
1353 errprint(gettext("can't open file %s"), nextf
);
1356 strcpy(cfname
[ifi
+1], nextf
);
1357 cfline
[ifi
] = numtab
[CD
].val
; /*hold line counter*/
1381 caself() /* set line number and file */
1388 cfline
[ifi
] = numtab
[CD
].val
= n
- 2;
1392 strcpy(cfname
[ifi
], nextf
);
1400 { /* copy file without change */
1404 extern int hpos
, esc
, po
;
1406 if (skip() || !getname() || (fd
= open(nextf
, 0)) < 0) {
1407 errprint(gettext("can't open file %s"), nextf
);
1411 /* make it into a clean state, be sure that everything is out */
1419 while ((n
= read(fd
, buf
, sizeof buf
)) > 0)
1420 write(ptid
, buf
, n
);
1428 casesy() /* call system */
1436 for (i
= 0; i
< NTM
- 2; i
++)
1437 if ((sybuf
[i
] = getch()) == '\n')
1467 if (isdigit((unsigned char)*a
)) {
1469 n
= 10 * n
+ *a
++ - '0';
1470 while (isdigit((unsigned char)*a
));
1474 *pnp
++ = neg
? -n
: n
;
1476 if (pnp
>= &pnlist
[NPN
-2]) {
1477 errprint(gettext("too many page numbers"));
1503 if (i
< 0 || cbits(j
= getch0()) == RPT
)
1506 while (i
>0 && pbp
< &pbbuf
[NC
-3]) {
1523 debug
= max(atoi(), 0);