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