xref: /freebsd/contrib/tcsh/gethost.c (revision d93a896e)
1 /* $Header: /p/tcsh/cvsroot/tcsh/gethost.c,v 1.19 2014/03/09 00:11:54 christos Exp $ */
2 /*
3  * gethost.c: Create version file from prototype
4  */
5 /*-
6  * Copyright (c) 1980, 1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 #include "sh.h"
34 
35 RCSID("$tcsh: gethost.c,v 1.19 2014/03/09 00:11:54 christos Exp $")
36 
37 #ifdef SCO
38 # define perror __perror
39 # define rename __rename
40 # define getopt __getopt
41 # define system __system
42 #endif
43 #include <stdio.h>
44 #ifdef SCO
45 # undef perror
46 # undef rename
47 # undef getopt
48 # undef system
49 #endif
50 
51 #include <ctype.h>
52 
53 #define ISSPACE(p)	(isspace((unsigned char) (p)) && (p) != '\n')
54 
55 /*
56  * We cannot do that, because some compilers like #line and others
57  * like # <lineno>
58  * #define LINEDIRECTIVE
59  */
60 
61 static const char *keyword[] =
62 {
63     "vendor",
64 #define T_VENDOR	0
65     "hosttype",
66 #define T_HOSTTYPE	1
67     "machtype",
68 #define T_MACHTYPE	2
69     "ostype",
70 #define T_OSTYPE	3
71     "newdef",
72 #define T_NEWDEF	4
73     "enddef",
74 #define T_ENDDEF	5
75     "newcode",
76 #define T_NEWCODE	6
77     "endcode",
78 #define T_ENDCODE	7
79     "comment",
80 #define T_COMMENT	8
81     "macro",
82 #define T_MACRO		9
83     NULL
84 #define T_NONE		10
85 };
86 
87 #define S_DISCARD	0
88 #define S_COMMENT	1
89 #define S_CODE		2
90 #define S_KEYWORD	3
91 
92 static int findtoken (char *);
93 static char *gettoken (char **, char  *);
94 static char *pname;
95 
96 int main (int, char *[]);
97 
98 /* findtoken():
99  *	Return the token number of the given token
100  */
101 static int
102 findtoken(char *ptr)
103 {
104     int i;
105 
106     if (ptr == NULL || *ptr == '\0')
107 	return T_NONE;
108 
109     for (i = 0; keyword[i] != NULL; i++)
110 	if (strcmp(keyword[i], ptr) == 0)
111 	    return i;
112 
113     return T_NONE;
114 }
115 
116 
117 /* gettoken():
118  *	Get : delimited token and remove leading/trailing blanks/newlines
119  */
120 static char *
121 gettoken(char **pptr, char *token)
122 {
123     char *ptr = *pptr;
124     char *tok = token;
125 
126     for (; *ptr && ISSPACE(*ptr); ptr++)
127 	continue;
128 
129     for (; *ptr && *ptr != ':'; *tok++ = *ptr++)
130 	continue;
131 
132     if (*ptr == ':')
133 	ptr++;
134     else
135 	tok--;
136 
137     for (tok--; tok >= token && *tok && ISSPACE(*tok); tok--)
138 	continue;
139 
140     *++tok = '\0';
141 
142     *pptr = ptr;
143     return token;
144 }
145 
146 static char *
147 cat(const char *a, const char *b, size_t len)
148 {
149 	size_t l;
150 	char *r;
151 
152 	if (len == 0)
153 		len = strlen(b) + 1;
154 	if (a)
155 	    l = strlen(a) + len;
156 	else
157 	    l = len;
158 	if ((r = malloc(l)) == NULL)
159 		abort();
160 	if (a)
161 	    snprintf(r, l, "%s%.*s", a, (int)len, b);
162 	else
163 	    snprintf(r, l, "%.*s", (int)len, b);
164 	return r;
165 }
166 
167 static const char *
168 explode(const char *defs)
169 {
170 	static const char def[] = "defined("; /* ) */
171 	static char *buf;
172 	size_t len;
173 	const char *ptr, *bptr, *eptr = NULL, *name;
174 
175 	if (strstr(defs, "#machine(" /* ) */))
176 		return defs;
177 	if (!strstr(defs, def))
178 		return defs;
179 
180 	free(buf);
181 	buf = NULL;
182 	for (ptr = defs; (bptr = strstr(ptr, def)) != NULL; ptr = eptr + 1) {
183 		if (ptr != bptr)
184 			buf = cat(buf, ptr, bptr - ptr + 1);
185 		buf = cat(buf, "(", 0); /* ) */
186 		if ((eptr = strchr(ptr + sizeof(def) - 1, ')')) == NULL) {
187 			(void) fprintf(stderr, "%s: missing close paren `%s'\n",
188 			    pname, defs);
189 			free(buf);
190 			return defs;
191 		}
192 		buf = cat(buf, bptr, eptr - bptr + 1);
193 		name = bptr + sizeof(def) - 1;
194 		len = eptr - name;
195 		if (len < 1) {
196 			(void) fprintf(stderr, "%s: empty define `%s'\n",
197 			    pname, defs);
198 			free(buf);
199 			return defs;
200 		}
201 		if (*name != '_' && (*name != 'M' && name[1] != '_')) {
202 			char *undername = malloc(len + 10);
203 			if (undername == NULL)
204 				abort();
205 			buf = cat(buf, ") || defined(", 0);
206 			snprintf(undername, len + 10, "__%.*s__)", (int)len,
207 			    name);
208 			buf = cat(buf, undername, len + 5);
209 			buf = cat(buf, ") || defined(", 0);
210 			snprintf(undername, len + 10, "__%.*s)", (int)len,
211 			    name);
212 			buf = cat(buf, undername, len + 3);
213 		}
214 		buf = cat(buf, "))", 0);
215 	}
216 	if (!eptr) {
217 	    (void) fprintf(stderr, "%s: invalid input `%s'\n", pname, defs);
218 	    return defs;
219         }
220 	buf = cat(buf, eptr + 1, 0);
221 	return buf;
222 }
223 
224 
225 int
226 main(int argc, char *argv[])
227 {
228     char line[INBUFSIZE];
229     const char *fname = "stdin";
230     char *ptr, *tok;
231     char defs[INBUFSIZE];
232     char stmt[INBUFSIZE];
233     FILE *fp = stdin;
234     int lineno = 0;
235     int inprocess = 0;
236     int token, state;
237     int errs = 0;
238 
239     if ((pname = strrchr(argv[0], '/')) == NULL)
240 	pname = argv[0];
241     else
242 	pname++;
243 
244     if (argc > 2) {
245 	(void) fprintf(stderr, "Usage: %s [<filename>]\n", pname);
246 	return 1;
247     }
248 
249     if (argc == 2)
250 	if ((fp = fopen(fname = argv[1], "r")) == NULL) {
251 	    (void) fprintf(stderr, "%s: Cannot open `%s'\n", pname, fname);
252 	    return 1;
253 	}
254 
255     state = S_DISCARD;
256 
257     while ((ptr = fgets(line, sizeof(line), fp)) != NULL) {
258 	lineno++;
259 	switch (token = findtoken(gettoken(&ptr, defs))) {
260 	case T_NEWCODE:
261 	    state = S_CODE;
262 	    break;
263 
264 	case T_ENDCODE:
265 	    state = S_DISCARD;
266 	    break;
267 
268 	case T_COMMENT:
269 	    state = S_COMMENT;
270 	    break;
271 
272 	case T_NEWDEF:
273 	    state = S_KEYWORD;
274 	    break;
275 
276 	case T_ENDDEF:
277 	    state = S_DISCARD;
278 	    break;
279 
280 	case T_VENDOR:
281 	    state = S_KEYWORD;
282 	    break;
283 
284 	case T_HOSTTYPE:
285 	    state = S_KEYWORD;
286 	    break;
287 
288 	case T_MACHTYPE:
289 	    state = S_KEYWORD;
290 	    break;
291 
292 	case T_OSTYPE:
293 	    state = S_KEYWORD;
294 	    break;
295 
296 	case T_MACRO:
297 	    if (gettoken(&ptr, defs) == NULL) {
298 		(void) fprintf(stderr, "%s: \"%s\", %d: Missing macro name\n",
299 			       pname, fname, lineno);
300 		break;
301 	    }
302 	    if (gettoken(&ptr, stmt) == NULL) {
303 		(void) fprintf(stderr, "%s: \"%s\", %d: Missing macro body\n",
304 			       pname, fname, lineno);
305 		break;
306 	    }
307 	    (void) fprintf(stdout, "\n#if %s\n# define %s\n#endif\n\n",
308 		explode(stmt), defs);
309 	    break;
310 
311 	case T_NONE:
312 	    if (state != S_CODE && *defs != '\0') {
313 		(void) fprintf(stderr, "%s: \"%s\", %d: Discarded\n",
314 			       pname, fname, lineno);
315 		if (++errs == 30) {
316 		    (void) fprintf(stderr, "%s: Too many errors\n", pname);
317 		    return 1;
318 		}
319 		break;
320 	    }
321 	    (void) fprintf(stdout, "%s", line);
322 	    break;
323 
324 	default:
325 	    (void) fprintf(stderr, "%s: \"%s\", %d: Unexpected token\n",
326 			   pname, fname, lineno);
327 	    return 1;
328 	}
329 
330 	switch (state) {
331 	case S_DISCARD:
332 	    if (inprocess) {
333 		inprocess = 0;
334 		(void) fprintf(stdout, "#endif\n");
335 	    }
336 	    break;
337 
338 	case S_KEYWORD:
339 	    tok = gettoken(&ptr, defs);
340 	    if (token == T_NEWDEF) {
341 		if (inprocess) {
342 		    (void) fprintf(stderr, "%s: \"%s\", %d: Missing enddef\n",
343 				   pname, fname, lineno);
344 		    return 1;
345 		}
346 		if (tok == NULL) {
347 		    (void) fprintf(stderr, "%s: \"%s\", %d: No defs\n",
348 				   pname, fname, lineno);
349 		    return 1;
350 		}
351 		(void) fprintf(stdout, "\n\n");
352 #ifdef LINEDIRECTIVE
353 		(void) fprintf(stdout, "# %d \"%s\"\n", lineno + 1, fname);
354 #endif /* LINEDIRECTIVE */
355 		(void) fprintf(stdout, "#if (%s)\n", explode(defs));
356 		inprocess = 1;
357 	    }
358 	    else {
359 		if (tok && *tok)
360 		    (void) fprintf(stdout, "# if (%s) && !defined(_%s_)\n",
361 				   explode(defs), keyword[token]);
362 		else
363 		    (void) fprintf(stdout, "# if !defined(_%s_)\n",
364 				   keyword[token]);
365 
366 		if (gettoken(&ptr, stmt) == NULL) {
367 		    (void) fprintf(stderr, "%s: \"%s\", %d: No statement\n",
368 				   pname, fname, lineno);
369 		    return 1;
370 		}
371 		(void) fprintf(stdout, "# define _%s_\n", keyword[token]);
372 		(void) fprintf(stdout, "    %s = %s;\n", keyword[token], stmt);
373 		(void) fprintf(stdout, "# endif\n");
374 	    }
375 	    break;
376 
377 	case S_COMMENT:
378 	    if (gettoken(&ptr, defs))
379 		(void) fprintf(stdout, "    /* %s */\n", defs);
380 	    break;
381 
382 	case S_CODE:
383 	    if (token == T_NEWCODE) {
384 #ifdef LINEDIRECTIVE
385 		(void) fprintf(stdout, "# %d \"%s\"\n", lineno + 1, fname);
386 #endif /* LINEDIRECTIVE */
387 	    }
388 	    break;
389 
390 	default:
391 	    (void) fprintf(stderr, "%s: \"%s\", %d: Unexpected state\n",
392 			   pname, fname, lineno);
393 	    return 1;
394 	}
395     }
396 
397     if (inprocess) {
398 	(void) fprintf(stderr, "%s: \"%s\", %d: Missing enddef\n",
399 		       pname, fname, lineno);
400 	return 1;
401     }
402 
403     if (fp != stdin)
404 	(void) fclose(fp);
405 
406     return 0;
407 }
408