1 /*
2  * Copyright (C) 1992,1993 NEC Corporation.
3  */
4 #ifndef lint
5 static char rcsid[] =
6 	"$Id: macro.c,v 2.10 1994/04/19 10:16:48 uchida Exp $ (NEC)";
7 #endif
8 
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <stdarg.h>
12 #include "plain2.h"
13 #include "macro.h"
14 
15 #define	MACRO_SUFFIX	".p2"
16 
17 struct	macNames macNames[] = {
18 	"DOC_BEGIN",	M_DOC_BEGIN,	"#$$",
19 	"DOC_END",	M_DOC_END,	"",
20 	"PLAIN_BEGIN",	M_PLAIN_BEGIN,	"",
21 	"PLAIN_END",	M_PLAIN_END,	"",
22 	"EXAM_BEGIN",	M_EXAM_BEGIN,	"#",
23 	"EXAM_END",	M_EXAM_END,	"",
24 	"JEXAM_BEGIN",	M_JEXAM_BEGIN,	"#",
25 	"JEXAM_END",	M_JEXAM_END,	"",
26 	"SET_SEC",	M_SET_SEC,	"#$",
27 	"APPENDIX",	M_APPENDIX,	"$",
28 	"APDX_BEGIN",	M_APDX_BEGIN,	"",
29 	"BLANK",	M_BLANK,	"",
30 	"PAGE",		M_PAGE,		"",
31 	"NEWLINE",	M_NEWLINE,	"",
32 	"CENTER_BEGIN",	M_CENTER_BEGIN,	"",
33 	"CENTER_END",	M_CENTER_END,	"",
34 	"RIGHT_BEGIN",	M_RIGHT_BEGIN,	"",
35 	"RIGHT_END",	M_RIGHT_END,	"",
36 	"INDENT",	M_INDENT,	"#",
37 	"INDENT0",	M_INDENT0,	"",
38 	"TITLE",	M_TITLE,	"&&&&&&&&&",
39 	"FOOTN_BEGIN",	M_FOOTN_BEGIN,	"",
40 	"FOOTN_END",	M_FOOTN_END,	"",
41 	"REFER_BEGIN",	M_REFER_BEGIN,	"",
42 	"REFER_END",	M_REFER_END,	"",
43 	"BOLD_BEGIN",	M_BOLD_BEGIN,	"",
44 	"BOLD_END",	M_BOLD_END,	"",
45 	"INDEX_BEGIN",	M_INDEX_BEGIN,	"",
46 	"INDEX_END",	M_INDEX_END,	"",
47 	"SECTION_END",	M_SECTION_END,	"",
48 	"SECTION_1",	M_SECTION_1,	"$",
49 	"SECTION_2",	M_SECTION_2,	"$",
50 	"SECTION_3",	M_SECTION_3,	"$",
51 	"SECTION_4",	M_SECTION_4,	"$",
52 	"SECTION_5",	M_SECTION_5,	"$",
53 	"SECTION",	M_SECTION,	"#$",
54 	"SETSEC_1",	M_SETSEC_1,	"#",
55 	"SETSEC_2",	M_SETSEC_2,	"#",
56 	"SETSEC_3",	M_SETSEC_3,	"#",
57 	"SETSEC_4",	M_SETSEC_4,	"#",
58 	"SETSEC_5",	M_SETSEC_5,	"#",
59 	"SETSEC",	M_SETSEC,	"##",
60 };
61 
62 struct	cmpMac *outMacro[M_MAXNUM];
63 
64 #define	ATYPE_VOID	0
65 #define	ATYPE_INT	1
66 #define	ATYPE_STR	2
67 #define	ATYPE_PSTR	3
68 
69 static	int
atype(c)70 atype(c)
71 char	c;
72 {
73 	if (c == '#')
74 		return ATYPE_INT;
75 	if (c == '$' || c == '@')
76 		return ATYPE_STR;
77 	if (c == '&')
78 		return ATYPE_PSTR;
79 	return ATYPE_VOID;
80 }
81 
82 struct	cmpMac	*
macroParse(s,macroNum,orig)83 macroParse(s, macroNum, orig)
84 int	macroNum;
85 char	*s;
86 char	*orig;
87 {
88 	struct	cmpMac	*mip, *new_mip;
89 	int	def_type;
90 	mip = (struct cmpMac *)malloc(sizeof(struct cmpMac));
91 	if(mip == NULL){ /* Add Nide */
92 	malloc_error:
93 		fprintf(stderr, "PANIC(malloc in macroParse)\n");
94 		exit (2);
95 	}
96 	mip->cmac_next = NULL;
97 	mip->cmac_argnum  = -1;
98 	mip->cmac_str = s;
99 	while (*s) {
100 		if (isdigit(*(s+1)) && (def_type = atype(*s)) != ATYPE_VOID) {
101 			new_mip=(struct cmpMac *)malloc(sizeof(struct cmpMac));
102 			if(new_mip == NULL) goto malloc_error; /* Add Nide */
103 			mip->cmac_next = new_mip;
104 			new_mip->cmac_next = NULL;
105 			new_mip->cmac_argtype = *s;
106 			new_mip->cmac_argnum  = *(s + 1) - '0';
107 			if (new_mip->cmac_argnum >
108 			    strlen(macNames[macroNum].mname_argattr)) {
109 				fprintf(stderr,"Argnum too big %d in \"%s %s\"\n",
110 					new_mip->cmac_argnum,
111 					macNames[macroNum].mname_name, orig);
112 				exit(1);
113 			}
114 			else if (atype(macNames[macroNum].
115 				       mname_argattr[new_mip->cmac_argnum - 1])
116 				 != def_type) {
117 				fprintf(stderr,"Improper argtype in \"%s %s\"\n",
118 					macNames[macroNum].mname_name, orig);
119 				exit(1);
120 			}
121 			*s = '\0';
122 			if (*(s + 2) == '\0')
123 				return mip;;
124 			new_mip->cmac_next = macroParse(s + 2, macroNum, orig);
125 			break;
126 		}
127 		s++;
128 	}
129 	return mip;
130 }
131 char	*
getMacroNum(buf,macroNump)132 getMacroNum(buf, macroNump)
133 char	*buf;
134 int	*macroNump;
135 {
136 	char	*rval = NULL;
137 	char	*s = buf;
138 	int	i;
139 	*macroNump = -1;
140 	while (!isspace(*s))
141 		s++;
142 	if (*s != '\n')
143 		rval = s + 1;
144 	*s = '\0';
145 	for (i = 0; i < sizeof(macNames)/sizeof(struct macNames); i++) {
146 		if (strcmp(macNames[i].mname_name, buf) == 0) {
147 			*macroNump = i;
148 			return rval;
149 		}
150 	}
151 	return rval;
152 }
getMacroDef(buf,rstr)153 getMacroDef(buf, rstr)
154 char	*buf;
155 char	*rstr;
156 {
157 	int in_escape = 0;
158 	rstr[0] = '\0';
159 	while (1) {
160 		if (!in_escape && *buf == '"') {
161 			*rstr = '\0';
162 			return 0;
163 		}
164 		if (in_escape) {
165 			in_escape = 0;
166 			switch(*buf) {
167 			    case '\n':
168 				*rstr++ = '\0';
169 				return -2;
170 			    case 'n':
171 				*rstr++ = '\n';
172 				break;
173 			    case 't':
174 				*rstr++ = '\t';
175 				break;
176 			    default:
177 				*rstr++ = *buf;
178 				break;
179 			}
180 		}
181 		else if (*buf == '\n')
182 			return 1;
183 		else if (*buf == '\\')
184 			in_escape = 1;
185 		else {
186 			in_escape = 0;
187 			*rstr++ = *buf;
188 		}
189 		buf++;
190 	}
191 }
putMacro(int macroNum,char * fmt,...)192 putMacro(int macroNum, char *fmt, ...)
193 {
194 	va_list	ap;
195 	union	macroArg {
196 		int	ma_num;
197 		char	*ma_str;
198 		char	**ma_pstr;
199 	} margs[MACRO_MAXARG];
200 	int	argtype[MACRO_MAXARG];
201 	struct	cmpMac	*mip = outMacro[macroNum];
202 	int	i, maxarg = 0;
203 
204 	for (i = 1; i < MACRO_MAXARG; i++)
205 		argtype[i] = ATYPE_VOID;
206 	if (mip == NULL)
207 		return -1;
208 	while(mip) {
209 		if (mip->cmac_argnum > 0) {
210 			if (maxarg < mip->cmac_argnum)
211 				maxarg = mip->cmac_argnum;
212 			switch(mip->cmac_argtype) {
213 			    case '#':
214 				argtype[mip->cmac_argnum] = ATYPE_INT;
215 				break;
216 			    case '$':
217 			    case '@':
218 				argtype[mip->cmac_argnum] = ATYPE_STR;
219 				break;
220 			    case '&':
221 				argtype[mip->cmac_argnum] = ATYPE_PSTR;
222 				break;
223 			}
224 		}
225 		mip = mip->cmac_next;
226 	}
227 	va_start(ap, fmt);
228 	for (i = 1; i <= maxarg; i++) {
229 		switch(argtype[i]) {
230 		    case ATYPE_VOID:
231 			va_arg(ap, char *);
232 			break;
233 		    case ATYPE_INT:
234 			margs[i].ma_num = (int)va_arg(ap, int *);
235 			break;
236 		    case ATYPE_STR:
237 			margs[i].ma_str = va_arg(ap, char *);
238 			break;
239 		    case ATYPE_PSTR:
240 			margs[i].ma_pstr = (char **)va_arg(ap, char **);
241 			break;
242 		}
243 	}
244 	mip = outMacro[macroNum];
245 	while(mip) {
246 		if (mip->cmac_argnum > 0) {
247 			switch(mip->cmac_argtype) {
248 			    case '#':
249 				printf ("%d", margs[mip->cmac_argnum].ma_num);
250 				break;
251 			    case '$':
252 				printf ("%s", codeCvt((*put->quote1)(margs[mip->cmac_argnum].ma_str)));
253 				break;
254 			    case '@':
255 				printf ("%s", codeCvt((*put->quote2)(margs[mip->cmac_argnum].ma_str)));
256 				break;
257 			    case '&':
258 				{
259 					char	**argp;
260 					argp = margs[mip->cmac_argnum].ma_pstr;
261 					while (*argp) {
262 						printf("%s", codeCvt((*put->quote1)(*argp)));
263 						if (*++argp) {
264 							if (put == &texPut) {
265 								printf("~\\\\");
266 							}
267 							putchar('\n');
268 						}
269 					}
270 					break;
271 				}
272 			}
273 		}
274 		else
275 			printf ("%s", codeCvt(mip->cmac_str));
276 		mip = mip->cmac_next;
277 	}
278 	va_end(ap);
279 	return 0;
280 }
clearMacro()281 clearMacro()
282 {
283 	int	i;
284 	for (i = 0; i < M_MAXNUM; i++)
285 		outMacro[i] = NULL;
286 }
287 initMacroDefs(mcp)
288 struct	macDefs	*mcp;
289 {
290 	while(mcp->mdef_number >= 0) {
291 		if (outMacro[mcp->mdef_number] == NULL)
292 			outMacro[mcp->mdef_number] =
293 				macroParse(mcp->mdef_def, mcp->mdef_number,
294 					   mcp->mdef_def);
295 		mcp++;
296 	}
297 }
298 
299 FILE	*
macroFopen(fname)300 macroFopen(fname)
301 char	*fname;
302 {
303 	FILE	*fd;
304 	char	buf[1024];
305 	if ((fd = fopen(fname, "r")) != NULL)
306 		return fd;
307 	strcpy(buf, fname);
308 	strcat(buf, MACRO_SUFFIX);
309 	return fopen(buf, "r");
310 }
311 
macroFile(fname)312 macroFile(fname)
313 char	*fname;
314 {
315 	char	defstr[1024];
316 	char	buf[1024];
317 	char	path[1024];
318 	FILE	*fd;
319 	int	macroNum;
320 	char	*s;
321 	fd = macroFopen(fname);
322 	if (fd == NULL && plain2Lib != NULL && fname[0] != '/') {
323 		char	*colon;
324 		fd = NULL;
325 
326 		colon = index(plain2Lib, ':');
327 		while (colon && colon != NULL) {
328 			*colon = '\0';
329 			sprintf(path, "%s/%s", plain2Lib, fname);
330 			if ((fd = macroFopen(path)) != NULL)
331 				break;
332 			plain2Lib = colon+1;
333 			colon = index(plain2Lib, ':');
334 		}
335 		if (fd == NULL && *plain2Lib != '\0') {
336 			sprintf(path, "%s/%s", plain2Lib, fname);
337 			fd = macroFopen(path);
338 		}
339 	}
340 	if (fd == NULL) {
341 #ifdef	MACRO_LIB
342 		sprintf(path, "%s/%s", MACRO_LIB, fname);
343 		if ((fd = macroFopen(path)) == NULL) {
344 			fprintf(stderr, "Can't open %s\n", fname);
345 			exit(1);
346 		}
347 #else
348 		fprintf(stderr, "Can't open %s\n", fname);
349 		exit(1);
350 #endif
351 	}
352 	while(fgets(buf, sizeof(buf), fd) != NULL) {
353 		char	*macro_body;
354 		int	ret;
355 		if (buf[0] == '#')
356 			continue;
357 		macro_body = getMacroNum(buf, &macroNum);
358 		if (macroNum < 0 || macro_body == NULL)
359 			continue;
360 		while (isspace(*macro_body))
361 			macro_body++;
362 		if (*macro_body != '"') {
363 			fprintf(stderr,"Macro body must start with \" in \"%s\"\n",
364 				macNames[macroNum].mname_name);
365 			fclose(fd);
366 			exit(1);
367 		}
368 		macro_body++;
369 		ret = getMacroDef(macro_body, defstr);
370 		while(ret == -2) {
371 			for (s = defstr; *s; s++);
372 			if (fgets(buf, sizeof(buf), fd) == NULL)
373 				break;
374 			ret = getMacroDef(buf, s);
375 		}
376 		if (ret == -1)
377 			continue;
378 		s = strsave(defstr); /* Changed Nide (but don't we need free?)*/
379 		outMacro[macroNum] = macroParse(s, macroNum, s);
380 	}
381 	fclose(fd);
382 	return 0;
383 }
384