home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / emxtutor.zip / emxsrcd1.zip / emx / src / emximp / emximp.c < prev    next >
C/C++ Source or Header  |  1998-12-19  |  37KB  |  1,255 lines

  1. /* emximp.c  -- Manage import libraries
  2.    Copyright (c) 1992-1998 Eberhard Mattes
  3.  
  4. This file is part of emximp.
  5.  
  6. emximp is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. emximp is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with emximp; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27. #include <getopt.h>
  28. #include <process.h>
  29. #include <ar.h>
  30. #include <time.h>
  31. #include <sys/moddef.h>
  32. #include "defs.h"
  33. #include <sys/omflib.h>
  34.  
  35. #define VERSION "0.9d"
  36.  
  37. #define NORETURN2 __attribute__ ((noreturn))
  38.  
  39. #define MOD_PREDEF   0
  40. #define MOD_DEF      1
  41. #define MOD_REF      2
  42.  
  43. #define N_EXT  0x01
  44. #define N_ABS  0x02
  45. #define N_IMP1 0x68
  46. #define N_IMP2 0x6a
  47.  
  48. #define PARMS_REG     (-1)
  49. #define PARMS_FAR16   (-2)
  50.  
  51. struct lib
  52. {
  53.   struct lib *next;
  54.   char *name;
  55.   int lbl;
  56. };
  57.  
  58. struct predef
  59. {
  60.   struct predef *next;
  61.   char *name;
  62. };
  63.  
  64. enum modes
  65. {
  66.   M_NONE,                       /* No mode selected */
  67.   M_LIB_TO_IMP,                 /* .lib -> .imp */
  68.   M_IMP_TO_S,                   /* .imp -> .s or .o */
  69.   M_IMP_TO_DEF,                 /* .imp -> .def */
  70.   M_LIB_TO_A,                   /* .lib -> .a */
  71.   M_IMP_TO_A,                   /* .imp -> .a */
  72.   M_IMP_TO_LIB,                 /* .imp -> .lib */
  73.   M_DEF_TO_IMP,                 /* .def -> .imp */
  74.   M_DEF_TO_A,                   /* .def -> .a */
  75.   M_DEF_TO_LIB                  /* .def -> .lib */
  76. };
  77.  
  78. static FILE *out_file = NULL;
  79. static char out_fname[128];
  80. static struct lib *libs;
  81. static struct predef *predefs;
  82. static char *out_base;
  83. static int base_len;
  84. static char *as_name;
  85. static int pipe_flag;
  86. static int profile_flag;
  87. static int opt_b;
  88. static int opt_q;
  89. static int opt_s;
  90. static enum modes mode = M_NONE;
  91. static long mod_lbl;
  92. static long seq_no = 1;
  93. static char *first_module = NULL;
  94. static int warnings = 0;
  95. static struct omflib *out_lib;
  96. static char lib_errmsg[512];
  97. static char *module_name = NULL;
  98.  
  99.  
  100. static void error (const char *fmt, ...) NORETURN2;
  101. static void write_error (const char *fname) NORETURN2;
  102. static void lib_error (void) NORETURN2;
  103. static void write_a_import (const char *func_name, const char *mod_name,
  104.     int ordinal, const char *proc_name);
  105.  
  106.  
  107. static void usage (void)
  108. {
  109.   puts ("emximp " VERSION " -- Copyright (c) 1992-1996 by Eberhard Mattes\n");
  110.   puts ("Usage:");
  111.   puts ("  emximp [-a[<assembler>]] [-b <base_name>|<prefix_length>] "
  112.         "[-p <module>] ...");
  113.   puts ("         [-s] <input_file>.imp");
  114.   puts ("  emximp [-m] -o <output_file>.a <input_file>.def ...");
  115.   puts ("  emximp [-m] -o <output_file>.a <input_file>.imp ...");
  116.   puts ("  emximp [-m] -o <output_file>.a <input_file>.lib ...");
  117.   puts ("  emximp -o <output_file>.def <input_file>.imp ...");
  118.   puts ("  emximp -o <output_file>.imp <input_file>.def ...");
  119.   puts ("  emximp -o <output_file>.imp <input_file>.lib ...");
  120.   puts ("  emximp [-p#] -o <output_file>.lib <input_file>.def ...");
  121.   puts ("  emximp [-p#] -o <output_file>.lib <input_file>.imp...");
  122.   puts ("Options:");
  123.   puts ("  -p#  Set page size");
  124.   puts ("  -q   Be quiet");
  125.   puts ("  -m   Call _mcount for profiling");
  126.   exit (1);
  127. }
  128.  
  129.  
  130. static void error (const char *fmt, ...)
  131. {
  132.   va_list arg_ptr;
  133.  
  134.   va_start (arg_ptr, fmt);
  135.   fprintf (stderr, "emximp: ");
  136.   vfprintf (stderr, fmt, arg_ptr);
  137.   fputc ('\n', stderr);
  138.   exit (2);
  139. }
  140.  
  141.  
  142. static void warning (const char *fmt, ...)
  143. {
  144.   va_list arg_ptr;
  145.  
  146.   va_start (arg_ptr, fmt);
  147.   fprintf (stderr, "emximp: ");
  148.   vfprintf (stderr, fmt, arg_ptr);
  149.   fputc ('\n', stderr);
  150.   ++warnings;
  151. }
  152.  
  153.  
  154. /* Like warning(), but don't increment `warnings'. */
  155.  
  156. static void information (const char *fmt, ...)
  157. {
  158.   va_list arg_ptr;
  159.  
  160.   va_start (arg_ptr, fmt);
  161.   fprintf (stderr, "emximp: ");
  162.   vfprintf (stderr, fmt, arg_ptr);
  163.   fputc ('\n', stderr);
  164. }
  165.  
  166.  
  167. void *xmalloc (size_t n)
  168. {
  169.   void *p;
  170.   
  171.   p = malloc (n);
  172.   if (p == NULL)
  173.     error ("Out of memory");
  174.   return p;
  175. }
  176.  
  177.  
  178. void *xrealloc (void *p, size_t n)
  179. {
  180.   void *q;
  181.   
  182.   q = realloc (p, n);
  183.   if (q == NULL)
  184.     error ("Out of memory");
  185.   return q;
  186. }
  187.  
  188.  
  189. char *xstrdup (const char *s)
  190. {
  191.   char *p;
  192.   
  193.   p = xmalloc (strlen (s) + 1);
  194.   strcpy (p, s);
  195.   return p;
  196. }
  197.  
  198.  
  199. static void write_error (const char *fname)
  200. {
  201.   error ("Write error on output file `%s'", fname);
  202. }
  203.  
  204.  
  205. static void lib_error (void)
  206. {
  207.   error ("%s", lib_errmsg);
  208. }
  209.  
  210.  
  211. static void out_flush (void)
  212. {
  213.   char name[512];
  214.   char *nargv[5];
  215.   int rc;
  216.   
  217.   if (out_file != NULL)
  218.     {
  219.       if (fflush (out_file) != 0)
  220.         write_error (out_fname);
  221.       if (pipe_flag)
  222.         {
  223.           rc = pclose (out_file);
  224.           if (rc == -1)
  225.             error ("Error while closing pipe");
  226.           if (rc > 0)
  227.             error ("Assembly failed, return code = %d", rc);
  228.         }
  229.       else
  230.         {
  231.           if (fclose (out_file) != 0)
  232.             error ("Cannot close output file `%s'", out_fname);
  233.           if (as_name != NULL)
  234.             {
  235.               _splitpath (out_fname, NULL, NULL, name, NULL);
  236.               strcat (name, ".o");
  237.               nargv[0] = as_name;
  238.               nargv[1] = "-o";
  239.               nargv[2] = name;
  240.               nargv[3] = out_fname;
  241.               nargv[4] = NULL;
  242.               rc = spawnvp (P_WAIT, as_name, nargv);
  243.               if (rc < 0)
  244.                 error ("Cannot run `%s'", as_name);
  245.               if (rc > 0)
  246.                 error ("Assembly of `%s' failed, return code = %d",
  247.                        out_fname, rc);
  248.               remove (out_fname);
  249.             }
  250.         }
  251.       out_file = NULL;
  252.     }
  253. }
  254.  
  255.  
  256. static void out_start (void)
  257. {
  258.   struct lib *lp1, *lp2;
  259.   char name[512], cmd[512];
  260.   
  261.   if (pipe_flag)
  262.     {
  263.       _splitpath (out_fname, NULL, NULL, name, NULL);
  264.       strcat (name, ".o");
  265.       sprintf (cmd, "%s -o %s", as_name, name);
  266.       out_file = popen (cmd, "wt");
  267.       if (out_file == NULL)
  268.         error ("Cannot open pipe to `%s'", as_name);
  269.     }
  270.   else
  271.     {
  272.       out_file = fopen (out_fname, "wt");
  273.       if (out_file == NULL)
  274.         error ("Cannot open output file `%s'", out_fname);
  275.     }
  276.   fprintf (out_file, "/ %s (emx+gcc)\n\n", out_fname);
  277.   fprintf (out_file, "\t.text\n");
  278.   for (lp1 = libs; lp1 != NULL; lp1 = lp2)
  279.     {
  280.       lp2 = lp1->next;
  281.       free (lp1->name);
  282.       free (lp1);
  283.     }
  284.   libs = NULL; mod_lbl = 1;
  285. }
  286.  
  287.  
  288. static void write_lib_import (const char *func, const char *module, long ord,
  289.                               const char *name)
  290. {
  291.   byte omfbuf[1024];
  292.   int i, len;
  293.   word page;
  294.  
  295.   if (omflib_write_module (out_lib, func, &page, lib_errmsg) != 0)
  296.     lib_error ();
  297.   if (omflib_add_pub (out_lib, func, page, lib_errmsg) != 0)
  298.     lib_error ();
  299.   i = 0;
  300.   omfbuf[i++] = 0x00;
  301.   omfbuf[i++] = IMPDEF_CLASS;
  302.   omfbuf[i++] = IMPDEF_SUBTYPE;
  303.   omfbuf[i++] = (ord < 1 ? 0x00 : 0x01);
  304.   len = strlen (func);
  305.   omfbuf[i++] = (byte)len;
  306.   memcpy (omfbuf+i, func, len); i += len;
  307.   len = strlen (module);
  308.   omfbuf[i++] = (byte)len;
  309.   memcpy (omfbuf+i, module, len); i += len;
  310.   if (ord < 1)
  311.     {
  312.       if (strcmp (func, name) == 0)
  313.         len = 0;
  314.       else
  315.         len = strlen (name);
  316.       omfbuf[i++] = (byte)len;
  317.       memcpy (omfbuf+i, name, len); i += len;
  318.     }
  319.   else
  320.     {
  321.       omfbuf[i++] = (byte)ord;
  322.       omfbuf[i++] = (byte)(ord >> 8);
  323.     }
  324.   if (omflib_write_record (out_lib, COMENT, i, omfbuf, TRUE,
  325.                            lib_errmsg) != 0)
  326.     lib_error ();
  327.   omfbuf[0] = 0x00;
  328.   if (omflib_write_record (out_lib, MODEND, 1, omfbuf, TRUE,
  329.                            lib_errmsg) != 0)
  330.     lib_error ();
  331. }
  332.  
  333.  
  334. #define DELIM(c) ((c) == 0 || isspace ((unsigned char)c))
  335.  
  336.  
  337. static void read_imp (const char *fname)
  338. {
  339.   FILE *inp_file;
  340.   char buf[512], func[256], name[256], module[256], mod_ref[256], *p, *q;
  341.   char tmp[512];
  342.   long line_no, ord, parms, file_no;
  343.   int mod_type;
  344.   struct lib *lp1;
  345.   struct predef *pp1;
  346.  
  347.   libs = NULL; mod_lbl = 1;
  348.   inp_file = fopen (fname, "rt");
  349.   if (inp_file == NULL)
  350.     error ("Cannot open input file `%s'", fname);
  351.   line_no = 0;
  352.   while (fgets (buf, sizeof (buf), inp_file) != NULL)
  353.     {
  354.       ++line_no;
  355.       p = strchr (buf, '\n');
  356.       if (p != NULL) *p = 0;
  357.       p = buf;
  358.       while (isspace ((unsigned char)*p)) ++p;
  359.       if (*p == '+')
  360.         {
  361.           if (mode == M_IMP_TO_S)
  362.             {
  363.               if (opt_b)
  364.                 error ("Output file name in line %ld of %s not allowed "
  365.                        "as -b is used", line_no, fname);
  366.               ++p;
  367.               while (isspace ((unsigned char)*p)) ++p;
  368.               out_flush ();
  369.               q = out_fname;
  370.               while (!DELIM (*p))
  371.                 *q++ = *p++;
  372.               *q = 0;
  373.               while (isspace ((unsigned char)*p)) ++p;
  374.               if (*p != 0 && *p != ';')
  375.                 error ("Invalid file name in line %ld of %s", line_no, fname);
  376.               out_start ();
  377.             }
  378.         }
  379.       else if (*p == 0 || *p == ';')
  380.         ;           /* empty line */
  381.       else
  382.         {
  383.           if (!opt_b && out_file == NULL && mode != M_IMP_TO_LIB)
  384.             error ("No output file selected in line %ld of %s",
  385.                    line_no, fname);
  386.           if (DELIM (*p))
  387.             error ("Function name expected in line %ld of %s", line_no, fname);
  388.           q = func;
  389.           while (!DELIM (*p))
  390.             *q++ = *p++;
  391.           *q = 0;
  392.           while (isspace ((unsigned char)*p)) ++p;
  393.           if (DELIM (*p))
  394.             error ("Module name expected in line %ld of %s", line_no, fname);
  395.           q = module;
  396.           while (!DELIM (*p))
  397.             *q++ = *p++;
  398.           *q = 0;
  399.           while (isspace ((unsigned char)*p)) ++p;
  400.           if (DELIM (*p))
  401.             error ("External name or ordinal expected in line %ld of %s",
  402.                    line_no, fname);
  403.           if (isdigit ((unsigned char)*p))
  404.             {
  405.               name[0] = 0;
  406.               ord = strtol (p, &p, 10);
  407.               if (ord < 1 || ord > 65535 || !DELIM (*p))
  408.                 error ("Invalid ordinal in line %ld of %s", line_no, fname);
  409.             }
  410.           else
  411.             {
  412.               if (opt_b && !opt_s)
  413.                 error ("External name in line %ld of %s cannot be used "
  414.                        "as -b is given", line_no, fname);
  415.               ord = -1;
  416.               q = name;
  417.               while (!DELIM (*p))
  418.                 *q++ = *p++;
  419.               *q = 0;
  420.             }
  421.           while (isspace ((unsigned char)*p)) ++p;
  422.           if (DELIM (*p))
  423.             error ("Number of arguments expected in line %ld of %s",
  424.                    line_no, fname);
  425.           if (*p == '?')
  426.             {
  427.               ++p;
  428.               parms = 0;
  429.               if (mode == M_IMP_TO_S)
  430.                 warning ("Unknown number of arguments in line %ld of %s",
  431.                          line_no, fname);
  432.             }
  433.           else if (*p == 'R')
  434.             {
  435.               ++p;
  436.               parms = PARMS_REG;
  437.             }
  438.           else if (*p == 'F')
  439.             {
  440.               ++p;
  441.               parms = PARMS_FAR16;
  442.               if (mode == M_IMP_TO_S)
  443.                 warning ("16-bit function not supported (line %ld of %s)",
  444.                          line_no, fname);
  445.               if (strlen (func) + 4 >= sizeof (func))
  446.                 error ("Function name too long in line %ld of %s",
  447.                        line_no, fname);
  448.               strcpy (tmp, func);
  449.               strcpy (func, "_16_");
  450.               strcat (func, tmp);
  451.             }
  452.           else
  453.             {
  454.               parms = strtol (p, &p, 10);
  455.               if (parms < 0 || parms > 255 || !DELIM (*p))
  456.                 error ("Invalid number of parameters in line %ld of %s",
  457.                        line_no, fname);
  458.             }
  459.           while (isspace ((unsigned char)*p)) ++p;
  460.           if (*p != 0 && *p != ';')
  461.             error ("Unexpected characters at end of line %ld of %s",
  462.                    line_no, fname);
  463.           switch (mode)
  464.             {
  465.             case M_IMP_TO_DEF:
  466.               if (first_module == NULL)
  467.                 {
  468.                   first_module = xstrdup (module);
  469.                   fprintf (out_file, "LIBRARY %s\n", module);
  470.                   fprintf (out_file, "EXPORTS\n");
  471.                 }
  472.               else if (strcmp (first_module, module) != 0)
  473.                 error ("All functions must be in the same module "
  474.                        "(input file %s)", fname);
  475.               if (ord >= 0)
  476.                 fprintf (out_file, "  %-32s @%ld\n", func, ord);
  477.               else if (strcmp (func, name) == 0)
  478.                 fprintf (out_file, "  %-32s\n", func);
  479.               else
  480.                 fprintf (out_file, "  %-32s = %s\n", name, func);
  481.               break;
  482.             case M_IMP_TO_A:
  483.               if (ord < 1)
  484.                 write_a_import (func, module, ord, name);
  485.               else
  486.                 write_a_import (func, module, ord, NULL);
  487.               break;
  488.             case M_IMP_TO_LIB:
  489.               write_lib_import (func, module, ord, name);
  490.               break;
  491.             case M_IMP_TO_S:
  492.               if (opt_b)
  493.                 {
  494.                   out_flush ();
  495.                   if (opt_s)
  496.                     file_no = seq_no++;
  497.                   else
  498.                     file_no = ord;
  499.                   if (out_base != NULL)
  500.                     sprintf (out_fname, "%s%ld.s", out_base, file_no);
  501.                   else
  502.                     sprintf (out_fname, "%.*s%ld.s",
  503.                              base_len, module, file_no);
  504.                   out_start ();
  505.                 }
  506.               for (pp1 = predefs; pp1 != NULL; pp1 = pp1->next)
  507.                 if (stricmp (module, pp1->name) == 0)
  508.                   break;
  509.               if (pp1 != NULL)
  510.                 {
  511.                   mod_type = MOD_PREDEF;
  512.                   sprintf (mod_ref, "__os2_%s", pp1->name);
  513.                 }
  514.               else
  515.                 {
  516.                   for (lp1 = libs; lp1 != NULL; lp1 = lp1->next)
  517.                     if (stricmp (module, lp1->name) == 0)
  518.                       break;
  519.                   if (lp1 == NULL)
  520.                     {
  521.                       mod_type = MOD_DEF;
  522.                       lp1 = xmalloc (sizeof (struct lib));
  523.                       lp1->name = xstrdup (module);
  524.                       lp1->lbl = mod_lbl++;
  525.                       lp1->next = libs;
  526.                       libs = lp1;
  527.                     }
  528.                   else
  529.                     mod_type = MOD_REF;
  530.                   sprintf (mod_ref, "L%d", lp1->lbl);
  531.                 }
  532.               fprintf (out_file, "\n\t.globl\t_%s\n", func);
  533.               fprintf (out_file, "\t.align\t2, %d\n", 0x90);
  534.               fprintf (out_file, "_%s:\n", func);
  535.               if (parms >= 0)
  536.                 fprintf (out_file, "\tmovb\t$%d, %%al\n", (int)parms);
  537.               fprintf (out_file, "1:\tjmp\t__os2_bad\n");
  538.               if (ord >= 0)
  539.                 fprintf (out_file, "2:\t.long\t1, 1b+1, %s, %d\n",
  540.                          mod_ref, (int)ord);
  541.               else
  542.                 fprintf (out_file, "2:\t.long\t0, 1b+1, %s, 4f\n", mod_ref);
  543.               if (mod_type == MOD_DEF)
  544.                 fprintf (out_file, "%s:\t.asciz\t\"%s\"\n", mod_ref, module);
  545.               if (ord < 0)
  546.                 fprintf (out_file, "4:\t.asciz\t\"%s\"\n", name);
  547.               fprintf (out_file, "\t.stabs  \"__os2dll\", 23, 0, 0, 2b\n");
  548.               break;
  549.             default:
  550.               abort ();
  551.             }
  552.         }
  553.     }
  554.   if (mode == M_IMP_TO_S)
  555.     out_flush ();
  556.   if (ferror (inp_file))
  557.     error ("Read error on input file `%s'", fname);
  558.   fclose (inp_file);
  559. }
  560.  
  561.  
  562. static void set_ar (char *dst, const char *src, int size)
  563. {
  564.   while (*src != 0 && size > 0)
  565.     {
  566.       *dst++ = *src++;
  567.       --size;
  568.     }
  569.   while (size > 0)
  570.     {
  571.       *dst++ = ' ';
  572.       --size;
  573.     }
  574. }
  575.  
  576.  
  577. static long ar_member_size;
  578.  
  579. static void write_ar (const char *name, long size)
  580. {
  581.   struct ar_hdr ar;
  582.   char tmp[20];
  583.  
  584.   ar_member_size = size;
  585.   set_ar (ar.ar_name, name, sizeof (ar.ar_name));
  586.   sprintf (tmp, "%ld", (long)time (NULL));
  587.   set_ar (ar.ar_date, tmp, sizeof (ar.ar_date));
  588.   set_ar (ar.ar_uid, "0", sizeof (ar.ar_uid));
  589.   set_ar (ar.ar_gid, "0", sizeof (ar.ar_gid));
  590.   set_ar (ar.ar_mode, "100666", sizeof (ar.ar_gid));
  591.   sprintf (tmp, "%ld", size);
  592.   set_ar (ar.ar_size, tmp, sizeof (ar.ar_size));
  593.   set_ar (ar.ar_fmag, ARFMAG, sizeof (ar.ar_fmag));
  594.   fwrite (&ar, 1, sizeof (ar), out_file);
  595. }
  596.  
  597.  
  598. static void finish_ar (void)
  599. {
  600.   if (ar_member_size & 1)
  601.     fputc (0, out_file);
  602. }
  603.  
  604.  
  605. static dword aout_str_size;
  606. static char aout_str_tab[2048];
  607. static int aout_sym_count;
  608. static struct nlist aout_sym_tab[6];
  609.  
  610. static byte aout_text[64];
  611. static int aout_text_size;
  612.  
  613. static struct reloc aout_treloc_tab[2];
  614. static int aout_treloc_count;
  615.  
  616. static int aout_size;
  617.  
  618.  
  619. static void aout_init (void)
  620. {
  621.   aout_str_size = sizeof (dword);
  622.   aout_sym_count = 0;
  623.   aout_text_size = 0;
  624.   aout_treloc_count = 0;
  625. }
  626.  
  627. static int aout_sym (const char *name, byte type, byte other,
  628.                      word desc, dword value)
  629. {
  630.   int len;
  631.  
  632.   len = strlen (name);
  633.   if (aout_str_size + len + 1 > sizeof (aout_str_tab))
  634.     error ("a.out string table overflow");
  635.   if (aout_sym_count >= sizeof (aout_sym_tab) / sizeof (aout_sym_tab[0]))
  636.     error ("a.out symbol table overflow");
  637.   aout_sym_tab[aout_sym_count].string = aout_str_size;
  638.   aout_sym_tab[aout_sym_count].type = type;
  639.   aout_sym_tab[aout_sym_count].other = other;
  640.   aout_sym_tab[aout_sym_count].desc = desc;
  641.   aout_sym_tab[aout_sym_count].value = value;
  642.   strcpy (aout_str_tab + aout_str_size, name);
  643.   aout_str_size += len + 1;
  644.   return aout_sym_count++;
  645. }
  646.  
  647.  
  648. static void aout_text_byte (byte b)
  649. {
  650.   if (aout_text_size >= sizeof (aout_text))
  651.     error ("a.out text segment overflow");
  652.   aout_text[aout_text_size++] = b;
  653. }
  654.  
  655.  
  656. static void aout_text_dword (dword d)
  657. {
  658.   aout_text_byte ((d >> 0) & 0xff);
  659.   aout_text_byte ((d >> 8) & 0xff);
  660.   aout_text_byte ((d >> 16) & 0xff);
  661.   aout_text_byte ((d >> 24) & 0xff);
  662. }
  663.  
  664.  
  665. static void aout_treloc (dword address, int symbolnum, int pcrel, int length,
  666.                          int ext)
  667. {
  668.   if (aout_treloc_count >= sizeof (aout_treloc_tab) / sizeof (struct reloc))
  669.     error ("a.out text relocation buffer overflow");
  670.   aout_treloc_tab[aout_treloc_count].address = address;
  671.   aout_treloc_tab[aout_treloc_count].symbolnum = symbolnum;
  672.   aout_treloc_tab[aout_treloc_count].pcrel = pcrel;
  673.   aout_treloc_tab[aout_treloc_count].length = length;
  674.   aout_treloc_tab[aout_treloc_count].ext = ext;
  675.   aout_treloc_tab[aout_treloc_count].unused = 0;
  676.   ++aout_treloc_count;
  677. }
  678.  
  679.  
  680. static void aout_finish (void)
  681. {
  682.   while (aout_text_size & 3)
  683.     aout_text_byte (0x90);
  684.   aout_size = (sizeof (struct a_out_header) + aout_text_size
  685.                + aout_treloc_count * sizeof (struct reloc)
  686.                + aout_sym_count * sizeof (aout_sym_tab[0])
  687.                + aout_str_size);
  688. }
  689.  
  690.  
  691. static void aout_write (void)
  692. {
  693.   struct a_out_header ao;
  694.  
  695.   ao.magic = 0407;
  696.   ao.machtype = 0;
  697.   ao.flags = 0;
  698.   ao.text_size = aout_text_size;
  699.   ao.data_size = 0;
  700.   ao.bss_size = 0;
  701.   ao.sym_size = aout_sym_count * sizeof (aout_sym_tab[0]);
  702.   ao.entry = 0;
  703.   ao.trsize = aout_treloc_count * sizeof (struct reloc);
  704.   ao.drsize = 0;
  705.   fwrite (&ao, 1, sizeof (ao), out_file);
  706.   fwrite (aout_text, 1, aout_text_size, out_file);
  707.   fwrite (aout_treloc_tab, aout_treloc_count, sizeof (struct reloc), out_file);
  708.   fwrite (aout_sym_tab, aout_sym_count, sizeof (aout_sym_tab[0]), out_file);
  709.   *(dword *)aout_str_tab = aout_str_size;
  710.   fwrite (aout_str_tab, 1, aout_str_size, out_file);
  711. }
  712.  
  713.  
  714. static void write_a_import (const char *func_name, const char *mod_name,
  715.                             int ordinal, const char *proc_name)
  716. {
  717.   char tmp1[256], tmp2[257], tmp3[1024];
  718.   int sym_mcount, sym_entry, sym_import;
  719.   dword fixup_mcount, fixup_import;
  720.  
  721.   aout_init ();
  722.   sprintf (tmp2, "_%s", func_name);
  723.   if (profile_flag && strncmp (func_name, "_16_", 4) != 0)
  724.     {
  725.       sym_entry = aout_sym (tmp2, N_TEXT|N_EXT, 0, 0, aout_text_size);
  726.       sym_mcount = aout_sym ("__mcount", N_EXT, 0, 0, 0);
  727.  
  728.       /* Use, say, "_$U_DosRead" for "DosRead" to import the
  729.          non-profiled function. */
  730.       sprintf (tmp2, "__$U_%s", func_name);
  731.       sym_import = aout_sym (tmp2, N_EXT, 0, 0, 0);
  732.  
  733.       aout_text_byte (0x55);    /* push ebp */
  734.       aout_text_byte (0x89);    /* mov ebp, esp */
  735.       aout_text_byte (0xe5);
  736.       aout_text_byte (0xe8);    /* call _mcount*/
  737.       fixup_mcount = aout_text_size;
  738.       aout_text_dword (0 - (aout_text_size + 4));
  739.       aout_text_byte (0x5d);    /* pop ebp */
  740.       aout_text_byte (0xe9);    /* jmp _$U_DosRead*/
  741.       fixup_import = aout_text_size;
  742.       aout_text_dword (0 - (aout_text_size + 4));
  743.  
  744.       aout_treloc (fixup_mcount, sym_mcount, 1, 2, 1);
  745.       aout_treloc (fixup_import, sym_import, 1, 2, 1);
  746.     }
  747.   sprintf (tmp1, "IMPORT#%ld", seq_no);
  748.   if (proc_name == NULL)
  749.     sprintf (tmp3, "%s=%s.%d", tmp2, mod_name, ordinal);
  750.   else
  751.     sprintf (tmp3, "%s=%s.%s", tmp2, mod_name, proc_name);
  752.   aout_sym (tmp2, N_IMP1|N_EXT, 0, 0, 0);
  753.   aout_sym (tmp3, N_IMP2|N_EXT, 0, 0, 0);
  754.   aout_finish ();
  755.   write_ar (tmp1, aout_size);
  756.   aout_write ();
  757.   finish_ar ();
  758.   seq_no++;
  759.   if (ferror (out_file))
  760.     write_error (out_fname);
  761. }
  762.  
  763.  
  764. static void read_lib (const char *fname)
  765. {
  766.   FILE *inp_file;
  767.   int n, i, next, more, impure_warned, ord_flag;
  768.   unsigned char *buf;
  769. #pragma pack(1)
  770.   struct record
  771.     {
  772.       unsigned char type;
  773.       unsigned short length;
  774.     } record, *rec_ptr;
  775. #pragma pack()
  776.   unsigned char func_name[256];
  777.   unsigned char mod_name[256];
  778.   unsigned char proc_name[256];
  779.   unsigned char theadr_name[256];
  780.   int ordinal;
  781.   long pos, size;
  782.   int page_size;
  783.  
  784.   if (mode == M_LIB_TO_IMP)
  785.     fprintf (out_file, "; -------- %s --------\n", fname);
  786.   if (ferror (out_file))
  787.     write_error (out_fname);
  788.   inp_file = fopen (fname, "rb");
  789.   if (inp_file == NULL)
  790.     error ("Cannot open input file `%s'", fname);
  791.   if (fread (&record, sizeof (record), 1, inp_file) != 1)
  792.     goto read_error;
  793.   if (record.type != LIBHDR || record.length < 5)
  794.     error ("`%s' is not a library file", fname);
  795.   page_size = record.length + 3;
  796.   if (fread (&pos, sizeof (pos), 1, inp_file) != 1)
  797.     goto read_error;
  798.   if (fseek (inp_file, 0L, SEEK_END) != 0)
  799.     goto read_error;
  800.   size = ftell (inp_file);
  801.   if (pos < size)
  802.     size = pos;
  803.   buf = xmalloc (size);
  804.   if (fseek (inp_file, 0L, SEEK_SET) != 0)
  805.     goto read_error;
  806.   size = fread (buf, 1, size, inp_file);
  807.   if (size == 0 || ferror (inp_file))
  808.     goto read_error;
  809.   i = 0; more = TRUE; impure_warned = FALSE; theadr_name[0] = 0;
  810.   while (more)
  811.     {
  812.       rec_ptr = (struct record *)(buf + i);
  813.       i += sizeof (struct record);
  814.       if (i > size) goto bad;
  815.       next = i + rec_ptr->length;
  816.       if (next > size) goto bad;
  817.       switch (rec_ptr->type)
  818.         {
  819.         case MODEND:
  820.         case MODEND|REC32:
  821.           if ((next & (page_size-1)) != 0)
  822.             next = (next | (page_size-1)) + 1;
  823.           break;
  824.  
  825.         case THEADR:
  826.           n = buf[i++];
  827.           if (i + n > next) goto bad;
  828.           memcpy (theadr_name, buf+i, n);
  829.           theadr_name[n] = 0;
  830.           impure_warned = FALSE;
  831.           break;
  832.  
  833.         case COMENT:
  834.           if (record.length >= 11 && buf[i+0] == 0x00 && buf[i+1] == 0xa0 &&
  835.               buf[i+2] == 0x01)
  836.             {
  837.               ord_flag = buf[i+3];
  838.               i += 4;
  839.               if (i + 1 > next) goto bad;
  840.               n = buf[i++];
  841.               if (i + n > next) goto bad;
  842.               memcpy (func_name, buf+i, n);
  843.               func_name[n] = 0;
  844.               i += n;
  845.               if (i + 1 > next) goto bad;
  846.               n = buf[i++];
  847.               if (i + n > next) goto bad;
  848.               memcpy (mod_name, buf+i, n);
  849.               mod_name[n] = 0;
  850.               i += n;
  851.  
  852.               if (ord_flag == 0)
  853.                 {
  854.                   ordinal = -1;
  855.                   if (i + 1 > next) goto bad;
  856.                   n = buf[i++];
  857.                   if (i + n > next) goto bad;
  858.                   if (n == 0)
  859.                     strcpy (proc_name, func_name);
  860.                   else
  861.                     {
  862.                       memcpy (proc_name, buf+i, n);
  863.                       proc_name[n] = 0;
  864.                       i += n;
  865.                     }
  866.                 }
  867.               else
  868.                 {
  869.                   if (i + 2 > next) goto bad;
  870.                   ordinal = *(unsigned short *)(buf + i);
  871.                   i += 2;
  872.                   proc_name[0] = 0;
  873.                 }
  874.               ++i;              /* Skip checksum */
  875.               if (i != next) goto bad;
  876.               switch (mode)
  877.                 {
  878.                 case M_LIB_TO_IMP:
  879.                   if (ordinal != -1)
  880.                     sprintf (proc_name, "%3d", ordinal);
  881.                   if (strncmp (func_name, "_16_", 4) != 0)
  882.                     fprintf (out_file, "%-23s %-8s %s ?\n",
  883.                              func_name, mod_name, proc_name);
  884.                   else
  885.                     fprintf (out_file, "%-23s %-8s %s F\n",
  886.                              func_name+4, mod_name, proc_name);
  887.                   if (ferror (out_file))
  888.                     write_error (out_fname);
  889.                   break;
  890.                 case M_LIB_TO_A:
  891.                   if (ordinal == -1)
  892.                     write_a_import (func_name, mod_name, ordinal, proc_name);
  893.                   else
  894.                     write_a_import (func_name, mod_name, ordinal, NULL);
  895.                   break;
  896.                 default:
  897.                   abort ();
  898.                 }
  899.             }
  900.           break;
  901.  
  902.         case EXTDEF:
  903.         case PUBDEF:
  904.         case PUBDEF|REC32:
  905.         case SEGDEF:
  906.         case SEGDEF|REC32:
  907.         case COMDEF:
  908.         case COMDAT:
  909.         case COMDAT|REC32:
  910.           if (!opt_q && !impure_warned)
  911.             {
  912.               impure_warned = TRUE;
  913.               information ("%s (%s) is not a pure import library",
  914.                            fname, theadr_name);
  915.             }
  916.           break;
  917.  
  918.         case LIBEND:
  919.           more = FALSE;
  920.           break;
  921.         }
  922.       i = next;
  923.     }
  924.   free (buf);
  925.   fclose (inp_file);
  926.   return;
  927.  
  928. read_error:
  929.   error ("Read error on file `%s'", fname);
  930.  
  931. bad:
  932.   error ("Malformed import library file `%s'", fname);
  933. }
  934.  
  935.  
  936. static void create_output_file (int bin)
  937. {
  938.   out_file = fopen (out_fname, (bin ? "wb" : "wt"));
  939.   if (out_file == NULL)
  940.     error ("Cannot open output file `%s'", out_fname);
  941.   if (!bin)
  942.     fprintf (out_file, ";\n; %s (created by emximp)\n;\n", out_fname);
  943. }
  944.  
  945.  
  946. static void close_output_file (void)
  947. {
  948.   if (fflush (out_file) != 0)
  949.     error ("Write error on output file `%s'", out_fname);
  950.   if (fclose (out_file) != 0)
  951.       error ("Cannot close output file `%s'", out_fname);
  952. }
  953.  
  954.  
  955. static void init_archive (void)
  956. {
  957.   static char ar_magic[SARMAG+1] = ARMAG;
  958.  
  959.   fwrite (ar_magic, 1, SARMAG, out_file);
  960. }
  961.  
  962.  
  963. static int md_export (struct _md *md, const _md_stmt *stmt, _md_token token,
  964.                       void *arg)
  965. {
  966.   const char *internal;
  967.  
  968.   switch (token)
  969.     {
  970.     case _MD_LIBRARY:
  971.       module_name = xstrdup (stmt->library.name);
  972.       break;
  973.     case _MD_EXPORTS:
  974.       if (module_name == NULL)
  975.         error ("No module name given in module definition file");
  976.       if (stmt->export.internalname[0] != 0)
  977.         internal = stmt->export.internalname;
  978.       else
  979.         internal = stmt->export.entryname;
  980.       switch (mode)
  981.         {
  982.         case M_DEF_TO_IMP:
  983.           if (stmt->export.flags & _MDEP_ORDINAL)
  984.             fprintf (out_file, "%-23s %-8s %3u ?\n",
  985.                      stmt->export.entryname, module_name,
  986.                      (unsigned)stmt->export.ordinal);
  987.           else
  988.             fprintf (out_file, "%-23s %-8s %-23s ?\n",
  989.                      stmt->export.entryname, module_name, internal);
  990.           if (ferror (out_file))
  991.             write_error (out_fname);
  992.           break;
  993.         case M_DEF_TO_A:
  994.           if (stmt->export.flags & _MDEP_ORDINAL)
  995.             write_a_import (stmt->export.entryname, module_name,
  996.                             stmt->export.ordinal, NULL);
  997.           else
  998.             write_a_import (stmt->export.entryname, module_name,
  999.                             0, internal);
  1000.           break;
  1001.         case M_DEF_TO_LIB:
  1002.           write_lib_import (stmt->export.entryname, module_name,
  1003.                             stmt->export.ordinal, internal);
  1004.           break;
  1005.         default:
  1006.           abort ();
  1007.         }
  1008.       break;
  1009.     case _MD_parseerror:
  1010.       error ("%s (line %ld of %s)", _md_errmsg (stmt->error.code),
  1011.              _md_get_linenumber (md), (const char *)arg);
  1012.       break;
  1013.     default:
  1014.       break;
  1015.     }
  1016.   return 0;
  1017. }
  1018.  
  1019.  
  1020. static void read_def (const char *fname)
  1021. {
  1022.   struct _md *md;
  1023.  
  1024.   module_name = NULL;
  1025.   md = _md_open (fname);
  1026.   if (md == NULL)
  1027.     error ("Cannot open input file `%s'", fname);
  1028.   if (mode == M_DEF_TO_IMP)
  1029.     {
  1030.       fprintf (out_file, "; -------- %s --------\n", fname);
  1031.       if (ferror (out_file))
  1032.         write_error (out_fname);
  1033.     }
  1034.   _md_next_token (md);
  1035.   _md_parse (md, md_export, (void *)fname);
  1036.   _md_close (md);
  1037. }
  1038.  
  1039.  
  1040. int main (int argc, char *argv[])
  1041. {
  1042.   int i, c;
  1043.   int imp_count, lib_count, def_count, page_size;
  1044.   struct predef *pp1;
  1045.   char *q, *ext, *opt_o;
  1046.   
  1047.   _response (&argc, &argv);
  1048.   predefs = NULL; out_base = NULL; as_name = NULL; pipe_flag = FALSE;
  1049.   profile_flag = FALSE; page_size = 16;
  1050.   opt_b = FALSE; opt_q = FALSE; opt_s = FALSE; base_len = 0; opt_o = NULL;
  1051.   opterr = 0;
  1052.   optswchar = "-";
  1053.   optind = 0;
  1054.   while ((c = getopt (argc, argv, "a::b:mo:p:qsP:")) != EOF)
  1055.     {
  1056.       switch (c)
  1057.         {
  1058.         case 'a':
  1059.           as_name = (optarg != NULL ? optarg : "as");
  1060.           pipe_flag = (_osmode != DOS_MODE);
  1061.           break;
  1062.         case 'b':
  1063.           opt_b = TRUE;
  1064.           base_len = strtol (optarg, &q, 10);
  1065.           if (base_len > 1 && *q == 0)
  1066.             out_base = NULL;
  1067.           else
  1068.             {
  1069.               out_base = optarg;
  1070.               base_len = 0;
  1071.             }
  1072.           break;
  1073.         case 'm':
  1074.           profile_flag = TRUE;
  1075.           break;
  1076.         case 'o':
  1077.           if (opt_o != NULL)
  1078.             usage ();
  1079.           opt_o = optarg;
  1080.           break;
  1081.         case 'p':
  1082.           pp1 = xmalloc (sizeof (struct predef));
  1083.           pp1->name = xstrdup (optarg);
  1084.           pp1->next = predefs;
  1085.           predefs = pp1;
  1086.           break;
  1087.         case 'q':
  1088.           opt_q = TRUE;
  1089.           break;
  1090.         case 's':
  1091.           opt_s = TRUE;
  1092.           break;
  1093.         default:
  1094.           error ("Invalid option");
  1095.         }
  1096.     }
  1097.   imp_count = 0; lib_count = 0; def_count = 0;
  1098.   for (i = optind; i < argc; ++i)
  1099.     {
  1100.       ext = _getext (argv[i]);
  1101.       if (ext != NULL && stricmp (ext, ".lib") == 0)
  1102.         ++lib_count;
  1103.       else if (ext != NULL && stricmp (ext, ".imp") == 0)
  1104.         ++imp_count;
  1105.       else if (ext != NULL && stricmp (ext, ".def") == 0)
  1106.         ++def_count;
  1107.       else
  1108.         error ("Input file `%s' has unknown file name extension", argv[i]);
  1109.     }
  1110.   if (imp_count == 0 && lib_count == 0 && def_count == 0)
  1111.     usage ();
  1112.   if ((imp_count != 0) + (lib_count != 0) + (def_count != 0) > 1)
  1113.     error ("More than one type of input files");
  1114.   if (opt_o == NULL)
  1115.     {
  1116.       if (lib_count != 0)
  1117.         error ("Cannot convert .lib files to %s files",
  1118.                (as_name == NULL ? ".s" : ".o"));
  1119.       if (def_count != 0)
  1120.         error ("Cannot convert .def files to %s files",
  1121.                (as_name == NULL ? ".s" : ".o"));
  1122.       mode = M_IMP_TO_S;
  1123.     }
  1124.   else
  1125.     {
  1126.       ext = _getext (opt_o);
  1127.       if (ext != NULL && stricmp (ext, ".imp") == 0)
  1128.         {
  1129.           if (imp_count != 0)
  1130.             error ("Cannot convert .imp files to .imp file");
  1131.           if (lib_count != 0)
  1132.             mode = M_LIB_TO_IMP;
  1133.           else
  1134.             mode = M_DEF_TO_IMP;
  1135.         }
  1136.       else if (ext != NULL && stricmp (ext, ".a") == 0)
  1137.         {
  1138.           if (def_count != 0)
  1139.             mode = M_DEF_TO_A;
  1140.           else if (imp_count != 0)
  1141.             mode = M_IMP_TO_A;
  1142.           else
  1143.             mode = M_LIB_TO_A;
  1144.         }
  1145.       else if (ext != NULL && stricmp (ext, ".def") == 0)
  1146.         {
  1147.           if (def_count != 0)
  1148.             error ("Cannot convert .def files to .def file");
  1149.           if (lib_count != 0)
  1150.             error ("Cannot convert .lib files to .def file");
  1151.           mode = M_IMP_TO_DEF;
  1152.         }
  1153.       else if (ext != NULL && stricmp (ext, ".lib") == 0)
  1154.         {
  1155.           if (lib_count != 0)
  1156.             error ("Cannot convert .lib files to .lib file");
  1157.           if (def_count != 0)
  1158.             mode = M_DEF_TO_LIB;
  1159.           else
  1160.             mode = M_IMP_TO_LIB;
  1161.           if (predefs != NULL)
  1162.             {
  1163.               if (predefs->next != NULL)
  1164.                 usage ();
  1165.               page_size = strtol (predefs->name, &q, 10);
  1166.               if (page_size < 1 || *q != 0)
  1167.                 usage ();
  1168.               predefs = NULL;   /* See below */
  1169.             }
  1170.         }
  1171.       else
  1172.         error ("File name extension of output file not supported");
  1173.       _strncpy (out_fname, opt_o, sizeof (out_fname));
  1174.     }
  1175.   if (mode != M_IMP_TO_S)
  1176.     if (as_name != NULL || opt_b || opt_s || predefs != NULL)
  1177.       usage ();
  1178.   if (profile_flag && mode != M_DEF_TO_A && mode != M_IMP_TO_A
  1179.       && mode != M_LIB_TO_A)
  1180.     usage ();
  1181.   switch (mode)
  1182.     {
  1183.     case M_LIB_TO_IMP:
  1184.       create_output_file (FALSE);
  1185.       for (i = optind; i < argc; ++i)
  1186.         read_lib (argv[i]);
  1187.       close_output_file ();
  1188.       break;
  1189.     case M_LIB_TO_A:
  1190.       create_output_file (TRUE);
  1191.       init_archive ();
  1192.       for (i = optind; i < argc; ++i)
  1193.         read_lib (argv[i]);
  1194.       close_output_file ();
  1195.       break;
  1196.     case M_IMP_TO_S:
  1197.       for (i = optind; i < argc; ++i)
  1198.         read_imp (argv[i]);
  1199.       break;
  1200.     case M_IMP_TO_DEF:
  1201.       create_output_file (FALSE);
  1202.       for (i = optind; i < argc; ++i)
  1203.         read_imp (argv[i]);
  1204.       close_output_file ();
  1205.       break;
  1206.     case M_IMP_TO_LIB:
  1207.       out_lib = omflib_create (out_fname, page_size, lib_errmsg);
  1208.       if (out_lib == NULL)
  1209.         lib_error ();
  1210.       if (omflib_header (out_lib, lib_errmsg) != 0)
  1211.         lib_error ();
  1212.       for (i = optind; i < argc; ++i)
  1213.         read_imp (argv[i]);
  1214.       if (omflib_finish (out_lib, lib_errmsg) != 0
  1215.           || omflib_close (out_lib, lib_errmsg) != 0)
  1216.         lib_error ();
  1217.       break;
  1218.     case M_IMP_TO_A:
  1219.       create_output_file (TRUE);
  1220.       init_archive ();
  1221.       for (i = optind; i < argc; ++i)
  1222.         read_imp (argv[i]);
  1223.       close_output_file ();
  1224.       break;
  1225.     case M_DEF_TO_A:
  1226.       create_output_file (TRUE);
  1227.       init_archive ();
  1228.       for (i = optind; i < argc; ++i)
  1229.         read_def (argv[i]);
  1230.       close_output_file ();
  1231.       break;
  1232.     case M_DEF_TO_IMP:
  1233.       create_output_file (FALSE);
  1234.       for (i = optind; i < argc; ++i)
  1235.         read_def (argv[i]);
  1236.       close_output_file ();
  1237.       break;
  1238.     case M_DEF_TO_LIB:
  1239.       out_lib = omflib_create (out_fname, page_size, lib_errmsg);
  1240.       if (out_lib == NULL)
  1241.         lib_error ();
  1242.       if (omflib_header (out_lib, lib_errmsg) != 0)
  1243.         lib_error ();
  1244.       for (i = optind; i < argc; ++i)
  1245.         read_def (argv[i]);
  1246.       if (omflib_finish (out_lib, lib_errmsg) != 0
  1247.           || omflib_close (out_lib, lib_errmsg) != 0)
  1248.         lib_error ();
  1249.       break;
  1250.     default:
  1251.       usage ();
  1252.     }
  1253.   return (warnings == 0 ? 0 : 1);
  1254. }
  1255.