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