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