Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/misc.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2012 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 Research
24
*
25
* make support routines
26
*/
27
28
#include "make.h"
29
30
/*
31
* stat() that checks for read access
32
* if res!=0 then resolve(name,fd,mode) must be called
33
*/
34
35
int
36
rstat(char* name, Stat_t* st, int res)
37
{
38
Time_t t;
39
40
if (internal.openfile)
41
{
42
internal.openfile = 0;
43
close(internal.openfd);
44
}
45
while ((internal.openfd = open(name, O_RDONLY|O_BINARY|O_cloexec)) < 0)
46
{
47
if (errno != EINTR)
48
{
49
if (errno == EACCES)
50
{
51
if (state.maxview && !state.fsview)
52
{
53
int oerrno = errno;
54
Stat_t rm;
55
56
if (!stat(name, st) && st->st_nlink > 1 && !st->st_size && !(st->st_mode & S_IPERM))
57
{
58
edit(internal.tmp, name, KEEP, ".../...", DELETE);
59
if (!stat(sfstruse(internal.tmp), &rm) && rm.st_ino == st->st_ino)
60
{
61
/*
62
* not in this or any lower view
63
*/
64
65
errno = ENODEV;
66
return -1;
67
}
68
}
69
errno = oerrno;
70
}
71
if (!stat(name, st) && (st->st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
72
goto found;
73
error(1, "%s ignored -- not readable", name);
74
}
75
return -1;
76
}
77
}
78
internal.openfile = name;
79
if (res && resolve(internal.openfile, internal.openfd, O_RDONLY))
80
return -1;
81
if (fstat(internal.openfd, st))
82
return -1;
83
#if _WINIX
84
if (st->st_nlink > 1)
85
{
86
internal.openfile = 0;
87
close(internal.openfd);
88
internal.openfd = -1;
89
}
90
#endif
91
found:
92
if (!tmxgetmtime(st))
93
{
94
if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))
95
error(1, "%s modify time must be after the epoch", name);
96
tmxsetmtime(st, OLDTIME);
97
}
98
if (state.regress && (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)))
99
{
100
t = CURTIME;
101
tmxsetmtime(st, t);
102
}
103
return 0;
104
}
105
106
/*
107
* allocate a chunk of units
108
* free units linked onto head
109
*/
110
111
void*
112
newchunk(char** head, register size_t unit)
113
{
114
#if __hppa || __hppa__ || hppa /* cc botches e arithmetic -- off by 8! */
115
NoP(head);
116
return newof(0, char, unit, 0);
117
#else
118
register char* p;
119
register char* e;
120
register char** x;
121
int n;
122
void* v;
123
124
n = (4096 / unit) * unit;
125
v = p = newof(0, char, n, 0);
126
e = p + n - unit;
127
x = head;
128
while (((char*)(x = (char**)(*x = p += unit))) < e);
129
return v;
130
#endif
131
}
132
133
/*
134
* append a list q onto the end of list p
135
* list p is surgically modified
136
*/
137
138
List_t*
139
append(List_t* p, List_t* q)
140
{
141
register List_t* t;
142
143
if (t = p)
144
{
145
if (q)
146
{
147
while (t->next)
148
t = t->next;
149
t->next = q;
150
}
151
return p;
152
}
153
else return q;
154
}
155
156
/*
157
* add rule r onto the front of list p
158
* list p is not modified
159
*/
160
161
List_t*
162
cons(Rule_t* r, List_t* p)
163
{
164
register List_t* q;
165
166
newlist(q);
167
q->next = p;
168
q->rule = r;
169
return q;
170
}
171
172
/*
173
* construct and return a copy of list p
174
* the items in the list are not copied
175
*/
176
177
List_t*
178
listcopy(register List_t* p)
179
{
180
register List_t* q;
181
register List_t* r;
182
register List_t* t;
183
184
if (!p)
185
return 0;
186
newlist(r);
187
q = r;
188
while (p)
189
{
190
q->rule = p->rule;
191
if (p = p->next)
192
{
193
newlist(t);
194
q = q->next = t;
195
}
196
}
197
q->next = 0;
198
return r;
199
}
200
201
/*
202
* format time or convert to number
203
*/
204
205
char*
206
timefmt(const char* fmt, Time_t t)
207
{
208
if (!t)
209
t = 0;
210
else if (t == NOTIME)
211
t = 100000000;
212
else if (t == OLDTIME)
213
t = 200000000;
214
else if (state.regress)
215
{
216
if (t < state.start)
217
t = 300000000;
218
else
219
t = 400000000;
220
}
221
else
222
return fmttmx((fmt && *fmt) ? fmt : "%s.%6N", t);
223
return fmttmx((fmt && *fmt) ? fmt : "%s.%1N", t);
224
}
225
226
/*
227
* convert numeric string time to Time_t
228
*/
229
230
Time_t
231
timenum(const char* s, char** p)
232
{
233
Time_t t;
234
unsigned long n;
235
unsigned long m;
236
char* e;
237
238
if ((t = strtoull(s, &e, 10)) == (Time_t)(-1))
239
{
240
if (p)
241
*p = (char*)s;
242
return TMX_NOTIME;
243
}
244
n = 0;
245
if (*e == '.')
246
{
247
m = 1000000000;
248
while (isdigit(*++e))
249
n += (*e - '0') * (m /= 10);
250
}
251
if (p)
252
*p = e;
253
return tmxsns(t, n);
254
}
255
256
/*
257
* convert time t to a string for tracing
258
*/
259
260
char*
261
timestr(Time_t t)
262
{
263
if (!t)
264
return "not found";
265
else if (t == NOTIME)
266
return "not checked";
267
else if (t == OLDTIME)
268
return "really old";
269
else if (!state.regress)
270
return fmttmx("%?%K.%6N", t);
271
else if (t < state.start)
272
return "recent";
273
else
274
return "current";
275
}
276
277
/*
278
* printext() value types
279
*/
280
281
#if _ast_intmax_long
282
#undef strtoll
283
#define strtoll strtol
284
#undef strtoull
285
#define strtoull strtoul
286
#endif
287
288
typedef union Value_u
289
{
290
char** p;
291
char* s;
292
intmax_t q;
293
unsigned long u;
294
long l;
295
int i;
296
short h;
297
char c;
298
double d;
299
} Value_t;
300
301
typedef struct Fmt_s
302
{
303
Sffmt_t fmt;
304
char* arg;
305
int all;
306
Sfio_t* tmp;
307
} Fmt_t;
308
309
/*
310
* printf %! extension function
311
*/
312
313
static int
314
printext(Sfio_t* sp, void* vp, Sffmt_t* dp)
315
{
316
register Fmt_t* fp = (Fmt_t*)dp;
317
Value_t* value = (Value_t*)vp;
318
register char* s;
319
char* txt;
320
char* e;
321
Time_t tm;
322
323
if (fp->all)
324
{
325
s = fp->arg;
326
fp->arg += strlen(s);
327
}
328
else if (!(s = getarg(&fp->arg, NiL)))
329
return -1;
330
if (dp->n_str > 0)
331
{
332
if (!fp->tmp)
333
fp->tmp = sfstropen();
334
sfprintf(fp->tmp, "%.*s", dp->n_str, dp->t_str);
335
txt = sfstruse(fp->tmp);
336
}
337
else
338
txt = 0;
339
dp->flags |= SFFMT_VALUE;
340
switch (dp->fmt)
341
{
342
case 'C':
343
error(1, "%%%c: obsolete: use the %%c format", dp->fmt);
344
dp->fmt = 'c';
345
/*FALLTHROUGH*/
346
case 'c':
347
value->c = *s;
348
break;
349
case 'd':
350
dp->size = sizeof(value->q);
351
value->q = strtoll(s, NiL, 0);
352
break;
353
case 'F':
354
dp->fmt = 'f';
355
/*FALLTHROUGH*/
356
case 'a':
357
case 'A':
358
case 'e':
359
case 'E':
360
case 'f':
361
case 'g':
362
case 'G':
363
dp->size = sizeof(value->d);
364
value->d = strtod(s, NiL);
365
break;
366
case 'o':
367
case 'u':
368
case 'x':
369
case 'X':
370
dp->size = sizeof(value->q);
371
value->q = strtoull(s, NiL, 0);
372
break;
373
case 'p':
374
value->p = (char**)strtol(s, NiL, 0);
375
break;
376
case 'S':
377
error(1, "%%%c: obsolete: use the %%s format", dp->fmt);
378
dp->fmt = 's';
379
/*FALLTHROUGH*/
380
case 's':
381
value->s = s;
382
if (txt)
383
{
384
if (streq(txt, "identifier"))
385
{
386
if (*s && !istype(*s, C_ID1))
387
*s++ = '_';
388
for (; *s; s++)
389
if (!istype(*s, C_ID1|C_ID2))
390
*s = '_';
391
}
392
else if (streq(txt, "invert"))
393
{
394
for (; *s; s++)
395
if (isupper(*s))
396
*s = tolower(*s);
397
else if (islower(*s))
398
*s = toupper(*s);
399
}
400
else if (streq(txt, "lower"))
401
{
402
for (; *s; s++)
403
if (isupper(*s))
404
*s = tolower(*s);
405
}
406
else if (streq(txt, "upper"))
407
{
408
for (; *s; s++)
409
if (islower(*s))
410
*s = toupper(*s);
411
}
412
else if (streq(txt, "variable"))
413
{
414
for (; *s; s++)
415
if (!istype(*s, C_VARIABLE1|C_VARIABLE2))
416
*s = '.';
417
}
418
}
419
dp->size = -1;
420
break;
421
case 't':
422
case 'T':
423
if (!isdigit(*s) || ((tm = timenum(s, &e)), *e))
424
tm = tmxdate(s, &e, TMX_NOW);
425
if (*e || tm == TMX_NOTIME)
426
tm = CURTIME;
427
value->s = txt ? fmttmx(txt, tm) : timestr(tm);
428
dp->fmt = 's';
429
dp->size = -1;
430
break;
431
case 'Z':
432
dp->fmt = 'c';
433
value->c = 0;
434
break;
435
case '.':
436
value->i = (int)strtol(s, NiL, 0);
437
break;
438
default:
439
tmpname[0] = dp->fmt;
440
tmpname[1] = 0;
441
value->s = tmpname;
442
error(2, "%%%c: unknown format", dp->fmt);
443
dp->fmt = 's';
444
dp->size = -1;
445
break;
446
}
447
return 0;
448
}
449
450
/*
451
* printf from args in argp into sp
452
* all!=0 if %s gets all of argp
453
* term is an sfputr terminator
454
*/
455
456
int
457
strprintf(Sfio_t* sp, const char* format, char* argp, int all, int term)
458
{
459
int n;
460
int i;
461
Sfio_t* tp;
462
Fmt_t fmt;
463
464
memset(&fmt, 0, sizeof(fmt));
465
fmt.fmt.version = SFIO_VERSION;
466
tp = sfstropen();
467
sfprintf(tp, "%s", format);
468
stresc(fmt.fmt.form = sfstruse(tp));
469
fmt.fmt.extf = printext;
470
fmt.arg = argp;
471
fmt.all = all;
472
n = 0;
473
while ((i = sfprintf(sp, "%!", &fmt)) >= 0)
474
{
475
n += i;
476
if (fmt.arg <= argp || !*(argp = fmt.arg))
477
break;
478
}
479
if (term != -1)
480
{
481
sfputc(sp, term);
482
n++;
483
}
484
sfstrclose(tp);
485
if (fmt.tmp)
486
sfstrclose(fmt.tmp);
487
return n;
488
}
489
490
/*
491
* return next (possibly quoted) space-separated arg in *buf
492
* *buf points past end of arg on return
493
* the contents of buf are modified
494
* if flags!=0 then it is set with metarule specific A_* flags
495
*/
496
497
char*
498
getarg(char** buf, register int* flags)
499
{
500
register char* s;
501
register char* t;
502
register int c;
503
char* a;
504
char* q;
505
int paren;
506
507
if (flags)
508
*flags &= ~(A_group|A_metarule|A_scope);
509
for (s = *buf; isspace(*s); s++);
510
if (flags && !(*flags & A_nooptions) && s[0] == '-' && s[1] == '-')
511
{
512
if (!s[2] || isspace(s[2]))
513
{
514
for (s += 2; isspace(*s); s++);
515
*flags |= A_nooptions;
516
}
517
else
518
*flags |= A_scope;
519
}
520
if (!*(a = t = s))
521
return 0;
522
paren = 0;
523
for (;;)
524
{
525
switch (c = *s++)
526
{
527
case '\\':
528
if (*s)
529
{
530
*t++ = c;
531
c = *s++;
532
}
533
break;
534
case '(':
535
paren++;
536
if (flags)
537
*flags |= A_group;
538
break;
539
case ')':
540
paren--;
541
break;
542
case '"':
543
case '\'':
544
if (!paren)
545
{
546
for (q = t; *s && *s != c; *t++ = *s++)
547
if (*s == '\\' && *(s + 1))
548
*t++ = *s++;
549
if (*s)
550
s++;
551
*t = 0;
552
t = q + stresc(q);
553
continue;
554
}
555
break;
556
case '%':
557
if (flags && !(*flags & A_scope))
558
*flags |= A_metarule;
559
break;
560
case '=':
561
if (flags && !(*flags & (A_group|A_metarule)))
562
*flags |= A_scope;
563
break;
564
case ',':
565
if (flags)
566
*flags |= A_group;
567
break;
568
default:
569
if (paren || !isspace(c))
570
break;
571
/*FALLTHROUGH*/
572
case 0:
573
*t = 0;
574
if (!c)
575
s--;
576
*buf = s;
577
if (flags && !(*flags & (A_nooptions|A_scope)))
578
*flags |= A_nooptions;
579
return a;
580
}
581
*t++ = c;
582
}
583
}
584
585
/*
586
* list explanation
587
*/
588
589
void
590
explain(int level, ...)
591
{
592
va_list ap;
593
594
va_start(ap, level);
595
errorv(NiL, state.explain ? 0 : EXPTRACE, ap);
596
va_end(ap);
597
}
598
599