8f3d929f1175b1d73f377275d9162843e0e9771e
[openafs.git] / src / rx / test / generator.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * generator.c -- phase 2 of the generator.
12  *
13  * takes a file, which has a list of signature as input,
14  * and outputs the client, server, .xg, and makefiles
15  * This file is normally created by running tableGen.c,
16  * but theoretically could be generated by a human.
17  *
18  * Format of the signatures : no_of_args list_of_arg_signs
19  *  arg_sign : (dir type)
20  *
21  *
22  * This program is used to generate client/server pairs that
23  * make and verify random rpcs.  It can be used to generate
24  * both pthread and lwp versions of the client and server.
25  * It was designed to verify that the new pthread rx library
26  * was functioning correctly.
27  *
28  * The key to understanding how this program works is to realize
29  * that all the data necessary to generate the client/server
30  * code is generated first, in char string format.
31  * For example, if you are generating 10 rpc's, the input and
32  * output values of all the parameters are generated - and
33  * stored as strings.  This allows you to write out the values
34  * as the client and server are created without having to worry
35  * about data type conversion.
36  *
37  * In addition, these strings (along with other information) are
38  * stored in a structure that is iterated over many times during
39  * the construction of the client and server.
40  *
41  * Often this iteration takes the form of:
42  *     for (i=0; i < argsP->argCount; i++)
43  *
44  * It may be possible to eliminate some of these iterations for
45  * efficiency sake, but this was not done - allowing an easier
46  * implementation.
47  *
48  * The bulk of this code was lifted from the delight project.
49  *
50  */
51
52 #include <afsconfig.h>
53 #include <afs/param.h>
54
55
56 #include <stdio.h>
57 #include <string.h>
58 #include <stdlib.h>
59 #include <limits.h>
60 #include <float.h>
61 #include <assert.h>
62 #include "generator.h"
63
64 static char *unix_symbols[] = {
65     "make -f",
66     "include ../../../config/Makefile.$(SYS_NAME)\n",
67     "o",
68     "$(CC) $(CFLAGS) -c",
69     "#include <netdb.h>\n",
70     "",
71
72 /* all one string */
73     "LIBS = $(DESTDIR)lib/libafsrpc.so \\\n"
74         "\t$(DESTDIR)lib/afs/libcmd.a \\\n"
75         "\t$(DESTDIR)lib/afs/libafs_com_err.a \\\n"
76         "\t$(DESTDIR)lib/afs/util.a \n",
77
78 /* all one string */
79     "LIBS = $(DESTDIR)lib/librxkad.a \\\n" "\t$(DESTDIR)lib/libdes.a \\\n"
80         "\t$(DESTDIR)lib/librx.a \\\n" "\t$(DESTDIR)lib/liblwp.a \\\n"
81         "\t$(DESTDIR)lib/afs/libcmd.a \\\n"
82         "\t$(DESTDIR)lib/afs/libafs_com_err.a \\\n"
83         "\t$(DESTDIR)lib/afs/util.a \\\n" "\t/usr/ucblib/libucb.a \n",
84
85 /* all one string */
86     "\t@if [ ! -r DEST ] ; \\\n" "\tthen \\\n"
87         "\t\techo \"Must create DEST link by hand before building tests\"; \\\n"
88         "\t\texit 1; \\\n" "\tfi\n"
89 };
90
91 static char *nt_symbols[] = {
92     "nmake /f",
93     "!INCLUDE ../../../config/NTMakefile.$(SYS_NAME)\n",
94     "obj",
95     "$(C2OBJ)",
96     "#include <windows.h>\n",
97     "all",
98
99 /* all one string */
100     "LIBS = $(DESTDIR)/lib/afsrpc.lib \\\n"
101         "\t$(DESTDIR)/lib/afs/afscmd.lib \\\n"
102         "\t$(DESTDIR)/lib/afs/afsafs_com_err.lib \\\n"
103         "\t$(DESTDIR)/lib/afs/afsutil.lib \\\n"
104         "\t$(DESTDIR)/lib/pthread.lib \\\n" "\t$(DESTDIR)/lib/afsreg.lib \\\n"
105         "\t$(XLIBS)\n",
106
107 /* all one string */
108     "LIBS = $(DESTDIR)/lib/afsrxkad.lib \\\n"
109         "\t$(DESTDIR)/lib/afsdes.lib \\\n" "\t$(DESTDIR)/lib/afsrx.lib \\\n"
110         "\t$(DESTDIR)/lib/afslwp.lib \\\n"
111         "\t$(DESTDIR)/lib/afs/afscmd.lib \\\n"
112         "\t$(DESTDIR)/lib/afs/afsafs_com_err.lib \\\n"
113         "\t$(DESTDIR)/lib/afs/afsutil.lib \\\n"
114         "\t$(DESTDIR)/lib/afsreg.lib \n",
115
116 /* all one string */
117     "!\tIF (!EXIST(DEST))\n"
118         "!\t\tERROR Must create DEST link by hand before building tests\n"
119         "!\tENDIF\n",
120 };
121
122 static char **platform = nt_symbols;
123
124 #if defined(WIN32)
125 #define strdup(x)               _strdup(x)
126 #endif /* WIN32 */
127
128 /*
129  * 31 bit random number generator, we don't really care how random
130  * these numbers are, it is more important that identical rx files
131  * are generated no matter what platform the generator runs on
132  */
133 static unsigned long randVal = 0x330E16;
134
135 typedef enum {
136     PTHREADS,
137     LWPS
138 } threadModel_t;
139
140 static threadModel_t threadModel = PTHREADS;
141
142 PRIVATE double
143 drand32(void)
144 {
145     randVal = ((randVal * 0xEECE66D) + 0xB) & 0xFFFFFFFF;
146     return ((double)(randVal) / 4294967296.0);
147 }
148
149 /*
150  * GetDescription writes a one line comment describing the parameters
151  * used in an rpc in the client program
152  */
153 PRIVATE char *
154 GetDescription(rpcArgs * argsP)
155 {
156     char *bufP2;
157     int i;
158
159     bufP2 = calloc((MAX_TYP_STR + MAX_DIR_STR + ATTRIB_LEN * ATTRIB_NO)
160                        * argsP->argCount + 3, sizeof(char));
161     MEM_CHK(bufP2, "GetDescription: out of mem bufP2\n");
162
163     for (i = 0; i < argsP->argCount; i++) {
164         strcat(bufP2, argsP->argDescr[i].direction);
165         strcat(bufP2, argsP->argDescr[i].type);
166     }
167     return (bufP2);
168 }
169
170 /*
171  * GetName -- get the name of the current server/instance
172  */
173 PRIVATE char *
174 GetName(char *serverName, int sign_no)
175 {
176     /* itl file name 8.3 format */
177     char *bufP;
178
179     bufP = malloc(32 * sizeof(char));
180     MEM_CHK(bufP, "GetName: bufP out of mem\n");
181
182     sprintf(bufP, "%s%d", serverName, sign_no);
183     return bufP;
184 }
185
186 /*
187  * OpenOutFile -- open a file in the output directory
188  */
189 PRIVATE FILE *
190 OpenOutFile(char *outDir, char *fileName, char *tailStr)
191 {
192     char *bufP;
193     FILE *fP;
194
195     if (outDir) {
196         bufP =
197             (char *)malloc(sizeof(char) *
198                            (strlen(fileName) + strlen(tailStr) +
199                             strlen(outDir) + 2));
200         MEM_CHK(bufP, "OpenOutFile : Out of mem -- bufP\n");
201         sprintf(bufP, "%s/%s%s", outDir, fileName, tailStr);
202     } else {
203         bufP =
204             (char *)malloc(sizeof(char) *
205                            (strlen(fileName) + strlen(tailStr) + 1));
206         MEM_CHK(bufP, "OpenOutFile : Out of mem -- bufP\n");
207         sprintf(bufP, "%s%s", fileName, tailStr);
208     }
209     fP = fopen(bufP, "w");
210     MEM_CHK(fP, "main: Unable to open output file\n");
211     free(bufP);
212     return (fP);
213 }
214
215 /*
216  * WriteXGDecl -- write the declaration for a parameter
217  */
218 PRIVATE void
219 WriteXGDecl(arg_tuple * arg, FILE * xg_h, int i, int structFlag, int lastFlag)
220 {
221     if (structFlag) {
222         if (!strcmp(arg->type, "varString")) {
223             fprintf(xg_h, "\tchar a%d[STR_MAX];\n", i);
224         } else {
225             fprintf(xg_h, "\tdrpc_%s_t a%d;\n", arg->type, i);
226         }
227     } else {
228         if (!strncmp(arg->type, "ar_", 2)) {
229             fprintf(xg_h, "\t%s drpc_out_%s_t *a%d", arg->direction,
230                     arg->type, i);
231         } else if (!strcmp(arg->type, "varString")) {
232             fprintf(xg_h, "\t%s string a%d<STR_MAX>", arg->direction, i);
233         } else if (!strcmp(arg->direction, "IN")) {
234             fprintf(xg_h, "\t%s drpc_%s_t a%d", arg->direction, arg->type, i);
235         } else {
236             fprintf(xg_h, "\t%s drpc_%s_t *a%d", arg->direction, arg->type,
237                     i);
238         }
239         if (lastFlag) {
240             fputs(");\n", xg_h);
241         } else {
242             fputs(",\n", xg_h);
243         }
244     }
245 }
246
247 /*
248  * WriteXG -- write the body of the xg interface
249  */
250 PRIVATE void
251 WriteXG(rpcArgs * argsP, FILE * xg_h, char *serverName, int sign_no)
252 {
253     int i;
254     char *name = GetName(serverName, sign_no);
255
256     /*
257      * CASE 1: all arguments passed as parameters
258      */
259
260     fprintf(xg_h, "\nproc %s(\n", name);
261
262     /* declare each arg */
263     for (i = 0; i < argsP->argCount; i++) {
264         WriteXGDecl(&argsP->argDescr[i], xg_h, i, FALSE,
265                     (i == argsP->argCount - 1));
266     }
267
268     /* Now pass the paramaters inside a structure */
269     fprintf(xg_h, "\nstruct %s_t {\n", name);
270     for (i = 0; i < argsP->argCount; i++) {
271         WriteXGDecl(&argsP->argDescr[i], xg_h, i, TRUE,
272                     (i == argsP->argCount - 1));
273     }
274     fprintf(xg_h, "} ;\n");
275     fprintf(xg_h, "\nproc %s_s(\n", name);
276     fprintf(xg_h, "\tINOUT struct %s_t *s);\n", name);
277
278     free(name);
279 }
280
281 /*
282  * GetRandStr -- get a random string
283  */
284 PRIVATE void
285 GetRandStr(int strLen, char **ret, int *rP)
286 {
287     int i, randI;
288     char buf[5];
289
290     strcpy(*ret, "\"");
291     i = 0;
292     while (i < strLen) {
293         randI = 'A' + ('Z' - 'A') * drand32();
294         sprintf(buf, "%c", randI);
295         strcat(*ret, buf);
296         i++;
297     }
298     strcat(*ret, "\"");
299     *rP = randI;
300 }
301
302 /*
303  * GetRandP -- sets a string to a random value of the data type
304  * inthe case of a char type, ret holds "%c" and ret2 holds '%c'
305  */
306 PRIVATE void
307 GetRandP(char *typ, char **ret, char **ret2)
308 {
309     int randI, strLen;
310     float f;
311     double d, d1;
312     short shI;
313
314     *ret = calloc(MAX_RAND_LENGTH + 1, sizeof(char));
315     *ret2 = calloc(MAX_RAND_LENGTH + 1, sizeof(char));
316
317     if (strstr(typ, "char")) {
318         GetRandStr(1, ret2, &randI);
319         if (randI == '\\')
320             strcpy(*ret2, "'\\\\'");
321         else if (randI == '\'')
322             strcpy(*ret2, "'\\''");
323         else
324             sprintf(*ret, "'%c'", randI);
325         return;
326     } else if (strstr(typ, "short")) {
327         shI = SHRT_MIN + (SHRT_MAX - SHRT_MIN) * drand32();
328         sprintf(*ret, "%d", shI);
329         strcpy(*ret2, *ret);
330     } else if (strstr(typ, "afs_int32")) {
331         randI = INT_MIN + UINT_MAX * drand32();
332         if (randI < INT_MIN || randI > INT_MAX) {
333             fprintf(stderr, "GetRandP: afs_int32 %d out of bounds\n", randI);
334             exit(1);
335         }
336         sprintf(*ret, "%d", randI);
337         strcpy(*ret2, *ret);
338     } else if (strstr(typ, "float")) {
339         d = drand32();
340         f = d;
341         sprintf(*ret, "%2.8e", f);
342         strcpy(*ret2, *ret);
343
344     } else if (strstr(typ, "double")) {
345         d1 = drand32();
346         sprintf(*ret, "%2.16e", d1);
347         strcpy(*ret2, *ret);
348
349     } else if (strstr(typ, "String")) {
350         strLen = (MAX_RAND_LENGTH - 2) * drand32();
351         GetRandStr(strLen, ret, &randI);
352         strcpy(*ret2, *ret);
353     }
354 }
355
356
357 /*
358  * GenParamValues -- generate the parameter values for an rpc
359  */
360 PRIVATE void
361 GenParamValues(rpcArgs * argsP)
362 {
363     char *typ;
364     int i, j;
365
366     /* generate random values for each argument */
367     for (i = 0; i < argsP->argCount; i++) {
368
369         argsP->argDescr[i].vc_low = 0;
370         argsP->argDescr[i].vc_max = IDL_FIX_ARRAY_SIZE - 1;
371         argsP->argDescr[i].vc_high = IDL_FIX_ARRAY_SIZE - 1;
372         argsP->argDescr[i].ovc_low = 0;
373         argsP->argDescr[i].ovc_high = IDL_FIX_ARRAY_SIZE - 1;
374
375         if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
376             typ = argsP->argDescr[i].type + 3;
377             for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++) {
378                 GetRandP(typ, &argsP->argDescr[i].inValue[j],
379                          &argsP->argDescr[i].inValue2[j]);
380                 GetRandP(typ, &argsP->argDescr[i].outValue[j],
381                          &argsP->argDescr[i].outValue2[j]);
382             }
383         } else {
384             GetRandP(argsP->argDescr[i].type, &argsP->argDescr[i].inValue[0],
385                      &argsP->argDescr[i].inValue2[0]);
386             GetRandP(argsP->argDescr[i].type, &argsP->argDescr[i].outValue[0],
387                      &argsP->argDescr[i].outValue2[0]);
388         }
389     }
390 }
391
392 /*
393  * WriteServC -- write the rpcs in the server file
394  */
395 PRIVATE void
396 WriteServC(rpcArgs * argsP, FILE * srv_h, char *serverName, int sign_no)
397 {
398     char *name, *typ;
399     int i, j;
400
401     name = GetName(serverName, sign_no);
402     fprintf(srv_h, "\nint A%s(struct rx_call *c,\n", name);
403
404     /* declare each arg */
405     for (i = 0; i < argsP->argCount; i++) {
406
407         if (!strcmp(argsP->argDescr[i].type, "varString")) {
408             if (!strcmp(argsP->argDescr[i].direction, "IN")) {
409                 fprintf(srv_h, "\tchar *a%d", i);
410             } else {
411                 fprintf(srv_h, "\tchar **a%d", i);
412             }
413         } else if (strncmp(argsP->argDescr[i].type, "ar_", 3)
414                    && (!strcmp(argsP->argDescr[i].direction, "IN"))) {
415             fprintf(srv_h, "\tdrpc_%s_t a%d", argsP->argDescr[i].type, i);
416         } else {
417             if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
418                 fprintf(srv_h, "\tdrpc_out_%s_t *a%d",
419                         argsP->argDescr[i].type, i);
420             } else {
421                 fprintf(srv_h, "\tdrpc_%s_t *a%d", argsP->argDescr[i].type,
422                         i);
423             }
424         }
425         if (i < (argsP->argCount - 1)) {
426             fprintf(srv_h, ",\n");
427         }
428     }
429     fputs(")\n{\n", srv_h);     /* balance the } */
430     fputs("\tint errFlag = 0;", srv_h);
431
432     /*
433      * check the in and inout parameters
434      */
435     for (i = 0; i < argsP->argCount; i++) {
436
437         if (!strcmp(argsP->argDescr[i].direction, "IN")
438             || (!strcmp(argsP->argDescr[i].direction, "INOUT")
439                 && !strcmp(argsP->argDescr[i].type, "varString"))) {
440
441             typ = argsP->argDescr[i].type;
442
443             if (strstr(typ, "String")) {
444                 if (!strcmp(argsP->argDescr[i].direction, "INOUT")) {
445                     fprintf(srv_h, "\n\tCHECK%s((char *)*a%d, %s, \"%s\");",
446                             typ, i, argsP->argDescr[i].inValue[0], name);
447                 } else {
448                     fprintf(srv_h, "\n\tCHECK%s((char *)a%d, %s, \"%s\");",
449                             typ, i, argsP->argDescr[i].inValue[0], name);
450                 }
451             } else if (!strcmp(typ, "afs_int32")) {
452                 fprintf(srv_h, "\n\tCHECK%s(a%d, %sL, \"%s\");", typ, i,
453                         argsP->argDescr[i].inValue[0], name);
454             } else {
455                 if (!strncmp(typ, "ar_", 3)) {
456                     for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
457                         fprintf(srv_h,
458                                 "\n\tCHECK%s(a%d->drpc_out_%s_t_val[%d], %s, \"%s\");",
459                                 (typ + 3), i, typ, j,
460                                 argsP->argDescr[i].inValue[j], name);
461                 } else {
462                     fprintf(srv_h, "\n\tCHECK%s(a%d, %s, \"%s\");", typ, i,
463                             argsP->argDescr[i].inValue[0], name);
464                 }
465             }
466         } else if (!strcmp(argsP->argDescr[i].direction, "INOUT")) {
467
468             typ = argsP->argDescr[i].type;
469
470             if (strstr(typ, "String")) {
471                 fprintf(srv_h, "\n\tCHECK%s((char *)*a%d, %s, \"%s\");", typ,
472                         i, argsP->argDescr[i].inValue[0], name);
473             } else if (!strcmp(typ, "afs_int32")) {
474                 fprintf(srv_h, "\n\tCHECK%s(*a%d, %sL, \"%s\");", typ, i,
475                         argsP->argDescr[i].inValue[0], name);
476             } else {
477                 if (!strncmp(typ, "ar_", 3)) {
478                     for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
479                         fprintf(srv_h,
480                                 "\n\tCHECK%s(a%d->drpc_out_%s_t_val[%d], %s, \"%s\");",
481                                 (typ + 3), i, typ, j,
482                                 argsP->argDescr[i].inValue[j], name);
483                 } else {
484                     fprintf(srv_h, "\n\tCHECK%s(*a%d, %s, \"%s\");", typ, i,
485                             argsP->argDescr[i].inValue[0], name);
486                 }
487             }
488         }
489     }
490
491     /*
492      * free up memory for dynamic input args
493      */
494     for (i = 0; i < argsP->argCount; i++) {
495         if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
496             typ = argsP->argDescr[i].type;
497             if (!strcmp(argsP->argDescr[i].direction, "INOUT")) {
498                 fprintf(srv_h,
499                         "\n\tif (a%d->drpc_out_%s_t_val) "
500                         "free(a%d->drpc_out_%s_t_val);", i, typ, i, typ);
501             }
502             if (!strcmp(argsP->argDescr[i].direction, "INOUT")
503                 || !strcmp(argsP->argDescr[i].direction, "OUT")) {
504                 fprintf(srv_h,
505                         "\n\ta%d->drpc_out_%s_t_val = (%s *) "
506                         "malloc(FIX_ARRAY_SIZE * sizeof(%s));", i, typ,
507                         (typ + 3), (typ + 3));
508                 fprintf(srv_h, "\n\ta%d->drpc_out_%s_t_len = FIX_ARRAY_SIZE;",
509                         i, typ);
510             }
511         }
512     }
513
514     /*
515      * set the inout and out parameters
516      */
517     for (i = 0; i < argsP->argCount; i++) {
518
519         if (!strcmp(argsP->argDescr[i].direction, "INOUT")
520             || !strcmp(argsP->argDescr[i].direction, "OUT")) {
521
522             typ = argsP->argDescr[i].type;
523
524             if (!strncmp(typ, "ar_", 3)) {
525                 for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
526                     fprintf(srv_h, "\n\ta%d->drpc_out_%s_t_val[%d] = %s;", i,
527                             typ, j, argsP->argDescr[i].outValue[j]);
528             } else if (!strcmp(typ, "afs_int32")) {
529                 fprintf(srv_h, "\n\t*a%d = %sL;", i,
530                         argsP->argDescr[i].outValue[0]);
531             } else if (!strcmp(typ, "varString")) {
532                 if (!strcmp(argsP->argDescr[i].direction, "OUT")) {
533                     fprintf(srv_h, "\n\t*a%d = malloc(STR_MAX);", i);
534                 }
535                 fprintf(srv_h, "\n\tstrcpy((char *)*a%d, %s);", i,
536                         argsP->argDescr[i].outValue[0]);
537             } else if (strstr(typ, "String")) {
538                 fprintf(srv_h, "\n\t*a%d = (drpc_%s_t)rpc_ss_allocate(%d);",
539                         i, typ, strlen(argsP->argDescr[i].outValue[0]) - 1);
540                 fprintf(srv_h, "\n\tstrcpy((char *)*a%d, %s);", i,
541                         argsP->argDescr[i].outValue[0]);
542             } else {
543                 fprintf(srv_h, "\n\t*a%d = %s;", i,
544                         argsP->argDescr[i].outValue[0]);
545             }
546         }
547     }
548
549     fprintf(srv_h,
550             "\n\tif (errFlag) {" "\n\t\tprintf(\"%s: failed\\n\");"
551             "\n\t\tfflush(stdout);" "\n\t}" "\n\treturn errFlag;\n}\n", name);
552
553     /*
554      * second routine with arguments inside a structure
555      */
556     fprintf(srv_h,
557             "\nint A%s_s(struct rx_call *c,\n\t%s_t *s)\n{"
558             "\n\tint errFlag = 0;", name, name);
559
560     /*
561      * check the in and inout parameters
562      */
563     for (i = 0; i < argsP->argCount; i++) {
564
565         if (!strcmp(argsP->argDescr[i].direction, "IN")
566             || (!strstr(argsP->argDescr[i].type, "String")
567                 && !strcmp(argsP->argDescr[i].direction, "INOUT"))) {
568
569             typ = argsP->argDescr[i].type;
570
571             if (!strncmp(typ, "ar_", 3)) {
572                 for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
573                     fprintf(srv_h, "\n\tCHECK%s(s->a%d[%d], %s, \"%s_s\");",
574                             (typ + 3), i, j, argsP->argDescr[i].inValue[j],
575                             name);
576             } else if (strstr(typ, "String")) {
577                 fprintf(srv_h, "\n\tCHECK%s((char *)s->a%d, %s, \"%s_s\");",
578                         typ, i, argsP->argDescr[i].inValue[0], name);
579             } else if (!strcmp(typ, "afs_int32")) {
580                 fprintf(srv_h, "\n\tCHECK%s(s->a%d, %sL, \"%s_s\");", typ, i,
581                         argsP->argDescr[i].inValue[0], name);
582             } else {
583                 fprintf(srv_h, "\n\tCHECK%s(s->a%d, %s, \"%s_s\");", typ, i,
584                         argsP->argDescr[i].inValue[0], name);
585             }
586         }
587     }
588
589     /*
590      * set the inout and out parameters
591      */
592     for (i = 0; i < argsP->argCount; i++) {
593
594         if (!strcmp(argsP->argDescr[i].direction, "INOUT")
595             || !strcmp(argsP->argDescr[i].direction, "OUT")) {
596
597             typ = argsP->argDescr[i].type;
598
599             if (!strncmp(typ, "ar_", 3)) {
600                 for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
601                     fprintf(srv_h, "\n\ts->a%d[%d]= %s;", i, j,
602                             argsP->argDescr[i].outValue[j]);
603             } else if (!strcmp(typ, "afs_int32")) {
604                 fprintf(srv_h, "\n\ts->a%d = %sL;", i,
605                         argsP->argDescr[i].outValue[0]);
606             } else if (!strcmp(typ, "varString")) {
607                 fprintf(srv_h, "\n\tstrcpy((char *)s->a%d, %s);", i,
608                         argsP->argDescr[i].outValue[0]);
609             } else if (strstr(typ, "String")) {
610                 fprintf(srv_h, "\n\ts->a%d = rpc_ss_allocate(%d);", i,
611                         strlen(argsP->argDescr[i].outValue[0]) - 1);
612                 fprintf(srv_h, "\n\tstrcpy((char *)s->a%d, %s);", i,
613                         argsP->argDescr[i].outValue[0]);
614             } else {
615                 fprintf(srv_h, "\n\ts->a%d = %s;", i,
616                         argsP->argDescr[i].outValue[0]);
617             }
618         }
619     }
620
621     fprintf(srv_h,
622             "\n\tif (errFlag) {" "\n\t\tprintf(\"%s_s: failed\\n\");" "\n\t}"
623             "\n\tfflush(stdout);" "\n\treturn errFlag;\n}\n", name);
624
625
626     free(name);
627 }
628
629 /*
630  * WriteMake - write the makefile for a particular client/server pair
631  */
632 PRIVATE void
633 WriteMake(char *serverName, int srv_no, FILE * mak_h)
634 {
635     char p[1024];
636     char *obj = platform[2];
637
638     sprintf(p, "%s%d", serverName, srv_no);
639     fprintf(mak_h, "%s", platform[1]);
640     if (threadModel == PTHREADS) {
641         fprintf(mak_h, "CFLAGS = -KPIC -g -mt -I$(DESTDIR)include\n" "%s",
642                 platform[6]
643             );
644     } else {
645         fprintf(mak_h, "CFLAGS = -g -I$(DESTDIR)include\n" "%s", platform[7]
646             );
647     }
648     fprintf(mak_h,
649             "\n\ntest: all\ntests: all\nall: %sClt %sSrv\n\n"
650             "%sClt: %s.cs.%s %s.xdr.%s %sClt.%s $(LIBS)\n", p, p, p, p, obj,
651             p, obj, p, obj);
652     if (platform == nt_symbols) {
653         fprintf(mak_h, "\t$(EXECONLINK)\n\n");
654     } else {
655         fprintf(mak_h,
656                 "\t$(CC) $(CFLAGS) -o $@ %sClt.%s %s.cs.%s %s.xdr.%s "
657                 "$(LIBS) $(XLIBS)\n\n", p, obj, p, obj, p, obj);
658     }
659     fprintf(mak_h,
660             "%s.xdr.c: %s.xg\n\n" "%s.h %s.cs.c %s.ss.c: %s.xg\n"
661             "\t$(RXGEN) %s.xg\n" "\t%s %s.cs.c\n" "\t%s %s.ss.c\n\n", p, p, p,
662             p, p, p, p, platform[3], p, platform[3], p);
663     fprintf(mak_h, "%sSrv: %s.ss.%s %s.xdr.%s %sSrv.%s $(LIBS)\n", p, p, obj,
664             p, obj, p, obj);
665
666     if (platform == nt_symbols) {
667         fprintf(mak_h, "\t$(EXECONLINK)\n\n");
668     } else {
669         fprintf(mak_h,
670                 "\t$(CC) $(CFLAGS) -o $@ %sSrv.o %s.ss.o %s.xdr.o "
671                 "$(LIBS) $(XLIBS)\n\n", p, p, p);
672     }
673
674     if (platform == unix_symbols) {
675         fprintf(mak_h,
676                 "clean:\n" "\t/bin/rm -f %sClt %s.h %s.cs.c %s.ss.c core "
677                 "%sSrv %sSrv.o \\\n"
678                 "\t%sClt.o %s.cs.o %s.ss.o %s.xdr.c %s.xdr.o\n", p, p, p, p,
679                 p, p, p, p, p, p, p);
680     }
681
682 }
683
684 /*
685  * WriteCltTrailer - finish writing client source
686  */
687 PRIVATE void
688 WriteCltTrailer(char *serverName, int first, int last, FILE * itl_h)
689 {
690     int i = 0;
691
692     /*
693      * Write out 1 function that calls all the manager functions
694      */
695     if (threadModel == PTHREADS) {
696         fprintf(itl_h, "\n\nvoid *threadFunc(void *arg) {\n");
697     } else {
698         fprintf(itl_h, "\n\nint threadFunc(int *arg) {\n");
699     }
700
701     fprintf(itl_h,
702             "\tstruct rx_connection *conn;\n" "\tint error=0;\n\n"
703             "\tint i = (int) arg;\n\n");
704
705     fprintf(itl_h,
706             "\tconn = rx_GetCachedConnection(serverAddr,serverPort,4,secClass,secIndex);\n");
707
708     fprintf(itl_h, "\twhile(i--) {\n");
709
710     if (first == 0)
711         first = 1;
712     for (i = first; i < last; i++) {
713         fprintf(itl_h, "\t\tC_%s%d(conn);\n", serverName, i);
714         fprintf(itl_h, "\t\tC_%s%d_s(conn);\n", serverName, i);
715     }
716     fprintf(itl_h, "\t}\n");
717
718     fprintf(itl_h, "\trx_ReleaseCachedConnection(conn);\n");
719
720     if (threadModel == PTHREADS) {
721         fprintf(itl_h, "\treturn (void *) 0;\n");
722     } else {
723         fprintf(itl_h,
724                 "\tLWP_CALL(LWP_SignalProcess,(&done));\n" "\treturn 0;\n");
725     }
726
727     fprintf(itl_h, "}\n");
728
729     fprintf(itl_h,
730             "\n\nstatic void DoRun(struct cmd_syndesc *as, void *arock) {\n");
731
732     if (threadModel == PTHREADS) {
733         fprintf(itl_h, "\tpthread_t *tid;\n");
734     } else {
735         fprintf(itl_h, "\tPROCESS *tid;\n");
736     }
737
738     fprintf(itl_h,
739             "\tint i,j;\n" "\tunsigned int numThreads=0,numIterations=0;\n"
740             "\tint errflg=0;\n" "\tstruct hostent *host=NULL;\n\n"
741             "\tnumThreads = atoi(as->parms[0].items->data);\n"
742             "\tnumIterations = atoi(as->parms[1].items->data);\n"
743             "\tsecType = atoi(as->parms[2].items->data);\n"
744             "\tencLevel = atoi(as->parms[3].items->data);\n"
745             "\tserverPort = htons(atoi(as->parms[4].items->data));\n"
746             "\tif ((host = hostutil_GetHostByName(as->parms[5].items->data))==0) {\n"
747             "\t\terrflg++;\n" "\t}\n" "\telse {\n"
748             "\t\tmemcpy((void *) &serverAddr, (const void *)host->h_addr, sizeof(serverAddr));\n"
749             "\t}\n" "\tif ((secType<1) || (secType>2)) errflg++;\n"
750             "\tif ((encLevel<0) || (encLevel>2)) errflg++;\n"
751             "\tif ((serverPort == 0) ||(numThreads == 0) ||(numIterations == 0)) errflg++;\n"
752             "\tif (errflg) {\n" "\t\tprintf(\"invalid argument\\n\");\n"
753             "\t\texit(1);\n" "\t}\n\n" "\tif(rx_Init(htons(0)) < 0) {\n"
754             "\t\texit(1);\n" "\t}\n\n" "\tswitch(secType) {\n" "\t\tcase 1:\n"
755             "\t\t\tsecIndex = 0;\n"
756             "\t\t\tsecClass = rxnull_NewClientSecurityObject();\n"
757             "\t\t\tbreak;\n" "\t\tcase 2:\n"
758             "\t\t\tif (GetTicket (&kvno, &Ksession, &ticketLen, ticket) == 0) {\n"
759             "\t\t\t\tsecIndex = 2;\n"
760             "\t\t\t\tsecClass = rxkad_NewClientSecurityObject(encLevel,\n"
761             "\t\t\t\t&Ksession, kvno, ticketLen, ticket);\n" "\t\t\t}\n"
762             "\t\t\tbreak;\n" "\t\tdefault:\n" "\t\t\tbreak;\n" "\t}\n"
763             "\tassert(secClass);\n\n");
764     if (threadModel == PTHREADS) {
765         fprintf(itl_h,
766                 "#if defined sun\n" "\tthr_setconcurrency(numThreads);\n"
767                 "#endif\n" "\ttid = (pthread_t *) "
768                 "malloc(numThreads*(sizeof(pthread_t)));\n");
769     } else {
770         fprintf(itl_h,
771                 "\ttid = malloc(numThreads*(sizeof(PROCESS *)));\n");
772     }
773
774     fprintf(itl_h, "\tassert(tid);\n" "\tfor(j=0;j<numThreads;j++) {\n");
775     if (threadModel == PTHREADS) {
776         fprintf(itl_h,
777                 "\t\ti = pthread_create(&tid[j], (const pthread_attr_t *) 0,\n"
778                 "\t\tthreadFunc, (void *) numIterations);\n"
779                 "\t\tassert(i==0);\n");
780     } else {
781         fprintf(itl_h,
782                 "\t\tLWP_CALL(LWP_CreateProcess,(threadFunc, 10*4096, LWP_NORMAL_PRIORITY, numIterations, \"foo\", &tid[j]));\n");
783     }
784
785     fprintf(itl_h, "\t}\n" "\tfor(j=0;j<numThreads;j++) {\n");
786     if (threadModel == PTHREADS) {
787         fprintf(itl_h,
788                 "\t\ti = pthread_join(tid[j], (void **) 0);\n"
789                 "\t\tassert(i==0);\n");
790     } else {
791         fprintf(itl_h, "\t\tLWP_CALL(LWP_WaitProcess,(&done));\n");
792     }
793     fprintf(itl_h, "\t}\n" "\trx_Finalize();\n" "\tfree(tid);\n" "}\n");
794
795     /*
796      * Write command syntax function
797      */
798
799     fprintf(itl_h,
800             "static void SetupRunCmd(void) {\n" "\tstruct cmd_syndesc *ts;\n"
801             "\tts = cmd_CreateSyntax(NULL,DoRun, NULL, \"run the test client program\");\n"
802             "\tcmd_AddParm(ts, \"-threadCount\", CMD_SINGLE, CMD_REQUIRED, \"number of threads to spawn\");\n"
803             "\tcmd_AddParm(ts, \"-iterationCount\", CMD_SINGLE, CMD_REQUIRED, \"number of iterations to make over entire interface for each thread\");\n"
804             "\tcmd_AddParm(ts, \"-secType\", CMD_SINGLE, CMD_REQUIRED, \"security level to use (1 -> unauthenticated, 2 -> authenticated)\");\n"
805             "\tcmd_AddParm(ts, \"-encLevel\", CMD_SINGLE, CMD_REQUIRED, \"encryption level to use, (0-> rxkad_clear, 1 -> rxkad_auth, 2 -> rxkad_crypt)\");\n"
806             "\tcmd_AddParm(ts, \"-serverPort\", CMD_SINGLE, CMD_REQUIRED, \"port that server is using\");\n"
807             "\tcmd_AddParm(ts, \"-serverHost\", CMD_SINGLE, CMD_REQUIRED, \"host where server is running\");\n"
808             "}\n");
809
810     /*
811      * Write client main
812      */
813
814     fprintf(itl_h,
815             "int main (int argc, char *argv[]) {\n" "\tint code;\n\n"
816             "\tinitialize_CMD_error_table();\n" "\tSetupRunCmd();\n"
817             "\tcode = cmd_Dispatch(argc, argv);\n\n" "\treturn(code);\n"
818             "\t}\n");
819
820 }
821
822 /*
823  * Create macros useful for checking input/output parameters
824  */
825
826 PRIVATE void
827 WriteTestMacros(FILE * f)
828 {
829     fprintf(f,
830             "\n#define CHECKchar(x,y,z) if ((x)!=(y)) { printf(\"%%s: Got '%%c',"
831             "expected '%%c'\\n\", z, (char)x, (char)(y)); fflush(stdout); "
832             "errFlag = 1; } " "\n#define CHECKshort(x,y,z) if ((x)!=(y)) "
833             "{ printf(\"%%s: Got 0x%%04x, "
834             "expected 0x%%04x\\n\", z, x, y); fflush(stdout); "
835             "errFlag = 1; } " "\n#define CHECKint32(x,y,z) if ((x)!=(y)) "
836             "{ printf(\"%%s: Got 0x%%08x, "
837             "expected 0x%%08x\\n\", z, x, y); fflush(stdout); "
838             "errFlag = 1; } "
839             "\n#define CHECKfloat(x,y,z) if (((x)/(y)<.999999) "
840             "|| ((x)/(y)>1.000001)) "
841             "{ printf(\"%%s: Got %%2.8e, expected %%2.8e\\n\", z, x, y); "
842             "fflush(stdout); " "errFlag = 1; } "
843             "\n#define CHECKdouble(x,y,z) if (((x)/(y)<.999999999999999) || "
844             "((x)/(y)>1.000000000000001)) { printf(\"%%s: Got %%2.16e, "
845             "expected %%2.16e\\n\", z, x, y); fflush(stdout); errFlag = 1; }"
846             "\n#define CHECKvarString(x,y,z) if (strcmp((x),(y))) { printf(\"%%s: "
847             "Got \\\"%%s\\\", expected \\\"%%s\\\"\\n\", z, x, y); fflush(stdout); "
848             "errFlag = 1; } \n");
849 }
850
851 /*
852  * WriteCltHeader - write the begining of the client code.
853  */
854 PRIVATE void
855 WriteCltHeader(char *serverName, int srv_no, FILE * itl_h)
856 {
857     fprintf(itl_h, "#include <stdio.h>\n");
858     if (threadModel == PTHREADS) {
859         fprintf(itl_h, "#include <pthread.h>\n");
860     }
861     fprintf(itl_h,
862             "%s" "#include <assert.h>\n" "#include <rx/rx.h>\n"
863             "#include <rx/rx_null.h>\n" "#include <rx/rxkad.h>\n"
864             "#include <afs/cmd.h>\n" "#include \"%s%d.h\"\n", platform[4],
865             serverName, srv_no);
866     if (threadModel == LWPS) {
867         fprintf(itl_h,
868                 "\n\n#define LWP_CALL(fnName, params) \\\n" "{ \\\n"
869                 "\tint rc; \\\n" "\trc = fnName params; \\\n"
870                 "\tif (rc != LWP_SUCCESS) { \\\n"
871                 "\t\tprintf(\"call to %%s failed with %%d\\n\", # fnName, rc); \\\n"
872                 "\t\texit(1); \\\n" "\t} \\\n" "};\n\n" "char done;\n\n");
873     }
874
875     fprintf(itl_h,
876             "struct ktc_encryptionKey serviceKey =\n"
877             "\t{0x45, 0xe3, 0x3d, 0x16, 0x29, 0x64, 0x8a, 0x8f};\n"
878             "long serviceKeyVersion = 7;\n"
879             "\nextern struct hostent *hostutil_GetHostByName();\n\n"
880             "static long GetTicket (long *versionP,\n"
881             "\tstruct ktc_encryptionKey *session,\n"
882             "\tint * ticketLenP, char *ticket)\n" "{\n" "\tlong code;\n"
883             "\tdes_init_random_number_generator (&serviceKey);\n"
884             "\tcode = des_random_key (session);\n"
885             "\tif (code) return code;\n" "\t*ticketLenP = 0;\n"
886             "\tcode = tkt_MakeTicket(ticket, ticketLenP, &serviceKey,\n"
887             "\t\t\"tclnt\", \"\", \"\",\n" "\t\t0, 0xffffffff, session, 0,\n"
888             "\t\t\"tsrvr\", \"\");\n" "\tif (code) return code;\n"
889             "\t*versionP = serviceKeyVersion;\n" "\treturn 0;\n" "}\n\n"
890             "static int secType,encLevel,serverPort,serverAddr;\n"
891             "struct rx_securityClass *secClass;\n" "int secIndex;\n"
892             "long kvno;\n" "char ticket[MAXKTCTICKETLEN];\n"
893             "int ticketLen;\n" "struct ktc_encryptionKey Ksession;\n\n");
894     WriteTestMacros(itl_h);
895
896 }
897
898 /*
899  * WriteCltInit -- write the initialization for each param
900  */
901 PRIVATE void
902 WriteCltInit(arg_tuple * arg, FILE * itl_h, int i, int structFlag)
903 {
904     int j;
905     char *s = (structFlag) ? "s." : "";
906
907     if ((!strncmp(arg->direction, "IN", 2) || structFlag)) {
908         if (!strncmp(arg->type, "varString", 9)) {
909             fprintf(itl_h, "\tstrcpy(%sa%d, %s);\n", s, i, arg->inValue[0]);
910         } else if (!strncmp(arg->type, "ar_", 3)) {
911             if (!structFlag) {
912                 fprintf(itl_h,
913                         "\t%sa%d.drpc_out_%s_t_len = FIX_ARRAY_SIZE;\n", s, i,
914                         arg->type);
915                 fprintf(itl_h,
916                         "\t%sa%d.drpc_out_%s_t_val = "
917                         "malloc(FIX_ARRAY_SIZE * sizeof(%s));\n", s, i,
918                         arg->type, (arg->type + 3));
919             }
920             for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++) {
921                 if (structFlag) {
922                     fprintf(itl_h, "\t%sa%d[%d] = %s;\n", s, i, j,
923                             arg->inValue[j]);
924                 } else {
925                     fprintf(itl_h, "\t%sa%d.drpc_out_%s_t_val[%d] = %s;\n", s,
926                             i, arg->type, j, arg->inValue[j]);
927                 }
928             }
929         } else {
930             fprintf(itl_h, "\t%sa%d = %s;\n", s, i, arg->inValue[0]);
931         }
932     }
933 }
934
935 /*
936  * WriteCltCall -- write each parameter for a call
937  */
938 PRIVATE void
939 WriteCltCall(arg_tuple * arg, FILE * itl_h, int i)
940 {
941
942     if (!strncmp(arg->type, "varString", 9)) {
943         if ((!strncmp(arg->direction, "OUT", 3))
944             || (!strncmp(arg->direction, "INOUT", 5))) {
945             fprintf(itl_h, "&a%d_p", i);
946         } else {
947             fprintf(itl_h, "a%d_p", i);
948         }
949     } else {
950         if ((!strncmp(arg->direction, "OUT", 3))
951             || (!strncmp(arg->direction, "INOUT", 5))
952             || (!strncmp(arg->type, "ar_", 3))) {
953             fprintf(itl_h, "&a%d", i);
954         } else {
955             fprintf(itl_h, "a%d", i);
956         }
957     }
958 }
959
960 /*
961  * WriteCltDecl -- write the declaration for a parameter
962  */
963 PRIVATE void
964 WriteCltDecl(arg_tuple * arg, FILE * itl_h, int i)
965 {
966
967     if (!strncmp(arg->type, "ar_", 3)) {
968         if (!strncmp(arg->direction, "OUT", 3)) {
969             fprintf(itl_h, "\tdrpc_out_%s_t a%d = {0,0};\n", arg->type, i);
970         } else {
971             fprintf(itl_h, "\tdrpc_out_%s_t a%d;\n", arg->type, i);
972         }
973     } else if (!strncmp(arg->type, "varString", 9)) {
974         fprintf(itl_h, "\tchar a%d[STR_MAX];\n", i);
975         fprintf(itl_h, "\tchar *a%d_p = a%d;\n", i, i);
976     } else {
977         fprintf(itl_h, "\t%s a%d;\n", arg->type, i);
978     }
979 }
980
981
982 /*
983  * WriteClt -- write the rpcs in the client
984  */
985 PRIVATE void
986 WriteClt(rpcArgs * argsP, char *serverName, int sign_no, FILE * itl_h)
987 {
988     char *name, *name2, *typ;
989     int i, j;
990
991     name = GetName(serverName, sign_no);
992     name2 = GetDescription(argsP);
993
994     fprintf(itl_h, "\n/* %s */\n\n", name2);
995
996     fprintf(itl_h, "\nvoid C_%s(struct rx_connection *conn) {\n", name);
997
998     /* declare each arg */
999     for (i = 0; i < argsP->argCount; i++) {
1000         WriteCltDecl(&argsP->argDescr[i], itl_h, i);
1001     }
1002     fprintf(itl_h, "\tint error;\n\tint errFlag;\n\n");
1003
1004     /* initialize IN/INOUT args */
1005     for (i = 0; i < argsP->argCount; i++) {
1006         WriteCltInit(&argsP->argDescr[i], itl_h, i, FALSE);
1007     }
1008
1009     /* call the server */
1010     fprintf(itl_h, "\terror = A%s(conn, ", name);
1011
1012     /* pass each arg */
1013     for (i = 0; i < argsP->argCount; i++) {
1014         WriteCltCall(&argsP->argDescr[i], itl_h, i);
1015         fprintf(itl_h, ((i < (argsP->argCount - 1))) ? "," : ");\n");
1016     }
1017
1018     fprintf(itl_h,
1019             "\tif (error != 0) {\n"
1020             "\t\tprintf(\"C_%s failed %%d\\n\", error);\n"
1021             "\t\tfflush(stdout);\n" "\t\treturn;\n" "\t}\n", name);
1022
1023     /*
1024      * check the in and inout parameters
1025      */
1026     for (i = 0; i < argsP->argCount; i++) {
1027
1028         if ((!strcmp(argsP->argDescr[i].direction, "OUT"))
1029             || (!strcmp(argsP->argDescr[i].direction, "INOUT"))) {
1030
1031             typ = argsP->argDescr[i].type;
1032
1033             if (!strncmp(typ, "ar_", 3)) {
1034                 for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
1035                     fprintf(itl_h,
1036                             "\n\tCHECK%s(a%d.drpc_out_%s_t_val[%d], %s, \"C_%s_s\");",
1037                             (typ + 3), i, typ, j,
1038                             argsP->argDescr[i].outValue[j], name);
1039             } else if (strstr(typ, "String")) {
1040                 fprintf(itl_h, "\n\tCHECK%s((char *)a%d, %s, \"C_%s_s\");",
1041                         typ, i, argsP->argDescr[i].outValue[0], name);
1042             } else if (!strcmp(typ, "afs_int32")) {
1043                 fprintf(itl_h, "\n\tCHECK%s(a%d, %sL, \"C_%s_s\");", typ, i,
1044                         argsP->argDescr[i].outValue[0], name);
1045             } else {
1046                 fprintf(itl_h, "\n\tCHECK%s(a%d, %s, \"C_%s_s\");", typ, i,
1047                         argsP->argDescr[i].outValue[0], name);
1048             }
1049         }
1050     }
1051
1052     /*
1053      * free up memory for dynamic input args
1054      */
1055     for (i = 0; i < argsP->argCount; i++) {
1056         if (!strncmp(argsP->argDescr[i].type, "ar_", 3)) {
1057             typ = argsP->argDescr[i].type;
1058             fprintf(itl_h,
1059                     "\n\tif (a%d.drpc_out_%s_t_val) "
1060                     "free(a%d.drpc_out_%s_t_val);", i, typ, i, typ);
1061         }
1062     }
1063
1064
1065     fprintf(itl_h, "\n}\n");
1066
1067     /*
1068      * Call the structure oriented rpc interface
1069      */
1070
1071     fprintf(itl_h, "\nvoid C_%s_s(struct rx_connection *conn) {\n", name);
1072     fprintf(itl_h, "\tstruct %s_t s;\n", name);
1073     fprintf(itl_h, "\tint error;\n\tint errFlag;\n\n");
1074
1075     /* initialize IN/INOUT args */
1076     for (i = 0; i < argsP->argCount; i++) {
1077         WriteCltInit(&argsP->argDescr[i], itl_h, i, TRUE);
1078     }
1079
1080     /* call the server */
1081     fprintf(itl_h, "\terror = A%s_s(conn, &s);\n", name);
1082
1083     fprintf(itl_h,
1084             "\tif (error != 0) {\n"
1085             "\t\tprintf(\"C_%s_s failed %%d\\n\", error);\n"
1086             "\t\tfflush(stdout);\n" "\t\treturn;\n" "\t}\n", name);
1087
1088     /*
1089      * check the in and inout parameters
1090      */
1091     for (i = 0; i < argsP->argCount; i++) {
1092
1093         if ((!strcmp(argsP->argDescr[i].direction, "OUT"))
1094             || (!strcmp(argsP->argDescr[i].direction, "INOUT"))) {
1095
1096             typ = argsP->argDescr[i].type;
1097
1098             if (!strncmp(typ, "ar_", 3)) {
1099                 for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++)
1100                     fprintf(itl_h, "\n\tCHECK%s(s.a%d[%d], %s, \"C_%s_s\");",
1101                             (typ + 3), i, j, argsP->argDescr[i].outValue[j],
1102                             name);
1103             } else if (strstr(typ, "String")) {
1104                 fprintf(itl_h, "\n\tCHECK%s((char *)s.a%d, %s, \"C_%s_s\");",
1105                         typ, i, argsP->argDescr[i].outValue[0], name);
1106             } else if (!strcmp(typ, "afs_int32")) {
1107                 fprintf(itl_h, "\n\tCHECK%s(s.a%d, %sL, \"C_%s_s\");", typ, i,
1108                         argsP->argDescr[i].outValue[0], name);
1109             } else {
1110                 fprintf(itl_h, "\n\tCHECK%s(s.a%d, %s, \"C_%s_s\");", typ, i,
1111                         argsP->argDescr[i].outValue[0], name);
1112             }
1113         }
1114     }
1115
1116
1117     fprintf(itl_h, "\n}\n");
1118
1119     free(name);
1120     free(name2);
1121 }
1122
1123 /*
1124  * WriteXGHeader -- fill in Header info in the xg file
1125  */
1126 PRIVATE void
1127 WriteXGHeader(char *serverName, FILE * xg_h, int srv_no)
1128 {
1129
1130     /* create the interface header */
1131
1132     fprintf(xg_h,
1133             "\n/* Do not edit this file -- it was created by a generator */\n"
1134             "\npackage A\n\n" "const STR_MAX = %d; \n"
1135             "const FIX_ARRAY_SIZE = %d; \n" "typedef char drpc_char_t; \n"
1136             "typedef short drpc_short_t; \n" "typedef long drpc_int32_t; \n"
1137             "typedef string drpc_varString_t<STR_MAX>; \n"
1138             "typedef drpc_char_t drpc_ar_char_t[FIX_ARRAY_SIZE]; \n"
1139             "typedef drpc_char_t drpc_out_ar_char_t<FIX_ARRAY_SIZE>; \n"
1140             "typedef drpc_short_t drpc_ar_short_t[FIX_ARRAY_SIZE]; \n"
1141             "typedef drpc_short_t drpc_out_ar_short_t<FIX_ARRAY_SIZE>; \n"
1142             "typedef drpc_int32_t drpc_ar_int32_t[FIX_ARRAY_SIZE]; \n"
1143             "typedef drpc_int32_t drpc_out_ar_int32_t<FIX_ARRAY_SIZE>; \n",
1144             IDL_STR_MAX, IDL_FIX_ARRAY_SIZE);
1145 }
1146
1147 /*
1148  * WriteServHeader -- fill in the Header info in the server file
1149  */
1150 PRIVATE void
1151 WriteServHeader(FILE * srv_h, char *serverName, int srv_no)
1152 {
1153     char *name;
1154
1155     name = GetName(serverName, srv_no);
1156
1157     fprintf(srv_h,
1158             "\n/* Do not edit this file -- it's been created by a generator */\n\n"
1159             "%s\n" "#include <stdio.h>\n" "#include <string.h>\n"
1160             "#include <stdlib.h>\n" "#include <rx/rx.h>\n"
1161             "#include <rx/rx_null.h>\n" "#include <rx/rxkad.h>\n"
1162             "#include <afs/cmd.h>\n" "#include \"%s.h\"\n\n"
1163             "struct ktc_encryptionKey serviceKey =\n"
1164             "\t{0x45, 0xe3, 0x3d, 0x16, 0x29, 0x64, 0x8a, 0x8f};\n"
1165             "long serviceKeyVersion = 7;\n\n"
1166             "extern int AExecuteRequest();\n" "extern char *optarg;\n"
1167             "extern int optind, opterr, optopt;\n\n"
1168             "#define VERIFY(x,y) if (!(x)) { printf y ; exit(1); }\n"
1169             "#define CHECK(x) ASSERT(x)\n", platform[4], name);
1170
1171     WriteTestMacros(srv_h);
1172     free(name);
1173 }
1174
1175 /*
1176  * WriteServTrailer -- finish up the server file
1177  */
1178 PRIVATE void
1179 WriteServTrailer(FILE * srv_h)
1180 {
1181
1182     fprintf(srv_h,
1183             "\nstatic long GetKey (char *rock, long kvno, struct ktc_encryptionKey *key) {\n"
1184             "\tmemcpy ((void *) key, (void *) &serviceKey, sizeof(*key));\n"
1185             "\treturn 0;\n" "}\n\n"
1186             "static void DoRun(struct cmd_syndesc *as, void *arock) {\n"
1187             "\tstruct rx_service *serv;\n"
1188             "\tstruct rx_securityClass *sc[3];\n\n"
1189             "\tint port=0, errflg=0;\n" "\tint lowThreads=4, highThreads=8;\n"
1190             "\tlowThreads = atoi(as->parms[0].items->data);\n"
1191             "\thighThreads = atoi(as->parms[1].items->data);\n"
1192             "\tport = atoi(as->parms[2].items->data);\n"
1193             "\tif (port == 0) errflg++;\n" "\tif (errflg) {\n"
1194             "\t\tprintf(\"invalid argument\\n\");\n" "\t\texit(1);\n" "\t}\n"
1195             "\trx_Init(htons(port));\n"
1196             "\tsc[0] = rxnull_NewServerSecurityObject();\n" "\tsc[1] = 0;\n"
1197             "\tsc[2] = rxkad_NewServerSecurityObject (rxkad_clear, 0, GetKey, 0);\n"
1198             "\tif (serv = rx_NewService(0,4,\"foo\",sc,3,AExecuteRequest)) {\n"
1199             "\t\trx_SetMinProcs(serv,lowThreads);\n"
1200             "\t\trx_SetMaxProcs(serv,highThreads);\n"
1201             "\t\trx_StartServer(1);\n" "\t}\n" "\texit(0);\n" "}\n\n"
1202             "static void SetupRunCmd(void) {\n" "\tstruct cmd_syndesc *ts;\n"
1203             "\tts = cmd_CreateSyntax(NULL,DoRun, NULL, \"run the test server program\");\n"
1204             "\tcmd_AddParm(ts, \"-lowThreadCount\", CMD_SINGLE, CMD_REQUIRED, \"minimum number of threads to spawn\");\n"
1205             "\tcmd_AddParm(ts, \"-highThreadCount\", CMD_SINGLE, CMD_REQUIRED, \"maximum number of threads to spawn\");\n"
1206             "\tcmd_AddParm(ts, \"-serverPort\", CMD_SINGLE, CMD_REQUIRED, \"port that server is using\");\n"
1207             "}\n" "int main(int argc, char **argv) {\n" "\tint code;\n"
1208             "\tinitialize_CMD_error_table();\n" "\tSetupRunCmd();\n"
1209             "\tcode = cmd_Dispatch(argc, argv);\n" "\treturn(code);\n" "}\n");
1210 }
1211
1212 /*
1213  * ProcessCmdLine -- processes the command line args
1214  */
1215 PRIVATE void
1216 ProcessCmdLine(int argc, char **argv, char **serverName, char **ipFileName,
1217                char **outputDir)
1218 {
1219     if (argc == 1) {
1220         PrintShortUsage;
1221         exit(1);
1222     }
1223     /* command line processing */
1224     while (--argc > 0) {
1225         if ((*++argv)[0] == '-') {
1226             switch ((*argv)[1]) {
1227
1228             case 'f':
1229             case 'F':           /* input table file */
1230                 *ipFileName = *++argv;
1231                 --argc;
1232                 break;
1233             case 'h':           /* display help */
1234             case 'H':
1235                 PrintLongUsage;
1236                 exit(0);
1237                 break;
1238             case 'l':
1239             case 'L':           /* use LWP threads */
1240                 threadModel = LWPS;
1241                 break;
1242             case 's':
1243             case 'S':           /* serverName */
1244                 *serverName = *++argv;
1245                 /* need 8 char file name, and so truncate the server name */
1246                 if ((int)strlen(*serverName) > MAX_SERV_NAME)
1247                     *(*serverName + MAX_SERV_NAME) = '\0';
1248                 --argc;
1249                 break;
1250             case 'o':
1251             case 'O':
1252                 *outputDir = *++argv;
1253                 --argc;
1254                 break;
1255             case 'p':
1256             case 'P':
1257                 if (strcmp(*++argv, "NT"))
1258                     platform = unix_symbols;
1259                 --argc;
1260                 break;
1261             default:
1262                 PrintLongUsage;
1263                 exit(1);
1264                 break;
1265             }
1266         } else {
1267             PrintShortUsage;
1268             exit(1);
1269         }
1270     }
1271     if (!*serverName)
1272         FATAL("Please set server name using -s switch\n");
1273 }
1274
1275
1276 void
1277 main(int argc, char **argv)
1278 {
1279     FILE *table_h, *srv_h, *xg_h, *clt_h, *mak_h;
1280     int i, j;
1281     rpcArgs args;
1282     char *name, *ifName;
1283     char *serverName = NULL;
1284     char *ipFileName = NULL;
1285     char *outputDir = NULL;
1286     int sign_no = 0, start_no, srv_no;
1287
1288     ProcessCmdLine(argc, argv, &serverName, &ipFileName, &outputDir);
1289
1290     /* open input file */
1291     table_h = fopen(ipFileName, "r");
1292     MEM_CHK(table_h, "main: Unable to open input file\n");
1293
1294     srv_no = 1;
1295     start_no = sign_no;
1296
1297     /*
1298      * open the first set of output files
1299      */
1300
1301     name = GetName(serverName, srv_no);
1302
1303     srv_h = OpenOutFile(outputDir, name, "Srv.c");
1304     xg_h = OpenOutFile(outputDir, name, ".xg");
1305     clt_h = OpenOutFile(outputDir, name, "Clt.c");
1306     mak_h = OpenOutFile(outputDir, name, ".mak");
1307
1308     WriteXGHeader(serverName, xg_h, srv_no);
1309     WriteServHeader(srv_h, serverName, srv_no);
1310     WriteCltHeader(serverName, srv_no, clt_h);
1311     WriteMake(serverName, srv_no, mak_h);
1312
1313     ifName = name;
1314
1315     /* read the table */
1316     while (fscanf(table_h, "%d", &(args.argCount)) != EOF) {
1317
1318         /* increment signature number 8.3 format-- only 10^7 dif sign */
1319         sign_no++;
1320         if (sign_no > 1.0e+7)
1321             FATAL("Max no: of signatures overflow\n");
1322
1323         /* allocate for the arg struct */
1324         args.argDescr =
1325             (arg_tuple *) calloc(args.argCount, sizeof(arg_tuple));
1326         MEM_CHK(args.argDescr, "main: Out of memory -- args.argDescr\n");
1327
1328         /* pick out the dirs and the types */
1329         for (i = 0; i < args.argCount; i++) {
1330             if (!fscanf
1331                 (table_h, " ( %s %s )", args.argDescr[i].direction,
1332                  args.argDescr[i].type)) {
1333                 FATAL("main: Incorrect input file format\n");
1334             }
1335         }
1336
1337         /*
1338          * switch files when we hit TESTS_PER_FILE
1339          */
1340         if (sign_no - start_no >= TESTS_PER_FILE) {
1341             /*
1342              * Finish up the current files
1343              */
1344             WriteServTrailer(srv_h);
1345             WriteCltTrailer(serverName, start_no, sign_no, clt_h);
1346             fclose(xg_h);
1347             fclose(srv_h);
1348             fclose(clt_h);
1349             fclose(mak_h);
1350
1351             /*
1352              * Open the next set of output files
1353              */
1354
1355             srv_no++;
1356             free(ifName);
1357             name = GetName(serverName, srv_no);
1358
1359             srv_h = OpenOutFile(outputDir, name, "Srv.c");
1360             xg_h = OpenOutFile(outputDir, name, ".xg");
1361             clt_h = OpenOutFile(outputDir, name, "Clt.c");
1362             mak_h = OpenOutFile(outputDir, name, ".mak");
1363             WriteXGHeader(serverName, xg_h, srv_no);
1364             WriteServHeader(srv_h, serverName, srv_no);
1365             WriteCltHeader(serverName, srv_no, clt_h);
1366             WriteMake(serverName, srv_no, mak_h);
1367
1368             start_no = sign_no;
1369             ifName = name;
1370         }
1371
1372         /* initialize parameter values */
1373         for (i = 0; i < args.argCount; i++) {
1374             for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++) {
1375                 args.argDescr[i].inValue[j] = NULL;
1376                 args.argDescr[i].inValue2[j] = NULL;
1377                 args.argDescr[i].outValue[j] = NULL;
1378                 args.argDescr[i].outValue2[j] = NULL;
1379             }
1380         }
1381         GenParamValues(&args);
1382
1383         /* write rpc desc into body of the interface */
1384         WriteXG(&args, xg_h, serverName, sign_no);
1385
1386         /* write the rpc into the manager file */
1387         WriteServC(&args, srv_h, serverName, sign_no);
1388
1389         /* write out ITL test */
1390         WriteClt(&args, serverName, sign_no, clt_h);
1391
1392         /* free saved values */
1393         for (i = 0; i < args.argCount; i++) {
1394             for (j = 0; j < IDL_FIX_ARRAY_SIZE; j++) {
1395                 if (args.argDescr[i].inValue[j])
1396                     free(args.argDescr[i].inValue[j]);
1397                 if (args.argDescr[i].inValue2[j])
1398                     free(args.argDescr[i].inValue2[j]);
1399                 if (args.argDescr[i].outValue[j])
1400                     free(args.argDescr[i].outValue[j]);
1401                 if (args.argDescr[i].outValue2[j])
1402                     free(args.argDescr[i].outValue2[j]);
1403             }
1404         }
1405         free(args.argDescr);
1406     }
1407
1408     WriteServTrailer(srv_h);
1409     WriteCltTrailer(serverName, start_no, (sign_no + 1), clt_h);
1410
1411     fclose(clt_h);
1412
1413     fclose(table_h);
1414     fclose(xg_h);
1415     fclose(srv_h);
1416     fclose(mak_h);
1417
1418     /*
1419      * create 1 makefile that drives all the rest
1420      */
1421
1422     mak_h = OpenOutFile(outputDir, "Makefile", "");
1423     fprintf(mak_h, "\ntest:all\ntests:all\nall:\n");
1424     fprintf(mak_h, "%s", platform[8]);
1425     for (i = 1; i <= srv_no; i++)
1426         fprintf(mak_h, "\t%s %s%d.mak %s\n", platform[0], serverName, i,
1427                 platform[5]);
1428     fprintf(mak_h, "\nclean:\n");
1429     for (i = 1; i <= srv_no; i++)
1430         fprintf(mak_h, "\t%s %s%d.mak clean\n", platform[0], serverName, i);
1431     fclose(mak_h);
1432
1433     exit(0);
1434 }