Add more changes from TI-RPC 2.3 for rpcgen to fix include/C++ bug and
[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   pipe (pd);
353   switch (fork ())
354     {
355     case 0:
356       find_cpp ();
357       putarg (0, CPP);
358       putarg (1, CPPFLAGS);
359       addarg (define);
360       if (infile)
361         addarg (infile);
362       addarg ((char *) NULL);
363       close (1);
364       dup2 (pd[1], 1);
365       close (pd[0]);
366       execv (arglist[0], (char **) arglist);
367       perror ("execv");
368       exit (1);
369     case -1:
370       perror ("fork");
371       exit (1);
372     }
373   close (pd[1]);
374   fin = fdopen (pd[0], "r");
375   if (fin == NULL)
376     {
377       fprintf (stderr, "%s: ", cmdname);
378       perror (infilename);
379       crash ();
380     }
381 }
382
383 /* valid tirpc nettypes */
384 static const char *valid_ti_nettypes[] =
385 {
386   "netpath",
387   "visible",
388   "circuit_v",
389   "datagram_v",
390   "circuit_n",
391   "datagram_n",
392   "udp",
393   "tcp",
394   "raw",
395   NULL
396 };
397
398 /* valid inetd nettypes */
399 static const char *valid_i_nettypes[] =
400 {
401   "udp",
402   "tcp",
403   NULL
404 };
405
406 static int
407 check_nettype (const char *name, const char *list_to_check[])
408 {
409   int i;
410   for (i = 0; list_to_check[i] != NULL; i++)
411     {
412       if (strcmp (name, list_to_check[i]) == 0)
413         {
414           return 1;
415         }
416     }
417   fprintf (stderr, _ ("illegal nettype :\'%s\'\n"), name);
418   return 0;
419 }
420
421 /*
422  * Compile into an XDR routine output file
423  */
424
425 static void
426 c_output (const char *infile, const char *define, int extend,
427           const char *outfile)
428 {
429   definition *def;
430   char *include;
431   const char *outfilename;
432   long tell;
433
434   c_initialize ();
435   open_input (infile, define);
436   outfilename = extend ? extendfile (infile, outfile) : outfile;
437   open_output (infile, outfilename);
438   add_warning ();
439   if (infile && (include = extendfile (infile, ".h")))
440     {
441       fprintf (fout, "#include \"%s\"\n", include);
442       free (include);
443       /* .h file already contains rpc/rpc.h */
444     }
445   else
446     fprintf (fout, "#include <rpc/rpc.h>\n");
447   tell = ftell (fout);
448   while ((def = get_definition ()) != NULL)
449     emit (def);
450
451   if (extend && tell == ftell (fout))
452     unlink (outfilename);
453 }
454
455 void
456 c_initialize (void)
457 {
458
459   /* add all the starting basic types */
460
461   add_type (1, "int");
462   add_type (1, "long");
463   add_type (1, "short");
464   add_type (1, "bool");
465
466   add_type (1, "u_int");
467   add_type (1, "u_long");
468   add_type (1, "u_short");
469
470 }
471
472 char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
473         char    *(*proc)();\n\
474         xdrproc_t       xdr_arg;\n\
475         unsigned        len_arg;\n\
476         xdrproc_t       xdr_res;\n\
477         unsigned        len_res;\n\
478 };\n";
479
480
481 static char *
482 generate_guard (const char *pathname)
483 {
484   const char *filename;
485   char *guard, *tmp;
486
487   filename = strrchr (pathname, '/');   /* find last component */
488   filename = ((filename == NULL) ? pathname : filename + 1);
489   guard = strdup (filename);
490   /* convert to upper case */
491   tmp = guard;
492   while (*tmp)
493     {
494       if (islower (*tmp))
495         *tmp = toupper (*tmp);
496       tmp++;
497     }
498
499   guard = extendfile (guard, "_H_RPCGEN");
500   return guard;
501 }
502
503 /*
504  * Compile into an XDR header file
505  */
506
507
508 static void
509 h_output (const char *infile, const char *define, int extend,
510           const char *outfile)
511 {
512   xdrfunc *xdrfuncp;
513   definition *def;
514   const char *ifilename;
515   const char *outfilename;
516   long tell;
517   char *guard;
518   list *l;
519
520   open_input (infile, define);
521   outfilename = extend ? extendfile (infile, outfile) : outfile;
522   open_output (infile, outfilename);
523   add_warning ();
524   ifilename = (infile == NULL) ? "STDIN" : infile;
525   guard = generate_guard (outfilename ? outfilename : ifilename);
526
527   fprintf (fout, "#ifndef _%s\n#define _%s\n\n", guard,
528            guard);
529
530   fprintf (fout, "#include <rpc/rpc.h>\n\n");
531
532   if (mtflag)
533     {
534       fprintf (fout, "#include <pthread.h>\n");
535     }
536
537   /* put the C++ support */
538   if (Cflag && !CCflag)
539     {
540       fprintf (fout, "\n#ifdef __cplusplus\n");
541       fprintf (fout, "extern \"C\" {\n");
542       fprintf (fout, "#endif\n\n");
543     }
544
545   tell = ftell (fout);
546   /* print data definitions */
547   while ((def = get_definition ()) != NULL)
548     {
549       print_datadef (def);
550     }
551
552   /* print function declarations.
553      Do this after data definitions because they might be used as
554      arguments for functions */
555   for (l = defined; l != NULL; l = l->next)
556     {
557       print_funcdef (l->val);
558     }
559   /* Now  print all xdr func declarations */
560   if (xdrfunc_head != NULL)
561     {
562       fprintf (fout, "\n/* the xdr functions */\n");
563       if (CCflag)
564         {
565           fprintf (fout, "\n#ifdef __cplusplus\n");
566           fprintf (fout, "extern \"C\" {\n");
567           fprintf (fout, "#endif\n");
568         }
569       if (!Cflag)
570         {
571           xdrfuncp = xdrfunc_head;
572           while (xdrfuncp != NULL)
573             {
574               print_xdr_func_def (xdrfuncp->name,
575                                   xdrfuncp->pointerp, 2);
576               xdrfuncp = xdrfuncp->next;
577             }
578         }
579       else
580         {
581           int i;
582
583           for (i = 1; i < 3; ++i)
584             {
585               if (i == 1)
586                 fprintf (fout, "\n#if defined(__STDC__) || defined(__cplusplus)\n");
587               else
588                 fprintf (fout, "\n#else /* K&R C */\n");
589
590               xdrfuncp = xdrfunc_head;
591               while (xdrfuncp != NULL)
592                 {
593                   print_xdr_func_def (xdrfuncp->name,
594                                       xdrfuncp->pointerp, i);
595                   xdrfuncp = xdrfuncp->next;
596                 }
597             }
598           fprintf (fout, "\n#endif /* K&R C */\n");
599         }
600     }
601
602   if (extend && tell == ftell (fout))
603     {
604       unlink (outfilename);
605     }
606   else if (tblflag)
607     {
608       fprintf (fout, rpcgen_table_dcl);
609     }
610
611   if (Cflag)
612     {
613       fprintf (fout, "\n#ifdef __cplusplus\n");
614       fprintf (fout, "}\n");
615       fprintf (fout, "#endif\n");
616     }
617
618   fprintf (fout, "\n#endif /* !_%s */\n", guard);
619 }
620
621 /*
622  * Compile into an RPC service
623  */
624 static void
625 s_output (int argc, const char *argv[], const char *infile, const char *define,
626           int extend, const char *outfile, int nomain, int netflag)
627 {
628   char *include;
629   definition *def;
630   int foundprogram = 0;
631   const char *outfilename;
632
633   open_input (infile, define);
634   outfilename = extend ? extendfile (infile, outfile) : outfile;
635   open_output (infile, outfilename);
636   add_warning ();
637   if (infile && (include = extendfile (infile, ".h")))
638     {
639       fprintf (fout, "#include \"%s\"\n", include);
640       free (include);
641     }
642   else
643     fprintf (fout, "#include <rpc/rpc.h>\n");
644
645   fprintf (fout, "#include <stdio.h>\n");
646   fprintf (fout, "#include <stdlib.h>\n");
647   if (Cflag)
648     {
649       fprintf (fout, "#include <rpc/pmap_clnt.h>\n");
650       fprintf (fout, "#include <string.h>\n");
651     }
652   if (strcmp (svcclosetime, "-1") == 0)
653     indefinitewait = 1;
654   else if (strcmp (svcclosetime, "0") == 0)
655     exitnow = 1;
656   else if (inetdflag || pmflag)
657     {
658       fprintf (fout, "#include <signal.h>\n");
659       timerflag = 1;
660     }
661
662   if (!tirpcflag && inetdflag)
663 #ifdef __GNU_LIBRARY__
664     fprintf (fout, "#include <sys/ioctl.h> /* ioctl, TIOCNOTTY */\n");
665 #else
666     fprintf (fout, "#include <sys/ttycom.h>/* TIOCNOTTY */\n");
667 #endif
668   if (Cflag && (inetdflag || pmflag))
669     {
670 #ifdef __GNU_LIBRARY__
671       fprintf (fout, "#include <sys/types.h> /* open */\n");
672       fprintf (fout, "#include <sys/stat.h> /* open */\n");
673       fprintf (fout, "#include <fcntl.h> /* open */\n");
674       fprintf (fout, "#include <unistd.h> /* getdtablesize */\n");
675 #else
676       fprintf (fout, "#ifdef __cplusplus\n");
677       fprintf (fout, "#include <sysent.h> /* getdtablesize, open */\n");
678       fprintf (fout, "#endif /* __cplusplus */\n");
679       if (tirpcflag)
680         fprintf (fout, "#include <unistd.h> /* setsid */\n");
681 #endif
682     }
683 #ifdef __GNU_LIBRARY__
684   if (tirpcflag && !(Cflag && (inetdflag || pmflag)))
685 #else
686   if (tirpcflag)
687 #endif
688     fprintf (fout, "#include <sys/types.h>\n");
689
690   fprintf (fout, "#include <memory.h>\n");
691 #ifndef __GNU_LIBRARY__
692   fprintf (fout, "#include <stropts.h>\n");
693 #endif
694   if (inetdflag || !tirpcflag)
695     {
696       fprintf (fout, "#include <sys/socket.h>\n");
697       fprintf (fout, "#include <netinet/in.h>\n");
698     }
699
700   if ((netflag || pmflag) && tirpcflag && !nomain)
701     {
702       fprintf (fout, "#include <netconfig.h>\n");
703     }
704   if ( /*timerflag && */ tirpcflag)
705     fprintf (fout, "#include <sys/resource.h> /* rlimit */\n");
706   if (logflag || inetdflag || pmflag)
707     {
708 #ifdef __GNU_LIBRARY__
709       fprintf (fout, "#include <syslog.h>\n");
710 #else
711       fprintf (fout, "#ifdef SYSLOG\n");
712       fprintf (fout, "#include <syslog.h>\n");
713       fprintf (fout, "#else\n");
714       fprintf (fout, "#define LOG_ERR 1\n");
715       fprintf (fout, "#define openlog(a, b, c)\n");
716       fprintf (fout, "#endif\n");
717 #endif
718     }
719
720   /* for ANSI-C */
721   if (Cflag)
722     fprintf (fout, "\n#ifndef SIG_PF\n#define SIG_PF void(*)(int)\n#endif\n");
723
724 #ifndef __GNU_LIBRARY__
725   fprintf (fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n");
726 #endif
727   if (timerflag)
728     fprintf (fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime);
729   while ((def = get_definition ()) != NULL)
730     {
731       foundprogram |= (def->def_kind == DEF_PROGRAM);
732     }
733   if (extend && !foundprogram)
734     {
735       unlink (outfilename);
736       return;
737     }
738   write_most (infile, netflag, nomain);
739   if (!nomain)
740     {
741       if (!do_registers (argc, argv))
742         {
743           if (outfilename)
744             unlink (outfilename);
745           usage ();
746         }
747       write_rest ();
748     }
749 }
750
751 /*
752  * generate client side stubs
753  */
754 static void
755 l_output (const char *infile, const char *define, int extend,
756           const char *outfile)
757 {
758   char *include;
759   definition *def;
760   int foundprogram = 0;
761   const char *outfilename;
762
763   open_input (infile, define);
764   outfilename = extend ? extendfile (infile, outfile) : outfile;
765   open_output (infile, outfilename);
766   add_warning ();
767   if (Cflag)
768     fprintf (fout, "#include <memory.h> /* for memset */\n");
769   if (infile && (include = extendfile (infile, ".h")))
770     {
771       fprintf (fout, "#include \"%s\"\n", include);
772       free (include);
773     }
774   else
775     fprintf (fout, "#include <rpc/rpc.h>\n");
776   while ((def = get_definition ()) != NULL)
777     {
778       foundprogram |= (def->def_kind == DEF_PROGRAM);
779     }
780   if (extend && !foundprogram)
781     {
782       unlink (outfilename);
783       return;
784     }
785   write_stubs ();
786 }
787
788 /*
789  * generate the dispatch table
790  */
791 static void
792 t_output (const char *infile, const char *define, int extend,
793           const char *outfile)
794 {
795   definition *def;
796   int foundprogram = 0;
797   const char *outfilename;
798
799   open_input (infile, define);
800   outfilename = extend ? extendfile (infile, outfile) : outfile;
801   open_output (infile, outfilename);
802   add_warning ();
803   while ((def = get_definition ()) != NULL)
804     {
805       foundprogram |= (def->def_kind == DEF_PROGRAM);
806     }
807   if (extend && !foundprogram)
808     {
809       unlink (outfilename);
810       return;
811     }
812   write_tables ();
813 }
814
815 /* sample routine for the server template */
816 static void
817 svc_output (const char *infile, const char *define, int extend,
818             const char *outfile)
819 {
820   definition *def;
821   char *include;
822   const char *outfilename;
823   long tell;
824
825   open_input (infile, define);
826   outfilename = extend ? extendfile (infile, outfile) : outfile;
827   checkfiles (infile, outfilename);
828   /*check if outfile already exists.
829      if so, print an error message and exit */
830   open_output (infile, outfilename);
831   add_sample_msg ();
832
833   if (infile && (include = extendfile (infile, ".h")))
834     {
835       fprintf (fout, "#include \"%s\"\n", include);
836       free (include);
837     }
838   else
839     fprintf (fout, "#include <rpc/rpc.h>\n");
840
841   tell = ftell (fout);
842   while ((def = get_definition ()) != NULL)
843     {
844       write_sample_svc (def);
845     }
846   if (extend && tell == ftell (fout))
847     {
848       unlink (outfilename);
849     }
850 }
851
852
853 /* sample main routine for client */
854 static void
855 clnt_output (const char *infile, const char *define, int extend,
856              const char *outfile)
857 {
858   definition *def;
859   char *include;
860   const char *outfilename;
861   long tell;
862   int has_program = 0;
863
864   open_input (infile, define);
865   outfilename = extend ? extendfile (infile, outfile) : outfile;
866   checkfiles (infile, outfilename);
867   /*check if outfile already exists.
868      if so, print an error message and exit */
869
870   open_output (infile, outfilename);
871   add_sample_msg ();
872   if (infile && (include = extendfile (infile, ".h")))
873     {
874       fprintf (fout, "#include \"%s\"\n", include);
875       free (include);
876     }
877   else
878     fprintf (fout, "#include <rpc/rpc.h>\n");
879   tell = ftell (fout);
880   while ((def = get_definition ()) != NULL)
881     {
882       has_program += write_sample_clnt (def);
883     }
884
885   if (has_program)
886     write_sample_clnt_main ();
887
888   if (extend && tell == ftell (fout))
889     {
890       unlink (outfilename);
891     }
892 }
893
894 static char *
895 file_name (const char *file, const char *ext)
896 {
897   char *temp;
898   temp = extendfile (file, ext);
899
900   if (access (temp, F_OK) != -1)
901     return (temp);
902   else
903     return ((char *) " ");
904 }
905
906 static void
907 mkfile_output (struct commandline *cmd)
908 {
909   char *mkfilename;
910   const char *clientname, *clntname, *xdrname, *hdrname;
911   const char *servername, *svcname, *servprogname, *clntprogname;
912   char *temp;
913
914   svcname = file_name (cmd->infile, "_svc.c");
915   clntname = file_name (cmd->infile, "_clnt.c");
916   xdrname = file_name (cmd->infile, "_xdr.c");
917   hdrname = file_name (cmd->infile, ".h");
918
919   if (allfiles)
920     {
921       servername = extendfile (cmd->infile, "_server.c");
922       clientname = extendfile (cmd->infile, "_client.c");
923     }
924   else
925     {
926       servername = " ";
927       clientname = " ";
928     }
929   servprogname = extendfile (cmd->infile, "_server");
930   clntprogname = extendfile (cmd->infile, "_client");
931
932   if (allfiles)
933     {
934       mkfilename = alloc (strlen ("Makefile.") +
935                           strlen (cmd->infile) + 1);
936       temp = (char *) rindex (cmd->infile, '.');
937       strcat (mkfilename, "Makefile.");
938       strncat (mkfilename, cmd->infile,
939                (temp - cmd->infile));
940     }
941   else
942     mkfilename = (char *) cmd->outfile;
943
944   checkfiles (NULL, mkfilename);
945   open_output (NULL, mkfilename);
946
947   fprintf (fout, "\n# This is a template Makefile generated by rpcgen\n");
948
949   f_print (fout, "\n# Parameters\n\n");
950
951   f_print (fout, "CLIENT = %s\nSERVER = %s\n\n", clntprogname, servprogname);
952   f_print (fout, "SOURCES_CLNT.c = \nSOURCES_CLNT.h = \n");
953   f_print (fout, "SOURCES_SVC.c = \nSOURCES_SVC.h = \n");
954   f_print (fout, "SOURCES.x = %s\n\n", cmd->infile);
955   f_print (fout, "TARGETS_SVC.c = %s %s %s \n",
956            svcname, servername, xdrname);
957   f_print (fout, "TARGETS_CLNT.c = %s %s %s \n",
958            clntname, clientname, xdrname);
959   f_print (fout, "TARGETS = %s %s %s %s %s %s\n\n",
960            hdrname, xdrname, clntname,
961            svcname, clientname, servername);
962
963   f_print (fout, "OBJECTS_CLNT = $(SOURCES_CLNT.c:%%.c=%%.o) \
964 $(TARGETS_CLNT.c:%%.c=%%.o)");
965
966   f_print (fout, "\nOBJECTS_SVC = $(SOURCES_SVC.c:%%.c=%%.o) \
967 $(TARGETS_SVC.c:%%.c=%%.o)");
968
969   f_print (fout, "\n# Compiler flags \n");
970   if (mtflag)
971     fprintf (fout, "\nCPPFLAGS += -D_REENTRANT\nCFLAGS += -g \nLDLIBS \
972 += -lnsl -lpthread \n ");
973   else
974     f_print (fout, "\nCFLAGS += -g \nLDLIBS += -lnsl\n");
975   f_print (fout, "RPCGENFLAGS = \n");
976
977   f_print (fout, "\n# Targets \n\n");
978
979   f_print (fout, "all : $(CLIENT) $(SERVER)\n\n");
980   f_print (fout, "$(TARGETS) : $(SOURCES.x) \n");
981   f_print (fout, "\trpcgen $(RPCGENFLAGS) $(SOURCES.x)\n\n");
982   f_print (fout, "$(OBJECTS_CLNT) : $(SOURCES_CLNT.c) $(SOURCES_CLNT.h) \
983 $(TARGETS_CLNT.c) \n\n");
984
985   f_print (fout, "$(OBJECTS_SVC) : $(SOURCES_SVC.c) $(SOURCES_SVC.h) \
986 $(TARGETS_SVC.c) \n\n");
987   f_print (fout, "$(CLIENT) : $(OBJECTS_CLNT) \n");
988   f_print (fout, "\t$(LINK.c) -o $(CLIENT) $(OBJECTS_CLNT) \
989 $(LDLIBS) \n\n");
990   f_print (fout, "$(SERVER) : $(OBJECTS_SVC) \n");
991   f_print (fout, "\t$(LINK.c) -o $(SERVER) $(OBJECTS_SVC) $(LDLIBS)\n\n ");
992   f_print (fout, "clean:\n\t $(RM) core $(TARGETS) $(OBJECTS_CLNT) \
993 $(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
994 }
995
996 /*
997  * Perform registrations for service output
998  * Return 0 if failed; 1 otherwise.
999  */
1000 static int
1001 do_registers (int argc, const char *argv[])
1002 {
1003   int i;
1004
1005   if (inetdflag || !tirpcflag)
1006     {
1007       for (i = 1; i < argc; i++)
1008         {
1009           if (streq (argv[i], "-s"))
1010             {
1011               if (!check_nettype (argv[i + 1], valid_i_nettypes))
1012                 return 0;
1013               write_inetd_register (argv[i + 1]);
1014               i++;
1015             }
1016         }
1017     }
1018   else
1019     {
1020       for (i = 1; i < argc; i++)
1021         if (streq (argv[i], "-s"))
1022           {
1023             if (!check_nettype (argv[i + 1], valid_ti_nettypes))
1024               return 0;
1025             write_nettype_register (argv[i + 1]);
1026             i++;
1027           }
1028         else if (streq (argv[i], "-n"))
1029           {
1030             write_netid_register (argv[i + 1]);
1031             i++;
1032           }
1033     }
1034   return 1;
1035 }
1036
1037 /*
1038  * Add another argument to the arg list
1039  */
1040 static void
1041 addarg (const char *cp)
1042 {
1043   if (argcount >= ARGLISTLEN)
1044     {
1045       fprintf (stderr, _("rpcgen: too many defines\n"));
1046       crash ();
1047       /*NOTREACHED */
1048     }
1049   arglist[argcount++] = cp;
1050 }
1051
1052 static void
1053 putarg (int whereto, const char *cp)
1054 {
1055   if (whereto >= ARGLISTLEN)
1056     {
1057       fprintf (stderr, _("rpcgen: arglist coding error\n"));
1058       crash ();
1059       /*NOTREACHED */
1060     }
1061   arglist[whereto] = cp;
1062 }
1063
1064 /*
1065  * if input file is stdin and an output file is specified then complain
1066  * if the file already exists. Otherwise the file may get overwritten
1067  * If input file does not exist, exit with an error
1068  */
1069
1070 static void
1071 checkfiles (const char *infile, const char *outfile)
1072 {
1073   struct stat buf;
1074
1075   if (infile)                   /* infile ! = NULL */
1076     if (stat (infile, &buf) < 0)
1077       {
1078         perror (infile);
1079         crash ();
1080       }
1081   if (outfile)
1082     {
1083       if (stat (outfile, &buf) < 0)
1084         return;                 /* file does not exist */
1085       else
1086         {
1087           fprintf (stderr,
1088                    _("file '%s' already exists and may be overwritten\n"),
1089                    outfile);
1090           crash ();
1091         }
1092     }
1093 }
1094
1095 /*
1096  * Parse command line arguments
1097  */
1098 static int
1099 parseargs (int argc, const char *argv[], struct commandline *cmd)
1100 {
1101   int i;
1102   int j;
1103   int c;
1104   char flag[(1 << 8 * sizeof (char))];
1105   int nflags;
1106
1107   cmdname = argv[0];
1108   cmd->infile = cmd->outfile = NULL;
1109   if (argc < 2)
1110     {
1111       return (0);
1112     }
1113   allfiles = 0;
1114   flag['c'] = 0;
1115   flag['h'] = 0;
1116   flag['l'] = 0;
1117   flag['m'] = 0;
1118   flag['o'] = 0;
1119   flag['s'] = 0;
1120   flag['n'] = 0;
1121   flag['t'] = 0;
1122   flag['S'] = 0;
1123   flag['C'] = 0;
1124   flag['M'] = 0;
1125
1126   for (i = 1; i < argc; i++)
1127     {
1128       if (argv[i][0] != '-')
1129         {
1130           if (cmd->infile)
1131             {
1132               fprintf (stderr,
1133                        _("Cannot specify more than one input file!\n"));
1134               return 0;
1135             }
1136           cmd->infile = argv[i];
1137         }
1138       else
1139         {
1140           for (j = 1; argv[i][j] != 0; j++)
1141             {
1142               c = argv[i][j];
1143               switch (c)
1144                 {
1145                 case 'a':
1146                   allfiles = 1;
1147                   break;
1148                 case 'c':
1149                 case 'h':
1150                 case 'l':
1151                 case 'm':
1152                 case 't':
1153                   if (flag[c])
1154                     return 0;
1155                   flag[c] = 1;
1156                   break;
1157                 case 'S':
1158                   /* sample flag: Ss or Sc.
1159                      Ss means set flag['S'];
1160                      Sc means set flag['C'];
1161                      Sm means set flag['M']; */
1162                   c = argv[i][++j];     /* get next char */
1163                   if (c == 's')
1164                     c = 'S';
1165                   else if (c == 'c')
1166                     c = 'C';
1167                   else if (c == 'm')
1168                     c = 'M';
1169                   else
1170                     return 0;
1171
1172                   if (flag[c])
1173                     return 0;
1174                   flag[c] = 1;
1175                   break;
1176                 case 'C':       /* ANSI C syntax */
1177                   Cflag = 1;
1178                   break;
1179
1180 #ifdef __GNU_LIBRARY__
1181                 case 'k':  /* K&R C syntax */
1182                   Cflag = 0;
1183                   break;
1184
1185 #endif
1186                 case 'b':  /* turn TIRPC flag off for
1187                               generating backward compatible
1188                            */
1189                   tirpcflag = 0;
1190                   break;
1191
1192 #ifdef __GNU_LIBRARY__
1193                 case '5':  /* turn TIRPC flag on for
1194                               generating SysVr4 compatible
1195                            */
1196                   tirpcflag = 1;
1197                   break;
1198 #endif
1199                 case 'I':
1200                   inetdflag = 1;
1201                   break;
1202                 case 'N':
1203                   newstyle = 1;
1204                   break;
1205                 case 'L':
1206                   logflag = 1;
1207                   break;
1208                 case 'K':
1209                   if (++i == argc)
1210                     {
1211                       return (0);
1212                     }
1213                   svcclosetime = argv[i];
1214                   goto nextarg;
1215                 case 'T':
1216                   tblflag = 1;
1217                   break;
1218                 case 'M':
1219                   mtflag = 1;
1220                   break;
1221                 case 'i':
1222                   if (++i == argc)
1223                     {
1224                       return (0);
1225                     }
1226                   inlineflag = atoi (argv[i]);
1227                   goto nextarg;
1228                 case 'n':
1229                 case 'o':
1230                 case 's':
1231                   if (argv[i][j - 1] != '-' ||
1232                       argv[i][j + 1] != 0)
1233                     {
1234                       return (0);
1235                     }
1236                   flag[c] = 1;
1237                   if (++i == argc)
1238                     {
1239                       return (0);
1240                     }
1241                   if (c == 's')
1242                     {
1243                       if (!streq (argv[i], "udp") &&
1244                           !streq (argv[i], "tcp"))
1245                         return 0;
1246                     }
1247                   else if (c == 'o')
1248                     {
1249                       if (cmd->outfile)
1250                         return 0;
1251                       cmd->outfile = argv[i];
1252                     }
1253                   goto nextarg;
1254                 case 'D':
1255                   if (argv[i][j - 1] != '-')
1256                     return 0;
1257                   addarg (argv[i]);
1258                   goto nextarg;
1259                 case 'Y':
1260                   if (++i == argc)
1261                     return 0;
1262                   {
1263                     size_t len = strlen (argv[i]);
1264                     pathbuf = malloc (len + 5);
1265                     if (pathbuf == NULL)
1266                       {
1267                         perror (cmdname);
1268                         crash ();
1269                       }
1270                     stpcpy (stpcpy (pathbuf,
1271                                     argv[i]),
1272                             "/cpp");
1273                     CPP = pathbuf;
1274                     cppDefined = 1;
1275                     goto nextarg;
1276                   }
1277
1278                 default:
1279                   return 0;
1280                 }
1281               }
1282         nextarg:
1283           ;
1284         }
1285     }
1286
1287   cmd->cflag = flag['c'];
1288   cmd->hflag = flag['h'];
1289   cmd->lflag = flag['l'];
1290   cmd->mflag = flag['m'];
1291   cmd->nflag = flag['n'];
1292   cmd->sflag = flag['s'];
1293   cmd->tflag = flag['t'];
1294   cmd->Ssflag = flag['S'];
1295   cmd->Scflag = flag['C'];
1296   cmd->makefileflag = flag['M'];
1297
1298   if (tirpcflag)
1299     {
1300       pmflag = inetdflag ? 0 : 1;    /* pmflag or inetdflag is always TRUE */
1301       if ((inetdflag && cmd->nflag))
1302         {                       /* netid not allowed with inetdflag */
1303           fprintf (stderr, _("Cannot use netid flag with inetd flag!\n"));
1304           return 0;
1305         }
1306     }
1307   else
1308     {                           /* 4.1 mode */
1309       pmflag = 0;               /* set pmflag only in tirpcmode */
1310 #ifndef __GNU_LIBRARY__
1311       inetdflag = 1;            /* inetdflag is TRUE by default */
1312 #endif
1313       if (cmd->nflag)
1314         {                       /* netid needs TIRPC */
1315           f_print (stderr, _("Cannot use netid flag without TIRPC!\n"));
1316           return (0);
1317         }
1318     }
1319
1320   if (newstyle && (tblflag || cmd->tflag))
1321     {
1322       f_print (stderr, _("Cannot use table flags with newstyle!\n"));
1323       return (0);
1324     }
1325
1326   /* check no conflicts with file generation flags */
1327   nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
1328     cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag;
1329
1330   if (nflags == 0)
1331     {
1332       if (cmd->outfile != NULL || cmd->infile == NULL)
1333         {
1334           return (0);
1335         }
1336     }
1337   else if (cmd->infile == NULL &&
1338            (cmd->Ssflag || cmd->Scflag || cmd->makefileflag))
1339     {
1340       fprintf (stderr,
1341                _("\"infile\" is required for template generation flags.\n"));
1342       return 0;
1343     }
1344   if (nflags > 1)
1345     {
1346       fprintf (stderr, _("Cannot have more than one file generation flag!\n"));
1347       return 0;
1348     }
1349   return 1;
1350 }
1351
1352 static void
1353 usage (void)
1354 {
1355   fprintf (stderr, _("usage:  %s infile\n"), cmdname);
1356   fprintf (stderr, _("\t%s [-abkCLNTM][-Dname[=value]] [-i size] \
1357 [-I [-K seconds]] [-Y path] infile\n"), cmdname);
1358   fprintf (stderr, _("\t%s [-c | -h | -l | -m | -t | -Sc | -Ss | -Sm] \
1359 [-o outfile] [infile]\n"), cmdname);
1360   fprintf (stderr, _("\t%s [-s nettype]* [-o outfile] [infile]\n"), cmdname);
1361   fprintf (stderr, _("\t%s [-n netid]* [-o outfile] [infile]\n"), cmdname);
1362   options_usage ();
1363   exit (1);
1364 }
1365
1366 static void
1367 options_usage (void)
1368 {
1369   f_print (stderr, "options:\n");
1370   f_print (stderr, "-a\t\tgenerate all files, including samples\n");
1371   f_print (stderr, "-b\t\tbackward compatibility mode (generates code for SunOS 4.1)\n");
1372   f_print (stderr, "-c\t\tgenerate XDR routines\n");
1373   f_print (stderr, "-C\t\tANSI C mode\n");
1374   f_print (stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
1375   f_print (stderr, "-h\t\tgenerate header file\n");
1376   f_print (stderr, "-i size\t\tsize at which to start generating inline code\n");
1377   f_print (stderr, "-I\t\tgenerate code for inetd support in server (for SunOS 4.1)\n");
1378   f_print (stderr, "-K seconds\tserver exits after K seconds of inactivity\n");
1379   f_print (stderr, "-l\t\tgenerate client side stubs\n");
1380   f_print (stderr, "-L\t\tserver errors will be printed to syslog\n");
1381   f_print (stderr, "-m\t\tgenerate server side stubs\n");
1382   f_print (stderr, "-M\t\tgenerate MT-safe code\n");
1383   f_print (stderr, "-n netid\tgenerate server code that supports named netid\n");
1384   f_print (stderr, "-N\t\tsupports multiple arguments and call-by-value\n");
1385   f_print (stderr, "-o outfile\tname of the output file\n");
1386   f_print (stderr, "-s nettype\tgenerate server code that supports named nettype\n");
1387   f_print (stderr, "-Sc\t\tgenerate sample client code that uses remote procedures\n");
1388   f_print (stderr, "-Ss\t\tgenerate sample server code that defines remote procedures\n");
1389   f_print (stderr, "-Sm \t\tgenerate makefile template \n");
1390   f_print (stderr, "-t\t\tgenerate RPC dispatch table\n");
1391   f_print (stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
1392   f_print (stderr, "-Y path\t\tdirectory name to find C preprocessor (cpp)\n");
1393
1394   exit (1);
1395 }