2 * expand.c - macro expansion functions for cawf(1)
6 * Copyright (c) 1991 Purdue University Research Foundation,
7 * West Lafayette, Indiana 47907. All rights reserved.
9 * Written by Victor A. Abell <abe@mace.cc.purdue.edu>, Purdue
10 * University Computing Center. Not derived from licensed software;
11 * derived from awf(1) by Henry Spencer of the University of Toronto.
13 * Permission is granted to anyone to use this software for any
14 * purpose on any computer system, and to alter it and redistribute
15 * it freely, subject to the following restrictions:
17 * 1. The author is not responsible for any consequences of use of
18 * this software, even if they arise from flaws in it.
20 * 2. The origin of this software must not be misrepresented, either
21 * by explicit claim or by omission. Credits must appear in the
24 * 3. Altered versions must be plainly marked as such, and must not
25 * be misrepresented as being the original software. Credits must
26 * appear in the documentation.
28 * 4. This notice may not be removed or altered.
34 * Expand(line) - expand macro or if/ie/el line
41 unsigned char buf
[2*MAXLINE
]; /* line buffer */
42 unsigned char cmd
[4]; /* nroff command */
43 int cmdl
; /* command length */
44 int cmdx
; /* cmd index in Macrotab[] */
45 int cond
= 0; /* conditional statuses */
46 int i
, j
; /* temporary indexes */
47 int iflen
; /* if statement length */
48 int invert
; /* inversion status */
49 unsigned char *lp
; /* line pointer */
50 int mx
= -1; /* Macrotab[] index */
51 int n1
, n2
; /* temporary numbers */
52 int nargs
= 0; /* number of arguments */
53 int nleft
= 0; /* number of macro lines left */
54 char op
; /* comparison operator */
55 int prevcond
; /* previous condition (for else's) */
56 int ptr
= -1; /* Macrotxt[] index */
57 int quote
; /* quoted string status */
58 unsigned char *s1
, *s2
; /* temporary string pointers */
61 (void) sprintf((char *)buf
, ".^= %d %s", NR
, (char *)Inname
);
64 for (lp
= line
; *lp
; ) {
65 invert
= regexec(Pat
[1].pat
, lp
);
68 if (regexec(Pat
[0].pat
, lp
) == 0) {
70 * Not conditional: - ! "^[.'](i[ef]|el)"
76 else if (regexec(Pat
[2].pat
, lp
)) {
78 * Argument count comparison: -
79 * "^[.']i[ef] !?\\n\(\.\$(>|>=|=|<|<=)[0-9] "
81 iflen
= strlen(".if \\n(.$=n ") + invert
;
84 if (*s1
== '=' && (op
== '>' || op
== '<')) {
86 op
= (op
== '>') ? 'G' : 'L';
88 n1
= (int)(*s1
- '0');
91 if ((nargs
- 1) == n1
)
103 if ((nargs
- 1) >= n1
)
107 if ((nargs
- 1) <= n1
)
112 else if (regexec(Pat
[3].pat
, lp
)) {
114 * Argument string comparison: - "^[.']i[ef] !?'\\\$[0-9]'[^']*' "
116 iflen
= strlen(".if '\\$n'") + invert
;
117 n1
= (int)(*(lp
+ iflen
- 2) - '0');
118 if (n1
>= 0 && n1
< nargs
)
121 s1
= (unsigned char *)"";
122 if ((s2
= (unsigned char *)strchr((char *)lp
125 n2
= s2
- lp
- iflen
;
126 if (strncmp((char *)s1
, (char *)lp
+ iflen
, n2
)
133 else if (regexec(Pat
[4].pat
, lp
)) {
135 * Nroff or troff: - "^[.']i[ef] !?[nt] "
137 iflen
= strlen(".if n ") + invert
;
138 if (*(lp
+ iflen
- 2) == 'n')
142 else if ((*lp
== '.' || *lp
== '\'')
143 && strncmp((char *)lp
+1, "el ", 3) == 0) {
145 * Else clause: - "^[.']el "
153 * Unknown conditional:
157 (void) sprintf((char *)buf
,
158 ".tm unknown .if/.ie form: %s", (char *)lp
);
162 * Handle conditional. If case is true, locate predicate.
163 * If predicate is an .i[ef], process it.
167 if (cond
&& iflen
> 0) {
169 if (regexec(Pat
[15].pat
, lp
))
173 * Do argument substitution, as necessary.
175 if (cond
&& regexec(Pat
[5].pat
, lp
)) { /* "\$[0-9]" ??? */
177 if ((n1
= Pat
[5].pat
->startp
[0] - lp
) > 0) {
178 (void) strncpy((char *)s1
, (char *)lp
,
183 lp
= Pat
[5].pat
->endp
[0];
184 n1
= (int)(*(lp
-1) - '0');
185 if (n1
>= 0 && n1
< nargs
) {
186 (void) strcpy((char *)s1
,
188 s1
+= strlen((char *)Args
[n1
]);
192 if (regexec(Pat
[5].pat
, lp
) == 0) {
193 (void) strcpy((char *)s1
, (char *)lp
);
200 * Check for nroff command.
204 if (cond
&& (*lp
== '.' || *lp
== '\'')) {
205 if ((*cmd
= *(lp
+1)) != '\0') {
207 if ((*(cmd
+1) = *(lp
+2)) == ' ')
216 i
= i
; /* do nothing if condition is false */
217 else if (cmdl
== 0 || ((cmdx
= Findmacro(cmd
, 0)) < 0))
219 else if (Sp
>= MAXSP
) {
220 (void) sprintf((char *)buf
, " macro nesting > %d",
222 Error(WARN
, LINE
, (char *)buf
, NULL
);
231 Nleftstack
[Sp
] = nleft
;
234 Condstack
[Sp
] = cond
;
235 for (i
= 10*Sp
, j
= 0; j
< 10; i
++, j
++) {
236 Argstack
[i
] = Args
[j
];
240 * Start new stack entry.
243 ptr
= Macrotab
[mx
].bx
;
245 nleft
= Macrotab
[mx
].ct
;
246 Args
[0] = Newstr(cmd
);
250 for (s1
= lp
+ cmdl
+ 1, nargs
= 1; nargs
< 10;) {
251 while (*s1
&& (*s1
== ' ' || *s1
== '\t'))
261 if (!quote
&& (*s1
== ' ' || *s1
== '\t')) {
265 if ((*s2
= *s1
) == '\0')
268 if (quote
&& *s2
== '"') {
275 Args
[nargs
++] = Newstr(buf
);
277 for (i
= nargs
; i
< 10; i
++) {
282 * Unstack completed macros.
284 while (nleft
<= 0 && Sp
>= 0) {
285 nleft
= Nleftstack
[Sp
];
288 cond
= Condstack
[Sp
];
289 for (i
= 10*Sp
, j
= 0, nargs
= -1; j
< 10; i
++, j
++) {
291 if ((Args
[j
] = Argstack
[i
]) != NULL
)
301 lp
= Macrotxt
[ptr
++];
304 lp
= (unsigned char *)"";
306 (void) sprintf((char *)buf
, ".^# %d %s", NR
, (char *)Inname
);