1/*
2 * Copyright (c) 1999, 2008 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 "error.h"
109#include "lexxer.h"
110#include "global.h"
111#include "write.h"
112
113extern int yyparse();
114static FILE *myfopen();
115
116static void
117parseArgs(int argc,char *argv[])
118{
119  while (--argc > 0)
120    if ((++argv)[0][0] == '-') {
121      switch (argv[0][1]) {
122
123        case 'q':
124          BeQuiet = TRUE;
125          break;
126
127        case 'Q':
128          BeQuiet = FALSE;
129          break;
130
131        case 'v':
132          BeVerbose = TRUE;
133          break;
134
135        case 'V':
136          BeVerbose = FALSE;
137          break;
138
139        case 'r':
140          UseMsgRPC = TRUE;
141          break;
142
143        case 'R':
144          UseMsgRPC = FALSE;
145          break;
146
147        case 'l':
148          UseEventLogger = FALSE;
149          break;
150
151        case 'L':
152          UseEventLogger = TRUE;
153          break;
154
155        case 'k':
156          BeAnsiC = TRUE;
157          break;
158
159        case 'K':
160          BeAnsiC = FALSE;
161          break;
162
163        case 'n':
164	  if (streql(argv[0], "-novouchers")) {
165            IsVoucherCodeAllowed = FALSE;
166          } else {
167	    CheckNDR = TRUE;
168	  }
169          break;
170
171        case 'N':
172          CheckNDR = FALSE;
173          break;
174
175        case 's':
176          if (streql(argv[0], "-server")) {
177            --argc; ++argv;
178            if (argc == 0)
179              fatal("missing name for -server option");
180            ServerFileName = strmake(argv[0]);
181          }
182          else if (streql(argv[0], "-sheader")) {
183            --argc; ++argv;
184            if (argc == 0)
185              fatal ("missing name for -sheader option");
186            ServerHeaderFileName = strmake(argv[0]);
187          }
188          else if (streql(argv[0], "-split"))
189            UseSplitHeaders = TRUE;
190          else
191            GenSymTab = TRUE;
192          break;
193
194        case 'S':
195          GenSymTab = FALSE;
196          break;
197
198        case 't':
199          warn("Mach RPC traps not fully supported");
200          TestRPCTrap = TRUE;
201          UseRPCTrap = TRUE;
202          break;
203
204        case 'T':
205          UseRPCTrap = FALSE;
206          break;
207
208        case 'i':
209          if (streql(argv[0], "-iheader")) {
210            --argc; ++argv;
211            if (argc == 0)
212              fatal("missing name for -iheader option");
213            InternalHeaderFileName = strmake(argv[0]);
214          }
215          else {
216            --argc; ++argv;
217            if (argc == 0)
218              fatal("missing prefix for -i option");
219            UserFilePrefix = strmake(argv[0]);
220          }
221          break;
222
223        case 'u':
224          if (streql(argv[0], "-user")) {
225            --argc; ++argv;
226            if (argc == 0)
227              fatal("missing name for -user option");
228            UserFileName = strmake(argv[0]);
229          }
230          else
231            fatal("unknown flag: '%s'", argv[0]);
232          break;
233
234        case 'h':
235          if (streql(argv[0], "-header")) {
236            --argc; ++argv;
237            if (argc == 0)
238              fatal("missing name for -header option");
239            UserHeaderFileName = strmake(argv[0]);
240          }
241          else
242            fatal("unknown flag: '%s'", argv[0]);
243          break;
244
245        case 'd':
246          if (streql(argv[0], "-dheader")) {
247            --argc; ++argv;
248            if (argc == 0)
249              fatal("missing name for -dheader option");
250            DefinesHeaderFileName = strmake(argv[0]);
251          }
252          else
253            fatal("unknown flag: '%s'", argv[0]);
254          break;
255
256        case 'm':
257          if (streql(argv[0], "-maxonstack")) {
258            --argc; ++argv;
259            if (argc == 0)
260              fatal("missing size for -maxonstack option");
261            MaxMessSizeOnStack = atoi(argv[0]);
262          }
263          else
264            fatal("unknown flag: '%s'", argv[0]);
265          break;
266
267        case 'X':
268          ShortCircuit = FALSE;
269          break;
270
271        case 'x':
272          ShortCircuit = TRUE;
273          /* fall thru - no longer supported */
274
275        default:
276          fatal("unknown/unsupported flag: '%s'", argv[0]);
277          /*NOTREACHED*/
278      }
279    }
280    else
281      fatal("bad argument: '%s'", *argv);
282}
283
284FILE *uheader, *server, *user;
285
286int
287main(int argc, char *argv[])
288{
289  FILE *iheader = 0;
290  FILE *sheader = 0;
291  FILE *dheader = 0;
292  time_t loc;
293  extern time_t time();
294  extern string_t ctime();
295  extern string_t GenerationDate;
296
297  set_program_name("mig");
298  parseArgs(argc, argv);
299  init_global();
300  init_type();
301  loc = time((time_t *)0);
302  GenerationDate = ctime(&loc);
303
304  LookNormal();
305  (void) yyparse();
306
307  if (mig_errors > 0)
308    fatal("%d errors found. Abort.\n", mig_errors);
309
310  more_global();
311
312  uheader = myfopen(UserHeaderFileName, "w");
313  if (!UserFilePrefix)
314    user = myfopen(UserFileName, "w");
315  server = myfopen(ServerFileName, "w");
316  if (ServerHeaderFileName)
317    sheader = myfopen(ServerHeaderFileName, "w");
318  if (IsKernelServer) {
319    iheader = myfopen(InternalHeaderFileName, "w");
320  }
321  if (DefinesHeaderFileName)
322    dheader = myfopen(DefinesHeaderFileName, "w");
323  if (BeVerbose) {
324    printf("Writing %s ... ", UserHeaderFileName);
325    fflush(stdout);
326  }
327  WriteUserHeader(uheader, stats);
328  fclose(uheader);
329  if (ServerHeaderFileName) {
330    if (BeVerbose) {
331      printf ("done.\nWriting %s ...", ServerHeaderFileName);
332      fflush (stdout);
333    }
334    WriteServerHeader(sheader, stats);
335    fclose(sheader);
336  }
337  if (IsKernelServer) {
338    if (BeVerbose) {
339      printf("done.\nWriting %s ... ", InternalHeaderFileName);
340      fflush(stdout);
341    }
342    WriteInternalHeader(iheader, stats);
343    fclose(iheader);
344  }
345  if (DefinesHeaderFileName) {
346    if (BeVerbose) {
347      printf ("done.\nWriting %s ...", DefinesHeaderFileName);
348      fflush (stdout);
349    }
350    WriteDefinesHeader(dheader, stats);
351    fclose(dheader);
352  }
353  if (UserFilePrefix) {
354    if (BeVerbose) {
355      printf("done.\nWriting individual user files ... ");
356      fflush(stdout);
357    }
358    WriteUserIndividual(stats);
359  }
360  else {
361    if (BeVerbose) {
362      printf("done.\nWriting %s ... ", UserFileName);
363      fflush(stdout);
364    }
365    WriteUser(user, stats);
366    fclose(user);
367  }
368  if (BeVerbose) {
369    printf("done.\nWriting %s ... ", ServerFileName);
370    fflush(stdout);
371  }
372  WriteServer(server, stats);
373  fclose(server);
374  if (BeVerbose)
375    printf("done.\n");
376
377  exit(0);
378}
379
380static FILE *
381myfopen(char *name, char *mode)
382{
383  char *realname;
384  FILE *file;
385
386  if (name == strNULL)
387    realname = "/dev/null";
388  else
389    realname = name;
390
391  file = fopen(realname, mode);
392  if (file == NULL)
393    fatal("fopen(%s): %s", realname, strerror(errno));
394
395  return file;
396}
397