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