Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/mam/mamold.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Bell Laboratories
24
*
25
* convert a make abstract machine stream on stdin
26
* to an oldmake makefile on stdout
27
*/
28
29
static const char usage[] =
30
"[-?\n@(#)$Id: mamold (AT&T Research) 1989-03-22 $\n]"
31
USAGE_LICENSE
32
"[+NAME?mamold - make abstract machine to oldmake makefile conversion filter]"
33
"[+DESCRIPTION?\bmamold\b reads MAM (Make Abstract Machine) target and"
34
" prerequisite file descriptions from the standard input and writes"
35
" an equivalent \bgmake\b(1) makefile on the standard output. Mamfiles"
36
" are generated by the \b--mam\b option of \bnmake\b(1) and"
37
" \bgmake\b(1).]"
38
"[+?Symbolic information is preserved where possible in the output makefile."
39
" Comments, however, are lost in the conversion. Recursive makefiles"
40
" are not converted; each makefile level must be converted separately.]"
41
42
"[d:debug?]#[level]"
43
"[g:graph?Verify the dependency graph but do not generate a makefile on"
44
" the standard output.]"
45
"[h:header?Use \atext\as instead of the default for the generated makefile"
46
" header.]#[text]"
47
"[x:omit?Omit pathnames with directory \aprefix\a.]#[prefix]"
48
49
"[+SEE ALSO?\bmamnew\b(1), \bgmake\b(1), \bnmake\b(1)]"
50
"[+REFERENCES]{"
51
" [+A Make abstract machine, Glenn Fowler, 1994,?"
52
" http://www.research.att.com/~gsf/mam/]"
53
"}"
54
;
55
56
#include <ast.h>
57
#include <mam.h>
58
#include <ctype.h>
59
#include <error.h>
60
#include <stdio.h>
61
62
#define LONGLINE 72 /* too long output line length */
63
64
#define A_listprereq (A_LAST<<1) /* prereqs listed */
65
#define A_listtarg (A_LAST<<2) /* listed as target */
66
67
struct state /* program state */
68
{
69
int graph; /* output dependency graph info */
70
int header; /* header supplied */
71
int heredoc; /* last value had << */
72
struct mam* mam; /* make abstract machine info */
73
struct block* omit; /* dir prefixes to omit */
74
};
75
76
static struct state state;
77
78
/*
79
* clear listprereq for all prerequisites
80
*/
81
82
static void
83
clrprereqs(register struct rule* r)
84
{
85
register struct list* p;
86
87
r->attributes &= ~A_listprereq;
88
for (p = r->prereqs; p; p = p->next)
89
if (p->rule->attributes & A_listprereq)
90
clrprereqs(p->rule);
91
for (p = r->implicit; p; p = p->next)
92
if (p->rule->attributes & A_listprereq)
93
clrprereqs(p->rule);
94
}
95
96
/*
97
* dump a value that may be expanded by oldmake
98
*/
99
100
static int
101
dumpvalue(register int col, register char* s, int sep)
102
{
103
register int c;
104
register char* v;
105
int dollar;
106
int escape = 0;
107
int quote = 0;
108
109
if (sep)
110
{
111
sfputc(sfstdout, sep);
112
col++;
113
}
114
for (;;)
115
switch (c = *s++)
116
{
117
case 0:
118
if (sep && sep != '\t')
119
{
120
col = 1;
121
sfputc(sfstdout, '\n');
122
}
123
return col;
124
case ' ':
125
case '\t':
126
if (sep == '\t' && state.heredoc || col < LONGLINE - 8)
127
goto emit;
128
while (isspace(*s))
129
s++;
130
if (*s)
131
{
132
sfputr(sfstdout, " \\\n\t", -1);
133
col = 8;
134
}
135
break;
136
case '#':
137
sfputr(sfstdout, "$(sharp)", -1);
138
col += 8;
139
break;
140
case '<':
141
if (sep == '\t' && *s == c)
142
state.heredoc = 1;
143
goto emit;
144
case '\'':
145
quote = !quote;
146
goto emit;
147
case '\\':
148
if (*s != '$' && *s != '\'')
149
goto emit;
150
s++;
151
escape = -1;
152
/*FALLTHROUGH*/
153
case '$':
154
escape++;
155
dollar = 1;
156
if (isalpha(*s) || *s == '_')
157
{
158
for (v = s; isalnum(*v) || *v == '_'; v++);
159
c = *v;
160
*v = 0;
161
if (getvar(state.mam->main, s))
162
{
163
sfprintf(sfstdout, "$(%s)", s);
164
col += (v - s) + 3;
165
*(s = v) = c;
166
escape = 0;
167
break;
168
}
169
*v = c;
170
}
171
if (escape)
172
{
173
escape = 0;
174
if (!quote)
175
switch (*s)
176
{
177
case '{':
178
if (*(v = s + 1))
179
v++;
180
while (isalnum(*v) || *v == '_')
181
v++;
182
switch (*v)
183
{
184
case ':':
185
case '-':
186
case '+':
187
break;
188
default:
189
dollar = 0;
190
break;
191
}
192
break;
193
case '$':
194
s--;
195
do
196
{
197
sfputc(sfstdout, '$');
198
col++;
199
} while (*++s == '$');
200
break;
201
default:
202
sfputc(sfstdout, '\\');
203
col++;
204
break;
205
}
206
}
207
else
208
dollar = 0;
209
c = '$';
210
if (dollar)
211
{
212
sfputc(sfstdout, c);
213
col++;
214
}
215
/*FALLTHROUGH*/
216
default:
217
emit:
218
sfputc(sfstdout, c);
219
col++;
220
break;
221
}
222
}
223
224
/*
225
* dump a name keeping track of the right margin
226
*/
227
228
static int
229
dumpname(int col, char* s)
230
{
231
register int n;
232
233
if (!state.graph)
234
{
235
n = strlen(s);
236
if (col + n >= LONGLINE)
237
{
238
sfputr(sfstdout, " \\\n\t\t", -1);
239
col = 16;
240
}
241
else if (col <= 1)
242
col = 1;
243
else
244
{
245
sfputc(sfstdout, ' ');
246
col++;
247
}
248
col += n;
249
}
250
else if (col++ > 1)
251
sfputc(sfstdout, ' ');
252
dumpvalue(0, s, 0);
253
return col;
254
}
255
256
/*
257
* dump an action
258
*/
259
260
static void
261
dumpaction(register struct block* p)
262
{
263
if (p)
264
{
265
state.heredoc = 0;
266
for (;;)
267
{
268
dumpvalue(0, p->data, '\t');
269
if (!(p = p->next))
270
break;
271
sfputr(sfstdout, "$(newline)", -1);
272
if (!state.heredoc)
273
sfputr(sfstdout, " \\\n", -1);
274
}
275
sfputc(sfstdout, '\n');
276
}
277
}
278
279
/*
280
* dump r and its implicit prerequisites
281
*/
282
283
static int
284
dumpprereqs(register int col, register struct rule* r)
285
{
286
register struct block* d;
287
register struct list* p;
288
289
if (!(r->attributes & A_listprereq))
290
{
291
r->attributes |= A_listprereq;
292
for (d = state.omit; d; d = d->next)
293
if (strmatch(r->name, d->data))
294
return col;
295
col = dumpname(col, r->name);
296
for (p = r->implicit; p; p = p->next)
297
col = dumpprereqs(col, p->rule);
298
}
299
return col;
300
}
301
302
/*
303
* dump the rules
304
*/
305
306
static void
307
dump(register struct rule* r)
308
{
309
register int col;
310
register struct list* p;
311
312
if (!(r->attributes & (A_listtarg|A_metarule)))
313
{
314
r->attributes |= A_listtarg;
315
if (r->action || r->prereqs)
316
{
317
clrprereqs(r);
318
r->attributes |= A_listprereq;
319
sfputc(sfstdout, '\n');
320
col = dumpname(1, r->name);
321
col = dumpname(col, ":");
322
for (p = r->prereqs; p; p = p->next)
323
if (!(p->rule->attributes & A_listprereq))
324
{
325
clrprereqs(p->rule);
326
col = dumpprereqs(col, p->rule);
327
}
328
sfputc(sfstdout, '\n');
329
if (!state.graph)
330
dumpaction(r->action);
331
}
332
for (p = r->prereqs; p; p = p->next)
333
if (p->rule != r)
334
dump(p->rule);
335
for (p = r->implicit; p; p = p->next)
336
if (p->rule != r)
337
dump(p->rule);
338
}
339
}
340
341
/*
342
* dump var definition
343
*/
344
345
static int
346
dumpvar(const char* an, char* av, void* handle)
347
{
348
char* name = (char*)an;
349
struct var* v = (struct var*)av;
350
register char* s;
351
register char* t;
352
register int c;
353
354
NoP(handle);
355
if (*v->value)
356
{
357
s = t = v->value;
358
while (c = *t++ = *s++)
359
{
360
if (c == '\\')
361
{
362
if (!(*t++ = *s++))
363
break;
364
}
365
else if (c == '"')
366
t--;
367
}
368
dumpvalue(dumpname(0, name), v->value, '=');
369
}
370
return 0;
371
}
372
373
/*
374
* add prefix to list of dir prefixes to omit
375
*/
376
377
static void
378
omit(char* prefix)
379
{
380
int n;
381
struct block* p;
382
383
n = strlen(prefix);
384
p = newof(0, struct block, 1, n + 1);
385
strcpy(p->data = (char*)p + sizeof(struct block), prefix);
386
strcpy(p->data + n, "*");
387
p->next = state.omit;
388
state.omit = p;
389
}
390
391
int
392
main(int argc, char** argv)
393
{
394
register struct list* p;
395
396
NoP(argc);
397
error_info.id = "mamold";
398
for (;;)
399
{
400
switch (optget(argv, usage))
401
{
402
case 'd':
403
error_info.trace = -opt_info.num;
404
continue;
405
case 'g':
406
state.graph = 1;
407
continue;
408
case 'h':
409
state.header = 1;
410
sfputr(sfstdout, opt_info.arg, '\n');
411
continue;
412
case 'x':
413
omit(opt_info.arg);
414
continue;
415
case '?':
416
error(ERROR_USAGE|4, opt_info.arg);
417
break;
418
case ':':
419
error(2, opt_info.arg);
420
break;
421
}
422
break;
423
}
424
if (error_info.errors)
425
error(ERROR_USAGE|4, "%s", optusage(NiL));
426
427
/*
428
* initialize
429
*/
430
431
omit("/usr/include");
432
omit("/");
433
434
/*
435
* scan, collect and dump
436
*/
437
438
if (!state.graph && !state.header)
439
{
440
sfprintf(sfstdout, "# # oldmake makefile generated by mamold # #\n");
441
sfprintf(sfstdout, "# oldmake ... null='' sharp='$(null)#' newline='$(null)\n");
442
sfprintf(sfstdout, "# '\n");
443
sfprintf(sfstdout, "newline=;\n");
444
}
445
if (!(state.mam = mamalloc()))
446
error(3, "cannot initialize");
447
mamvar(state.mam->main, "HOME", "");
448
mamvar(state.mam->main, "newline", "");
449
if (mamscan(state.mam, NiL) < 0)
450
error(3, "invalid input");
451
if (!state.graph)
452
hashwalk(state.mam->main->vars, 0, dumpvar, NiL);
453
for (p = state.mam->main->root->prereqs; p; p = p->next)
454
dump(p->rule);
455
exit(error_info.errors != 0);
456
}
457
458