source: vendor/emx/current/src/emxbind/emxbind.c

Last change on this file was 18, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 18.7 KB
Line 
1/* emxbind.c -- Create an .exe executable from an a.out executable
2 Copyright (c) 1991-1997 Eberhard Mattes
3
4This file is part of emxbind.
5
6emxbind is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxbind is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxbind; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#define EXTERN
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <sys/moddef.h>
29#include "defs.h"
30#include "emxbind.h"
31
32
33/* The name of the module definition file (set by the -d option) or
34 NULL (if there is no module definition file). If it's the empty
35 string, the input file name with .def extension will be used. */
36
37static char *opt_d = NULL;
38
39/* The banner line of emxbind. */
40
41static char *title = "emxbind " VERSION " -- "
42 "Copyright (c) 1991-1997 by Eberhard Mattes";
43
44/* These strings contain the valid option letters of the DOS and OS/2
45 versions of emx, respectively. Depending on the string in which an
46 option is found, the option is put into the DOS or OS/2 emxbind
47 header. Option letters which don't appear in any of the strings
48 are invalid. */
49
50static char *valid_dos_options = "CLRZacdehopqst";
51static char *valid_os2_options = "EKchnqtx";
52
53/* File names of various files. inp_fname holds the name of the input
54 executable, emx_fname the name of the emxl.exe or emx.exe file, and
55 def_fname the name of the module definition file (-d option). */
56
57static char inp_fname[FNAME_SIZE];
58static char emx_fname[FNAME_SIZE];
59static char def_fname[FNAME_SIZE];
60
61/* These global variables have the same values as the argc and argv
62 parameters, respectively, of main(). */
63
64static int gargc;
65static char **gargv;
66
67/* Automatically locate emxl.exe if this flag is true. Otherwise, use
68 the path name given on the command line. */
69
70static int auto_emxl = FALSE;
71
72/* The file name given by the STUB statement. */
73
74static char *stub_fname = NULL;
75
76
77/* Give the user a short reminder about how to call this program. */
78
79static void usage (void)
80{
81 puts (title);
82 puts ("\nUsage:");
83 puts (" emxbind [-b] [<options>] <emx>[.exe] <input> [<output>[.exe]] [<emx_opt>]");
84 puts (" emxbind [-b] [<options>] [-o <output>[.exe]] <input> [<emx_opt>]");
85 puts (" emxbind -u [<options>] <emx>[.exe] <input>[.exe]");
86 puts (" emxbind -e [<options>] <input>[.exe]");
87 puts (" emxbind -s [<options>] <input>[.exe]");
88 puts (" emxbind -x [<options>] <input>[.exe] <output>");
89 puts (" emxbind -i [<options>] <input>[.exe]");
90 puts (" emxbind -a [<options>] <input>[.exe] [<emx_opt>]");
91#if LIST_OPT
92 puts (" emxbind -L [<options>] <input>[.exe]");
93#endif
94 puts ("\nCommands:");
95 puts (" -b bind .exe (default)");
96 puts (" -u update emx in .exe");
97 puts (" -e set OS/2 .exe flags: -f, -p or -w");
98 puts (" -s strip symbols");
99 puts (" -x extract a.out");
100 puts (" -i show options");
101 puts (" -a alter options");
102#if LIST_OPT
103 puts (" -L list headers");
104#endif
105 puts ("\nOptions:");
106 puts (" -f application type: full screen (-b and -e)");
107 puts (" -p application type: Presentation Manager (-b and -e)");
108 puts (" -w application type: windowed (-b and -e)");
109 puts (" -q be quiet");
110 puts (" -v be verbose");
111 puts (" -s strip symbols (-b only)");
112 puts (" -C use old method for creating preloaded executables");
113 puts (" -c[<core>] add data from core dump file (-b only)");
114 puts (" -d[<def>] read module definition file (-b only)");
115 puts (" -E<dll> use <dll> instead of emx.dll (-b only)");
116 puts (" -h<size> set heap size for OS/2 (-b only)");
117 puts (" -k<size> set stack size for OS/2 (-b only)");
118 puts (" -m<map> write .map file (-b only)");
119 puts (" -r<res> add resources (-b only)");
120 exit (1);
121}
122
123
124/* A module statement is ignored: display a warning message if the
125 verbosity level is high enough. */
126
127static void def_ignored (const char *name)
128{
129 if (verbosity >= 2)
130 printf ("emxbind: %s statement not supported (warning)\n", name);
131}
132
133
134/* Callback function for reading the module definition file. Display
135 a warning for ignored statements if the verbosity level is high
136 enough. Save data from the other statements. */
137
138static int md_callback (struct _md *md, const _md_stmt *stmt, _md_token token,
139 void *arg)
140{
141 struct export exp;
142
143 switch (token)
144 {
145 case _MD_BASE:
146 def_ignored ("BASE");
147 break;
148
149 case _MD_CODE:
150 def_ignored ("CODE");
151 break;
152
153 case _MD_DATA:
154 def_ignored ("DATA");
155 break;
156
157 case _MD_DESCRIPTION:
158
159 /* Save the description string for putting it into the
160 non-resident name table. */
161
162 description = xstrdup (stmt->descr.string);
163 break;
164
165 case _MD_EXETYPE:
166 def_ignored ("EXETYPE");
167 break;
168
169 case _MD_EXPORTS:
170
171 /* Add an export entry. */
172
173 exp.ord = stmt->export.ordinal;
174 exp.resident = (stmt->export.flags & _MDEP_RESIDENTNAME) ? TRUE : FALSE;
175 exp.entryname = xstrdup (stmt->export.entryname);
176 if (stmt->export.internalname[0] != 0)
177 exp.internalname = xstrdup (stmt->export.internalname);
178 else
179 exp.internalname = xstrdup (stmt->export.entryname);
180 exp.offset = 0;
181 exp.object = 0;
182 add_export (&exp);
183 break;
184
185 case _MD_HEAPSIZE:
186 def_ignored ("HEAPSIZE");
187 break;
188
189 case _MD_IMPORTS:
190 def_ignored ("IMPORTS");
191 break;
192
193 case _MD_LIBRARY:
194
195 /* Create a DLL. Save the initialization and termination
196 policies after choosing default values for unspecified
197 values. */
198
199 dll_flag = TRUE;
200 switch (stmt->library.init)
201 {
202 case _MDIT_GLOBAL:
203 init_global = TRUE;
204 break;
205 case _MDIT_INSTANCE:
206 init_global = FALSE;
207 break;
208 default:
209 break;
210 }
211 switch (stmt->library.term)
212 {
213 case _MDIT_GLOBAL:
214 term_global = TRUE;
215 break;
216 case _MDIT_INSTANCE:
217 term_global = FALSE;
218 break;
219 default:
220 break;
221 }
222 if (stmt->library.init != _MDIT_DEFAULT
223 && stmt->library.term == _MDIT_DEFAULT)
224 term_global = init_global;
225 if (stmt->library.term != _MDIT_DEFAULT
226 && stmt->library.init == _MDIT_DEFAULT)
227 init_global = term_global;
228 break;
229
230 case _MD_NAME:
231
232 /* Create a program. Save the module name and the application
233 type. */
234
235 if (stmt->name.name[0] != 0)
236 module_name = xstrdup (stmt->name.name);
237 app_type = stmt->name.pmtype;
238 break;
239
240 case _MD_OLD:
241 def_ignored ("OLD");
242 break;
243
244 case _MD_PROTMODE:
245 def_ignored ("PROTMODE");
246 break;
247
248 case _MD_REALMODE:
249 def_ignored ("REALMODE");
250 break;
251
252 case _MD_SEGMENTS:
253 def_ignored ("SEGMENTS");
254 break;
255
256 case _MD_STACKSIZE:
257
258 /* Check and save the stack size. */
259
260 if (stmt->stacksize.size < 20*1024
261 || stmt->stacksize.size > 512*1024*1024)
262 error ("Invalid stack size in module definition file");
263 stack_size = (stmt->stacksize.size + 0xfff) & ~0xfff;
264 break;
265
266 case _MD_STUB:
267
268 /* Save the name of the stub. */
269
270 if (!stmt->stub.none)
271 stub_fname = xstrdup (stmt->stub.name);
272 break;
273
274 case _MD_VIRTUAL:
275 case _MD_PHYSICAL:
276 error ("VIRTUAL DEVICE and PHYSICAL DEVICE statements not supported");
277
278 case _MD_parseerror:
279
280 /* Handle a syntax error. */
281
282 error ("%s (line %ld of %s)", _md_errmsg (stmt->error.code),
283 _md_get_linenumber (md), def_fname);
284 break;
285
286 default:
287 abort ();
288 }
289 return 0;
290}
291
292
293/* Read the module definition file. */
294
295static void read_def_file (void)
296{
297 struct _md *md;
298
299 md = _md_open (def_fname);
300 if (md == NULL)
301 error ("cannot open `%s'", def_fname);
302 _md_next_token (md);
303 _md_parse (md, md_callback, NULL);
304 _md_close (md);
305}
306
307
308/* Fetch a file name from the command line. If there are no more
309 arguments or if the current argument looks like an option, don't
310 use an argument and use the default file name DEF instead. If DEF
311 is NULL, a file name must be provided. If EXT is non-NULL, it is
312 used as default extension. This function will update optind if it
313 uses an argument. */
314
315static void file_name (char *dst, const char *ext, const char *def)
316{
317 if (optind < gargc && gargv[optind][0] != '-')
318 {
319 if (strlen (gargv[optind]) > FNAME_SIZE - 5)
320 error ("file name too long");
321 strcpy (dst, gargv[optind]);
322 ++optind;
323 }
324 else if (def == NULL)
325 error ("file name missing");
326 else
327 {
328 strcpy (dst, def);
329 if (ext != NULL)
330 _remext (dst);
331 }
332 if (ext != NULL)
333 _defext (dst, ext);
334}
335
336
337/* Scan the remaining command line arguments as emx options and store
338 them to options_for_dos and options_for_os2. */
339
340static void emx_options (void)
341{
342 char c;
343 int dos_flag, os2_flag;
344 int i, index_dos, index_os2;
345 char *array_dos[100];
346 char *array_os2[100];
347
348 /* Collect the options in array_dos and array_os2. */
349
350 index_dos = index_os2 = 0;
351 while (optind < gargc)
352 {
353 if (gargv[optind][0] != '-')
354 error ("emx option expected");
355 c = gargv[optind][1];
356 dos_flag = (strchr (valid_dos_options, c) != NULL);
357 os2_flag = (strchr (valid_os2_options, c) != NULL);
358 if (!dos_flag && !os2_flag)
359 {
360 if (verbosity > 0) puts (title);
361 error ("invalid emx option: %s", gargv[optind]);
362 }
363 if (dos_flag)
364 {
365 for (i = 0; i < index_dos; ++i)
366 if (memcmp (array_dos[i], gargv[optind],
367 gargv[optind][1] == 'R' ? 3 : 2) == 0)
368 break;
369 if (i >= index_dos)
370 i = index_dos++;
371 array_dos[i] = gargv[optind];
372 }
373 if (os2_flag)
374 {
375 for (i = 0; i < index_os2; ++i)
376 if (memcmp (array_os2[i], gargv[optind], 2) == 0)
377 break;
378 if (i >= index_os2)
379 i = index_os2++;
380 array_os2[i] = gargv[optind];
381 }
382 ++optind;
383 }
384
385 /* Concatenate the options for DOS. */
386
387 options_for_dos[0] = 0;
388 for (i = 0; i < index_dos; ++i)
389 {
390 if (strlen (options_for_dos) + strlen (array_dos[i])
391 > sizeof (options_for_dos) - 3)
392 {
393 if (verbosity > 0) puts (title);
394 error ("too many emx options for MS-DOS");
395 }
396 if (options_for_dos[0] != 0)
397 strcat (options_for_dos, " ");
398 strcat (options_for_dos, array_dos[i]);
399 }
400
401 /* Concatenate the options for OS/2. */
402
403 options_for_os2[0] = 0;
404 for (i = 0; i < index_os2; ++i)
405 {
406 if (strlen (options_for_os2) + strlen (array_os2[i])
407 > sizeof (options_for_os2) - 3)
408 {
409 if (verbosity > 0) puts (title);
410 error ("too many emx options for OS/2");
411 }
412 if (options_for_os2[0] != 0)
413 strcat (options_for_os2, " ");
414 strcat (options_for_os2, array_os2[i]);
415 }
416}
417
418
419/* Parse the command line. */
420
421static void get_args (void)
422{
423 int c;
424 char *q;
425 const char *opt_o = NULL;
426
427 /* At least one argument, the command option, must be supplied. */
428
429 if (gargc <= 1)
430 usage ();
431
432 /* Don't let getopt() report errors, use `-' to introduce options. */
433
434 opterr = FALSE;
435 optswchar = "-";
436
437 /* No command option has been seen yet. */
438
439 mode = 0;
440
441 /* Examine the initial (emxbind) options, one by one. */
442
443 while ((c = getopt (gargc, gargv,
444 "abc::Cd::eE:fh:ik:lLm:o:pqr:suvwx")) != -1)
445 {
446 switch (c)
447 {
448 case 's':
449 if (mode == 'b')
450 {
451 opt_s = TRUE;
452 break;
453 }
454 /*NOBREAK*/
455 case 'a':
456 case 'b':
457 case 'e':
458#if LIST_OPT
459 case 'L':
460#endif
461 case 'i':
462 case 'u':
463 case 'x':
464 if (mode != 0)
465 error ("multiple commands specified");
466 mode = c;
467 break;
468 case 'c':
469 if (opt_c != NULL)
470 error ("multiple core files");
471 opt_c = (optarg != NULL ? optarg : "");
472 break;
473 case 'C':
474 old_heap = TRUE;
475 break;
476 case 'd':
477 if (opt_d != NULL)
478 error ("multiple module definition files");
479 opt_d = (optarg != NULL ? optarg : "");
480 break;
481 case 'E':
482 if (emx_dll != NULL)
483 error ("multiple -E options");
484 emx_dll = optarg;
485 break;
486 case 'f':
487 opt_f = TRUE;
488 break;
489 case 'h':
490 errno = 0;
491 heap_size = strtol (optarg, &q, 0);
492 if (errno != 0 || heap_size < 0 || heap_size > 512 || *q != 0)
493 error ("invalid heap size");
494 heap_size *= 1024*1024;
495 break;
496 case 'k':
497 errno = 0;
498 stack_size = strtol (optarg, &q, 0);
499 if (errno != 0 || *q != 0 ||
500 (stack_size < 20 || stack_size > 512*1024))
501 error ("invalid stack size");
502 stack_size *= 1024;
503 stack_size = (stack_size + 0xfff) & ~0xfff;
504 break;
505 case 'm':
506 if (opt_m != NULL)
507 error ("multiple map files");
508 opt_m = optarg;
509 break;
510 case 'o':
511 if (opt_o != NULL)
512 error ("multiple output files");
513 opt_o = optarg;
514 break;
515 case 'p':
516 opt_p = TRUE;
517 break;
518 case 'q':
519 verbosity = 0;
520 break;
521 case 'r':
522 opt_r = optarg;
523 break;
524 case 'v':
525 verbosity = 2;
526 break;
527 case 'w':
528 opt_w = TRUE;
529 break;
530 default:
531 error ("invalid option");
532 }
533 }
534
535 /* The default command option is -b. */
536
537 if (mode == 0)
538 mode = 'b';
539
540 /* Complain if an illegal combination of options is used. */
541
542 if (opt_o != NULL && mode != 'b')
543 error ("-o option can be used only with -b command");
544 if (opt_c != NULL && mode != 'b')
545 error ("-c option can be used only with -b command");
546 if ((opt_f || opt_p || opt_w) && mode != 'b' && mode != 'e')
547 error ("-f, -p and -w options can be used only with -b and -e commands");
548 if (opt_f + opt_p + opt_w > TRUE)
549 error ("more than one of -f, -p and -w options given");
550 if (mode == 'e' && !(opt_p || opt_f || opt_w))
551 error ("-e command requires -f, -p or -w option");
552 if (opt_d != NULL && mode != 'b')
553 error ("-d option can be used only with -b command");
554
555 /* If the -c option is used without argument, "core" will be used as
556 core dump file. */
557
558 if (opt_c != NULL && *opt_c == 0)
559 opt_c = "core";
560
561 /* If the -E option is not given and the name is not given by the
562 EMXBIND_DLL environment variable, "emx.dll" will be used. */
563
564 if (emx_dll == NULL)
565 emx_dll = getenv ("EMXBIND_DLL");
566 if (emx_dll == NULL)
567 emx_dll = "emx";
568
569 /* Parse the rest of the command line, depending on the command
570 option. */
571
572 switch (mode)
573 {
574 case 'a':
575 file_name (inp_fname, "exe", NULL);
576 emx_options ();
577 break;
578
579 case 'b':
580 if (gargc - optind <= 1 || gargv[optind+1][0] == '-')
581 auto_emxl = TRUE;
582 else if (opt_o != NULL)
583 error ("Too many file names specified");
584 else
585 file_name (emx_fname, "exe", NULL);
586 file_name (inp_fname, NULL, NULL);
587 if (opt_d != NULL)
588 {
589 if (opt_d[0] == 0)
590 {
591 _strncpy (def_fname, inp_fname, sizeof (def_fname) - 4);
592 _remext (def_fname);
593 }
594 else
595 _strncpy (def_fname, opt_d, sizeof (def_fname) - 4);
596 _defext (def_fname, "def");
597 read_def_file ();
598 }
599 if (auto_emxl)
600 {
601 if (stub_fname != NULL)
602 {
603 if (_path (emx_fname, stub_fname) != 0)
604 _strncpy (emx_fname, stub_fname, sizeof (emx_fname));
605 auto_emxl = FALSE;
606 }
607 else
608 {
609 strcpy (emx_fname, "\\emx\\bin\\emxl.exe");
610 if (!my_readable (emx_fname))
611 if (_path (emx_fname, "emxl.exe") != 0)
612 strcpy (emx_fname, "emxl.exe");
613 auto_emxl = TRUE;
614 }
615 }
616 file_name (out_fname, (dll_flag ? "dll" : "exe"),
617 (opt_o != NULL ? opt_o : inp_fname));
618 if (_fncmp (inp_fname, out_fname) == 0)
619 error ("The input and output files have the same name");
620 emx_options ();
621 break;
622
623 case 'e':
624 case 'L':
625 case 'i':
626 case 's':
627 file_name (inp_fname, "exe", NULL);
628 break;
629
630 case 'u':
631 file_name (emx_fname, "exe", NULL);
632 file_name (inp_fname, "exe", NULL);
633 break;
634
635 case 'x':
636 file_name (inp_fname, "exe", NULL);
637 file_name (out_fname, NULL, NULL);
638 if (_fncmp (inp_fname, out_fname) == 0)
639 error ("The input and output files have the same name");
640 break;
641 }
642
643 /* Complain if there are any unprocessed arguments left. */
644
645 if (optind < gargc)
646 error ("too many arguments");
647}
648
649
650static void cleanup (void)
651{
652 my_remove (&out_file);
653}
654
655
656/* Open the files, depending on the command option. The module
657 definition file (-d option) is not handled here. */
658
659static void open_files (void)
660{
661 atexit (cleanup);
662 switch (mode)
663 {
664 case 'a':
665 case 'e':
666 case 's':
667 my_open (&inp_file, inp_fname, open_read_write);
668 break;
669 case 'b':
670 my_open (&inp_file, inp_fname, open_read);
671 my_open (&emx_file, emx_fname, open_read);
672 if (opt_c != NULL)
673 my_open (&core_file, opt_c, open_read);
674 if (opt_r != NULL)
675 my_open (&res_file, opt_r, open_read);
676 my_open (&out_file, out_fname, create_write);
677 break;
678 case 'L':
679 case 'i':
680 my_open (&inp_file, inp_fname, open_read);
681 break;
682 case 'u':
683 my_open (&inp_file, inp_fname, open_read_write);
684 my_open (&emx_file, emx_fname, open_read);
685 break;
686 case 'x':
687 my_open (&inp_file, inp_fname, open_read);
688 my_open (&out_file, out_fname, create_write);
689 break;
690 }
691}
692
693
694/* Close all the open files. */
695
696static void close_files (void)
697{
698 my_close (&out_file);
699 my_close (&inp_file);
700 my_close (&emx_file);
701 my_close (&core_file);
702 my_close (&res_file);
703}
704
705
706/* This is the main function. Parse the command line and perform the
707 action requested by the user. */
708
709int main (int argc, char *argv[])
710{
711 /* Setup global variables for referencing the command line arguments. */
712
713 gargc = argc; gargv = argv;
714
715 /* Parse the command line. */
716
717 get_args ();
718
719 /* Display the banner line unless suppressed. */
720
721 if (verbosity > 0) puts (title);
722
723 /* If emxl.exe was located automatically by emxbind, display the
724 path name of emxl.exe. */
725
726 if (verbosity >= 2 && auto_emxl)
727 printf ("Loader program for DOS: %s\n", emx_fname);
728
729 /* Open the files. */
730
731 open_files ();
732
733 /* Further processing depends on the command. */
734
735 cmd (mode);
736
737 /* Close the files. */
738
739 close_files ();
740 return 0;
741}
Note: See TracBrowser for help on using the repository browser.