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