Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/proto/proto.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-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
* proto - make prototyped C compatible with K&R, ANSI, C++
26
*
27
* output to stdout unless -r
28
*
29
* NOTE: coded for minimal library support
30
*/
31
32
#if !PROTO_STANDALONE
33
34
static const char usage[] =
35
"[-?\n@(#)$Id: proto (AT&T Research) 2012-02-20 $\n]"
36
USAGE_LICENSE
37
"[+NAME?proto - make prototyped C source compatible with K&R, ANSI and C++]"
38
"[+DESCRIPTION?\bproto\b converts ANSI C prototype constructs in \afile\a"
39
" to constructs compatible with K&R C, ANSI C, and C++. Only files"
40
" with the line \b#pragma prototyped\b appearing in one of the first"
41
" 64 lines are processed; other files are silently ignored. Output is"
42
" written to the standard output unless the \b--replace\b option is"
43
" specified, in which case \afile\a is modified in-place.]"
44
45
"[c:comment?\ab[m[e]]]]\a are the beginning, middle, and end comment"
46
" characters. If \ae\a is omitted then it defaults to \ab\a. If \am\a is"
47
" omitted then it defaults to \ab\a. Use \"\b/*\b\" for C comments,"
48
" \"\b#\b\" for shell, and \"\b(*)\b\" for pascal. If \abme\a is \"\""
49
" (the empty string) then the comment style is determined from the"
50
" input \afile\a suffix; no notice is prepended if the comment"
51
" style cannot be determined.]:[bme:=\"/*\"]"
52
"[d:disable?Disable prototype conversion but still emit the identification"
53
" comment.]"
54
"[e:externs?All \bextern\b references are for \apackage\a. Some systems"
55
" require special attributes for imported and exported dll data symbols."
56
" If \b_BLD_\b\apackage\a is not defined then \bextern\b data references"
57
" will be assigned the dll import attribute when supported by the local"
58
" compiler.]:[package]"
59
"[f:force?Force conversion for files that do not contain"
60
" \b#pragma prototyped\b.]"
61
"[h!:header?Emit the \bproto\b header definition preamble.]"
62
"[i:inverse?Specifies inverse proto: classic function definitions are"
63
" converted to ANSI prototype form and non-ANSI directives are"
64
" commented out. In this case files with the line"
65
" \b#pragma noprototyped\b within the first 64 lines are silently"
66
" ignored. If \b--header\b is also specified then only \bextern\b"
67
" prototypes are emitted for each non-static function. This option"
68
" requires that all classic function formal arguments be declared,"
69
" i.e., omitted declarations for \bint\b formals will not generate"
70
" the correct prototype. Typical usage would be to first run"
71
" \bproto --inverse --header *.c\b to generate the external prototypes"
72
" that should be placed in a \b.h\b file shared by \b*.c\b and then"
73
" \bproto --inverse --replace *.c\b to convert the function prototypes"
74
" in place. Note that prototype code conditioned on \b__STDC__\b will"
75
" most likely confuse \b--inverse\b.]"
76
"[l:license?Generate a license notice comment at the top of the output"
77
" controlled by one or more \aname\a=\avalue\a pairs in \afile\a."
78
" If a \avalue\a contains space characters then it must be enclosed in"
79
" either single or double quotes. \aname\a may"
80
" be:]:[file]{"
81
" [+type?The license type:]{"
82
" [+bsd?The BSD open source license.]"
83
" [+cpl?The Common Public License.]"
84
" [+epl?The Eclipse Public License.]"
85
" [+gpl?The GNU Public License.]"
86
" [+mit?The MIT open source license.]"
87
" [+inline?License text already in source.]"
88
" [+none?No license.]"
89
" [+noncommercial?Non-commercial use.]"
90
" [+nonexclusive?Single person non-commercial use.]"
91
" [+open?Open source.]"
92
" [+proprietary?Only by individual agreement.]"
93
" [+special?License text in \bnotice\b.]"
94
" [+usage?License specific \boptget\b(3) usage strings.]"
95
" [+verbose?Include the disclaimer notice if any.]"
96
" [+zlib?The ZLIB open source license.]"
97
" }"
98
" [+author?A \b,\b separated list of \aname\a <\aemail\a> pairs.]"
99
" [+class?The license class. The default values are:]{"
100
" [+gpl?The GNU Public License.]"
101
" [+open?\bwww.opensource.org\b sanctioned open source.]"
102
" [+proprietary?Internal or non-disclosure use only.]"
103
" [+special?Nonstandard license text and notices.]"
104
" }"
105
" [+corporation?Within the parent, e.g., \bAT&T\b.]"
106
" [+company?Within the corporation, e.g., \bResearch\b.]"
107
" [+location?Company location.]"
108
" [+organization?Within the company, e.g., \bNetwork Services"
109
" Research Department\b.]"
110
" [+notice?\btype=special\b notice text with embedded newlines"
111
" or additional notice text listed by \btype=verbose\b.]"
112
" [+package?The generic software package name, e.g., \bast\b.]"
113
" [+parent?They own it all, e.g., \bAT&T\b.]"
114
" [+since?The year the software was first released.]"
115
" [+source?The year the input files was modified.]"
116
" [+start?The year the license was first applied to the software.]"
117
" [+url?The URL of the detailed license text, e.g.,"
118
" \bhttp://www.research.att.com/sw/license/open-ast.html\b.]"
119
" [+urlmd5?The \bmd5sum\b(1) of the downloaded URL data. Note that"
120
" the downloaded data may have embedded \b\\r\b not present"
121
" in the original source.]"
122
" [+query=\atext\a?If \atext\a is one of the \aname\as above"
123
" then its value is expanded, otherwise"
124
" \b${\b\aname\a\b}\b in \atext\a is expanded. The"
125
" result is printed as a line on the standard output"
126
" and \bproto\b exits. This should only be used via"
127
" \b--options\b.]"
128
"}"
129
"[n:sync?Output C style line syncs to retain the original line structure.]"
130
"[o:options?Additional space or \b,\b separated \aname=value\a \b--license\b"
131
" options.]:[name=value,...]"
132
"[p:pass?Pass input to output, even if not converted.]"
133
"[r:replace?Process the input files in place; original information is"
134
" replaced by \bproto\b output.]"
135
"[s:include?Output \b#include <prototyped.h>\b rather than expanding the"
136
" equivalent inline.]"
137
"[t:test?Enable test code. Use at your own risk.]"
138
"[v:verbose?List each file as it is processed.]"
139
"[x:externalize?Convert \bstatic\b function attributes to \bextern\b. Used"
140
" for analysis programs that only instrument \bextern\b functions.]"
141
"[z:zap?Disable conversion and remove \b#pragma prototyped\b.]"
142
"[C:copy?Convert each input \afile\a to \adirectory\a/\afile\a,"
143
" making intermediate directories as necessary.]:[directory]"
144
"[L:list?Input file names are read one per line from \afile\a.]:[file]"
145
"[P|+:plusplus?Convert \bextern()\b to \bextern(...)\b.]"
146
"[S:shell?Equivalent to \b--comment=\"#\".]"
147
148
"\n"
149
"\nfile ...\n"
150
"\n"
151
152
"[+SEE ALSO?\bcc\b(1), \bcpp\b(1)]"
153
;
154
155
#include <ast.h>
156
#include <error.h>
157
#include <times.h>
158
159
#define utime(p,t) touch(p,t[0],t[1],0)
160
161
#endif
162
163
#define PROTOMAIN 1
164
165
/*DELAY_CONTROL*/
166
167
#ifndef __STDC__
168
#ifndef creat
169
#define creat _huh_creat
170
#endif
171
#if PROTO_STANDALONE
172
#ifndef access
173
#define access _huh_access
174
#endif
175
#ifndef ctime
176
#define ctime _huh_ctime
177
#endif
178
#ifndef mkdir
179
#define mkdir _huh_mkdir
180
#endif
181
#endif
182
#endif
183
184
#include <sys/types.h>
185
#include <sys/stat.h>
186
#include <fcntl.h>
187
#if PROTO_STANDALONE
188
#include <stdio.h>
189
#else
190
#include <time.h>
191
#endif
192
193
#ifndef __STDC__
194
#undef access
195
#undef ctime
196
#undef creat
197
#undef mkdir
198
#endif
199
200
#ifndef O_RDONLY
201
#define O_RDONLY 0
202
#endif
203
204
#ifndef S_IRUSR
205
#define S_IRUSR 0400
206
#endif
207
#ifndef S_IWUSR
208
#define S_IWUSR 0200
209
#endif
210
#ifndef S_IXUSR
211
#define S_IXUSR 0100
212
#endif
213
#ifndef S_IRGRP
214
#define S_IRGRP 0040
215
#endif
216
#ifndef S_IWGRP
217
#define S_IWGRP 0020
218
#endif
219
#ifndef S_IXGRP
220
#define S_IXGRP 0010
221
#endif
222
#ifndef S_IROTH
223
#define S_IROTH 0004
224
#endif
225
#ifndef S_IWOTH
226
#define S_IWOTH 0002
227
#endif
228
#ifndef S_IXOTH
229
#define S_IXOTH 0001
230
#endif
231
232
#ifndef __STDC__
233
#if !_WIN32 && !_WINIX
234
#define remove(x) unlink(x)
235
#define rename(x,y) ((link(x,y)||remove(x))?-1:0)
236
#endif
237
238
#if PROTO_STANDALONE
239
extern int access(const char*, int);
240
extern int mkdir(const char*, int);
241
#endif
242
243
#endif
244
245
#if PROTO_STANDALONE
246
extern int utime(const char*, time_t*);
247
#endif
248
249
/*
250
* rename newfile to oldfile
251
* preserve!=0 preserves atime,mtime
252
*/
253
254
int
255
replace(const char* newfile, const char* oldfile, int preserve)
256
{
257
struct stat st;
258
time_t ut[2];
259
260
if (stat(oldfile, &st))
261
{
262
if (preserve)
263
return -1;
264
st.st_mode = 0;
265
}
266
if (remove(oldfile) || rename(newfile, oldfile))
267
return -1;
268
if (st.st_mode &= (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))
269
chmod(oldfile, st.st_mode);
270
if (preserve)
271
{
272
ut[0] = st.st_atime;
273
ut[1] = st.st_mtime;
274
preserve = utime(oldfile, ut);
275
}
276
return preserve;
277
}
278
279
#undef utime
280
#define utime ______utime
281
282
/*NODELAY_CONTROL*/
283
284
#include "ppproto.c"
285
286
#define PROTO_ERROR (PROTO_USER<<0)
287
#define PROTO_REPLACE (PROTO_USER<<1)
288
#define PROTO_VERBOSE (PROTO_USER<<2)
289
290
static int
291
proto(char* file, char* license, char* options, char* package, char* copy, char* comment, int flags)
292
{
293
char* b;
294
char* e;
295
char* p;
296
int n;
297
int m;
298
int x;
299
int fd;
300
char buf[1024];
301
302
if (file && access(file, 4))
303
proto_error(NiL, 2, file, "not found");
304
else if (b = pppopen(file, 0, license, options, package, comment, flags))
305
{
306
if (!file)
307
fd = 1;
308
else if (flags & PROTO_REPLACE)
309
{
310
e = file + strlen(file) - 1;
311
x = *e;
312
*e = '_';
313
if ((fd = creat(file, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
314
{
315
proto_error(b, 2, file, "cannot create temporary file");
316
pppclose(b);
317
return flags | PROTO_ERROR;
318
}
319
*e = x;
320
}
321
else if (copy)
322
{
323
if (((n = strlen(copy)) + strlen(file) + 2) > sizeof(buf))
324
{
325
proto_error(b, 2, copy, "copy path too long");
326
pppclose(b);
327
return flags | PROTO_ERROR;
328
}
329
strcpy(buf, copy);
330
e = buf + n;
331
if (*file != '/')
332
*e++ = '/';
333
strcpy(e, file);
334
if ((fd = creat(buf, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
335
{
336
for (e = buf; *e == '/'; e++);
337
do
338
{
339
if (*e == '/')
340
{
341
*e = 0;
342
if (access(buf, 0) && mkdir(buf, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH))
343
{
344
proto_error(b, 2, buf, "cannot create copy directory");
345
pppclose(b);
346
return flags | PROTO_ERROR;
347
}
348
*e = '/';
349
}
350
} while (*e++);
351
if ((fd = creat(buf, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
352
{
353
proto_error(b, 2, buf, "cannot create copy file");
354
pppclose(b);
355
return flags | PROTO_ERROR;
356
}
357
}
358
file = buf;
359
}
360
else
361
fd = 1;
362
if (file && (flags & PROTO_VERBOSE))
363
proto_error(b, 0, "convert to", file);
364
while ((n = pppread(b)) > 0)
365
{
366
p = b;
367
for (;;)
368
{
369
if ((m = write(fd, p, n)) <= 0)
370
{
371
proto_error(b, 2, "write error", NiL);
372
flags |= PROTO_ERROR;
373
break;
374
}
375
if ((n -= m) <= 0)
376
break;
377
p += m;
378
}
379
if (m < 0)
380
break;
381
}
382
if (fd > 1)
383
close(fd);
384
if (file && (flags & PROTO_REPLACE))
385
{
386
*e = '_';
387
strcpy(b, file);
388
*e = x;
389
if (replace(b, file, !(flags & PROTO_CLASSIC)))
390
proto_error(b, 2, "cannot rename to", file);
391
}
392
pppclose(b);
393
}
394
return flags;
395
}
396
397
#if !PROTO_STANDALONE
398
#undef error
399
#endif
400
401
typedef struct Sufcom_s
402
{
403
char suffix[4];
404
char comment[4];
405
} Sufcom_t;
406
407
static const Sufcom_t sufcom[] =
408
{
409
"c", "/*",
410
"cpp", "/*",
411
"cxx", "/*",
412
"c++", "/*",
413
"C", "/*",
414
"CPP", "/*",
415
"CXX", "/*",
416
"C++", "/*",
417
"f", "C",
418
"F", "C",
419
"h", "/*",
420
"hpp", "/*",
421
"hxx", "/*",
422
"H", "/*",
423
"HPP", "/*",
424
"HXX", "/*",
425
"ksh", "#",
426
"KSH", "#",
427
"l", "/*",
428
"L", "/*",
429
"p", "(*)",
430
"pas", "(*)",
431
"P", "(*)",
432
"PAS", "(*)",
433
"pl", "#",
434
"PL", "#",
435
"pl1", "/*",
436
"pli", "/*",
437
"PL1", "/*",
438
"PLI", "/*",
439
"sh", "#",
440
"SH", "#",
441
"sml", "(*)",
442
"SML", "(*)",
443
"y", "/*",
444
"Y", "/*",
445
};
446
447
/*
448
* if !comment || !*comment then return a value compatible with file
449
*/
450
451
static char*
452
type(register char* file, char* comment)
453
{
454
register char* suffix;
455
register int i;
456
457
if (file && (!comment || !*comment))
458
{
459
suffix = 0;
460
while (*file)
461
if (*file++ == '.')
462
suffix = file;
463
if (suffix && strlen(suffix) <= 3)
464
for (i = 0; i < sizeof(sufcom) / sizeof(sufcom[0]); i++)
465
if (!strcmp(suffix, sufcom[i].suffix))
466
return (char*)sufcom[i].comment;
467
}
468
return comment;
469
}
470
471
int
472
main(int argc, char** argv)
473
{
474
char* b;
475
char* file;
476
int fd;
477
int n;
478
char* op;
479
char* oe;
480
char* comment = 0;
481
char* copy = 0;
482
char* list = 0;
483
char* license = 0;
484
char* options = 0;
485
char* package = 0;
486
int flags = PROTO_HEADER;
487
char buf[1024];
488
char opt[4 * 1024];
489
490
NoP(argc);
491
#if PROTO_STANDALONE
492
while ((file = *++argv) && *file == '-' && *(file + 1))
493
{
494
for (;;)
495
{
496
switch (*++file)
497
{
498
case 0:
499
break;
500
case 'c':
501
if (!*(comment = ++file))
502
comment = *++argv;
503
break;
504
case 'd':
505
flags |= PROTO_DISABLE;
506
continue;
507
case 'e':
508
if (!*(package = ++file) && !(package = *++argv))
509
{
510
file = "??";
511
continue;
512
}
513
break;
514
case 'f':
515
flags |= PROTO_FORCE;
516
continue;
517
case 'h':
518
flags &= ~PROTO_HEADER;
519
continue;
520
case 'i':
521
flags |= PROTO_CLASSIC;
522
continue;
523
case 'l':
524
if (!*(license = ++file) && !(license = *++argv))
525
{
526
file = "??";
527
continue;
528
}
529
break;
530
case 'n':
531
flags |= PROTO_LINESYNC;
532
continue;
533
case 'o':
534
if (!*(b = ++file) && !(b = *++argv))
535
{
536
file = "??";
537
continue;
538
}
539
if (!options)
540
{
541
options = op = opt;
542
oe = op + sizeof(opt) - 1;
543
}
544
n = strlen(b);
545
if ((n + 1) >= (oe - op))
546
proto_error(NiL, 3, b, "too many options");
547
else
548
{
549
*op++ = '\n';
550
memcpy(op, b, n + 1);
551
op += n;
552
}
553
break;
554
case 'p':
555
flags |= PROTO_PASS;
556
continue;
557
case 'r':
558
flags |= PROTO_REPLACE;
559
continue;
560
case 's':
561
flags |= PROTO_INCLUDE;
562
continue;
563
case 't':
564
flags |= PROTO_TEST;
565
continue;
566
case 'v':
567
flags |= PROTO_VERBOSE;
568
continue;
569
case 'x':
570
flags |= PROTO_EXTERNALIZE;
571
continue;
572
case 'z':
573
flags |= PROTO_DISABLE|PROTO_NOPRAGMA;
574
continue;
575
case 'C':
576
if (!*(copy = ++file) && !(copy = *++argv))
577
{
578
file = "??";
579
continue;
580
}
581
break;
582
case 'L':
583
if (!*(list = ++file) && !(list = *++argv))
584
{
585
file = "??";
586
continue;
587
}
588
break;
589
case 'P':
590
case '+':
591
flags |= PROTO_PLUSPLUS;
592
continue;
593
case 'S':
594
comment = "#";
595
continue;
596
default:
597
proto_error(NiL, 2, file, "unknown option");
598
/*FALLTHROUGH*/
599
case '?':
600
b = "Usage: proto [-dfhinprstvzP+S] [-C directory] [-e package] [-l file]\n [-o \"name='value' ...\"] [-L file] file ...\n";
601
write(2, b, strlen(b));
602
return 2;
603
}
604
break;
605
}
606
}
607
#else
608
error_info.id = "proto";
609
for (;;)
610
{
611
switch (optget(argv, usage))
612
{
613
case 'c':
614
comment = opt_info.arg;
615
continue;
616
case 'd':
617
flags |= PROTO_DISABLE;
618
continue;
619
case 'e':
620
package = opt_info.arg;
621
continue;
622
case 'f':
623
flags |= PROTO_FORCE;
624
continue;
625
case 'h':
626
flags &= ~PROTO_HEADER;
627
continue;
628
case 'i':
629
flags |= PROTO_CLASSIC;
630
continue;
631
case 'l':
632
license = opt_info.arg;
633
continue;
634
case 'n':
635
flags |= PROTO_LINESYNC;
636
continue;
637
case 'o':
638
if (!options)
639
{
640
options = op = opt;
641
oe = op + sizeof(opt) - 1;
642
}
643
n = strlen(opt_info.arg);
644
if ((n + 1) >= (oe - op))
645
error(3, "%s: too many options", opt_info.arg);
646
else
647
{
648
*op++ = '\n';
649
memcpy(op, opt_info.arg, n + 1);
650
op += n;
651
}
652
continue;
653
case 'p':
654
flags |= PROTO_PASS;
655
continue;
656
case 'r':
657
flags |= PROTO_REPLACE;
658
continue;
659
case 's':
660
flags |= PROTO_INCLUDE;
661
continue;
662
case 't':
663
flags |= PROTO_TEST;
664
continue;
665
case 'v':
666
flags |= PROTO_VERBOSE;
667
continue;
668
case 'x':
669
flags |= PROTO_EXTERNALIZE;
670
continue;
671
case 'z':
672
flags |= PROTO_DISABLE|PROTO_NOPRAGMA;
673
continue;
674
case 'C':
675
copy = opt_info.arg;
676
continue;
677
case 'L':
678
list = opt_info.arg;
679
continue;
680
case 'P':
681
flags |= PROTO_PLUSPLUS;
682
continue;
683
case 'S':
684
comment = "#";
685
continue;
686
case '?':
687
error(ERROR_USAGE|4, "%s", opt_info.arg);
688
continue;
689
case ':':
690
error(2, "%s", opt_info.arg);
691
continue;
692
}
693
break;
694
}
695
if (error_info.errors)
696
error(ERROR_USAGE|4, "%s", optusage(NiL));
697
argv += opt_info.index;
698
file = *argv;
699
#endif
700
if (list)
701
{
702
if (*list == '-' && !*(list + 1))
703
fd = 0;
704
else if ((fd = open(list, O_RDONLY)) < 0)
705
proto_error(NiL, 3, list, "not found");
706
do
707
{
708
for (b = buf; (n = read(fd, b, 1)) > 0 && *b != '\n' && b < &buf[sizeof(buf) - 1]; b++);
709
if (b > buf)
710
{
711
*b = 0;
712
flags = proto(buf, license, options, package, copy, type(buf, comment), flags);
713
}
714
} while (n > 0);
715
if (fd > 0)
716
close(fd);
717
}
718
if (file)
719
do flags = proto(file, license, options, package, copy, type(file, comment), flags); while (file = *++argv);
720
else if (!list)
721
flags = proto(file, license, options, package, copy, type(file, comment), flags);
722
return errors ? 1 : (flags & PROTO_ERROR) ? 2 : 0;
723
}
724
725