source: trunk/emx/src/emxbind/emxbind.c@ 2525

Last change on this file since 2525 was 1282, checked in by bird, 22 years ago

recognize option 'e'.

  • Property cvs2svn:cvs-rev set to 1.10
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 14.1 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/* File names of various files. inp_fname holds the name of the
45 input executable, stub_fname the name of the DOS stub file and
46 def_fname the name of the module definition file (-d option). */
47
48static char inp_fname[FNAME_SIZE];
49static char stub_fname[FNAME_SIZE];
50static char def_fname[FNAME_SIZE];
51
52/* These global variables have the same values as the argc and argv
53 parameters, respectively, of main(). */
54
55static int gargc;
56static char **gargv;
57
58
59/* Give the user a short reminder about how to call this program. */
60
61static void usage (void)
62{
63 puts (title);
64 puts ("\nUsage:");
65 puts (" emxbind [-b] [<options>] <stub>[.exe] <input> [<output>[.exe]]");
66 puts (" emxbind [-b] [<options>] [-o <output>[.exe]] <input>");
67 puts (" emxbind -e [<options>] <input>[.exe]");
68 puts (" emxbind -s [<options>] <input>[.exe]");
69 puts ("\nCommands:");
70 puts (" -b bind .exe (default)");
71 puts (" -e set OS/2 .exe flags: -f, -p or -w");
72 puts (" -s strip symbols");
73 puts ("\nOptions:");
74 puts (" -f application type: full screen (-b and -e)");
75 puts (" -p application type: Presentation Manager (-b and -e)");
76 puts (" -w application type: windowed (-b and -e)");
77 puts (" -q be quiet");
78 puts (" -v be verbose");
79 puts (" -s strip symbols (-b only)");
80 puts (" -c[<core>] add data from core dump file (-b only)");
81 puts (" -d[<def>] read module definition file (-b only)");
82 puts (" -h<size> set heap size for OS/2 (-b only)");
83 puts (" -k<size> set stack size for OS/2 (-b only)");
84 puts (" -m<map> write .map file (-b only)");
85 puts (" -r<res> add resources (-b only)");
86 exit (1);
87}
88
89
90/* A module statement is ignored: display a warning message if the
91 verbosity level is high enough. */
92
93static void def_ignored (const char *name)
94{
95 if (verbosity >= 2)
96 printf ("emxbind: %s statement not supported (warning)\n", name);
97}
98
99
100/* Callback function for reading the module definition file. Display
101 a warning for ignored statements if the verbosity level is high
102 enough. Save data from the other statements. */
103
104static int md_callback (struct _md *md, const _md_stmt *stmt, _md_token token,
105 void *arg)
106{
107 struct export exp;
108
109 switch (token)
110 {
111 case _MD_BASE:
112 def_ignored ("BASE");
113 break;
114
115 case _MD_CODE:
116 def_ignored ("CODE");
117 break;
118
119 case _MD_DATA:
120 def_ignored ("DATA");
121 break;
122
123 case _MD_DESCRIPTION:
124
125 /* Save the description string for putting it into the
126 non-resident name table. */
127
128 description = xstrdup (stmt->descr.string);
129 break;
130
131 case _MD_EXETYPE:
132 def_ignored ("EXETYPE");
133 break;
134
135 case _MD_EXPORTS:
136
137 /* Add an export entry. */
138
139 exp.ord = stmt->export.ordinal;
140 exp.resident = (!exp.ord || (stmt->export.flags & _MDEP_RESIDENTNAME)) ? TRUE : FALSE;
141 exp.entryname = xstrdup (stmt->export.entryname);
142 exp.flags = stmt->export.flags;
143 if (stmt->export.internalname[0] != 0)
144 exp.internalname = xstrdup (stmt->export.internalname);
145 else
146 exp.internalname = xstrdup (stmt->export.entryname);
147 exp.offset = 0;
148 exp.object = 0;
149 add_export (&exp);
150 break;
151
152 case _MD_HEAPSIZE:
153 def_ignored ("HEAPSIZE");
154 break;
155
156 case _MD_IMPORTS:
157 def_ignored ("IMPORTS");
158 break;
159
160 case _MD_LIBRARY:
161
162 /* Create a DLL. Save the initialization and termination
163 policies after choosing default values for unspecified
164 values. */
165
166 dll_flag = TRUE;
167 switch (stmt->library.init)
168 {
169 case _MDIT_GLOBAL:
170 init_global = TRUE;
171 break;
172 case _MDIT_INSTANCE:
173 init_global = FALSE;
174 break;
175 default:
176 break;
177 }
178 switch (stmt->library.term)
179 {
180 case _MDIT_GLOBAL:
181 term_global = TRUE;
182 break;
183 case _MDIT_INSTANCE:
184 term_global = FALSE;
185 break;
186 default:
187 break;
188 }
189 if (stmt->library.init != _MDIT_DEFAULT
190 && stmt->library.term == _MDIT_DEFAULT)
191 term_global = init_global;
192 if (stmt->library.term != _MDIT_DEFAULT
193 && stmt->library.init == _MDIT_DEFAULT)
194 init_global = term_global;
195 break;
196
197 case _MD_NAME:
198
199 /* Create a program. Save the module name and the application
200 type. */
201
202 if (stmt->name.name[0] != 0)
203 module_name = xstrdup (stmt->name.name);
204 app_type = stmt->name.pmtype;
205 break;
206
207 case _MD_OLD:
208 def_ignored ("OLD");
209 break;
210
211 case _MD_PROTMODE:
212 def_ignored ("PROTMODE");
213 break;
214
215 case _MD_REALMODE:
216 def_ignored ("REALMODE");
217 break;
218
219 case _MD_SEGMENTS:
220 def_ignored ("SEGMENTS");
221 break;
222
223 case _MD_STACKSIZE:
224
225 /* Check and save the stack size. */
226
227 if (stmt->stacksize.size < 20*1024
228 || stmt->stacksize.size > 512*1024*1024)
229 error ("Invalid stack size in module definition file");
230 stack_size = (stmt->stacksize.size + 0xfff) & ~0xfff;
231 break;
232
233 case _MD_STUB:
234
235 /* Save the name of the stub. */
236
237 if (!stmt->stub.none)
238 _strncpy (stub_fname, stmt->stub.name, sizeof (stub_fname));
239 break;
240
241 case _MD_VIRTUAL:
242 case _MD_PHYSICAL:
243 error ("VIRTUAL DEVICE and PHYSICAL DEVICE statements not supported");
244
245 case _MD_parseerror:
246
247 /* Handle a syntax error. */
248
249 error ("%s (line %ld of %s)", _md_errmsg (stmt->error.code),
250 _md_get_linenumber (md), def_fname);
251 break;
252
253 default:
254 abort ();
255 }
256 return 0;
257}
258
259
260/* Read the module definition file. */
261
262static void read_def_file (void)
263{
264 struct _md *md;
265
266 md = _md_open (def_fname);
267 if (md == NULL)
268 error ("cannot open `%s'", def_fname);
269 _md_next_token (md);
270 _md_parse (md, md_callback, NULL);
271 _md_close (md);
272}
273
274
275/* Fetch a file name from the command line. If there are no more
276 arguments or if the current argument looks like an option, don't
277 use an argument and use the default file name DEF instead. If DEF
278 is NULL, a file name must be provided. If EXT is non-NULL, it is
279 used as default extension. This function will update optind if it
280 uses an argument. */
281
282static void file_name (char *dst, const char *ext, const char *def)
283{
284 if (optind < gargc && gargv[optind][0] != '-')
285 {
286 if (strlen (gargv[optind]) > FNAME_SIZE - 5)
287 error ("file name too long");
288 strcpy (dst, gargv[optind]);
289 ++optind;
290 }
291 else if (def == NULL)
292 error ("file name missing");
293 else
294 strcpy (dst, def);
295 if (ext)
296 {
297 char *curext = _getext2 (dst);
298 if (curext && *curext == '.')
299 curext++;
300 if (strcmp (curext, ext))
301 {
302 if (strlen (dst) > FNAME_SIZE - 5)
303 error ("file name too long");
304 strcat (dst, ".");
305 strcat (dst, ext);
306 }
307 }
308}
309
310
311/* Parse the command line. */
312
313static void get_args (void)
314{
315 int c;
316 char *q;
317 const char *opt_o = NULL;
318
319 /* At least one argument, the command option, must be supplied. */
320
321 if (gargc <= 1)
322 usage ();
323
324 /* Don't let getopt() report errors, use `-' to introduce options. */
325
326 opterr = FALSE;
327//optswchar = "-";
328
329 /* No command option has been seen yet. */
330
331 mode = 0;
332
333 /* Examine the initial (emxbind) options, one by one. */
334
335 while ((c = getopt (gargc, gargv,
336 "bc::d::efh:k:m:o:pqr:svw")) != -1)
337 {
338 switch (c)
339 {
340 case 's':
341 /* -s after -b selects 'strip on bind' mode.
342 -s without -b selects the 'strip in a executable' mode */
343 if (mode == 'b')
344 {
345 opt_s = TRUE;
346 break;
347 }
348 case 'b':
349 case 'e':
350 if (mode != 0)
351 error ("multiple commands specified");
352 mode = c;
353 break;
354 case 'c':
355 if (opt_c != NULL)
356 error ("multiple core files");
357 opt_c = (optarg != NULL ? optarg : "");
358 break;
359 case 'd':
360 if (opt_d != NULL)
361 error ("multiple module definition files");
362 opt_d = (optarg != NULL ? optarg : "");
363 break;
364 case 'f':
365 opt_f = TRUE;
366 break;
367 case 'h':
368 errno = 0;
369 heap_size = strtol (optarg, &q, 0);
370 if (errno != 0 || heap_size < 0 || heap_size > 512 || *q != 0)
371 error ("invalid heap size");
372 heap_size *= 1024*1024;
373 break;
374 case 'k':
375 errno = 0;
376 stack_size = strtol (optarg, &q, 0);
377 if (errno != 0 || *q != 0 ||
378 (stack_size < 20 || stack_size > 512*1024))
379 error ("invalid stack size");
380 stack_size *= 1024;
381 stack_size = (stack_size + 0xfff) & ~0xfff;
382 break;
383 case 'm':
384 if (opt_m != NULL)
385 error ("multiple map files");
386 opt_m = optarg;
387 break;
388 case 'o':
389 if (opt_o != NULL)
390 error ("multiple output files");
391 opt_o = optarg;
392 break;
393 case 'p':
394 opt_p = TRUE;
395 break;
396 case 'q':
397 verbosity = 0;
398 break;
399 case 'r':
400 opt_r = optarg;
401 break;
402 case 'v':
403 verbosity = 2;
404 break;
405 case 'w':
406 opt_w = TRUE;
407 break;
408 default:
409 error ("invalid option");
410 }
411 }
412
413 /* The default command option is -b. */
414
415 if (mode == 0)
416 mode = 'b';
417
418 /* Complain if an illegal combination of options is used. */
419
420 if (opt_o != NULL && mode != 'b')
421 error ("-o option can be used only with -b command");
422 if (opt_c != NULL && mode != 'b')
423 error ("-c option can be used only with -b command");
424 if ((opt_f || opt_p || opt_w) && mode != 'b' && mode != 'e')
425 error ("-f, -p and -w options can be used only with -b and -e commands");
426 if (opt_f + opt_p + opt_w > TRUE)
427 error ("more than one of -f, -p and -w options given");
428 if (mode == 'e' && !(opt_p || opt_f || opt_w))
429 error ("-e command requires -f, -p or -w option");
430 if (opt_d != NULL && mode != 'b')
431 error ("-d option can be used only with -b command");
432
433 /* If the -c option is used without argument, "core" will be used as
434 core dump file. */
435
436 if (opt_c != NULL && *opt_c == 0)
437 opt_c = "core";
438
439 /* Set the default path to the DOS stub */
440 _execname (stub_fname, sizeof (stub_fname));
441 strcpy (_getname (stub_fname), "os2stub.bin");
442
443 /* If the -E option is not given and the name is not given by the
444 EMXBIND_DLL environment variable, "emx.dll" will be used. */
445
446 /* Parse the rest of the command line, depending on the command
447 option. */
448
449 switch (mode)
450 {
451 case 'b':
452 if (gargc - optind <= 1 || gargv[optind+1][0] == '-')
453 ;
454 else if (opt_o != NULL)
455 error ("Too many file names specified");
456 else
457 file_name (stub_fname, "exe", NULL);
458 file_name (inp_fname, NULL, NULL);
459 if (opt_d != NULL)
460 {
461 if (opt_d[0] == 0)
462 {
463 _strncpy (def_fname, inp_fname, sizeof (def_fname) - 4);
464 _remext (def_fname);
465 }
466 else
467 _strncpy (def_fname, opt_d, sizeof (def_fname) - 4);
468 _defext (def_fname, "def");
469 read_def_file ();
470 }
471 file_name (out_fname, (dll_flag ? "dll" : "exe"),
472 (opt_o != NULL ? opt_o : inp_fname));
473 if (stricmp (inp_fname, out_fname) == 0)
474 error ("The input and output files have the same name");
475 break;
476
477 case 'e':
478 case 's':
479 file_name (inp_fname, "exe", NULL);
480 break;
481 }
482
483 /* Complain if there are any unprocessed arguments left. */
484
485 if (optind < gargc)
486 error ("too many arguments");
487}
488
489
490static void cleanup (void)
491{
492 my_remove (&out_file);
493}
494
495
496/* Open the files, depending on the command option. The module
497 definition file (-d option) is not handled here. */
498
499static void open_files (void)
500{
501 atexit (cleanup);
502 switch (mode)
503 {
504 case 'b':
505 my_open (&inp_file, inp_fname, open_read);
506 my_open (&stub_file, stub_fname, open_read);
507 if (opt_c != NULL)
508 my_open (&core_file, opt_c, open_read);
509 if (opt_r != NULL)
510 my_open (&res_file, opt_r, open_read);
511 my_open (&out_file, out_fname, create_write);
512 break;
513 case 'e':
514 case 's':
515 my_open (&inp_file, inp_fname, open_read_write);
516 break;
517 }
518}
519
520
521/* Close all the open files. */
522
523static void close_files (void)
524{
525 my_close (&out_file);
526 my_close (&inp_file);
527 my_close (&stub_file);
528 my_close (&core_file);
529 my_close (&res_file);
530}
531
532
533/* This is the main function. Parse the command line and perform the
534 action requested by the user. */
535
536int main (int argc, char *argv[])
537{
538 /* Setup global variables for referencing the command line arguments. */
539
540 gargc = argc; gargv = argv;
541
542 /* Parse the command line. */
543
544 get_args ();
545
546 /* Display the banner line unless suppressed. */
547
548 if (verbosity > 0) puts (title);
549
550 /* If emxl.exe was located automatically by emxbind, display the
551 path name of emxl.exe. */
552
553 if (verbosity >= 2)
554 printf ("Loader program for DOS: %s\n", stub_fname);
555
556 /* Open the files. */
557
558 open_files ();
559
560 /* Further processing depends on the command. */
561
562 cmd (mode);
563
564 /* Close the files. */
565
566 close_files ();
567 return 0;
568}
Note: See TracBrowser for help on using the repository browser.