xref: /freebsd/contrib/tcsh/gethost.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /* $Header: /p/tcsh/cvsroot/tcsh/gethost.c,v 1.15 2012/01/15 17:14: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.15 2012/01/15 17:14: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);
154 	l = strlen(a) + len + 1;
155 	if ((r = malloc(l)) == NULL)
156 		abort();
157 	snprintf(r, l, "%s%.*s", a, (int)len, b);
158 	return r;
159 }
160 
161 static const char *
162 explode(const char *defs)
163 {
164 	static const char def[] = "defined("; /* ) */
165 	static char *buf;
166 	size_t len;
167 	const char *ptr, *bptr, *eptr = NULL, *name;
168 	size_t buflen = 0;
169 
170 	if (strstr(defs, "#machine(" /* ) */))
171 		return defs;
172 
173 	free(buf);
174 	buf = strdup("("); /* ) */
175 	for (ptr = defs; (bptr = strstr(ptr, def)) != NULL; ptr = eptr + 1) {
176 		if (ptr != bptr)
177 			buf = cat(buf, ptr, bptr - ptr);
178 		if ((eptr = strchr(ptr + sizeof(def) - 1, ')')) == NULL) {
179 			(void) fprintf(stderr, "%s: missing close paren `%s'\n",
180 			    pname, defs);
181 			return defs;
182 		}
183 		buf = cat(buf, bptr, eptr - bptr + 1);
184 		name = bptr + sizeof(def) - 1;
185 		len = eptr - name;
186 		if (len < 1) {
187 			(void) fprintf(stderr, "%s: empty define `%s'\n",
188 			    pname, defs);
189 			return defs;
190 		}
191 		if (*name != '_') {
192 			char *undername = malloc(len + 10);
193 			buf = cat(buf, " || defined(", 0);
194 			snprintf(undername, len + 10, "__%.*s__)", (int)len,
195 			    name);
196 			buf = cat(buf, undername, len + 5);
197 			buf = cat(buf, " || defined(", 0);
198 			snprintf(undername, len + 10, "__%.*s)", (int)len,
199 			    name);
200 			buf = cat(buf, undername, len + 3);
201 		}
202 	}
203 	if (!eptr) {
204 	    (void) fprintf(stderr, "%s: invalid input `%s'\n", pname, defs);
205 	    return defs;
206         }
207 	buf = cat(buf, eptr + 1, 0);
208 	buf = cat(buf, ")", 0);
209 	return buf;
210 }
211 
212 
213 int
214 main(int argc, char *argv[])
215 {
216     char line[INBUFSIZE];
217     const char *fname = "stdin";
218     char *ptr, *tok;
219     char defs[INBUFSIZE];
220     char stmt[INBUFSIZE];
221     FILE *fp = stdin;
222     int lineno = 0;
223     int inprocess = 0;
224     int token, state;
225     int errs = 0;
226 
227     if ((pname = strrchr(argv[0], '/')) == NULL)
228 	pname = argv[0];
229     else
230 	pname++;
231 
232     if (argc > 2) {
233 	(void) fprintf(stderr, "Usage: %s [<filename>]\n", pname);
234 	return 1;
235     }
236 
237     if (argc == 2)
238 	if ((fp = fopen(fname = argv[1], "r")) == NULL) {
239 	    (void) fprintf(stderr, "%s: Cannot open `%s'\n", pname, fname);
240 	    return 1;
241 	}
242 
243     state = S_DISCARD;
244 
245     while ((ptr = fgets(line, sizeof(line), fp)) != NULL) {
246 	lineno++;
247 	switch (token = findtoken(gettoken(&ptr, defs))) {
248 	case T_NEWCODE:
249 	    state = S_CODE;
250 	    break;
251 
252 	case T_ENDCODE:
253 	    state = S_DISCARD;
254 	    break;
255 
256 	case T_COMMENT:
257 	    state = S_COMMENT;
258 	    break;
259 
260 	case T_NEWDEF:
261 	    state = S_KEYWORD;
262 	    break;
263 
264 	case T_ENDDEF:
265 	    state = S_DISCARD;
266 	    break;
267 
268 	case T_VENDOR:
269 	    state = S_KEYWORD;
270 	    break;
271 
272 	case T_HOSTTYPE:
273 	    state = S_KEYWORD;
274 	    break;
275 
276 	case T_MACHTYPE:
277 	    state = S_KEYWORD;
278 	    break;
279 
280 	case T_OSTYPE:
281 	    state = S_KEYWORD;
282 	    break;
283 
284 	case T_MACRO:
285 	    if (gettoken(&ptr, defs) == NULL) {
286 		(void) fprintf(stderr, "%s: \"%s\", %d: Missing macro name\n",
287 			       pname, fname, lineno);
288 		break;
289 	    }
290 	    if (gettoken(&ptr, stmt) == NULL) {
291 		(void) fprintf(stderr, "%s: \"%s\", %d: Missing macro body\n",
292 			       pname, fname, lineno);
293 		break;
294 	    }
295 	    (void) fprintf(stdout, "\n#if %s\n# define %s\n#endif\n\n", stmt,
296 			   defs);
297 	    break;
298 
299 	case T_NONE:
300 	    if (state != S_CODE && *defs != '\0') {
301 		(void) fprintf(stderr, "%s: \"%s\", %d: Discarded\n",
302 			       pname, fname, lineno);
303 		if (++errs == 30) {
304 		    (void) fprintf(stderr, "%s: Too many errors\n", pname);
305 		    return 1;
306 		}
307 		break;
308 	    }
309 	    (void) fprintf(stdout, "%s", line);
310 	    break;
311 
312 	default:
313 	    (void) fprintf(stderr, "%s: \"%s\", %d: Unexpected token\n",
314 			   pname, fname, lineno);
315 	    return 1;
316 	}
317 
318 	switch (state) {
319 	case S_DISCARD:
320 	    if (inprocess) {
321 		inprocess = 0;
322 		(void) fprintf(stdout, "#endif\n");
323 	    }
324 	    break;
325 
326 	case S_KEYWORD:
327 	    tok = gettoken(&ptr, defs);
328 	    if (token == T_NEWDEF) {
329 		if (inprocess) {
330 		    (void) fprintf(stderr, "%s: \"%s\", %d: Missing enddef\n",
331 				   pname, fname, lineno);
332 		    return 1;
333 		}
334 		if (tok == NULL) {
335 		    (void) fprintf(stderr, "%s: \"%s\", %d: No defs\n",
336 				   pname, fname, lineno);
337 		    return 1;
338 		}
339 		(void) fprintf(stdout, "\n\n");
340 #ifdef LINEDIRECTIVE
341 		(void) fprintf(stdout, "# %d \"%s\"\n", lineno + 1, fname);
342 #endif /* LINEDIRECTIVE */
343 		(void) fprintf(stdout, "#if %s\n", defs);
344 		inprocess = 1;
345 	    }
346 	    else {
347 		if (tok && *tok)
348 		    (void) fprintf(stdout, "# if (%s) && !defined(_%s_)\n",
349 				   explode(defs), keyword[token]);
350 		else
351 		    (void) fprintf(stdout, "# if !defined(_%s_)\n",
352 				   keyword[token]);
353 
354 		if (gettoken(&ptr, stmt) == NULL) {
355 		    (void) fprintf(stderr, "%s: \"%s\", %d: No statement\n",
356 				   pname, fname, lineno);
357 		    return 1;
358 		}
359 		(void) fprintf(stdout, "# define _%s_\n", keyword[token]);
360 		(void) fprintf(stdout, "    %s = %s;\n", keyword[token], stmt);
361 		(void) fprintf(stdout, "# endif\n");
362 	    }
363 	    break;
364 
365 	case S_COMMENT:
366 	    if (gettoken(&ptr, defs))
367 		(void) fprintf(stdout, "    /* %s */\n", defs);
368 	    break;
369 
370 	case S_CODE:
371 	    if (token == T_NEWCODE) {
372 #ifdef LINEDIRECTIVE
373 		(void) fprintf(stdout, "# %d \"%s\"\n", lineno + 1, fname);
374 #endif /* LINEDIRECTIVE */
375 	    }
376 	    break;
377 
378 	default:
379 	    (void) fprintf(stderr, "%s: \"%s\", %d: Unexpected state\n",
380 			   pname, fname, lineno);
381 	    return 1;
382 	}
383     }
384 
385     if (inprocess) {
386 	(void) fprintf(stderr, "%s: \"%s\", %d: Missing enddef\n",
387 		       pname, fname, lineno);
388 	return 1;
389     }
390 
391     if (fp != stdin)
392 	(void) fclose(fp);
393 
394     return 0;
395 }
396