Release 0.4.0
[wine] / tools / build.c
1 static char RCSId[] = "$Id: build.c,v 1.3 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 #ifdef linux
10 #define UTEXTSEL 0x23
11 #endif
12 #ifdef __NetBSD__
13 #define UTEXTSEL 0x1f
14 #endif
15
16 #define VARTYPE_BYTE    0
17 #define VARTYPE_SIGNEDWORD      0
18 #define VARTYPE_WORD    1
19 #define VARTYPE_LONG    2
20 #define VARTYPE_FARPTR  3
21
22 #define FUNCTYPE_PASCAL 16
23 #define FUNCTYPE_C      17
24 #define FUNCTYPE_REG    19
25
26 #define EQUATETYPE_ABS  18
27 #define TYPE_RETURN     20
28
29 #define MAX_ORDINALS    1024
30
31 typedef struct ordinal_definition_s
32 {
33     int valid;
34     int type;
35     char export_name[80];
36     void *additional_data;
37 } ORDDEF;
38
39 typedef struct ordinal_variable_definition_s
40 {
41     int n_values;
42     int *values;
43 } ORDVARDEF;
44
45 typedef struct ordinal_function_definition_s
46 {
47     int n_args_16;
48     int arg_types_16[16];
49     int arg_16_offsets[16];
50     int arg_16_size;
51     char internal_name[80];
52     int n_args_32;
53     int arg_indices_32[16];
54 } ORDFUNCDEF;
55
56 typedef struct ordinal_return_definition_s
57 {
58     int arg_size;
59     int ret_value;
60 } ORDRETDEF;
61
62 ORDDEF OrdinalDefinitions[MAX_ORDINALS];
63
64 char LowerDLLName[80];
65 char UpperDLLName[80];
66 int Limit;
67 int DLLId;
68 FILE *SpecFp;
69
70 char *ParseBuffer = NULL;
71 char *ParseNext;
72 char ParseSaveChar;
73 int Line;
74
75 int IsNumberString(char *s)
76 {
77     while (*s != '\0')
78         if (!isdigit(*s++))
79             return 0;
80
81     return 1;
82 }
83
84 char *strlower(char *s)
85 {
86     char *p;
87     
88     for(p = s; *p != '\0'; p++)
89         *p = tolower(*p);
90
91     return s;
92 }
93
94 char *strupper(char *s)
95 {
96     char *p;
97     
98     for(p = s; *p != '\0'; p++)
99         *p = toupper(*p);
100
101     return s;
102 }
103
104 int stricmp(char *s1, char *s2)
105 {
106     if (strlen(s1) != strlen(s2))
107         return -1;
108     
109     while (*s1 != '\0')
110         if (*s1++ != *s2++)
111             return -1;
112     
113     return 0;
114 }
115
116 char *
117 GetTokenInLine(void)
118 {
119     char *p;
120     char *token;
121
122     if (ParseNext != ParseBuffer)
123     {
124         if (ParseSaveChar == '\0')
125             return NULL;
126         *ParseNext = ParseSaveChar;
127     }
128     
129     /*
130      * Remove initial white space.
131      */
132     for (p = ParseNext; isspace(*p); p++)
133         ;
134     
135     if (*p == '\0')
136         return NULL;
137     
138     /*
139      * Find end of token.
140      */
141     token = p++;
142     if (*token != '(' && *token != ')')
143         while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
144             p++;
145     
146     ParseSaveChar = *p;
147     ParseNext = p;
148     *p = '\0';
149
150     return token;
151 }
152
153 char *
154 GetToken(void)
155 {
156     char *token;
157
158     if (ParseBuffer == NULL)
159     {
160         ParseBuffer = malloc(512);
161         ParseNext = ParseBuffer;
162         Line++;
163         while (1)
164         {
165             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
166                 return NULL;
167             if (ParseBuffer[0] != '#')
168                 break;
169         }
170     }
171
172     while ((token = GetTokenInLine()) == NULL)
173     {
174         ParseNext = ParseBuffer;
175         Line++;
176         while (1)
177         {
178             if (fgets(ParseBuffer, 511, SpecFp) == NULL)
179                 return NULL;
180             if (ParseBuffer[0] != '#')
181                 break;
182         }
183     }
184
185     return token;
186 }
187
188 int
189 ParseVariable(int ordinal, int type)
190 {
191     ORDDEF *odp;
192     ORDVARDEF *vdp;
193     char export_name[80];
194     char *token;
195     char *endptr;
196     int *value_array;
197     int n_values;
198     int value_array_size;
199     
200     strcpy(export_name, GetToken());
201
202     token = GetToken();
203     if (*token != '(')
204     {
205         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
206         exit(1);
207     }
208
209     n_values = 0;
210     value_array_size = 25;
211     value_array = malloc(sizeof(*value_array) * value_array_size);
212     
213     while ((token = GetToken()) != NULL)
214     {
215         if (*token == ')')
216             break;
217
218         value_array[n_values++] = strtol(token, &endptr, 0);
219         if (n_values == value_array_size)
220         {
221             value_array_size += 25;
222             value_array = realloc(value_array, 
223                                   sizeof(*value_array) * value_array_size);
224         }
225         
226         if (endptr == NULL || *endptr != '\0')
227         {
228             fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
229                     token);
230             exit(1);
231         }
232     }
233     
234     if (token == NULL)
235     {
236         fprintf(stderr, "%d: End of file in variable declaration\n", Line);
237         exit(1);
238     }
239
240     if (ordinal >= MAX_ORDINALS)
241     {
242         fprintf(stderr, "%d: Ordinal number too large\n", Line);
243         exit(1);
244     }
245     
246     odp = &OrdinalDefinitions[ordinal];
247     odp->valid = 1;
248     odp->type = type;
249     strcpy(odp->export_name, export_name);
250     
251     vdp = malloc(sizeof(*vdp));
252     odp->additional_data = vdp;
253     
254     vdp->n_values = n_values;
255     vdp->values = realloc(value_array, sizeof(*value_array) * n_values);
256
257     return 0;
258 }
259
260 int
261 ParseExportFunction(int ordinal, int type)
262 {
263     char *token;
264     ORDDEF *odp;
265     ORDFUNCDEF *fdp;
266     int arg_types[16];
267     int i;
268     int arg_num;
269     int current_offset;
270     int arg_size;
271         
272     
273     if (ordinal >= MAX_ORDINALS)
274     {
275         fprintf(stderr, "%d: Ordinal number too large\n", Line);
276         exit(1);
277     }
278     
279     odp = &OrdinalDefinitions[ordinal];
280     strcpy(odp->export_name, GetToken());
281     odp->valid = 1;
282     odp->type = type;
283     fdp = malloc(sizeof(*fdp));
284     odp->additional_data = fdp;
285
286     token = GetToken();
287     if (*token != '(')
288     {
289         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
290         exit(1);
291     }
292
293     fdp->arg_16_size = 0;
294     for (i = 0; i < 16; i++)
295     {
296         token = GetToken();
297         if (*token == ')')
298             break;
299
300         if (stricmp(token, "byte") == 0 || stricmp(token, "word") == 0)
301         {
302             fdp->arg_types_16[i] = VARTYPE_WORD;
303             fdp->arg_16_size += 2;
304             fdp->arg_16_offsets[i] = 2;
305         }
306         else if (stricmp(token, "s_byte") == 0 || 
307                  stricmp(token, "s_word") == 0)
308         {
309             fdp->arg_types_16[i] = VARTYPE_SIGNEDWORD;
310             fdp->arg_16_size += 2;
311             fdp->arg_16_offsets[i] = 2;
312         }
313         else if (stricmp(token, "long") == 0 || stricmp(token, "s_long") == 0)
314         {
315             fdp->arg_types_16[i] = VARTYPE_LONG;
316             fdp->arg_16_size += 4;
317             fdp->arg_16_offsets[i] = 4;
318         }
319         else if (stricmp(token, "ptr") == 0)
320         {
321             fdp->arg_types_16[i] = VARTYPE_FARPTR;
322             fdp->arg_16_size += 4;
323             fdp->arg_16_offsets[i] = 4;
324         }
325         else
326         {
327             fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
328             exit(1);
329         }
330     }
331     fdp->n_args_16 = i;
332
333     if (type == FUNCTYPE_PASCAL || type == FUNCTYPE_REG)
334     {
335         current_offset = 0;
336         for (i--; i >= 0; i--)
337         {
338             arg_size = fdp->arg_16_offsets[i];
339             fdp->arg_16_offsets[i] = current_offset;
340             current_offset += arg_size;
341         }
342     }
343     else
344     {
345         current_offset = 0;
346         for (i = 0; i < fdp->n_args_16; i++)
347         {
348             arg_size = fdp->arg_16_offsets[i];
349             fdp->arg_16_offsets[i] = current_offset;
350             current_offset += arg_size;
351         }
352     }
353
354     strcpy(fdp->internal_name, GetToken());
355     token = GetToken();
356     if (*token != '(')
357     {
358         fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
359         exit(1);
360     }
361     for (i = 0; i < 16; i++)
362     {
363         token = GetToken();
364         if (*token == ')')
365             break;
366
367         fdp->arg_indices_32[i] = atoi(token);
368         if (fdp->arg_indices_32[i] < 1 || 
369             fdp->arg_indices_32[i] > fdp->n_args_16)
370         {
371             fprintf(stderr, "%d: Bad argument index %d\n", Line,
372                     fdp->arg_indices_32[i]);
373             exit(1);
374         }
375     }
376     fdp->n_args_32 = i;
377
378     return 0;
379 }
380
381 int
382 ParseEquate(int ordinal)
383 {
384     ORDDEF *odp;
385     char *token;
386     char *endptr;
387     int value;
388     
389     if (ordinal >= MAX_ORDINALS)
390     {
391         fprintf(stderr, "%d: Ordinal number too large\n", Line);
392         exit(1);
393     }
394     
395     odp = &OrdinalDefinitions[ordinal];
396     strcpy(odp->export_name, GetToken());
397
398     token = GetToken();
399     value = strtol(token, &endptr, 0);
400     if (endptr == NULL || *endptr != '\0')
401     {
402         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
403                 token);
404         exit(1);
405     }
406
407     odp->valid = 1;
408     odp->type = EQUATETYPE_ABS;
409     odp->additional_data = (void *) value;
410
411     return 0;
412 }
413
414 int
415 ParseReturn(int ordinal)
416 {
417     ORDDEF *odp;
418     ORDRETDEF *rdp;
419     char *token;
420     char *endptr;
421     int value;
422     
423     if (ordinal >= MAX_ORDINALS)
424     {
425         fprintf(stderr, "%d: Ordinal number too large\n", Line);
426         exit(1);
427     }
428
429     rdp = malloc(sizeof(*rdp));
430     
431     odp = &OrdinalDefinitions[ordinal];
432     strcpy(odp->export_name, GetToken());
433     odp->valid = 1;
434     odp->type = TYPE_RETURN;
435     odp->additional_data = rdp;
436
437     token = GetToken();
438     rdp->arg_size = strtol(token, &endptr, 0);
439     if (endptr == NULL || *endptr != '\0')
440     {
441         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
442                 token);
443         exit(1);
444     }
445
446     token = GetToken();
447     rdp->ret_value = strtol(token, &endptr, 0);
448     if (endptr == NULL || *endptr != '\0')
449     {
450         fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
451                 token);
452         exit(1);
453     }
454
455     return 0;
456 }
457
458 int
459 ParseOrdinal(int ordinal)
460 {
461     char *token;
462     
463     token = GetToken();
464     if (token == NULL)
465     {
466         fprintf(stderr, "%d: Expected type after ordinal\n", Line);
467         exit(1);
468     }
469
470     if (stricmp(token, "byte") == 0)
471         return ParseVariable(ordinal, VARTYPE_BYTE);
472     else if (stricmp(token, "word") == 0)
473         return ParseVariable(ordinal, VARTYPE_WORD);
474     else if (stricmp(token, "long") == 0)
475         return ParseVariable(ordinal, VARTYPE_LONG);
476     else if (stricmp(token, "c") == 0)
477         return ParseExportFunction(ordinal, FUNCTYPE_C);
478     else if (stricmp(token, "p") == 0)
479         return ParseExportFunction(ordinal, FUNCTYPE_PASCAL);
480     else if (stricmp(token, "pascal") == 0)
481         return ParseExportFunction(ordinal, FUNCTYPE_PASCAL);
482     else if (stricmp(token, "register") == 0)
483         return ParseExportFunction(ordinal, FUNCTYPE_REG);
484     else if (stricmp(token, "equate") == 0)
485         return ParseEquate(ordinal);
486     else if (stricmp(token, "return") == 0)
487         return ParseReturn(ordinal);
488     else
489     {
490         fprintf(stderr, 
491                 "%d: Expected type after ordinal, found '%s' instead\n",
492                 Line, token);
493         exit(1);
494     }
495 }
496
497 int
498 ParseTopLevel(void)
499 {
500     char *token;
501     
502     while ((token = GetToken()) != NULL)
503     {
504         if (stricmp(token, "name") == 0)
505         {
506             strcpy(LowerDLLName, GetToken());
507             strlower(LowerDLLName);
508
509             strcpy(UpperDLLName, LowerDLLName);
510             strupper(UpperDLLName);
511         }
512         else if (stricmp(token, "id") == 0)
513         {
514             token = GetToken();
515             if (!IsNumberString(token))
516             {
517                 fprintf(stderr, "%d: Expected number after id\n", Line);
518                 exit(1);
519             }
520             
521             DLLId = atoi(token);
522         }
523         else if (stricmp(token, "length") == 0)
524         {
525             token = GetToken();
526             if (!IsNumberString(token))
527             {
528                 fprintf(stderr, "%d: Expected number after length\n", Line);
529                 exit(1);
530             }
531
532             Limit = atoi(token);
533         }
534         else if (IsNumberString(token))
535         {
536             int ordinal;
537             int rv;
538             
539             ordinal = atoi(token);
540             if ((rv = ParseOrdinal(ordinal)) < 0)
541                 return rv;
542         }
543         else
544         {
545             fprintf(stderr, 
546                     "%d: Expected name, id, length or ordinal\n", Line);
547             exit(1);
548         }
549     }
550
551     return 0;
552 }
553
554 void
555 OutputVariableCode(FILE *fp, char *storage, ORDDEF *odp)
556 {
557     ORDVARDEF *vdp;
558     int i;
559
560     fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
561
562     vdp = odp->additional_data;
563     for (i = 0; i < vdp->n_values; i++)
564     {
565         if ((i & 7) == 0)
566             fprintf(fp, "\t%s\t", storage);
567             
568         fprintf(fp, "%d", vdp->values[i]);
569         
570         if ((i & 7) == 7 || i == vdp->n_values - 1)
571             fprintf(fp, "\n");
572         else
573             fprintf(fp, ", ");
574     }
575     fprintf(fp, "\n");
576 }
577
578 main(int argc, char **argv)
579 {
580     ORDDEF *odp;
581     ORDFUNCDEF *fdp;
582     ORDRETDEF *rdp;
583     FILE *fp;
584     char filename[80];
585     char buffer[80];
586     char *p;
587     int i;
588     
589     if (argc < 2)
590     {
591         fprintf(stderr, "usage: build SPECNAME\n");
592         exit(1);
593     }
594
595     SpecFp = fopen(argv[1], "r");
596     if (SpecFp == NULL)
597     {
598         fprintf(stderr, "Could not open specification file, '%s'\n", argv[1]);
599         exit(1);
600     }
601
602     ParseTopLevel();
603
604     sprintf(filename, "dll_%s.S", LowerDLLName);
605     fp = fopen(filename, "w");
606
607     fprintf(fp, "\t.globl _%s_Dispatch\n", UpperDLLName);
608     fprintf(fp, "_%s_Dispatch:\n", UpperDLLName);
609     fprintf(fp, "\torl\t$0x%08x,%%eax\n", DLLId << 16);
610     fprintf(fp, "\tjmp\t_CallTo32\n\n");
611
612     odp = OrdinalDefinitions;
613     for (i = 0; i <= Limit; i++, odp++)
614     {
615         fprintf(fp, "\t.globl _%s_Ordinal_%d\n", UpperDLLName, i);
616
617         if (!odp->valid)
618         {
619             fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
620             fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n");
621             fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n");
622             fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
623             fprintf(fp, "\tpushw\t$0\n");
624             fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
625         }
626         else
627         {
628             fdp = odp->additional_data;
629             rdp = odp->additional_data;
630             
631             switch (odp->type)
632             {
633               case EQUATETYPE_ABS:
634                 fprintf(fp, "_%s_Ordinal_%d = %d\n\n", 
635                         UpperDLLName, i, (int) odp->additional_data);
636                 break;
637
638               case VARTYPE_BYTE:
639                 OutputVariableCode(fp, ".byte", odp);
640                 break;
641
642               case VARTYPE_WORD:
643                 OutputVariableCode(fp, ".word", odp);
644                 break;
645
646               case VARTYPE_LONG:
647                 OutputVariableCode(fp, ".long", odp);
648                 break;
649
650               case TYPE_RETURN:
651                 fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
652                 fprintf(fp, "\tmovw\t$%d,%%ax\n", rdp->ret_value & 0xffff);
653                 fprintf(fp, "\tmovw\t$%d,%%dx\n", 
654                         (rdp->ret_value >> 16) & 0xffff);
655                 fprintf(fp, "\t.byte\t0x66\n");
656                 if (rdp->arg_size != 0)
657                     fprintf(fp, "\tlret\t$%d\n", rdp->arg_size);
658                 else
659                     fprintf(fp, "\tlret\n");
660                 break;
661
662               case FUNCTYPE_REG:
663                 fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
664                 fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n");
665                 fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n");
666                 fprintf(fp, "\tpushw\t%%ax\n");
667                 fprintf(fp, "\tpushw\t%%cx\n");
668                 fprintf(fp, "\tpushw\t%%dx\n");
669                 fprintf(fp, "\tpushw\t%%bx\n");
670                 fprintf(fp, "\tpushw\t%%sp\n");
671                 fprintf(fp, "\tpushw\t%%bp\n");
672                 fprintf(fp, "\tpushw\t%%si\n");
673                 fprintf(fp, "\tpushw\t%%di\n");
674                 fprintf(fp, "\tpushw\t%%ds\n");
675                 fprintf(fp, "\tpushw\t%%es\n");
676                 fprintf(fp, "\tmovl\t%%ebp,%%eax\n");
677                 fprintf(fp, "\tmovw\t%%esp,%%ebp\n");
678                 fprintf(fp, "\tpushl\t20(%%ebp)\n");
679                 fprintf(fp, "\tmovl\t%%eax,%%ebp\n");
680                 fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
681                 fprintf(fp, "\tpushw\t$24\n");
682                 fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
683                 break;
684
685               case FUNCTYPE_PASCAL:
686                 fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
687                 fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n");
688                 fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n");
689                 fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
690                 fprintf(fp, "\tpushw\t$%d\n", fdp->arg_16_size);
691                 fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
692                 break;
693                 
694               case FUNCTYPE_C:
695               default:
696                 fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i);
697                 fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n");
698                 fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n");
699                 fprintf(fp, "\tmovl\t$%d,%%eax\n", i);
700                 fprintf(fp, "\tpushw\t$0\n");
701                 fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName);
702                 break;
703             }
704         }
705     }
706
707     fclose(fp);
708
709     sprintf(filename, "dll_%s_tab.c", LowerDLLName);
710     fp = fopen(filename, "w");
711
712     fprintf(fp, "#include <stdio.h>\n");
713     fprintf(fp, "#include <stdlib.h>\n");
714     fprintf(fp, "#include \042dlls.h\042\n\n");
715
716     for (i = 0; i <= Limit; i++)
717     {
718         fprintf(fp, "extern void %s_Ordinal_%d();\n", UpperDLLName, i);
719     }
720     
721     odp = OrdinalDefinitions;
722     for (i = 0; i <= Limit; i++, odp++)
723     {
724         if (odp->valid && 
725             (odp->type == FUNCTYPE_PASCAL || odp->type == FUNCTYPE_C ||
726              odp->type == FUNCTYPE_REG))
727         {
728             fdp = odp->additional_data;
729             fprintf(fp, "extern int %s();\n", fdp->internal_name);
730         }
731     }
732     
733     fprintf(fp, "\nstruct dll_table_entry_s %s_table[%d] =\n", 
734             UpperDLLName, Limit + 1);
735     fprintf(fp, "{\n");
736     odp = OrdinalDefinitions;
737     for (i = 0; i <= Limit; i++, odp++)
738     {
739         fdp = odp->additional_data;
740
741         if (!odp->valid)
742             odp->type = -1;
743         
744         switch (odp->type)
745         {
746           case FUNCTYPE_PASCAL:
747           case FUNCTYPE_REG:
748             fprintf(fp, "    { 0x%x, %s_Ordinal_%d, ", UTEXTSEL, UpperDLLName, i);
749             fprintf(fp, "\042%s\042, ", odp->export_name);
750             fprintf(fp, "%s, DLL_HANDLERTYPE_PASCAL, ", fdp->internal_name);
751 #ifdef WINESTAT
752             fprintf(fp, "0, ");
753 #endif      
754             fprintf(fp, "%d, ", fdp->n_args_32);
755             if (fdp->n_args_32 > 0)
756             {
757                 int argnum;
758                 
759                 fprintf(fp, "\n      {\n");
760                 for (argnum = 0; argnum < fdp->n_args_32; argnum++)
761                 {
762                     fprintf(fp, "        { %d, %d },\n",
763                             fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1],
764                             fdp->arg_types_16[argnum]);
765                 }
766                 fprintf(fp, "      }\n    ");
767             }
768             fprintf(fp, "}, \n");
769             break;
770                 
771           case FUNCTYPE_C:
772             fprintf(fp, "    { 0x%x, %s_Ordinal_%d, ", UTEXTSEL, UpperDLLName, i);
773             fprintf(fp, "\042%s\042, ", odp->export_name);
774             fprintf(fp, "%s, DLL_HANDLERTYPE_C, ", fdp->internal_name);
775 #ifdef WINESTAT
776             fprintf(fp, "0, ");
777 #endif      
778             fprintf(fp, "%d, ", fdp->n_args_32);
779             if (fdp->n_args_32 > 0)
780             {
781                 int argnum;
782                 
783                 fprintf(fp, "\n      {\n");
784                 for (argnum = 0; argnum < fdp->n_args_32; argnum++)
785                 {
786                     fprintf(fp, "        { %d, %d },\n",
787                             fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1],
788                             fdp->arg_types_16[argnum]);
789                 }
790                 fprintf(fp, "      }\n    ");
791             }
792             fprintf(fp, "}, \n");
793             break;
794             
795           default:
796             fprintf(fp, "    { 0x%x, %s_Ordinal_%d, \042\042, NULL },\n", 
797                     UTEXTSEL, UpperDLLName, i);
798             break;
799         }
800     }
801     fprintf(fp, "};\n");
802
803     fclose(fp);
804 }
805