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