Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/mam/mamnew.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 nmake makefile on stdout
27
*/
28
29
static const char usage[] =
30
"[-?\n@(#)$Id: mamnew (AT&T Research) 1990-06-11 $\n]"
31
USAGE_LICENSE
32
"[+NAME?mamnew - make abstract machine to nmake makefile conversion filter]"
33
"[+DESCRIPTION?\bmamnew\b reads MAM (Make Abstract Machine) target and"
34
" prerequisite file descriptions from the standard input and writes"
35
" an equivalent \bnmake\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. Header file"
40
" dependencies are omitted since these are implicitly determined by"
41
" \bnmake\b(1). Recursive makefiles are not converted; each makefile"
42
" level must be converted separately. Some targets are omitted; most"
43
" of these are provided as predefined \bnmake\b(1) targets.]"
44
"[+?\bmamnew\b is only an \aaid\a in the makefile conversion process. It is"
45
" a rare old-make makefile that requires no manual intervention after"
46
" \bmamnew\b conversion.]"
47
48
"[d:debug?]#[level]"
49
"[x:omit?Omit pathnames with directory \aprefix\a.]#[prefix]"
50
51
"[+SEE ALSO?\bmamold\b(1), \bgmake\b(1), \bnmake\b(1)]"
52
"[+REFERENCES]{"
53
" [+A Make abstract machine, Glenn Fowler, 1994.?"
54
" http://www.research.att.com/~gsf/mam/]"
55
"}"
56
;
57
58
#include <ast.h>
59
#include <mam.h>
60
#include <ctype.h>
61
#include <error.h>
62
63
#define LONGLINE 72 /* too long output line length */
64
#define MAXNAME 1024 /* max rule name */
65
66
#define message if(error_info.trace<0)error
67
68
#define A_ancestor (A_LAST<<1) /* ancestor directory */
69
#define A_command (A_LAST<<2) /* command target */
70
#define A_directory (A_LAST<<3) /* source directory */
71
#define A_implict (A_LAST<<4) /* metarules can handle it */
72
#define A_listprereq (A_LAST<<5) /* prereqs listed */
73
#define A_listtarg (A_LAST<<6) /* listed as target */
74
#define A_omit (A_LAST<<7) /* omit prereq */
75
76
#define V_state (V_LAST<<1) /* state var */
77
78
struct local /* local rule info */
79
{
80
char* base; /* base name */
81
struct rule* directory; /* directory prefix */
82
char* suffix; /* suffix */
83
char* target; /* target name if != base */
84
};
85
86
static struct /* program state */
87
{
88
int ancestor; /* ancestor dir .. count */
89
struct mam* mam; /* make abstract machine info */
90
struct block* omit; /* dir prefixes to omit */
91
92
struct
93
{
94
struct rule* source; /* .SOURCE */
95
struct rule* source_a; /* .SOURCE.a */
96
struct rule* source_h; /* .SOURCE.h */
97
struct rule* sources; /* .MAM.SOURCES. */
98
} atom; /* special atoms */
99
} state;
100
101
/*
102
* check if name is on omit list
103
*/
104
105
static int
106
omitted(char* name)
107
{
108
register char* s;
109
register char* t;
110
register struct block* d;
111
112
for (d = state.omit; d; d = d->next)
113
{
114
s = name;
115
t = d->data;
116
do if (!*t)
117
{
118
if (!*s || *s == '/')
119
return 1;
120
break;
121
} while (*s++ == *t++);
122
}
123
return 0;
124
}
125
126
/*
127
* initialize source dir
128
*/
129
130
static struct rule*
131
initdir(register char* s, char* suf)
132
{
133
register struct rule* d;
134
register int n;
135
struct rule* z;
136
char buf[MAXNAME];
137
138
d = mamrule(state.mam->main, s);
139
if (!(d->attributes & A_directory))
140
{
141
d->attributes |= A_directory;
142
n = 0;
143
while (*s == '.' && *(s + 1) == '.' && *(s + 2) == '/')
144
{
145
s += 3;
146
n++;
147
}
148
if (!strmatch(s, "include|lib"))
149
{
150
sfsprintf(buf, sizeof(buf), "%s%s", state.atom.source->name, suf);
151
z = mamrule(state.mam->main, buf);
152
z->attributes |= A_directory;
153
mamprereq(state.mam->main, z, d, NiL);
154
mamprereq(state.mam->main, state.atom.sources, z, NiL);
155
}
156
else if (n > state.ancestor)
157
state.ancestor = n;
158
}
159
return d;
160
}
161
162
/*
163
* dump a value that may be expanded by oldmake
164
*/
165
166
static int
167
dumpvalue(register int col, register char* s, int sep)
168
{
169
register int c;
170
register char* v;
171
172
if (sep && sep != '\\')
173
{
174
sfputc(sfstdout, sep);
175
col++;
176
}
177
for (;;)
178
switch (c = *s++)
179
{
180
case 0:
181
if (sep && sep != '\t')
182
{
183
col = 1;
184
sfputc(sfstdout, '\n');
185
}
186
return col;
187
case '\t':
188
col += 7 - (col % 8);
189
/*FALLTHROUGH*/
190
case ' ':
191
if (col < LONGLINE - 8)
192
goto emit;
193
while (isspace(*s))
194
s++;
195
if (*s)
196
{
197
sfputr(sfstdout, " \\\n\t", -1);
198
col = 8;
199
}
200
break;
201
case '\\':
202
if (sep == '\\')
203
c = *s++;
204
goto emit;
205
case '$':
206
if (isalpha(*s) || *s == '_')
207
{
208
for (v = s; isalnum(*v) || *v == '_'; v++);
209
c = *v;
210
*v = 0;
211
if (getvar(state.mam->main, s))
212
{
213
sfprintf(sfstdout, "$(%s)", s);
214
col += (v - s) + 3;
215
*(s = v) = c;
216
break;
217
}
218
*v = c;
219
c = '$';
220
}
221
/*FALLTHROUGH*/
222
default:
223
emit:
224
sfputc(sfstdout, c);
225
col++;
226
break;
227
}
228
}
229
230
/*
231
* dump a name keeping track of the right margin
232
*/
233
234
static int
235
dumpname(int col, char* s)
236
{
237
238
register int n;
239
240
n = strlen(s);
241
if (col + n >= LONGLINE)
242
{
243
sfputr(sfstdout, " \\\n\t\t", -1);
244
col = 16;
245
}
246
else if (col <= 1)
247
col = 1;
248
else
249
{
250
sfputc(sfstdout, ' ');
251
col++;
252
}
253
col += n;
254
dumpvalue(0, s, 0);
255
return col;
256
}
257
258
/*
259
* check s for interesting cc flags
260
* if v!=0 then it is var for s
261
*/
262
263
static void
264
ccflags(register char* s, struct var* v)
265
{
266
register char* t;
267
char* b;
268
char* u;
269
int n;
270
char buf[MAXNAME];
271
272
static int init;
273
274
b = buf;
275
for (;;)
276
{
277
while (*s && *s != '-')
278
s++;
279
if (!*s)
280
break;
281
for (t = s; *t; t++)
282
{
283
if (isspace(*t))
284
break;
285
if (*t == '\\' && !*++t)
286
break;
287
}
288
*t++ = 0;
289
switch (*(s + 1))
290
{
291
case 'c':
292
case 'U':
293
break;
294
case 'D':
295
for (u = s + 2; isalnum(*u); u++);
296
if (n = *u)
297
*u = 0;
298
mamvar(state.mam->main, s + 2, s);
299
if (n)
300
*u = n;
301
break;
302
case 'I':
303
pathcanon(s += 2, 0, 0);
304
if (s[0] && (s[0] != '.' || s[1]) && !omitted(s))
305
initdir(s, ".h");
306
break;
307
case 'O':
308
if (!*(s + 2))
309
break;
310
/*FALLTHROUGH*/
311
default:
312
if (b != buf)
313
*b++ = ' ';
314
b = strcopy(b, s);
315
break;
316
}
317
s = t;
318
}
319
if (v && b > buf)
320
{
321
if (!init)
322
{
323
init = 1;
324
sfputc(sfstdout, '\n');
325
}
326
*b = 0;
327
dumpvalue(dumpname(0, v->name), buf, '=');
328
}
329
}
330
331
/*
332
* initialize local rule info
333
*/
334
335
static int
336
initrule(const char* as, char* ar, void* handle)
337
{
338
register char* s = (char*)as;
339
register struct rule* r = (struct rule*)ar;
340
register struct local* x;
341
register struct block* p;
342
char* t;
343
344
NoP(handle);
345
if (!(x = newof(0, struct local, 1, 0)))
346
error(3, "out of space");
347
r->local.pointer = (char*)x;
348
pathcanon(r->name, 0, 0);
349
s = r->name + strlen(r->name);
350
if (s >= r->name + 2 && *(s -= 2) == '.')
351
x->suffix = s + 1;
352
else
353
s = "";
354
if (r->action || !(t = strrchr(r->name, '/')))
355
x->base = r->name;
356
else if (omitted(r->name))
357
{
358
r->attributes |= A_omit;
359
x->base = t + 1;
360
}
361
else
362
{
363
*t = 0;
364
x->directory = initdir(r->name, s);
365
*t++ = '/';
366
x->base = t;
367
}
368
if (strmatch(x->base, "lib*.a"))
369
{
370
x->target = x->base;
371
s = x->base = strdup(x->base + 1);
372
s[0] = '-';
373
s[1] = 'l';
374
s[strlen(s) - 2] = 0;
375
}
376
else if ((p = r->action) && s[1] == 'o' && !s[2])
377
{
378
r->action = 0;
379
r->prereqs = 0;
380
while (p)
381
{
382
ccflags(p->data, NiL);
383
p = p->next;
384
}
385
}
386
return 0;
387
}
388
389
/*
390
* clear listprereq for all prerequisites
391
*/
392
393
static void
394
clrprereqs(register struct rule* r)
395
{
396
register struct list* p;
397
398
r->attributes &= ~A_listprereq;
399
for (p = r->prereqs; p; p = p->next)
400
if (p->rule->attributes & A_listprereq)
401
clrprereqs(p->rule);
402
}
403
404
/*
405
* dump the (implicit) prerequisites for r
406
*/
407
408
static int
409
dumpprereqs(register int col, register struct rule* r)
410
{
411
register struct list* p;
412
413
if (!(r->attributes & (A_listprereq|A_omit)))
414
{
415
r->attributes |= A_listprereq;
416
col = dumpname(col, r->local.pointer ? ((struct local*)r->local.pointer)->base : r->name);
417
if (r->attributes & (A_directory))
418
for (p = r->prereqs; p; p = p->next)
419
if (p->rule->attributes & (A_directory))
420
col = dumpprereqs(col, p->rule);
421
}
422
return col;
423
}
424
425
/*
426
* dump an action
427
*/
428
429
static void
430
dumpaction(register struct block* p)
431
{
432
if (p) do
433
{
434
dumpvalue(0, p->data, '\t');
435
sfputc(sfstdout, '\n');
436
} while (p = p->next);
437
}
438
439
/*
440
* dump the rules
441
*/
442
443
static void
444
dump(register struct rule* r)
445
{
446
register int col;
447
register struct list* p;
448
449
if (!(r->attributes & (A_listtarg|A_metarule)))
450
{
451
r->attributes |= A_listtarg;
452
if (r->action || r->prereqs)
453
{
454
clrprereqs(r);
455
r->attributes |= A_listprereq;
456
sfputc(sfstdout, '\n');
457
message(-1, "%s:%s", r->name, r->action ? " action" : "");
458
col = dumpname(1, r->local.pointer ? (((struct local*)r->local.pointer)->target ? ((struct local*)r->local.pointer)->target : ((struct local*)r->local.pointer)->base) : r->name);
459
col = dumpname(col, ":");
460
for (p = r->prereqs; p; p = p->next)
461
if (!(p->rule->attributes & A_listprereq))
462
{
463
clrprereqs(p->rule);
464
col = dumpprereqs(col, p->rule);
465
}
466
sfputc(sfstdout, '\n');
467
dumpaction(r->action);
468
}
469
for (p = r->prereqs; p; p = p->next)
470
if (p->rule != r)
471
dump(p->rule);
472
}
473
}
474
475
/*
476
* dump state var definition
477
*/
478
479
static int
480
dumpstate(const char* an, char* av, void* handle)
481
{
482
char* name = (char*)an;
483
struct var* v = (struct var*)av;
484
register char* s = v->value;
485
register int col;
486
487
static int init;
488
489
NoP(handle);
490
if (*s++ == '-')
491
{
492
if (*s == 'D')
493
{
494
while (isalnum(*++s));
495
if (*s++ == '=')
496
{
497
if (!init)
498
{
499
init = 1;
500
sfputc(sfstdout, '\n');
501
}
502
v->attributes |= V_state;
503
col = dumpname(0, name);
504
sfputr(sfstdout, " == ", -1);
505
col += 2;
506
if (*s == '"')
507
{
508
s[strlen(s) - 1] = 0;
509
dumpvalue(col, s + 1, '\\');
510
}
511
else
512
dumpvalue(col, s, 0);
513
}
514
else
515
{
516
if (!init)
517
{
518
init = 1;
519
sfputc(sfstdout, '\n');
520
}
521
v->attributes |= V_state;
522
dumpname(0, name);
523
sfputr(sfstdout, " == 1\n", -1);
524
}
525
}
526
else if (*s == 'U')
527
{
528
if (!init)
529
{
530
init = 1;
531
sfputc(sfstdout, '\n');
532
}
533
v->attributes |= V_state;
534
dumpname(0, name);
535
sfputr(sfstdout, " ==\n", -1);
536
}
537
}
538
return 0;
539
}
540
541
/*
542
* dump interesting var definitions
543
*/
544
545
static void
546
dumpvar(void)
547
{
548
register struct var* v;
549
550
if (v = getvar(state.mam->main, "CCFLAGS"))
551
ccflags(v->value, v);
552
}
553
554
/*
555
* add prefix to list of dir prefixes to omit
556
*/
557
558
static void
559
omit(char* prefix)
560
{
561
struct block* p;
562
563
if (!(p = newof(0, struct block, 1, 0)))
564
error(3, "out of space");
565
p->data = prefix;
566
p->next = state.omit;
567
state.omit = p;
568
}
569
570
int
571
main(int argc, char** argv)
572
{
573
register struct list* p;
574
575
NoP(argc);
576
error_info.id = "mamnew";
577
for (;;)
578
{
579
switch (optget(argv, usage))
580
{
581
case 'd':
582
error_info.trace = -opt_info.num;
583
continue;
584
case 'x':
585
omit(opt_info.arg);
586
continue;
587
case '?':
588
error(ERROR_USAGE|4, opt_info.arg);
589
break;
590
case ':':
591
error(2, opt_info.arg);
592
break;
593
}
594
break;
595
}
596
if (error_info.errors)
597
error(ERROR_USAGE|4, "%s", optusage(NiL));
598
599
/*
600
* preventive maintenance
601
*/
602
603
error(1, "still under development -- send positive contributions to [email protected]");
604
605
/*
606
* initialize
607
*/
608
609
omit("/usr/include");
610
omit("/usr/lib");
611
612
/*
613
* scan, collect and dump
614
*/
615
616
sfprintf(sfstdout, "/* # # nmake makefile generated by mamnew # # */\n");
617
if (!(state.mam = mamalloc()))
618
error(3, "cannot initialize");
619
state.atom.source = mamrule(state.mam->main, ".SOURCE");
620
state.atom.source_a = mamrule(state.mam->main, ".SOURCE.a");
621
state.atom.source_h = mamrule(state.mam->main, ".SOURCE.h");
622
state.atom.sources = mamrule(state.mam->main, ".MAM.SOURCES.");
623
if (mamscan(state.mam, NiL) < 0)
624
error(3, "invalid input");
625
hashwalk(state.mam->main->rules, 0, initrule, NiL);
626
if (state.ancestor)
627
sfprintf(sfstdout, "\nancestor = %d\n", state.ancestor);
628
dumpvar();
629
hashwalk(state.mam->main->vars, 0, dumpstate, NiL);
630
for (p = state.atom.sources->prereqs; p; p = p->next)
631
if (p->rule->prereqs)
632
dump(p->rule);
633
for (p = state.mam->main->root->prereqs; p; p = p->next)
634
dump(p->rule);
635
exit(error_info.errors != 0);
636
}
637
638