Merge from vendor branch AWK:
[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.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.10 2004/08/30 18:06:50 eirikn 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                 warn("execv");
321                 exit(1);
322         case -1:
323                 warn("fork");
324                 exit(1);
325         }
326         close(pd[1]);
327         fin = fdopen(pd[0], "r");
328         if (fin == NULL) {
329                 warn("%s", infilename);
330                 crash();
331         }
332 }
333
334 /* valid tirpc nettypes */
335 static char* valid_ti_nettypes[] =
336 {
337         "netpath",
338         "visible",
339         "circuit_v",
340         "datagram_v",
341         "circuit_n",
342         "datagram_n",
343         "udp",
344         "tcp",
345         "raw",
346         NULL
347 };
348
349 /* valid inetd nettypes */
350 static char* valid_i_nettypes[] =
351 {
352         "udp",
353         "tcp",
354         NULL
355 };
356
357 static int check_nettype(name, list_to_check)
358 char* name;
359 char* list_to_check[];
360 {
361         int i;
362         for (i = 0; list_to_check[i] != NULL; i++) {
363                 if (strcmp(name, list_to_check[i]) == 0)
364                         return(1);
365         }
366         warnx("illegal nettype :\'%s\'", name);
367         return(0);
368 }
369
370 static char *
371 file_name(char *file, char *ext)
372 {
373         char *temp;
374         temp = extendfile(file, ext);
375
376         if (access(temp, F_OK) != -1)
377                 return(temp);
378         else
379                 return((char *)" ");
380
381 }
382
383 static void
384 c_output(char *infile, char *define, int extend, char *outfile)
385 {
386         definition *def;
387         char *include;
388         char *outfilename;
389         long tell;
390
391         c_initialize();
392         open_input(infile, define);
393         outfilename = extend ? extendfile(infile, outfile) : outfile;
394         open_output(infile, outfilename);
395         add_warning();
396         if (infile && (include = extendfile(infile, ".h"))) {
397                 f_print(fout, "#include \"%s\"\n", include);
398                 free(include);
399                 /* .h file already contains rpc/rpc.h */
400         } else
401                 f_print(fout, "#include <rpc/rpc.h>\n");
402         tell = ftell(fout);
403         while ( (def = get_definition()) )
404                 emit(def);
405         if (extend && tell == ftell(fout))
406                 unlink(outfilename);
407 }
408
409 void
410 c_initialize(void)
411 {
412         /* add all the starting basic types */
413         add_type(1, "int");
414         add_type(1, "long");
415         add_type(1, "short");
416         add_type(1, "bool");
417         add_type(1, "u_int");
418         add_type(1, "u_long");
419         add_type(1, "u_short");
420 }
421
422 char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
423         char    *(*proc)(); \n\
424         xdrproc_t       xdr_arg; \n\
425         unsigned        len_arg; \n\
426         xdrproc_t       xdr_res; \n\
427         unsigned        len_res; \n\
428 }; \n";
429
430 char *generate_guard(char *pathname)
431 {
432         char* filename, *guard, *tmp;
433
434         filename = strrchr(pathname, '/');  /* find last component */
435         filename = ((filename == 0) ? pathname : filename+1);
436         guard = strdup(filename);
437         /* convert to upper case */
438         tmp = guard;
439         while (*tmp) {
440                 if (islower(*tmp))
441                         *tmp = toupper(*tmp);
442                 tmp++;
443         }
444         guard = extendfile(guard, "_H_RPCGEN");
445         return(guard);
446 }
447
448 /*
449  * Compile into an XDR header file
450  */
451
452 static void
453 h_output(char *infile, char *define, int extend, char *outfile)
454 {
455         definition *def;
456         char *outfilename;
457         long tell;
458         char *guard;
459         list *l;
460         xdrfunc *xdrfuncp;
461         int i;
462
463         open_input(infile, define);
464         outfilename =  extend ? extendfile(infile, outfile) : outfile;
465         open_output(infile, outfilename);
466         add_warning();
467         if (outfilename || infile){
468                 guard = generate_guard(outfilename ? outfilename: infile);
469         } else
470                 guard = "STDIN_";
471
472         f_print(fout, "#ifndef _%s\n#define     _%s\n\n", guard,
473                 guard);
474
475         f_print(fout, "#include <rpc/rpc.h>\n");
476
477         if (mtflag)
478                 f_print(fout, "#include <pthread.h>\n");
479
480         /* put the C++ support */
481         if (Cflag && !CCflag){
482                 f_print(fout, "\n#ifdef __cplusplus\n");
483                 f_print(fout, "extern \"C\" {\n");
484                 f_print(fout, "#endif\n\n");
485         }
486
487         /* put in a typedef for quadprecision. Only with Cflag */
488
489         tell = ftell(fout);
490
491         /* print data definitions */
492         while ((def = get_definition()) != 0)
493                 print_datadef(def);
494
495         /*
496          * print function declarations.
497          *  Do this after data definitions because they might be used as
498          *  arguments for functions
499          */
500         for (l = defined; l != NULL; l = l->next)
501                 print_funcdef(l->val);
502
503         /* Now  print all xdr func declarations */
504         if (xdrfunc_head != NULL) {
505                 f_print(fout, "\n/* the xdr functions */\n");
506
507                 if (CCflag) {
508                     f_print(fout, "\n#ifdef __cplusplus\n");
509                     f_print(fout, "extern \"C\" {\n");
510                     f_print(fout, "#endif\n");
511                 }
512
513                 if (!Cflag) {
514                         xdrfuncp = xdrfunc_head;
515                         while (xdrfuncp != NULL) {
516                                 print_xdr_func_def(xdrfuncp->name,
517                                 xdrfuncp->pointerp, 2);
518                                 xdrfuncp = xdrfuncp->next;
519                         }
520                 } else {
521                         for (i = 1; i < 3; i++) {
522                                 if (i == 1)
523         f_print(fout, "\n#if defined(__STDC__) || defined(__cplusplus)\n");
524                                 else
525                                         f_print(fout, "\n#else /* K&R C */\n");
526
527                                 xdrfuncp = xdrfunc_head;
528                                 while (xdrfuncp != NULL) {
529                                         print_xdr_func_def(xdrfuncp->name,
530                                             xdrfuncp->pointerp, i);
531                                         xdrfuncp = xdrfuncp->next;
532                                 }
533                         }
534                         f_print(fout, "\n#endif /* K&R C */\n");
535                 }
536         }
537
538         if (extend && tell == ftell(fout))
539                 unlink(outfilename);
540         else if (tblflag)
541                 f_print(fout, rpcgen_table_dcl);
542
543         if (Cflag) {
544                 f_print(fout, "\n#ifdef __cplusplus\n");
545                 f_print(fout, "}\n");
546                 f_print(fout, "#endif\n");
547         }
548
549         f_print(fout, "\n#endif /* !_%s */\n", guard);
550 }
551
552 /*
553  * Compile into an RPC service
554  */
555 static void
556 s_output(int argc, char **argv, char *infile, char *define, int extend,
557          char *outfile, int nomain, int netflag)
558 {
559         char *include;
560         definition *def;
561         int foundprogram = 0;
562         char *outfilename;
563
564         open_input(infile, define);
565         outfilename = extend ? extendfile(infile, outfile) : outfile;
566         open_output(infile, outfilename);
567         add_warning();
568         if (infile && (include = extendfile(infile, ".h"))) {
569                 f_print(fout, "#include \"%s\"\n", include);
570                 free(include);
571         } else
572                 f_print(fout, "#include <rpc/rpc.h>\n");
573
574         f_print(fout, "#include <stdio.h>\n");
575         f_print(fout, "#include <stdlib.h> /* getenv, exit */\n");
576         if (Cflag) {
577                 f_print(fout,
578                     "#include <rpc/pmap_clnt.h> /* for pmap_unset */\n");
579                 f_print(fout, "#include <string.h> /* strcmp */\n");
580         }
581         if (strcmp(svcclosetime, "-1") == 0)
582                 indefinitewait = 1;
583         else if (strcmp(svcclosetime, "0") == 0)
584                 exitnow = 1;
585         else if (inetdflag || pmflag) {
586                 f_print(fout, "#include <signal.h>\n");
587                 timerflag = 1;
588         }
589
590         if (!tirpcflag && inetdflag)
591                 f_print(fout, "#include <sys/ttycom.h> /* TIOCNOTTY */\n");
592         if (Cflag && (inetdflag || pmflag)) {
593                 f_print(fout, "#ifdef __cplusplus\n");
594                 f_print(fout,
595                     "#include <sysent.h> /* getdtablesize, open */\n");
596                 f_print(fout, "#endif /* __cplusplus */\n");
597                 if (tirpcflag)
598                         f_print(fout, "#include <unistd.h> /* setsid */\n");
599         }
600         if (tirpcflag)
601                 f_print(fout, "#include <sys/types.h>\n");
602
603         f_print(fout, "#include <memory.h>\n");
604         if (tirpcflag)
605             f_print(fout, "#include <stropts.h>\n");
606         if (inetdflag || !tirpcflag) {
607                 f_print(fout, "#include <sys/socket.h>\n");
608                 f_print(fout, "#include <netinet/in.h>\n");
609         }
610
611         if ((netflag || pmflag) && tirpcflag && !nomain)
612                 f_print(fout, "#include <netconfig.h>\n");
613         if (tirpcflag)
614                 f_print(fout, "#include <sys/resource.h> /* rlimit */\n");
615         if (logflag || inetdflag || pmflag)
616                 f_print(fout, "#include <syslog.h>\n");
617
618         /* for ANSI-C */
619         if (Cflag)
620                 f_print(fout,
621                         "\n#ifndef SIG_PF\n#define      SIG_PF void(*)\
622 (int)\n#endif\n");
623
624         f_print(fout, "\n#ifdef DEBUG\n#define  RPC_SVC_FG\n#endif\n");
625         if (timerflag)
626                 f_print(fout, "\n#define        _RPCSVC_CLOSEDOWN %s\n",
627                         svcclosetime);
628         while ((def = get_definition()) != 0)
629                 foundprogram |= (def->def_kind == DEF_PROGRAM);
630         if (extend && !foundprogram) {
631                 unlink(outfilename);
632                 return;
633         }
634         write_most(infile, netflag, nomain);
635         if (!nomain) {
636                 if (!do_registers(argc, argv)) {
637                         if (outfilename)
638                                 unlink(outfilename);
639                         usage();
640                 }
641                 write_rest();
642         }
643 }
644
645 /*
646  * generate client side stubs
647  */
648 static void
649 l_output(char *infile, char *define, int extend, char *outfile)
650 {
651         char *include;
652         definition *def;
653         int foundprogram = 0;
654         char *outfilename;
655
656         open_input(infile, define);
657         outfilename = extend ? extendfile(infile, outfile) : outfile;
658         open_output(infile, outfilename);
659         add_warning();
660         if (Cflag)
661                 f_print (fout, "#include <memory.h> /* for memset */\n");
662         if (infile && (include = extendfile(infile, ".h"))) {
663                 f_print(fout, "#include \"%s\"\n", include);
664                 free(include);
665         } else
666                 f_print(fout, "#include <rpc/rpc.h>\n");
667         while ((def = get_definition()) != 0)
668                 foundprogram |= (def->def_kind == DEF_PROGRAM);
669         if (extend && !foundprogram)
670                 unlink(outfilename);
671         else
672                 write_stubs();
673 }
674
675 /*
676  * generate the dispatch table
677  */
678 static void
679 t_output(char *infile, char *define, int extend, char *outfile)
680 {
681         definition *def;
682         int foundprogram = 0;
683         char *outfilename;
684
685         open_input(infile, define);
686         outfilename = extend ? extendfile(infile, outfile) : outfile;
687         open_output(infile, outfilename);
688         add_warning();
689         while ((def = get_definition()) != 0)
690                 foundprogram |= (def->def_kind == DEF_PROGRAM);
691         if (extend && !foundprogram)
692                 unlink(outfilename);
693         else
694                 write_tables();
695 }
696
697 /* sample routine for the server template */
698 static void
699 svc_output(char *infile, char *define, int extend, char *outfile)
700 {
701         definition *def;
702         char *include;
703         char *outfilename;
704         long tell;
705         open_input(infile, define);
706         outfilename = extend ? extendfile(infile, outfile) : outfile;
707         checkfiles(infile, outfilename);
708         /*
709          * Check if outfile already exists.
710          * if so, print an error message and exit
711          */
712         open_output(infile, outfilename);
713         add_sample_msg();
714
715         if (infile && (include = extendfile(infile, ".h"))) {
716                 f_print(fout, "#include \"%s\"\n", include);
717                 free(include);
718         } else
719                 f_print(fout, "#include <rpc/rpc.h>\n");
720
721         tell = ftell(fout);
722         while ((def = get_definition()) != 0)
723                 write_sample_svc(def);
724         if (extend && tell == ftell(fout))
725                 unlink(outfilename);
726 }
727
728 /* sample main routine for client */
729 static void
730 clnt_output(char *infile, char *define, int extend, char *outfile)
731 {
732         definition *def;
733         char *include;
734         char *outfilename;
735         long tell;
736         int has_program = 0;
737
738         open_input(infile, define);
739         outfilename = extend ? extendfile(infile, outfile) : outfile;
740         checkfiles(infile, outfilename);
741         /*
742          * Check if outfile already exists.
743          * if so, print an error message and exit
744          */
745
746         open_output(infile, outfilename);
747         add_sample_msg();
748         if (infile && (include = extendfile(infile, ".h"))) {
749                 f_print(fout, "#include \"%s\"\n", include);
750                 free(include);
751         } else
752                 f_print(fout, "#include <rpc/rpc.h>\n");
753         tell = ftell(fout);
754         while ((def = get_definition()) != 0)
755                 has_program += write_sample_clnt(def);
756
757         if (has_program)
758                 write_sample_clnt_main();
759
760         if (extend && tell == ftell(fout))
761                 unlink(outfilename);
762 }
763
764
765 static void mkfile_output(cmd)
766 struct commandline *cmd;
767 {
768         char *mkfilename, *clientname, *clntname, *xdrname, *hdrname;
769         char *servername, *svcname, *servprogname, *clntprogname;
770         char *temp;
771
772         svcname = file_name(cmd->infile, "_svc.c");
773         clntname = file_name(cmd->infile, "_clnt.c");
774         xdrname = file_name(cmd->infile, "_xdr.c");
775         hdrname = file_name(cmd->infile, ".h");
776
777         if (allfiles) {
778                 servername = extendfile(cmd->infile, "_server.c");
779                 clientname = extendfile(cmd->infile, "_client.c");
780         } else {
781                 servername = " ";
782                 clientname = " ";
783         }
784         servprogname = extendfile(cmd->infile, "_server");
785         clntprogname = extendfile(cmd->infile, "_client");
786
787         if (allfiles) {
788                 mkfilename = alloc(strlen("makefile.") +
789                         strlen(cmd->infile) + 1);
790                 temp = strrchr(cmd->infile, '.');
791                 strcat(mkfilename, "makefile.");
792                 strncat(mkfilename, cmd->infile, (temp - cmd->infile));
793         } else
794                 mkfilename = cmd->outfile;
795
796         checkfiles(NULL, mkfilename);
797         open_output(NULL, mkfilename);
798
799         f_print(fout, "\n# This is a template makefile generated "
800                 "by rpcgen \n");
801
802         f_print(fout, "\n# Parameters \n\n");
803
804         f_print(fout, "CLIENT = %s\nSERVER = %s\n\n",
805                 clntprogname, servprogname);
806         f_print(fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n");
807         f_print(fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n");
808         f_print(fout, "SOURCES.x = %s\n\n", cmd->infile);
809         f_print(fout, "TARGETS_SVC.c = %s %s %s \n",
810                 svcname, servername, xdrname);
811         f_print(fout, "TARGETS_CLNT.c = %s %s %s \n",
812                 clntname, clientname, xdrname);
813         f_print(fout, "TARGETS = %s %s %s %s %s %s\n\n",
814                 hdrname, xdrname, clntname,
815                 svcname, clientname, servername);
816
817         f_print(fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) "
818                 "$(TARGETS_CLNT.c:%%.c=%%.o) ");
819
820         f_print(fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) "
821                 "$(TARGETS_SVC.c:%%.c=%%.o) ");
822
823
824         f_print(fout, "\n# Compiler flags \n");
825         if (mtflag)
826                 f_print(fout, "\nCPPFLAGS += -D_REENTRANT\n"
827                         "CFLAGS += -g \nLDLIBS += -lnsl -lthread\n");
828         else
829                 f_print(fout, "\nCFLAGS += -g \nLDLIBS +=\n");
830         f_print(fout, "RPCGENFLAGS = \n");
831
832         f_print(fout, "\n# Targets \n\n");
833
834         f_print(fout, "all : $(CLIENT) $(SERVER)\n\n");
835         f_print(fout, "$(TARGETS) : $(SOURCES.x) \n");
836         f_print(fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n");
837         f_print(fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) "
838                 "$(TARGETS_CLNT.c) \n\n");
839
840         f_print(fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) "
841                 "$(TARGETS_SVC.c) \n\n");
842         f_print(fout, "$(CLIENT) : $(OBJECTS_CLNT) \n");
843         f_print(fout, "\t$(CC) -o $(CLIENT) $(OBJECTS_CLNT) $(LDLIBS) \n\n");
844         f_print(fout, "$(SERVER) : $(OBJECTS_SVC) \n");
845         f_print(fout, "\t$(CC) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
846         f_print(fout, "clean:\n\t $(RM) -f core $(TARGETS) $(OBJECTS_CLNT) "
847                 "$(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
848 }
849
850
851
852 /*
853  * Perform registrations for service output
854  * Return 0 if failed; 1 otherwise.
855  */
856 static int
857 do_registers(int argc, char **argv)
858 {
859         int i;
860
861         if (inetdflag || !tirpcflag) {
862                 for (i = 1; i < argc; i++) {
863                         if (streq(argv[i], "-s")) {
864                                 if (!check_nettype(argv[i + 1],
865                                                     valid_i_nettypes))
866                                         return(0);
867                                 write_inetd_register(argv[i + 1]);
868                                 i++;
869                         }
870                 }
871         } else {
872                 for (i = 1; i < argc; i++)
873                         if (streq(argv[i], "-s")) {
874                                 if (!check_nettype(argv[i + 1],
875                                                     valid_ti_nettypes))
876                                         return(0);
877                                 write_nettype_register(argv[i + 1]);
878                                 i++;
879                         } else if (streq(argv[i], "-n")) {
880                                 write_netid_register(argv[i + 1]);
881                                 i++;
882                         }
883         }
884         return(1);
885 }
886
887 /*
888  * Add another argument to the arg list
889  */
890 static void
891 addarg(char *cp)
892 {
893         if (argcount >= ARGLISTLEN) {
894                 warnx("too many defines");
895                 crash();
896                 /*NOTREACHED*/
897         }
898         arglist[argcount++] = cp;
899
900 }
901
902 static void
903 putarg(where, cp)
904         char *cp;
905         int where;
906 {
907         if (where >= ARGLISTLEN) {
908                 warnx("arglist coding error");
909                 crash();
910                 /*NOTREACHED*/
911         }
912         arglist[where] = cp;
913 }
914
915 /*
916  * if input file is stdin and an output file is specified then complain
917  * if the file already exists. Otherwise the file may get overwritten
918  * If input file does not exist, exit with an error
919  */
920
921 static void
922 checkfiles(char *infile, char *outfile)
923 {
924         struct stat buf;
925
926         if (infile != NULL && stat(infile, &buf) < 0) {
927                 warn("%s", infile);
928                 crash();
929         }
930         if (outfile) {
931                 if (stat(outfile, &buf) < 0)
932                         return; /* file does not exist */
933                 else {
934                         warnx("file '%s' already exists and may be overwritten", outfile);
935                         crash();
936                 }
937         }
938 }
939
940 /*
941  * Parse command line arguments
942  */
943 static int
944 parseargs(int argc, char **argv,struct commandline *cmd)
945 {
946         int i;
947         int j;
948         char c, ch;
949         char flag[(1 << 8 * sizeof (char))];
950         int nflags;
951
952         cmd->infile = cmd->outfile = NULL;
953         if (argc < 2)
954                 return(0);
955
956         allfiles = 0;
957         flag['c'] = 0;
958         flag['h'] = 0;
959         flag['l'] = 0;
960         flag['m'] = 0;
961         flag['o'] = 0;
962         flag['s'] = 0;
963         flag['n'] = 0;
964         flag['t'] = 0;
965         flag['S'] = 0;
966         flag['C'] = 0;
967         flag['M'] = 0;
968
969         for (i = 1; i < argc; i++) {
970                 if (argv[i][0] != '-') {
971                         if (cmd->infile) {
972                                 warnx("cannot specify more than one input file");
973                                 return(0);
974                         }
975                         cmd->infile = argv[i];
976                 } else {
977                         for (j = 1; argv[i][j] != 0; j++) {
978                                 c = argv[i][j];
979                                 switch (c) {
980                                 case 'a':
981                                         allfiles = 1;
982                                         break;
983                                 case 'c':
984                                 case 'h':
985                                 case 'l':
986                                 case 'm':
987                                 case 't':
988                                         if (flag[(int)c])
989                                                 return(0);
990                                         flag[(int)c] = 1;
991                                         break;
992                                 case 'S':
993                                         /*
994                                          * sample flag: Ss or Sc.
995                                          *  Ss means set flag['S'];
996                                          *  Sc means set flag['C'];
997                                          *  Sm means set flag['M'];
998                                          */
999                                         ch = argv[i][++j]; /* get next char */
1000                                         if (ch == 's')
1001                                                 ch = 'S';
1002                                         else if (ch == 'c')
1003                                                 ch = 'C';
1004                                         else if (ch == 'm')
1005                                                 ch = 'M';
1006                                         else
1007                                                 return(0);
1008
1009                                         if (flag[(int)ch])
1010                                                 return(0);
1011                                         flag[(int)ch] = 1;
1012                                         break;
1013                                 case 'C': /* ANSI C syntax */
1014                                         Cflag = 1;
1015                                         ch = argv[i][j+1]; /* get next char */
1016
1017                                         if (ch != 'C')
1018                                                 break;
1019                                         CCflag = 1;
1020                                         break;
1021                                 case 'b':
1022                                         tirpcflag = 1;
1023                                         break;
1024
1025                                 case 'I':
1026                                         inetdflag = 1;
1027                                         break;
1028                                 case 'N':
1029                                         newstyle = 1;
1030                                         break;
1031                                 case 'L':
1032                                         logflag = 1;
1033                                         break;
1034                                 case 'K':
1035                                         if (++i == argc)
1036                                                 return(0);
1037                                         svcclosetime = argv[i];
1038                                         goto nextarg;
1039                                 case 'T':
1040                                         tblflag = 1;
1041                                         break;
1042                                 case 'M':
1043                                         mtflag = 1;
1044                                         break;
1045                                 case 'i' :
1046                                         if (++i == argc)
1047                                                 return(0);
1048                                         rpcgen_inline = atoi(argv[i]);
1049                                         goto nextarg;
1050                                 case 'n':
1051                                 case 'o':
1052                                 case 's':
1053                                         if (argv[i][j - 1] != '-' ||
1054                                             argv[i][j + 1] != 0)
1055                                                 return(0);
1056                                         flag[(int)c] = 1;
1057                                         if (++i == argc)
1058                                                 return(0);
1059                                         if (c == 'o') {
1060                                                 if (cmd->outfile)
1061                                                         return(0);
1062                                                 cmd->outfile = argv[i];
1063                                         }
1064                                         goto nextarg;
1065                                 case 'D':
1066                                         if (argv[i][j - 1] != '-')
1067                                                 return(0);
1068                                         addarg(argv[i]);
1069                                         goto nextarg;
1070                                 case 'Y':
1071                                         if (++i == argc)
1072                                                 return(0);
1073                                         strcpy(pathbuf, argv[i]);
1074                                         strcat(pathbuf, "/cpp");
1075                                         CPP = pathbuf;
1076                                         cppDefined = 1;
1077                                         goto nextarg;
1078
1079                                 default:
1080                                         return(0);
1081                                 }
1082                         }
1083                 nextarg:
1084                         ;
1085                 }
1086         }
1087
1088         cmd->cflag = flag['c'];
1089         cmd->hflag = flag['h'];
1090         cmd->lflag = flag['l'];
1091         cmd->mflag = flag['m'];
1092         cmd->nflag = flag['n'];
1093         cmd->sflag = flag['s'];
1094         cmd->tflag = flag['t'];
1095         cmd->Ssflag = flag['S'];
1096         cmd->Scflag = flag['C'];
1097         cmd->makefileflag = flag['M'];
1098
1099         if (tirpcflag) {
1100                 pmflag = inetdflag ? 0 : 1;
1101                 /* pmflag or inetdflag is always TRUE */
1102                 if ((inetdflag && cmd->nflag)) {
1103                         /* netid not allowed with inetdflag */
1104                         warnx("cannot use netid flag with inetd flag");
1105                         return(0);
1106                 }
1107         } else {                /* 4.1 mode */
1108                 pmflag = 0;     /* set pmflag only in tirpcmode */
1109                 if (cmd->nflag) { /* netid needs TIRPC */
1110                         warnx("cannot use netid flag without TIRPC");
1111                         return(0);
1112                 }
1113         }
1114
1115         if (newstyle && (tblflag || cmd->tflag)) {
1116                 warnx("cannot use table flags with newstyle");
1117                 return(0);
1118         }
1119
1120         /* check no conflicts with file generation flags */
1121         nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1122                 cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag +
1123                         cmd->Scflag + cmd->makefileflag;
1124
1125         if (nflags == 0) {
1126                 if (cmd->outfile != NULL || cmd->infile == NULL)
1127                         return(0);
1128         } else if (cmd->infile == NULL &&
1129             (cmd->Ssflag || cmd->Scflag || cmd->makefileflag)) {
1130                 warnx("\"infile\" is required for template generation flags");
1131                 return(0);
1132         } if (nflags > 1) {
1133                 warnx("cannot have more than one file generation flag");
1134                 return(0);
1135         }
1136         return(1);
1137 }
1138
1139 static void
1140 usage(void)
1141 {
1142         f_print(stderr, "%s\n%s\n%s\n%s\n%s\n", 
1143                 "usage: rpcgen infile",
1144                 "       rpcgen [-abCLNTM] [-Dname[=value]] [-i size]"
1145                 "[-I [-K seconds]] [-Y path] infile",
1146                 "       rpcgen [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm]"
1147                 "[-o outfile] [infile]",
1148                 "       rpcgen [-s nettype]* [-o outfile] [infile]",
1149                 "       rpcgen [-n netid]* [-o outfile] [infile]");
1150         options_usage();
1151         exit(1);
1152 }
1153
1154 static void
1155 options_usage(void)
1156 {
1157         f_print(stderr, "options:\n");
1158         f_print(stderr, "-a\t\tgenerate all files, including samples\n");
1159         f_print(stderr, "-b\t\tbackward compatibility mode (generates code"
1160                 "for SunOS 4.X)\n");
1161         f_print(stderr, "-c\t\tgenerate XDR routines\n");
1162         f_print(stderr, "-C\t\tANSI C mode\n");
1163         f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
1164         f_print(stderr, "-h\t\tgenerate header file\n");
1165         f_print(stderr, "-i size\t\tsize at which to start generating"
1166                 "inline code\n");
1167         f_print(stderr, "-I\t\tgenerate code for inetd support in server"
1168                 "(for SunOS 4.X)\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, "-s nettype\tgenerate server code that supports named"
1181                 "nettype\n");
1182         f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote"
1183                 "procedures\n");
1184         f_print(stderr, "-Ss\t\tgenerate sample server code that defines"
1185                 "remote procedures\n");
1186         f_print(stderr, "-Sm \t\tgenerate makefile template \n");
1187
1188         f_print(stderr, "-t\t\tgenerate RPC dispatch table\n");
1189         f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
1190         f_print(stderr, "-Y path\t\tpath where cpp is found\n");
1191         exit(1);
1192 }