Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[dragonfly.git] / usr.bin / rpcgen / rpc_main.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  *
29  * @(#)rpc_main.c       1.21    94/04/25 SMI; 1.30 89/03/30 (C) 1987 SMI
30  * $FreeBSD: src/usr.bin/rpcgen/rpc_main.c,v 1.33 2007/08/23 09:38:26 delphij Exp $
31  */
32
33
34 /*
35  * rpc_main.c, Top level of the RPC protocol compiler.
36  * Copyright (C) 1987, Sun Microsystems, Inc.
37  */
38
39 #include <err.h>
40 #include <ctype.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include "rpc_parse.h"
49 #include "rpc_scan.h"
50 #include "rpc_util.h"
51
52 static void     c_output(const char *, const char *, int, const char *);
53 static void     h_output(const char *, const char *, int, const char *, int);
54 static void     l_output(const char *, const char *, int, const char *);
55 static void     t_output(const char *, const char *, int, const char *);
56 static void     clnt_output(const char *, const char *, int, const char *);
57 static char     *generate_guard(const char *);
58 static void     c_initialize(void);
59
60 static void     usage(void);
61 static void     options_usage(void);
62 static int      do_registers(int, const char **);
63 static int      parseargs(int, const char **, struct commandline *);
64 static void     svc_output(const char *, const char *, int, const char *);
65 static void     mkfile_output(struct commandline *);
66 static void     s_output(int, const char **, const char *, const char *, int,
67                          const char *, int, int);
68
69 #define EXTEND          1               /* alias for TRUE */
70 #define DONT_EXTEND     0               /* alias for FALSE */
71
72 static int cppDefined = 0;      /* explicit path for C preprocessor */
73
74 static const char *svcclosetime = "120";
75 static const char *CPP = NULL;
76 static const char CPPFLAGS[] = "-C";
77 static char pathbuf[MAXPATHLEN + 1];
78 static const char *allv[] = {
79         "rpcgen", "-s", "udp", "-s", "tcp",
80 };
81 static int allc = sizeof (allv)/sizeof (allv[0]);
82 static const char *allnv[] = {
83         "rpcgen", "-s", "netpath",
84 };
85 static int allnc = sizeof (allnv)/sizeof (allnv[0]);
86
87 /*
88  * machinations for handling expanding argument list
89  */
90 static void addarg(const char *);       /* add another argument to the list */
91 static void putarg(int, const char *);  /* put argument at specified location */
92 static void clear_args(void);           /* clear argument list */
93 static void checkfiles(const char *, const char *);
94                                         /* check if out file already exists */
95
96
97
98 #define ARGLISTLEN      20
99 #define FIXEDARGS       2
100
101 static char *arglist[ARGLISTLEN];
102 static int argcount = FIXEDARGS;
103
104
105 int nonfatalerrors;     /* errors */
106 int inetdflag = 0;      /* Support for inetd is disabled by default, use -I */
107 int pmflag = 0;         /* Support for port monitors is disabled by default */
108 int tirpc_socket = 1;   /* TI-RPC on socket, no TLI library */
109 int logflag;            /* Use syslog instead of fprintf for errors */
110 int tblflag;            /* Support for dispatch table file */
111 int mtflag = 0;         /* Support for MT */
112
113 #define INLINE 0
114 /* length at which to start doing an inline */
115
116 int inline_size = INLINE;
117 /*
118  * Length at which to start doing an inline. INLINE = default
119  * if 0, no xdr_inline code
120  */
121
122 int indefinitewait;     /* If started by port monitors, hang till it wants */
123 int exitnow;            /* If started by port monitors, exit after the call */
124 int timerflag;          /* TRUE if !indefinite && !exitnow */
125 int newstyle;           /* newstyle of passing arguments (by value) */
126 int CCflag = 0;         /* C++ files */
127 static int allfiles;   /* generate all files */
128 int tirpcflag = 1;    /* generating code for tirpc, by default */
129 xdrfunc *xdrfunc_head = NULL; /* xdr function list */
130 xdrfunc *xdrfunc_tail = NULL; /* xdr function list */
131 pid_t childpid;
132
133
134 int
135 main(int argc, const char **argv)
136 {
137         struct commandline cmd;
138
139         memset(&cmd, 0, sizeof (struct commandline));
140         clear_args();
141         if (!parseargs(argc, argv, &cmd))
142                 usage();
143         /*
144          * Only the client and server side stubs are likely to be customized,
145          *  so in that case only, check if the outfile exists, and if so,
146          *  print an error message and exit.
147          */
148         if (cmd.Ssflag || cmd.Scflag || cmd.makefileflag)
149                 checkfiles(cmd.infile, cmd.outfile);
150         else
151                 checkfiles(cmd.infile, NULL);
152
153         if (cmd.cflag) {
154                 c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
155         } else if (cmd.hflag) {
156                 h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile,
157                     cmd.hflag);
158         } else if (cmd.lflag) {
159                 l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
160         } else if (cmd.sflag || cmd.mflag || (cmd.nflag)) {
161                 s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
162                         cmd.outfile, cmd.mflag, cmd.nflag);
163         } else if (cmd.tflag) {
164                 t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
165         } else if  (cmd.Ssflag) {
166                 svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND,
167                         cmd.outfile);
168         } else if (cmd.Scflag) {
169                 clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND,
170                             cmd.outfile);
171         } else if (cmd.makefileflag) {
172                 mkfile_output(&cmd);
173         } else {
174                 /* the rescans are required, since cpp may effect input */
175                 c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
176                 reinitialize();
177                 h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h", cmd.hflag);
178                 reinitialize();
179                 l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
180                 reinitialize();
181                 if (inetdflag || !tirpcflag)
182                         s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
183                         "_svc.c", cmd.mflag, cmd.nflag);
184                 else
185                         s_output(allnc, allnv, cmd.infile, "-DRPC_SVC",
186                                 EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
187                 if (tblflag) {
188                         reinitialize();
189                         t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
190                 }
191
192                 if (allfiles) {
193                         reinitialize();
194                         svc_output(cmd.infile, "-DRPC_SERVER", EXTEND,
195                                 "_server.c");
196                         reinitialize();
197                         clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND,
198                                 "_client.c");
199
200                 }
201                 if (allfiles || (cmd.makefileflag == 1)){
202                         reinitialize();
203                         mkfile_output(&cmd);
204                 }
205         }
206
207         exit(nonfatalerrors);
208         /* NOTREACHED */
209 }
210
211
212 /*
213  * add extension to filename
214  */
215 static char *
216 extendfile(const char *path, const char *ext)
217 {
218         char *res;
219         const char *p;
220         const char *file;
221
222         if ((file = strrchr(path, '/')) == NULL)
223                 file = path;
224         else
225                 file++;
226         res = xmalloc(strlen(file) + strlen(ext) + 1);
227         p = strrchr(file, '.');
228         if (p == NULL)
229                 p = file + strlen(file);
230         strcpy(res, file);
231         strcpy(res + (p - file), ext);
232         return(res);
233 }
234
235 /*
236  * Open output file with given extension
237  */
238 static void
239 open_output(const char *infile, const char *outfile)
240 {
241         if (outfile == NULL) {
242                 fout = stdout;
243                 return;
244         }
245
246         if (infile != NULL && streq(outfile, infile)) {
247                 warnx("%s already exists. No output generated", infile);
248                 crash();
249         }
250         fout = fopen(outfile, "w");
251         if (fout == NULL) {
252                 warn("unable to open %s", outfile);
253                 crash();
254         }
255         record_open(outfile);
256 }
257
258 static void
259 add_warning(void)
260 {
261         f_print(fout, "/*\n");
262         f_print(fout, " * Please do not edit this file.\n");
263         f_print(fout, " * It was generated using rpcgen.\n");
264         f_print(fout, " */\n\n");
265 }
266
267 /* clear list of arguments */
268 static void
269 clear_args(void)
270 {
271         int i;
272
273         for (i = FIXEDARGS; i < ARGLISTLEN; i++)
274                 arglist[i] = NULL;
275         argcount = FIXEDARGS;
276 }
277
278 /* make sure that a CPP exists */
279 static int
280 find_cpp(void)
281 {
282         if (CPP)
283                 return(0);
284         CPP = "cpp";
285         return(1);
286 }
287
288 /*
289  * Open input file with given define for C-preprocessor
290  */
291 static void
292 open_input(const char *infile, const char *define)
293 {
294         int pd[2];
295         int usevp;
296
297         infilename = (infile == NULL) ? "<stdin>" : infile;
298         pipe(pd);
299         switch (childpid = fork()) {
300         case 0:
301                 usevp = find_cpp();
302                 putarg(0, CPP);
303                 putarg(1, CPPFLAGS);
304                 addarg(define);
305                 if (infile)
306                         addarg(infile);
307                 addarg(NULL);
308                 close(1);
309                 dup2(pd[1], 1);
310                 close(pd[0]);
311                 if (usevp)
312                     execvp(arglist[0], arglist);
313                 else
314                     execv(arglist[0], arglist);
315                 err(1, "execv(%s)", arglist[0]);
316         case -1:
317                 err(1, "fork");
318         }
319         close(pd[1]);
320         fin = fdopen(pd[0], "r");
321         if (fin == NULL) {
322                 warn("%s", infilename);
323                 crash();
324         }
325 }
326
327 /* valid tirpc nettypes */
328 static const char *valid_ti_nettypes[] =
329 {
330         "netpath",
331         "visible",
332         "circuit_v",
333         "datagram_v",
334         "circuit_n",
335         "datagram_n",
336         "udp",
337         "tcp",
338         "raw",
339         NULL
340 };
341
342 /* valid inetd nettypes */
343 static const char *valid_i_nettypes[] =
344 {
345         "udp",
346         "tcp",
347         NULL
348 };
349
350 static int
351 check_nettype(const char *name, const char *list_to_check[])
352 {
353         int i;
354         for (i = 0; list_to_check[i] != NULL; i++) {
355                 if (strcmp(name, list_to_check[i]) == 0)
356                         return(1);
357         }
358         warnx("illegal nettype :\'%s\'", name);
359         return(0);
360 }
361
362 static const char *
363 file_name(const char *file, const char *ext)
364 {
365         char *temp;
366         temp = extendfile(file, ext);
367
368         if (access(temp, F_OK) != -1)
369                 return(temp);
370         else
371                 return(" ");
372
373 }
374
375 static void
376 c_output(const char *infile, const char *define, int extend, const char *outfile)
377 {
378         definition *def;
379         char *include;
380         const char *outfilename;
381         long tell;
382
383         c_initialize();
384         open_input(infile, define);
385         outfilename = extend ? extendfile(infile, outfile) : outfile;
386         open_output(infile, outfilename);
387         add_warning();
388         if (infile && (include = extendfile(infile, ".h"))) {
389                 f_print(fout, "#include \"%s\"\n", include);
390                 free(include);
391                 /* .h file already contains rpc/rpc.h */
392         } else
393                 f_print(fout, "#include <rpc/rpc.h>\n");
394         tell = ftell(fout);
395         while ( (def = get_definition()) )
396                 emit(def);
397         if (extend && tell == ftell(fout))
398                 unlink(outfilename);
399 }
400
401 void
402 c_initialize(void)
403 {
404         /* add all the starting basic types */
405         add_type(1, "int");
406         add_type(1, "long");
407         add_type(1, "short");
408         add_type(1, "bool");
409         add_type(1, "u_int");
410         add_type(1, "u_long");
411         add_type(1, "u_short");
412 }
413
414 const char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
415         char    *(*proc)(); \n\
416         xdrproc_t       xdr_arg; \n\
417         unsigned        len_arg; \n\
418         xdrproc_t       xdr_res; \n\
419         unsigned        len_res; \n\
420 }; \n";
421
422 char *
423 generate_guard(const char *pathname)
424 {
425         const char *filename;
426         char *guard, *tmp, *stopat;
427
428         filename = strrchr(pathname, '/');  /* find last component */
429         filename = ((filename == NULL) ? pathname : filename+1);
430         guard = xstrdup(filename);
431         stopat = strrchr(guard, '.');
432
433         /*
434          * Convert to a valid C macro name and make it upper case.
435          * Map macro unfriendly characterss to '_'.
436          */
437         for (tmp = guard; *tmp != '\000'; ++tmp) {
438                 if (islower(*tmp))
439                         *tmp = toupper(*tmp);
440                 else if (isupper(*tmp) || *tmp == '_')
441                         /* OK for C */;
442                 else if (tmp == guard)
443                         *tmp = '_';
444                 else if (isdigit(*tmp))
445                         /* OK for all but first character */;
446                 else if (tmp == stopat) {
447                         *tmp = '\0';
448                         break;
449                 } else
450                         *tmp = '_';
451         }
452         /*
453          * Can't have a '_' in front, because it'll end up being "__".
454          * "__" macros shoudln't be used. So, remove all of the
455          * '_' characters from the front.
456          */
457         if (*guard == '_') {
458                 for (tmp = guard; *tmp == '_'; ++tmp)
459                         ;
460                 strcpy(guard, tmp);
461         }
462         guard = extendfile(guard, "_H_RPCGEN");
463         return(guard);
464 }
465
466 /*
467  * Compile into an XDR header file
468  */
469
470 static void
471 h_output(const char *infile, const char *define, int extend, const char *outfile, int headeronly)
472 {
473         definition *def;
474         const char *outfilename;
475         long tell;
476         const char *guard;
477         list *l;
478         xdrfunc *xdrfuncp;
479
480         open_input(infile, define);
481         outfilename =  extend ? extendfile(infile, outfile) : outfile;
482         open_output(infile, outfilename);
483         add_warning();
484         if (outfilename || infile){
485                 guard = generate_guard(outfilename ? outfilename: infile);
486         } else
487                 guard = "STDIN_";
488
489         f_print(fout, "#ifndef _%s\n#define     _%s\n\n", guard,
490                 guard);
491
492         f_print(fout, "#include <rpc/rpc.h>\n");
493
494         if (mtflag)
495                 f_print(fout, "#include <pthread.h>\n");
496
497         /* put the C++ support */
498         if (!CCflag) {
499                 f_print(fout, "\n#ifdef __cplusplus\n");
500                 f_print(fout, "extern \"C\" {\n");
501                 f_print(fout, "#endif\n\n");
502         }
503
504         /* put in a typedef for quadprecision. Only with Cflag */
505
506         tell = ftell(fout);
507
508         /* print data definitions */
509         while ((def = get_definition()) != NULL)
510                 print_datadef(def, headeronly);
511
512         /*
513          * print function declarations.
514          *  Do this after data definitions because they might be used as
515          *  arguments for functions
516          */
517         for (l = defined; l != NULL; l = l->next)
518                 print_funcdef(l->val, headeronly);
519         /* Now  print all xdr func declarations */
520         if (xdrfunc_head != NULL) {
521                 f_print(fout, "\n/* the xdr functions */\n");
522
523                 if (CCflag) {
524                         f_print(fout, "\n#ifdef __cplusplus\n");
525                         f_print(fout, "extern \"C\" {\n");
526                         f_print(fout, "#endif\n");
527                 }
528
529                 xdrfuncp = xdrfunc_head;
530                 while (xdrfuncp != NULL) {
531                         print_xdr_func_def(xdrfuncp->name, xdrfuncp->pointerp);
532                         xdrfuncp = xdrfuncp->next;
533                 }
534         }
535
536         if (extend && tell == ftell(fout))
537                 unlink(outfilename);
538         else if (tblflag)
539                 f_print(fout, rpcgen_table_dcl);
540
541         f_print(fout, "\n#ifdef __cplusplus\n");
542         f_print(fout, "}\n");
543         f_print(fout, "#endif\n");
544
545         f_print(fout, "\n#endif /* !_%s */\n", guard);
546 }
547
548 /*
549  * Compile into an RPC service
550  */
551 static void
552 s_output(int argc, const char **argv, const char *infile, const char *define,
553     int extend, const char *outfile, int nomain, int netflag)
554 {
555         char *include;
556         definition *def;
557         int foundprogram = 0;
558         const char *outfilename;
559
560         open_input(infile, define);
561         outfilename = extend ? extendfile(infile, outfile) : outfile;
562         open_output(infile, outfilename);
563         add_warning();
564         if (infile && (include = extendfile(infile, ".h"))) {
565                 f_print(fout, "#include \"%s\"\n", include);
566                 free(include);
567         } else
568                 f_print(fout, "#include <rpc/rpc.h>\n");
569
570         f_print(fout, "#include <stdio.h>\n");
571         f_print(fout, "#include <stdlib.h> /* getenv, exit */\n");
572         f_print(fout, "#include <rpc/pmap_clnt.h> /* for pmap_unset */\n");
573         f_print(fout, "#include <string.h> /* strcmp */\n");
574         if (tirpcflag)
575                 f_print(fout, "#include <rpc/rpc_com.h>\n");
576         if (strcmp(svcclosetime, "-1") == 0)
577                 indefinitewait = 1;
578         else if (strcmp(svcclosetime, "0") == 0)
579                 exitnow = 1;
580         else if (inetdflag || pmflag) {
581                 f_print(fout, "#include <signal.h>\n");
582                 timerflag = 1;
583         }
584
585         if (!tirpcflag && inetdflag)
586                 f_print(fout, "#include <sys/ttycom.h> /* TIOCNOTTY */\n");
587         if (inetdflag || pmflag) {
588                 f_print(fout, "#ifdef __cplusplus\n");
589                 f_print(fout,
590                         "#include <sys/sysent.h> /* getdtablesize, open */\n");
591                 f_print(fout, "#endif /* __cplusplus */\n");
592         }
593         if (tirpcflag) {
594                 f_print(fout, "#include <fcntl.h> /* open */\n");
595                 f_print(fout, "#include <unistd.h> /* fork / setsid */\n");
596                 f_print(fout, "#include <sys/types.h>\n");
597         }
598
599         f_print(fout, "#include <string.h>\n");
600         if (inetdflag || !tirpcflag) {
601                 f_print(fout, "#include <sys/socket.h>\n");
602                 f_print(fout, "#include <netinet/in.h>\n");
603         }
604
605         if ((netflag || pmflag) && tirpcflag && !nomain)
606                 f_print(fout, "#include <netconfig.h>\n");
607         if (tirpcflag)
608                 f_print(fout, "#include <sys/resource.h> /* rlimit */\n");
609         if (logflag || inetdflag || pmflag || tirpcflag)
610                 f_print(fout, "#include <syslog.h>\n");
611
612         f_print(fout, "\n#ifdef DEBUG\n#define  RPC_SVC_FG\n#endif\n");
613         if (timerflag)
614                 f_print(fout, "\n#define        _RPCSVC_CLOSEDOWN %s\n",
615                         svcclosetime);
616         while ((def = get_definition()) != NULL)
617                 foundprogram |= (def->def_kind == DEF_PROGRAM);
618         if (extend && !foundprogram) {
619                 unlink(outfilename);
620                 return;
621         }
622         write_most(infile, netflag, nomain);
623         if (!nomain) {
624                 if (!do_registers(argc, argv)) {
625                         if (outfilename)
626                                 unlink(outfilename);
627                         usage();
628                 }
629                 write_rest();
630         }
631 }
632
633 /*
634  * generate client side stubs
635  */
636 static void
637 l_output(const char *infile, const char *define, int extend, const char *outfile)
638 {
639         char *include;
640         definition *def;
641         int foundprogram = 0;
642         const char *outfilename;
643
644         open_input(infile, define);
645         outfilename = extend ? extendfile(infile, outfile) : outfile;
646         open_output(infile, outfilename);
647         add_warning();
648         f_print(fout, "#include <string.h> /* for memset */\n");
649         if (infile && (include = extendfile(infile, ".h"))) {
650                 f_print(fout, "#include \"%s\"\n", include);
651                 free(include);
652         } else
653                 f_print(fout, "#include <rpc/rpc.h>\n");
654         while ((def = get_definition()) != NULL)
655                 foundprogram |= (def->def_kind == DEF_PROGRAM);
656         if (extend && !foundprogram)
657                 unlink(outfilename);
658         else
659                 write_stubs();
660 }
661
662 /*
663  * generate the dispatch table
664  */
665 static void
666 t_output(const char *infile, const char *define, int extend, const char *outfile)
667 {
668         definition *def;
669         int foundprogram = 0;
670         const char *outfilename;
671
672         open_input(infile, define);
673         outfilename = extend ? extendfile(infile, outfile) : outfile;
674         open_output(infile, outfilename);
675         add_warning();
676         while ((def = get_definition()) != NULL)
677                 foundprogram |= (def->def_kind == DEF_PROGRAM);
678         if (extend && !foundprogram)
679                 unlink(outfilename);
680         else
681                 write_tables();
682 }
683
684 /* sample routine for the server template */
685 static void
686 svc_output(const char *infile, const char *define, int extend, const char *outfile)
687 {
688         definition *def;
689         char *include;
690         const char *outfilename;
691         long tell;
692         open_input(infile, define);
693         outfilename = extend ? extendfile(infile, outfile) : outfile;
694         checkfiles(infile, outfilename);
695         /*
696          * Check if outfile already exists.
697          * if so, print an error message and exit
698          */
699         open_output(infile, outfilename);
700         add_sample_msg();
701
702         if (infile && (include = extendfile(infile, ".h"))) {
703                 f_print(fout, "#include \"%s\"\n", include);
704                 free(include);
705         } else
706                 f_print(fout, "#include <rpc/rpc.h>\n");
707
708         tell = ftell(fout);
709         while ((def = get_definition()) != NULL)
710                 write_sample_svc(def);
711         if (extend && tell == ftell(fout))
712                 unlink(outfilename);
713 }
714
715 /* sample main routine for client */
716 static void
717 clnt_output(const char *infile, const char *define, int extend, const char *outfile)
718 {
719         definition *def;
720         char *include;
721         const char *outfilename;
722         long tell;
723         int has_program = 0;
724
725         open_input(infile, define);
726         outfilename = extend ? extendfile(infile, outfile) : outfile;
727         checkfiles(infile, outfilename);
728         /*
729          * Check if outfile already exists.
730          * if so, print an error message and exit
731          */
732
733         open_output(infile, outfilename);
734         add_sample_msg();
735         if (infile && (include = extendfile(infile, ".h"))) {
736                 f_print(fout, "#include \"%s\"\n", include);
737                 free(include);
738         } else
739                 f_print(fout, "#include <rpc/rpc.h>\n");
740         tell = ftell(fout);
741         while ((def = get_definition()) != NULL)
742                 has_program += write_sample_clnt(def);
743
744         if (has_program)
745                 write_sample_clnt_main();
746
747         if (extend && tell == ftell(fout))
748                 unlink(outfilename);
749 }
750
751
752 static void
753 mkfile_output(struct commandline *cmd)
754 {
755         const char *mkfilename, *clientname, *clntname, *xdrname, *hdrname;
756         const char *servername, *svcname, *servprogname, *clntprogname;
757         char *temp, *mkftemp;
758
759         svcname = file_name(cmd->infile, "_svc.c");
760         clntname = file_name(cmd->infile, "_clnt.c");
761         xdrname = file_name(cmd->infile, "_xdr.c");
762         hdrname = file_name(cmd->infile, ".h");
763
764         if (allfiles) {
765                 servername = extendfile(cmd->infile, "_server.c");
766                 clientname = extendfile(cmd->infile, "_client.c");
767         } else {
768                 servername = " ";
769                 clientname = " ";
770         }
771         servprogname = extendfile(cmd->infile, "_server");
772         clntprogname = extendfile(cmd->infile, "_client");
773
774         if (allfiles) {
775                 mkftemp = xmalloc(strlen("makefile.") +
776                         strlen(cmd->infile) + 1);
777                 temp = strrchr(cmd->infile, '.');
778                 strcpy(mkftemp, "makefile.");
779                 strncat(mkftemp, cmd->infile, (temp - cmd->infile));
780                 mkfilename = mkftemp;
781         } else
782                 mkfilename = cmd->outfile;
783
784         checkfiles(NULL, mkfilename);
785         open_output(NULL, mkfilename);
786
787         f_print(fout, "\n# This is a template makefile generated "
788                 "by rpcgen \n");
789
790         f_print(fout, "\n# Parameters \n\n");
791
792         f_print(fout, "CLIENT = %s\nSERVER = %s\n\n",
793                 clntprogname, servprogname);
794         f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n");
795         f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n");
796         f_print(fout, "SOURCES.x = %s\n\n", cmd->infile);
797         f_print(fout, "TARGETS_SVC.c = %s %s %s \n",
798                 svcname, servername, xdrname);
799         f_print(fout, "TARGETS_CLNT.c = %s %s %s \n",
800                 clntname, clientname, xdrname);
801         f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n",
802                 hdrname, xdrname, clntname,
803                 svcname, clientname, servername);
804
805         f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) "
806                 "$(TARGETS_CLNT.c:%%.c=%%.o) ");
807
808         f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) "
809                 "$(TARGETS_SVC.c:%%.c=%%.o) ");
810
811
812         f_print(fout, "\n# Compiler flags \n");
813         if (mtflag)
814                 f_print(fout, "\nCFLAGS += -D_REENTRANT -D_THEAD_SAFE \nLDLIBS += -pthread\n");
815
816         f_print(fout, "RPCGENFLAGS = \n");
817
818         f_print(fout, "\n# Targets \n\n");
819
820         f_print(fout, "all : $(CLIENT) $(SERVER)\n\n");
821         f_print(fout, "$(TARGETS) : $(SOURCES.x) \n");
822         f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n");
823         f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) "
824                 "$(TARGETS_CLNT.c) \n\n");
825
826         f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) "
827                 "$(TARGETS_SVC.c) \n\n");
828         f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n");
829         f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) \n\n");
830         f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n");
831         f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
832         f_print(fout, "clean:\n\t $(RM) -f core $(TARGETS) $(OBJECTS_CLNT) "
833                 "$(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
834 }
835
836
837
838 /*
839  * Perform registrations for service output
840  * Return 0 if failed; 1 otherwise.
841  */
842 static int
843 do_registers(int argc, const char **argv)
844 {
845         int i;
846
847         if (inetdflag || !tirpcflag) {
848                 for (i = 1; i < argc; i++) {
849                         if (streq(argv[i], "-s")) {
850                                 if (!check_nettype(argv[i + 1],
851                                                     valid_i_nettypes))
852                                         return(0);
853                                 write_inetd_register(argv[i + 1]);
854                                 i++;
855                         }
856                 }
857         } else {
858                 for (i = 1; i < argc; i++)
859                         if (streq(argv[i], "-s")) {
860                                 if (!check_nettype(argv[i + 1],
861                                                     valid_ti_nettypes))
862                                         return(0);
863                                 write_nettype_register(argv[i + 1]);
864                                 i++;
865                         } else if (streq(argv[i], "-n")) {
866                                 write_netid_register(argv[i + 1]);
867                                 i++;
868                         }
869         }
870         return(1);
871 }
872
873 /*
874  * Add another argument to the arg list
875  */
876 static void
877 addarg(const char *cp)
878 {
879         if (argcount >= ARGLISTLEN) {
880                 warnx("too many defines");
881                 crash();
882                 /*NOTREACHED*/
883         }
884         if (cp != NULL)
885                 arglist[argcount++] = xstrdup(cp);
886         else
887                 arglist[argcount++] = NULL;
888
889 }
890
891 static void
892 putarg(int place, const char *cp)
893 {
894         if (place >= ARGLISTLEN) {
895                 warnx("arglist coding error");
896                 crash();
897                 /*NOTREACHED*/
898         }
899         if (cp != NULL)
900                 arglist[place] = xstrdup(cp);
901         else
902                 arglist[place] = NULL;
903 }
904
905 /*
906  * if input file is stdin and an output file is specified then complain
907  * if the file already exists. Otherwise the file may get overwritten
908  * If input file does not exist, exit with an error
909  */
910
911 static void
912 checkfiles(const char *infile, const char *outfile)
913 {
914         struct stat buf;
915
916         if (infile != NULL && stat(infile, &buf) < 0) {
917                 warn("%s", infile);
918                 crash();
919         }
920         if (outfile) {
921                 if (stat(outfile, &buf) < 0)
922                         return; /* file does not exist */
923                 else {
924                         warnx("file '%s' already exists and may be overwritten", outfile);
925                         crash();
926                 }
927         }
928 }
929
930 /*
931  * Parse command line arguments
932  */
933 static int
934 parseargs(int argc, const char **argv, struct commandline *cmd)
935 {
936         int i;
937         int j;
938         char c, ch;
939         char flag[(1 << 8 * sizeof (char))];
940         int nflags;
941
942         cmd->infile = cmd->outfile = NULL;
943         if (argc < 2)
944                 return(0);
945
946         allfiles = 0;
947         flag['c'] = 0;
948         flag['h'] = 0;
949         flag['l'] = 0;
950         flag['m'] = 0;
951         flag['o'] = 0;
952         flag['s'] = 0;
953         flag['n'] = 0;
954         flag['t'] = 0;
955         flag['S'] = 0;
956         flag['C'] = 0;
957         flag['M'] = 0;
958
959         for (i = 1; i < argc; i++) {
960                 if (argv[i][0] != '-') {
961                         if (cmd->infile) {
962                                 warnx("cannot specify more than one input file");
963                                 return(0);
964                         }
965                         cmd->infile = argv[i];
966                 } else {
967                         for (j = 1; argv[i][j] != 0; j++) {
968                                 c = argv[i][j];
969                                 switch (c) {
970                                 case 'a':
971                                         allfiles = 1;
972                                         break;
973                                 case 'c':
974                                 case 'h':
975                                 case 'l':
976                                 case 'm':
977                                 case 't':
978                                         if (flag[(int)c])
979                                                 return(0);
980                                         flag[(int)c] = 1;
981                                         break;
982                                 case 'S':
983                                         /*
984                                          * sample flag: Ss or Sc.
985                                          *  Ss means set flag['S'];
986                                          *  Sc means set flag['C'];
987                                          *  Sm means set flag['M'];
988                                          */
989                                         ch = argv[i][++j]; /* get next char */
990                                         if (ch == 's')
991                                                 ch = 'S';
992                                         else if (ch == 'c')
993                                                 ch = 'C';
994                                         else if (ch == 'm')
995                                                 ch = 'M';
996                                         else
997                                                 return(0);
998
999                                         if (flag[(int)ch])
1000                                                 return(0);
1001                                         flag[(int)ch] = 1;
1002                                         break;
1003                                 case 'C': /* ANSI C syntax */
1004                                         ch = argv[i][j+1]; /* get next char */
1005
1006                                         if (ch != 'C')
1007                                                 break;
1008                                         CCflag = 1;
1009                                         break;
1010                                 case 'b':
1011                                         /*
1012                                          *  Turn TIRPC flag off for
1013                                          *  generating backward compatible
1014                                          *  code
1015                                          */
1016                                         tirpcflag = 0;
1017                                         break;
1018
1019                                 case 'I':
1020                                         inetdflag = 1;
1021                                         break;
1022                                 case 'N':
1023                                         newstyle = 1;
1024                                         break;
1025                                 case 'L':
1026                                         logflag = 1;
1027                                         break;
1028                                 case 'P':
1029                                         pmflag = 1;
1030                                         break;
1031                                 case 'K':
1032                                         if (++i == argc)
1033                                                 return(0);
1034                                         svcclosetime = argv[i];
1035                                         goto nextarg;
1036                                 case 'T':
1037                                         tblflag = 1;
1038                                         break;
1039                                 case 'M':
1040                                         mtflag = 1;
1041                                         break;
1042                                 case 'i' :
1043                                         if (++i == argc)
1044                                                 return(0);
1045                                         inline_size = atoi(argv[i]);
1046                                         goto nextarg;
1047                                 case 'n':
1048                                 case 'o':
1049                                 case 's':
1050                                         if (argv[i][j - 1] != '-' ||
1051                                             argv[i][j + 1] != 0)
1052                                                 return(0);
1053                                         flag[(int)c] = 1;
1054                                         if (++i == argc)
1055                                                 return(0);
1056                                         if (c == 'o') {
1057                                                 if (cmd->outfile)
1058                                                         return(0);
1059                                                 cmd->outfile = argv[i];
1060                                         }
1061                                         goto nextarg;
1062                                 case 'D':
1063                                         if (argv[i][j - 1] != '-')
1064                                                 return(0);
1065                                         addarg(argv[i]);
1066                                         goto nextarg;
1067                                 case 'Y':
1068                                         if (++i == argc)
1069                                                 return(0);
1070                                         strlcpy(pathbuf, argv[i], sizeof(pathbuf));
1071                                         if (strlcat(pathbuf, "/cpp", sizeof(pathbuf))
1072                                             >= sizeof(pathbuf)) {
1073                                                 warnx("argument too long");
1074                                                 return (0);
1075                                         }
1076                                         CPP = pathbuf;
1077                                         cppDefined = 1;
1078                                         goto nextarg;
1079
1080                                 default:
1081                                         return(0);
1082                                 }
1083                         }
1084                 nextarg:
1085                         ;
1086                 }
1087         }
1088
1089         cmd->cflag = flag['c'];
1090         cmd->hflag = flag['h'];
1091         cmd->lflag = flag['l'];
1092         cmd->mflag = flag['m'];
1093         cmd->nflag = flag['n'];
1094         cmd->sflag = flag['s'];
1095         cmd->tflag = flag['t'];
1096         cmd->Ssflag = flag['S'];
1097         cmd->Scflag = flag['C'];
1098         cmd->makefileflag = flag['M'];
1099
1100         if (tirpcflag) {
1101                 if (inetdflag)
1102                         pmflag = 0;
1103                 if ((inetdflag && cmd->nflag)) {
1104                         /* netid not allowed with inetdflag */
1105                         warnx("cannot use netid flag with inetd flag");
1106                         return(0);
1107                 }
1108         } else {                /* 4.1 mode */
1109                 pmflag = 0;     /* set pmflag only in tirpcmode */
1110                 if (cmd->nflag) { /* netid needs TIRPC */
1111                         warnx("cannot use netid flag without TIRPC");
1112                         return(0);
1113                 }
1114         }
1115
1116         if (newstyle && (tblflag || cmd->tflag)) {
1117                 warnx("cannot use table flags with newstyle");
1118                 return(0);
1119         }
1120
1121         /* check no conflicts with file generation flags */
1122         nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1123                 cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag +
1124                         cmd->Scflag + cmd->makefileflag;
1125
1126         if (nflags == 0) {
1127                 if (cmd->outfile != NULL || cmd->infile == NULL)
1128                         return(0);
1129         } else if (cmd->infile == NULL &&
1130             (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) {
1131                 warnx("\"infile\" is required for template generation flags");
1132                 return(0);
1133         } if (nflags > 1) {
1134                 warnx("cannot have more than one file generation flag");
1135                 return(0);
1136         }
1137         return(1);
1138 }
1139
1140 static void
1141 usage(void)
1142 {
1143         f_print(stderr, "%s\n%s\n%s\n%s\n%s\n",
1144                 "usage: rpcgen infile",
1145                 "       rpcgen [-abCLNTM] [-Dname[=value]] [-i size]"
1146                 "[-I -P [-K seconds]] [-Y path] infile",
1147                 "       rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]"
1148                 "[-o outfile] [infile]",
1149                 "       rpcgen [-s nettype]* [-o outfile] [infile]",
1150                 "       rpcgen [-n netid]* [-o outfile] [infile]");
1151         options_usage();
1152         exit(1);
1153 }
1154
1155 static void
1156 options_usage(void)
1157 {
1158         f_print(stderr, "options:\n");
1159         f_print(stderr, "-a\t\tgenerate all files, including samples\n");
1160         f_print(stderr, "-b\t\tbackward compatibility mode (generates code"
1161                 "for SunOS 4.X)\n");
1162         f_print(stderr, "-c\t\tgenerate XDR routines\n");
1163         f_print(stderr, "-C\t\tANSI C mode\n");
1164         f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
1165         f_print(stderr, "-h\t\tgenerate header file\n");
1166         f_print(stderr, "-i size\t\tsize at which to start generating"
1167                 "inline code\n");
1168         f_print(stderr, "-I\t\tgenerate code for inetd support in server\n");
1169         f_print(stderr, "-K seconds\tserver exits after K seconds of"
1170                 "inactivity\n");
1171         f_print(stderr, "-l\t\tgenerate client side stubs\n");
1172         f_print(stderr, "-L\t\tserver errors will be printed to syslog\n");
1173         f_print(stderr, "-m\t\tgenerate server side stubs\n");
1174         f_print(stderr, "-M\t\tgenerate MT-safe code\n");
1175         f_print(stderr, "-n netid\tgenerate server code that supports"
1176                 "named netid\n");
1177         f_print(stderr, "-N\t\tsupports multiple arguments and"
1178                 "call-by-value\n");
1179         f_print(stderr, "-o outfile\tname of the output file\n");
1180         f_print(stderr, "-P\t\tgenerate code for port monitoring support in server\n");
1181         f_print(stderr, "-s nettype\tgenerate server code that supports named"
1182                 "nettype\n");
1183         f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote"
1184                 "procedures\n");
1185         f_print(stderr, "-Ss\t\tgenerate sample server code that defines"
1186                 "remote procedures\n");
1187         f_print(stderr, "-Sm \t\tgenerate makefile template \n");
1188
1189         f_print(stderr, "-t\t\tgenerate RPC dispatch table\n");
1190         f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
1191         f_print(stderr, "-Y path\t\tpath where cpp is found\n");
1192         exit(1);
1193 }