bootstrap_cmds/migcom.tproj/mig.c
1/*
2 * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Mach Operating System
25 * Copyright (c) 1991,1990 Carnegie Mellon University
26 * All Rights Reserved.
27 *
28 * Permission to use, copy, modify and distribute this software and its
29 * documentation is hereby granted, provided that both the copyright
30 * notice and this permission notice appear in all copies of the
31 * software, derivative works or modified versions, and any portions
32 * thereof, and that both notices appear in supporting documentation.
33 *
34 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
35 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
36 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
37 *
38 * Carnegie Mellon requests users of this software to return to
39 *
40 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
41 * School of Computer Science
42 * Carnegie Mellon University
43 * Pittsburgh PA 15213-3890
44 *
45 * any improvements or extensions that they make and grant Carnegie the
46 * rights to redistribute these changes.
47 */
48
49/*
50 * Switches are;
51 * -[v,Q] verbose or not quiet: prints out type
52 * and routine information as mig runs.
53 * -[V,q] not verbose or quiet : don't print
54 * information during compilation
55 * (this is the default)
56 * -[r,R] do or don't use rpc calls instead of
57 * send/receive pairs. Default is -r.
58 * -[s,S] generate symbol table or not: generate a
59 * table of rpc-name, number, routine triplets
60 * as an external data structure -- main use is
61 * for protection system's specification of rights
62 * and for protection dispatch code. Default is -s.
63 * -[l,L] -L generate code that insert code for logging
64 * the most important events that happen at the
65 * stub level (message conception, target routine
66 * calls). Default is -l.
67 * -[k,K] -K enforces MIG to generate K&R C language, with the
68 * addition of ANSI C syntax under #ifdef __STDC__.
69 * Default is -k.
70 * -[n,N] -n enforces NDR checking and conversion logic generation.
71 * Default is -N (no checking).
72 * -i <prefix>
73 * Put each user routine in its own file. The
74 * file is named <prefix><routine-name>.c.
75 * -user <name>
76 * Name the user-side file <name>
77 * -server <name>
78 * Name the server-side file <name>
79 * -header <name>
80 * Name the user-side header file <name>
81 * -iheader <name>
82 * Name the user-side internal header file <name>
83 * -sheader <name>
84 * Name the server-side header file <name>
85 * -dheader <name>
86 * Name the defines (msgh_ids) header file <name>
87 *
88 * DESIGN:
89 * Mig uses a lexxer module created by lex from lexxer.l and
90 * a parser module created by yacc from parser.y to parse an
91 * interface definitions module for a mach server.
92 * The parser module calls routines in statement.c
93 * and routines.c to build a list of statement structures.
94 * The most interesting statements are the routine definitions
95 * which contain information about the name, type, characteristics
96 * of the routine, an argument list containing information for
97 * each argument type, and a list of special arguments. The
98 * argument type structures are build by routines in type.c
99 * Once parsing is completed, the three code generation modules:
100 * header.c user.c and server.c are called sequentially. These
101 * do some code generation directly and also call the routines
102 * in utils.c for common (parameterized) code generation.
103 *
104 */
105
106#include <stdlib.h>
107#include <stdio.h>
108#include <time.h>
109#include "error.h"
110#include "lexxer.h"
111#include "global.h"
112#include "write.h"
113
114extern int yyparse(void);
115static FILE *myfopen(const char *name, const char *mode);
116
117static void
118parseArgs(int argc,char *argv[])
119{
120 if (argc == 2 && streql(argv[1], "-version")) {
121 PrintVersion = TRUE;
122 return;
123 }
124
125 while (--argc > 0)
126 if ((++argv)[0][0] == '-') {
127 switch (argv[0][1]) {
128
129 case 'q':
130 BeQuiet = TRUE;
131 break;
132
133 case 'Q':
134 BeQuiet = FALSE;
135 break;
136
137 case 'v':
138 BeVerbose = TRUE;
139 break;
140
141 case 'V':
142 BeVerbose = FALSE;
143 break;
144
145 case 'r':
146 UseMsgRPC = TRUE;
147 break;
148
149 case 'R':
150 UseMsgRPC = FALSE;
151 break;
152
153 case 'l':
154 UseEventLogger = FALSE;
155 break;
156
157 case 'L':
158 UseEventLogger = TRUE;
159 break;
160
161 case 'k':
162 BeAnsiC = TRUE;
163 break;
164
165 case 'K':
166 BeAnsiC = FALSE;
167 break;
168
169 case 'n':
170 if (streql(argv[0], "-novouchers")) {
171 IsVoucherCodeAllowed = FALSE;
172 } else {
173 CheckNDR = TRUE;
174 }
175 break;
176
177 case 'N':
178 CheckNDR = FALSE;
179 break;
180
181 case 'b':
182 EmitCountAnnotations = TRUE;
183 break;
184
185 case 'B':
186 EmitCountAnnotations = FALSE;
187 break;
188
189 case 's':
190 if (streql(argv[0], "-server")) {
191 --argc; ++argv;
192 if (argc == 0)
193 fatal("missing name for -server option");
194 ServerFileName = strmake(argv[0]);
195 }
196 else if (streql(argv[0], "-sheader")) {
197 --argc; ++argv;
198 if (argc == 0)
199 fatal ("missing name for -sheader option");
200 ServerHeaderFileName = strmake(argv[0]);
201 }
202 else if (streql(argv[0], "-split"))
203 UseSplitHeaders = TRUE;
204 else
205 GenSymTab = TRUE;
206 break;
207
208 case 'S':
209 GenSymTab = FALSE;
210 break;
211
212 case 't':
213 warn("Mach RPC traps not fully supported");
214 TestRPCTrap = TRUE;
215 UseRPCTrap = TRUE;
216 break;
217
218 case 'T':
219 UseRPCTrap = FALSE;
220 break;
221
222 case 'i':
223 if (streql(argv[0], "-iheader")) {
224 --argc; ++argv;
225 if (argc == 0)
226 fatal("missing name for -iheader option");
227 InternalHeaderFileName = strmake(argv[0]);
228 }
229 else {
230 --argc; ++argv;
231 if (argc == 0)
232 fatal("missing prefix for -i option");
233 UserFilePrefix = strmake(argv[0]);
234 }
235 break;
236
237 case 'u':
238 if (streql(argv[0], "-user")) {
239 --argc; ++argv;
240 if (argc == 0)
241 fatal("missing name for -user option");
242 UserFileName = strmake(argv[0]);
243 }
244 else
245 fatal("unknown flag: '%s'", argv[0]);
246 break;
247
248 case 'h':
249 if (streql(argv[0], "-header")) {
250 --argc; ++argv;
251 if (argc == 0)
252 fatal("missing name for -header option");
253 UserHeaderFileName = strmake(argv[0]);
254 }
255 else
256 fatal("unknown flag: '%s'", argv[0]);
257 break;
258
259 case 'd':
260 if (streql(argv[0], "-dheader")) {
261 --argc; ++argv;
262 if (argc == 0)
263 fatal("missing name for -dheader option");
264 DefinesHeaderFileName = strmake(argv[0]);
265 }
266 else
267 fatal("unknown flag: '%s'", argv[0]);
268 break;
269
270 case 'm':
271 if (streql(argv[0], "-maxonstack")) {
272 --argc; ++argv;
273 if (argc == 0)
274 fatal("missing size for -maxonstack option");
275 MaxMessSizeOnStack = atoi(argv[0]);
276 }
277 else if (streql(argv[0], "-mach_msg2"))
278 UseMachMsg2 = TRUE;
279 else if (streql(argv[0], "-max_descrs")) {
280 --argc; ++argv;
281 if (argc == 0)
282 fatal("missing count for -max_descrs option");
283 MaxServerDescrs = atoi(argv[0]);
284 } else if (streql(argv[0], "-max_reply_descrs")) {
285 --argc; ++argv;
286 if (argc == 0)
287 fatal("missing count for -max_reply_descrs option");
288 MaxServerReplyDescrs = atoi(argv[0]);
289 } else
290 fatal("unknown flag: '%s'", argv[0]);
291 break;
292
293 case 'X':
294 ShortCircuit = FALSE;
295 break;
296
297 case 'x':
298 ShortCircuit = TRUE;
299 /* fall thru - no longer supported */
300
301 default:
302 fatal("unknown/unsupported flag: '%s'", argv[0]);
303 /*NOTREACHED*/
304 }
305 }
306 else
307 fatal("bad argument: '%s'", *argv);
308
309 if (UseMachMsg2) {
310 if (!BeAnsiC || UseRPCTrap || CheckNDR) {
311 fatal("KernelServer does not support the given uptions.");
312 }
313 }
314}
315
316FILE *uheader, *server, *user;
317
318int
319main(int argc, char *argv[])
320{
321 FILE *iheader = 0;
322 FILE *sheader = 0;
323 FILE *dheader = 0;
324
325 set_program_name("mig");
326 parseArgs(argc, argv);
327 if (PrintVersion) {
328 printf("%s\n", MIG_VERSION);
329 fflush(stdout);
330 exit(0);
331 }
332 init_global();
333 init_type();
334
335 LookNormal();
336 (void) yyparse();
337
338 if (mig_errors > 0)
339 fatal("%d errors found. Abort.\n", mig_errors);
340
341 more_global();
342
343 uheader = myfopen(UserHeaderFileName, "w");
344 if (!UserFilePrefix)
345 user = myfopen(UserFileName, "w");
346 server = myfopen(ServerFileName, "w");
347 if (ServerHeaderFileName)
348 sheader = myfopen(ServerHeaderFileName, "w");
349 if (IsKernelServer) {
350 iheader = myfopen(InternalHeaderFileName, "w");
351 }
352 if (DefinesHeaderFileName)
353 dheader = myfopen(DefinesHeaderFileName, "w");
354 if (BeVerbose) {
355 printf("Writing %s ... ", UserHeaderFileName);
356 fflush(stdout);
357 }
358 WriteUserHeader(uheader, stats);
359 fclose(uheader);
360 if (ServerHeaderFileName) {
361 if (BeVerbose) {
362 printf ("done.\nWriting %s ...", ServerHeaderFileName);
363 fflush (stdout);
364 }
365 WriteServerHeader(sheader, stats);
366 fclose(sheader);
367 }
368 if (IsKernelServer) {
369 if (BeVerbose) {
370 printf("done.\nWriting %s ... ", InternalHeaderFileName);
371 fflush(stdout);
372 }
373 WriteInternalHeader(iheader, stats);
374 fclose(iheader);
375 }
376 if (DefinesHeaderFileName) {
377 if (BeVerbose) {
378 printf ("done.\nWriting %s ...", DefinesHeaderFileName);
379 fflush (stdout);
380 }
381 WriteDefinesHeader(dheader, stats);
382 fclose(dheader);
383 }
384 if (UserFilePrefix) {
385 if (BeVerbose) {
386 printf("done.\nWriting individual user files ... ");
387 fflush(stdout);
388 }
389 WriteUserIndividual(stats);
390 }
391 else {
392 if (BeVerbose) {
393 printf("done.\nWriting %s ... ", UserFileName);
394 fflush(stdout);
395 }
396 WriteUser(user, stats);
397 fclose(user);
398 }
399 if (BeVerbose) {
400 printf("done.\nWriting %s ... ", ServerFileName);
401 fflush(stdout);
402 }
403 WriteServer(server, stats);
404 fclose(server);
405 if (BeVerbose)
406 printf("done.\n");
407
408 exit(0);
409}
410
411static FILE *
412myfopen(const char *name, const char *mode)
413{
414 const char *realname;
415 FILE *file;
416
417 if (name == strNULL)
418 realname = "/dev/null";
419 else
420 realname = name;
421
422 file = fopen(realname, mode);
423 if (file == NULL)
424 fatal("fopen(%s): %s", realname, strerror(errno));
425
426 return file;
427}