gethost.c revision 316957
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
35RCSID("$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
61static 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
92static int findtoken (char *);
93static char *gettoken (char **, char  *);
94static char *pname;
95
96int main (int, char *[]);
97
98/* findtoken():
99 *	Return the token number of the given token
100 */
101static int
102findtoken(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 */
120static char *
121gettoken(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
146static char *
147cat(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
167static const char *
168explode(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
225int
226main(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