home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #4 / amigaacscoverdisc1998-041998.iso / utilities / shareware / dev / vbcc / machines / amiga68k / libsrc / fd2lib2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-30  |  25.5 KB  |  911 lines

  1. /*  fd2lib  by Volker Barthelmann                         */
  2. /*  rework 09/96 by Johnny Teveßen <j.tevessen@line.org>  */
  3.  
  4. /*  "T:"s removed: Not very portable!
  5. */
  6.  
  7. #define NDEBUG
  8.  
  9. #ifdef _DCC
  10. #  define CTYPE_NEAR
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <stdarg.h>
  18.  
  19. const char VersTag[] = "\0$VER: fd2lib 1.3 (15.9.96)";  /* AmigaOS version string. Doesn't hurt... */
  20.  
  21. char *clibname,*clibtext;
  22.  
  23. #define MAXLINELEN       1000
  24. #define BUFFEREDLEN     16384   /* 1024 is standard */
  25.  
  26. #define NUMREGS        16
  27.  
  28. static const char *regnames[NUMREGS] =
  29. {
  30.   "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
  31.   "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"
  32. };
  33.  
  34. enum
  35. {
  36.   A0=0, A1, A2, A3, A4, A5, A6, A7,
  37.   D0  , D1, D2, D3, D4, D5, D6, D7
  38. };
  39.  
  40. #define SMALLCODE        1
  41. #define SMALLDATA        2
  42. #define FASTCALL         4
  43. #define NEWNOTATE        8
  44. #define VARGSLOGIC      16
  45. #define DEBUG           32
  46.  
  47. #ifndef   TRUE
  48.    typedef short BOOL;
  49. #  define TRUE  1
  50. #  define FALSE 0
  51. #endif
  52.  
  53. #ifndef   NULL
  54. #  define NULL ((void *)0L)
  55. #endif
  56.  
  57. #ifdef __GNUC__
  58. #  define gnuspec(x) x
  59. #else
  60. #  define gnuspec(x)
  61. #endif
  62.  
  63. #define NORETURN gnuspec(__attribute__ ((noreturn)))
  64.  
  65. static const char *varargs[] =
  66. {
  67. #include "vargs.h"
  68.   NULL, NULL
  69. };
  70.  
  71. int get_type(char *dest,const char *p,const char *fname,int arg)
  72. {
  73.   int nest,carg,l=strlen(fname);const char *last=p,*m,*m2;
  74.   if(arg<0) return 0;
  75.   while(*p){
  76.     if(*p==';'||*p=='\n'){last=p;while(isspace((unsigned char)*last)) last++;}
  77.     if(!strncmp(p,fname,l)){
  78.       m=p;m2=p-1;p+=l;
  79.       while(isspace((unsigned char)*p)) p++;
  80.       if(*p!='('||isalnum((unsigned char)*m2)){
  81.         continue;
  82.       }else{
  83.         if(arg==0){
  84.           memcpy(dest,last,m-last);
  85.           dest[m-last]=0;
  86.           return 1;
  87.         }
  88.         p++;carg=1;nest=0;
  89.         while(1){
  90.           while(isspace((unsigned char)*p)) p++;
  91.           if(*p==')'||*p==0)
  92.             return 0;
  93.           if(carg==arg){
  94.             while(nest!=0||(*p!=','&&*p!=')')){
  95.               if(!*p) return 0;
  96.               if(*p=='(') nest++;
  97.               if(*p==')') nest--;
  98.               *dest++=*p++;
  99.             }
  100.             *dest=0;
  101.             return 1;
  102.           }
  103.           while(nest!=0||(*p!=','&&*p!=')')){
  104.             if(!*p) return 0;
  105.             if(*p=='(') nest++;
  106.             if(*p==')') nest--;
  107.             p++;
  108.           }
  109.           p++;
  110.           carg++;
  111.         }
  112.       }
  113.     }
  114.     p++;
  115.   }
  116.   return 0;
  117. }
  118.  
  119. static void ExitFailure(const char *, const char *) NORETURN;
  120.  
  121. static void
  122. ExitFailure(const char *cause, const char *insertme)
  123. {
  124.   fprintf(stderr, cause, insertme);
  125.  
  126.   exit(EXIT_FAILURE);
  127. }
  128.  
  129. static void
  130. check(const char *ptr)
  131. {
  132.   if(!*ptr)
  133.   {
  134.     ExitFailure("Unexpected EOL\n", NULL);
  135.   }
  136. }
  137.  
  138. static void warnhim(int linenr, const char *format, ...) gnuspec(__attribute__ ((format (printf, 2, 3))));
  139.  
  140. static void
  141. warnhim(int linenr, const char *format, ...)
  142. {
  143.   char linebuf[250];
  144.   va_list vl;
  145.  
  146.   va_start(vl,format);
  147.   vsprintf(linebuf, format, vl);
  148.   va_end(vl);
  149.  
  150.   fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
  151. }
  152.  
  153. static FILE *
  154. OpenLVO(const char *name, const char *outdir, const char *outform)
  155. {
  156.   FILE *lvos;
  157.   char lvoname[MAXLINELEN];
  158.  
  159.   strcpy(lvoname, outdir);
  160.  
  161.   if(name)
  162.   {
  163.     char *k = (char *)name, *p;
  164.     int lvonamlen;
  165.  
  166.     if((p = strrchr(k, '/')) != NULL) k = p + 1;
  167.     if((p = strrchr(k, ':')) != NULL) k = p + 1;
  168.  
  169.     strcat(lvoname, k);
  170.  
  171.     lvonamlen = strlen(lvoname);
  172.  
  173.     if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
  174.     {
  175.       lvoname[lvonamlen-7] = '\0';
  176.     }
  177.     else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
  178.     {
  179.       lvoname[lvonamlen-3] = '\0';
  180.     }
  181.  
  182.     strcat(lvoname, "_lvo.s");
  183.   }
  184.   else
  185.   {
  186.     strcat(lvoname, "fd_lvo.s");
  187.   }
  188.  
  189.   printf(outform, lvoname, lvoname, lvoname);
  190.  
  191.   lvos = fopen(lvoname, "w");
  192.  
  193.   return(lvos);
  194. }
  195.  
  196. static void
  197. ProcessFD(const char *name, int mode, const char *outdir, const char *outform)
  198. {
  199.     FILE *fd, *lvos;
  200.     FILE *out;
  201.     int offset = 0, i, j, count, savecount;
  202.     char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
  203.     char line[MAXLINELEN];
  204.     register char *p;
  205.     char *functionp;
  206.     int reg[NUMREGS], loops, linenr = 0;
  207.     BOOL public = -1;           /* Why FALSE? */
  208.     char typ[1024];
  209.  
  210.     /*  "-1" is the initial value for "public". It means:
  211.     **  no statement yet.
  212.     */
  213.  
  214.     *function = *base = *line = '\0';
  215.  
  216.     if(name) fd = fopen(name, "r");
  217.     else     fd = stdin;
  218.  
  219.     if(!fd) ExitFailure("Could not open `%s'\n", name);
  220.  
  221.     setvbuf(fd, NULL, _IOFBF, BUFFEREDLEN);             /* maybe _IOLBF? */
  222.  
  223.     if(!(lvos = OpenLVO(name, outdir, outform)))
  224.       ExitFailure("Could not create lvo file\n", NULL);
  225.  
  226.     setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
  227.  
  228.     for(;;)
  229.     {
  230.         char *k;
  231.  
  232.         if(!fgets(line, MAXLINELEN-1, fd)) ExitFailure("Unexpected EOF\n", NULL);
  233.  
  234.         linenr ++;
  235.  
  236.         if((*line == '*') || !*line) continue;
  237.  
  238.         switch(*line + line[2])
  239.         {
  240.           case ('#'+'b'):
  241.             if(!strncmp(line, "##base", 6))
  242.             {
  243.                 if(*base) warnhim(linenr, "##base detected more than once!");
  244.  
  245.                 p = line+6; while(isspace(*p)) p++;
  246.                 k = base  ; while(isgraph(*p)) *k++ = *p++;
  247.  
  248.                 *k = '\0';
  249.  
  250.                 if(mode & DEBUG) printf("Base set to `%s'\n", base);
  251.                 continue;
  252.             }
  253.  
  254.             if(!strncmp(line, "##bias", 6))
  255.             {
  256.                 p = line+6; while(isspace(*p)) p++;
  257.                 sscanf(p, "%i", &offset);
  258.  
  259.                 if(mode & DEBUG) printf("Bias set to -%d\n", offset);
  260.                 continue;
  261.             }
  262.             break;
  263.  
  264.           case ('#'+'p'):
  265.             if(!strncmp(line, "##public", 8))
  266.             {
  267.                 if(public == TRUE)  warnhim(linenr, "##public after ##public detected!");
  268.                 else                public = TRUE;
  269.  
  270.                 if(mode & DEBUG) printf("Turned on public mode at bias -%d\n", offset);
  271.                 continue;
  272.             }
  273.  
  274.             if(!strncmp(line, "##private", 9))
  275.             {
  276.                 if(public == FALSE) warnhim(linenr, "##private after ##private detected!");
  277.                 else                public = FALSE;
  278.  
  279.                 if(mode & DEBUG) printf("Turned off public mode at bias -%d\n", offset);
  280.                 continue;
  281.             }
  282.             break;
  283.  
  284.           case ('#'+'e'):
  285.             if(!strncmp(line, "##end", 5)) return;
  286.             break;
  287.         }
  288.  
  289.         if(*line == '#')
  290.         {
  291.           warnhim(linenr, "Unknown directive: `%s'!", line);
  292.           continue;
  293.         }
  294.  
  295.         if(!public)
  296.         {
  297.           offset += 6;
  298.           continue;
  299.         }
  300.  
  301.         if(public == -1)
  302.         {
  303.           warnhim(linenr, "Neither ##public nor ##private specified yet. Assuming ##public.");
  304.           public = TRUE;
  305.         }
  306.  
  307.         functionp = function;
  308.  
  309.         for(loops=0; loops<=1; loops++)
  310.         {
  311.             char *p = line; char *k = functionp;
  312.  
  313.             while(isspace(*p)) p++;
  314.  
  315.             if(!loops)
  316.             {
  317.                 while((*p != '(') && *p) *k++ = *p++;
  318.  
  319.                 check(p);
  320.                 *k = '\0';
  321.  
  322.                 fprintf(lvos, "_LVO%s\tequ\t-%d\n"
  323.                               "\txdef\t_LVO%s\n",
  324.                               functionp, offset, functionp
  325.                        );
  326.             }
  327.             else
  328.             {
  329.                 while((*p != '(') && *p) p++;
  330.                 check(p);
  331.             }
  332.  
  333.             if(mode & DEBUG) printf("function=%s, loops=%d\n", functionp, loops);
  334.  
  335.             /* Open function stub source file */
  336.  
  337.             sprintf(ff, "%s%s.s", outdir, functionp);
  338.  
  339.             printf(outform, ff, ff, ff);
  340.  
  341.             out = fopen(ff, "w");
  342.             if(!out) ExitFailure("Could not create <%s>\n", functionp);
  343.             setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
  344.  
  345.             /* Write assembler headers */
  346.  
  347.             if(mode & SMALLDATA) fprintf(out, "\tnear\t%s,-2\n", regnames[A4]);
  348.             if(mode & SMALLCODE) fputs  (     "\tnear\tcode\n" , out);
  349.  
  350.             if(*base) fprintf(out, "\txref\t%s\n", base);
  351.  
  352.             fprintf(out, "\txdef\t_%s\n"
  353.                          "\tsection\t\"CODE\",code\n"
  354.                          "\n"
  355.                          "_%s:\n",
  356.                          functionp, functionp
  357.                    );
  358.  
  359.             /* Set all registers to 'unused' */
  360.  
  361.             for(i=0; i<NUMREGS; i++) reg[i] = 0;
  362.  
  363.             /* Skip argument names */
  364.  
  365.             while((*p!=')') && *p) p++;
  366.  
  367.             check(p);
  368.             p++;
  369.  
  370.             if(clibtext&&!loops){
  371.                 if(!get_type(typ,clibtext,functionp,0)) strcpy(typ,"error");
  372.                 printf("%s __%s(",typ,functionp);
  373.             }
  374.  
  375.             /* Search for beginning of register list */
  376.  
  377.             while((*p!='(') && *p) p++;
  378.  
  379.             check(p);
  380.             p++;
  381.  
  382.             /* Scan register list */
  383.  
  384.             count = savecount = 0;
  385.  
  386.             while((*p!=')') && *p)
  387.             {
  388.                 /* Check whether register description is valid */
  389.  
  390.                 if((!((*p=='a') || (*p=='A') || (*p=='d') || (*p=='D'))) || !((p[1]>='0') && (p[1]<='7')))
  391.                     ExitFailure("Bad register description\n", NULL);
  392.  
  393.                 /* Convert description to internal enum format */
  394.                 /* Corrected: 'A' was not recognized           */
  395.  
  396.                 if((*p=='a') || (*p=='A')) j = p[1] -  '0';
  397.                 else                       j = p[1] - ('0'-8);
  398.  
  399.                 if(clibtext&&!loops){
  400.                     if(!get_type(typ,clibtext,functionp,count+1)) strcpy(typ,"error");
  401.                     printf("__reg(\"%s\") %s,",regnames[j],typ);
  402.                 }
  403.  
  404.                 /* Mark register as used and save its argument counter */
  405.  
  406.                 reg[j] = ++count;
  407.  
  408.                 /* Increase counter if register has to be saved */
  409.  
  410.                 if(!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
  411.                   savecount ++;
  412.  
  413.                 /* Search for next register */
  414.  
  415.                 p += 2;
  416.                 while(isspace(*p) && *p)     p++;
  417.  
  418.                 if((*p == '/') || (*p==',')) p++;
  419.                 else if(*p != ')') ExitFailure("Parse error - ')' expected\n", NULL);
  420.  
  421.                 while(isspace(*p) && *p)     p++;
  422.  
  423.                 check(p);
  424.             }
  425.  
  426.             if(clibtext&&!loops){
  427.                 int i;
  428.                 printf("__reg(\"a6\") void *)=\"\\tjsr\\t-%d(a6)\";\n",offset);
  429.                 printf("#define %s(",functionp);
  430.                 for(i=1;i<=count;i++){
  431.                     if(i>1) printf(",");
  432.                     printf("x%d",i);
  433.                 }
  434.                 printf(") __%s(",functionp);
  435.                 for(i=1;i<=count;i++) printf("(x%d),",i);
  436.                 printf("%s)\n",base+1);
  437.             }
  438.  
  439.  
  440.             if(savecount)
  441.             {
  442.                 /* 'savecount' registers have to be saved */
  443.  
  444.                 /* Always save library register */
  445.  
  446.                 if((mode & FASTCALL) || (savecount == 1))
  447.                 {
  448.                   /*  Store registers sequential. NEW: Changed that it'll also be
  449.                   **  used if only two (including library register) registers have
  450.                   **  to be stored. That's faster than the original method.
  451.                   */
  452.  
  453.                   fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
  454.                 }
  455.                 else
  456.                 {
  457.                   /*  It would be better to set A6 to the end of the list ...
  458.                   */
  459.  
  460.                   fprintf(out, "\tmovem.l\t%s", regnames[A6]);
  461.                 }
  462.  
  463.                 for(i=2; i<NUMREGS; i++)        /* Can start at 2, because 0 and 1 are ignored */
  464.                 {
  465.                     if(reg[i] != 0)
  466.                     {
  467.                       switch(i)
  468.                       {
  469.                         case D0:
  470.                         case D1:
  471.                           break;
  472.  
  473.                         case A6:
  474.                           warnhim(linenr, "Register conflict in `%s' (using libbasereg)!", functionp);
  475.                           break;
  476.  
  477.                         default:
  478.                           if((mode & FASTCALL) || (savecount == 1))
  479.                           {
  480.                             fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[i], regnames[A7]);
  481.                           }
  482.                           else
  483.                           {
  484.                             fprintf(out, "/%s", regnames[i]);
  485.                           }
  486.                           break;
  487.                       }
  488.                     }
  489.                 }
  490.  
  491.                 if(!((mode & FASTCALL) || (savecount == 1))) fprintf(out, ",-(%s)\n", regnames[A7]);
  492.             }
  493.             else
  494.             {
  495.                /*  No registers have to be saved, so just save the register
  496.                **  where the library base will be stored
  497.                */
  498.  
  499.                fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
  500.             }
  501.  
  502.             /* Load A6 with base NOW, so there's no conflict with SMALLDATA and A4 anymore ... */
  503.  
  504.             if(*base != '\0')
  505.             {
  506.                 if(mode & SMALLDATA)
  507.                 {
  508.                   fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%s,%s),%s\n"
  509.                                                   : "\tmove.l\t%s(%s),%s\n",
  510.                                base, regnames[A4], regnames[A6]
  511.                          );
  512.                 }
  513.                 else
  514.                 {
  515.                   fprintf(out, "\tmove.l\t%s,%s\n", base, regnames[A6]);
  516.                 }
  517.             }
  518.             else ExitFailure("No base defined!\n", NULL);
  519.  
  520.             for(j=1; j<=count; j++)     /* Arguments */
  521.             {
  522.                 for(i=0; i<NUMREGS; i++) /* Registers */
  523.                 {
  524.                     if(reg[i] == j)     /* Argument in THIS register? */
  525.                     {
  526.                         int saveoffset = (savecount+j+1)<<2;
  527.  
  528.                         if((i>=D7) || (reg[i+1] != j+1) || ((loops==1) && (j>=count-1)))
  529.                         {
  530.                             if(!loops || (j<count))
  531.                             {
  532.                                 fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%d,%s),%s\n"
  533.                                                                 : "\tmove.l\t%d(%s),%s\n",
  534.                                               saveoffset, regnames[A7], regnames[i]);
  535.                             }
  536.                             else
  537.                             {
  538.                               if(i <= 7)
  539.                               {
  540.                                 /*  adress register */
  541.  
  542.                                 fprintf(out, (mode & NEWNOTATE) ? "\tlea\t(%d,%s),%s\n"
  543.                                                                 : "\tlea\t%d(%s),%s\n",
  544.                                              saveoffset, regnames[A7], regnames[i]
  545.                                        );
  546.                               }
  547.                               else
  548.                               {
  549.                                 /*  data register  */
  550.  
  551.                                 /*  Changed: moveq.l will be forced if possible
  552.                                 **  (there are still assemblers that do not do this
  553.                                 **  automatically).
  554.                                 */
  555.  
  556.                                 fprintf(out, "\tmove%s\t#%d,%s\n" \
  557.                                              "\tadd.l\t%s,%s\n",
  558.                                              (saveoffset <= 127) ? "q" : ".l",
  559.                                              saveoffset, regnames[i], regnames[A7], regnames[i]
  560.                                        );
  561.                               }
  562.                             }
  563.                         }
  564.                         else
  565.                         {
  566.                             /* Here no fastcall - slower. :-( */
  567.  
  568.                             fprintf(out, (mode & NEWNOTATE) ? "\tmovem.l\t(%d,%s),%s"
  569.                                                             : "\tmovem.l\t%d(%s),%s",
  570.                                          saveoffset, regnames[A7], regnames[i]
  571.                                    );
  572.  
  573.                             while((i<D7) && (reg[i+1] == j+1) && (!loops || (j<count-1)))
  574.                             {
  575.                                 i++; j++;
  576.  
  577.                                 fprintf(out, "/%s", regnames[i]);
  578.                             }
  579.  
  580.                             fputc('\n', out);
  581.                         }
  582.                     } /* if reg[i]==j */
  583.                 } /* for i */
  584.             } /* for j */
  585.  
  586.             /* Now place the real function call */
  587.  
  588.             fprintf(out, (mode & NEWNOTATE) ? "\tjsr\t(-%d,%s)\n"
  589.                                             : "\tjsr\t-%d(%s)\n",
  590.                          offset, regnames[A6]
  591.                    );
  592.  
  593.             /* Start restoring registers ... libbasereg first. */
  594.  
  595.             if(!((mode & FASTCALL) || (savecount == 1)))
  596.             {
  597.               if(!savecount) fprintf(out, "\tmove.l\t(%s)+,%s" , regnames[A7], regnames[A6]);
  598.               else           fprintf(out, "\tmovem.l\t(%s)+,%s", regnames[A7], regnames[A6]);
  599.             }
  600.  
  601.             /* Now the others */
  602.  
  603.             for(i=2; i<NUMREGS; i++)
  604.             {
  605.                 if((mode & FASTCALL) || (savecount == 1))
  606.                 {
  607.                   j = (NUMREGS+1) - i;          /* swap direction; okay for != 16 regs? */
  608.                 }
  609.                 else
  610.                 {
  611.                   j = i;
  612.                 }
  613.  
  614.                 if(reg[j])
  615.                 {
  616.                   switch(j)
  617.                   {
  618.                     case A6:
  619.                     case D0:
  620.                     case D1:
  621.                       break;
  622.  
  623.                     default:
  624.                       if((mode & FASTCALL) || (savecount == 1))
  625.                       {
  626.                         fprintf(out, "\tmove.l\t(%s)+,%s\n", regnames[A7], regnames[j]);
  627.                       }
  628.                       else
  629.                       {
  630.                         fprintf(out, "/%s", regnames[j]);
  631.                       }
  632.                       break;
  633.                   }
  634.                 }
  635.             }
  636.  
  637.             /* If fastcall was used, a6 was put first. So we pop it last. */
  638.  
  639.             if((mode & FASTCALL) || (savecount == 1))
  640.             {
  641.               fprintf(out, "\tmove.l\t(%s)+,%s", regnames[A7], regnames[A6]);
  642.             }
  643.  
  644.             /* Return from subroutine */
  645.  
  646.             fputs("\n" \
  647.                   "\trts\n" \
  648.                   "\n" \
  649.                   "\tend\n",
  650.                   out
  651.                  );
  652.  
  653.             fclose(out);
  654.  
  655.             if(loops != 0) break;
  656.  
  657.             p = (char *) *varargs;
  658.             loops = 3;
  659.  
  660.             if(mode & DEBUG) printf("Searching function `%s' in vargs table...\n", functionp);
  661.  
  662.             if(p != NULL)
  663.             {
  664.               if(mode & VARGSLOGIC)
  665.               {
  666.                 int fnlen = strlen(functionp);
  667.  
  668.                 if((fnlen > 7) && (!strcmp(functionp + fnlen - 7, "TagList")))
  669.                 {
  670.                   /*  xxxTagList function found. Make xxxTags of it
  671.                   */
  672.  
  673.                   strncpy(tmpfuncnam, functionp, fnlen - 4);
  674.                   strcpy (tmpfuncnam + fnlen - 4,    "s"  );
  675.  
  676.                   functionp = tmpfuncnam;
  677.                   loops     = 0;
  678.                 }
  679.                 else if((fnlen > 1) && ((functionp[fnlen-1] == 'A') && (functionp[fnlen-2] >= 'a') && (functionp[fnlen-2] <= 'z')))
  680.                 {
  681.                   /*  Not that smart recognition... But you probably
  682.                   **  don't want to have a function CreateDA() varargs,
  683.                   **  want you?
  684.                   **
  685.                   **  Recognized are functions that end with 'A' and that
  686.                   **  have a lowercase letter before that.
  687.                   */
  688.  
  689.                   strcpy(tmpfuncnam, functionp);
  690.                   tmpfuncnam[fnlen-1] = '\0';
  691.  
  692.                   functionp = tmpfuncnam;
  693.                   loops     = 0;
  694.                 }
  695.  
  696.                 if(!loops)
  697.                 {
  698.                   if(mode & DEBUG) puts("Found via internal logic!");
  699.                 }
  700.               }
  701.  
  702.               if(loops) for(i=0; p != NULL; i+=2)
  703.               {
  704.                 if(!strcmp(p, functionp))
  705.                 {
  706.                     if(mode & DEBUG) puts("Found!");
  707.  
  708.                     functionp = (char *) varargs[i - 1];        /* [i+1] */
  709.                     loops = 0;
  710.                     break;
  711.                 }
  712.  
  713.                 /*i += 2;*/
  714.                 p = (char *) varargs[i];
  715.               }
  716.             }
  717.         }
  718.  
  719.         offset += 6;
  720.     } /* for(;;) */
  721.  
  722.     if(name) fclose(fd);
  723.  
  724.     fputs("\n\tend\n", lvos);
  725.  
  726.     fclose(lvos);
  727. }
  728.  
  729. /*  Append '/' to path if needed
  730. */
  731.  
  732. static void
  733. fillpath(char *dirpath)
  734. {
  735.   int sl = strlen(dirpath);
  736.  
  737.   switch(dirpath[sl-1])
  738.   {
  739.     case ':':   /* ':' should be AMIGA-only! This will be commented out. */
  740.     case '/':
  741.       break;
  742.  
  743.     default:
  744.       strcpy(dirpath+sl, "/");
  745.       break;
  746.   }
  747. }
  748.  
  749. /*  Show program usage
  750. */
  751.  
  752. static void Usage(const char *) NORETURN;
  753.  
  754. static void
  755. Usage(const char *myname)
  756. {
  757.   printf("fd2lib 1.3  (c) 9/96 by Volker Barthelmann / Johnny Teveßen\n"
  758.          "\n"
  759.          "  -- Caution: Needs ~5000 byte stack! --\n"
  760.          "\n"
  761.          "Usage : %s [-sc] [-sd] [-40] [-on] [-nv] [-o <dir>] [-of <format>]\n"
  762.          "           [-d] [-?|--help] [files/pattern]\n"
  763.          "\n"
  764.          "  -sc : Use small code model (else large code model)\n"
  765.          "  -sd : Use small data model (else large data model)\n"
  766.          "  -40 : Use fast call model for 68040\'s (no 'movem's)\n"
  767.          "  -on : Use old motorola assembler notation\n"
  768.          "  -nv : No varargs logic - ...A and ...TagList will not be detected\n"
  769.          "  -o  : Specify directory to store source files in\n"
  770.          "  -of : C printf style output format to generate compiling\n"
  771.          "        script. Three `%%s' are replaced with output file name\n"
  772.          "  -d  : Turn on debugging/verbose mode\n"
  773.          "  -?  : Show help/version and quit\n"
  774.          "files : FD files to convert, defaults to stdin\n"
  775.          "\n"
  776.          "Commandline is parsed left-to-right. Specifying\n"
  777.          "\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
  778.          "getting large data model.\n",
  779.          myname
  780.         );
  781.  
  782.   exit(0);
  783. }
  784.  
  785. /*  Remember: ixemul.library does command line expansion, eg.:
  786. **
  787. **  redrose# fd2lib -sc -sd /fd/a*_lib.fd
  788. **
  789. **  will become:
  790. **
  791. **  redrose# fd2lib -sc -sd /fd/amigaguide_lib.fd /fd/asl_lib.fd ...
  792. **
  793. */
  794.  
  795. int
  796. main(int argc, char **argv)
  797. {
  798.     int erg       = 0 /*EXIT_FAILURE*/;
  799.     int mode      = NEWNOTATE | VARGSLOGIC;
  800.     int filesdone = 0;
  801.  
  802.     char outdir[80] = "", outform[250] = "";
  803.  
  804.     if(argc > 1)
  805.     {
  806.       int i;
  807.  
  808.       for(i=1; i<argc; i++)
  809.       {
  810.         if(argv[i][0] == '-')
  811.         {
  812.           /* Parse option */
  813.  
  814.                if( !strcmp(argv[i], "-sc")) mode |=  SMALLCODE;
  815.           else if( !strcmp(argv[i], "-sd")) mode |=  SMALLDATA;
  816.           else if( !strcmp(argv[i], "-40")) mode |=  FASTCALL;
  817.           else if( !strcmp(argv[i], "-on")) mode &= ~NEWNOTATE;
  818.           else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
  819.           else if( !strcmp(argv[i], "-pr")) clibname=argv[++i];
  820.           else if( !strcmp(argv[i], "-o" ))
  821.           {
  822.             if(i < (argc-1))
  823.             {
  824.               i ++;
  825.  
  826.               if(strlen(argv[i]) < sizeof(outdir))
  827.               {
  828.                 strcpy  (outdir, argv[i]);
  829.                 fillpath(outdir);
  830.               }
  831.               else
  832.               {
  833.                 fprintf(stderr, "Path too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outdir));
  834.               }
  835.             }
  836.             else
  837.             {
  838.               fputs("No path specified after `-o'!\n", stderr);
  839.             }
  840.           }
  841.           else if( !strcmp(argv[i], "-of"))
  842.           {
  843.             if(i < (argc-1))
  844.             {
  845.               i ++;
  846.  
  847.               if(strlen(argv[i]) < sizeof(outform))
  848.               {
  849.                 strcpy(outform, argv[i]);
  850.                 strcat(outform, "\n"   );
  851.               }
  852.               else
  853.               {
  854.                 fprintf(stderr, "Format too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outform));
  855.               }
  856.             }
  857.             else
  858.             {
  859.               fputs("No format specified after `-of'!\n", stderr);
  860.             }
  861.           }
  862.           else if( !strcmp(argv[i], "-d" )) mode |=  DEBUG;
  863.           else if((!strcmp(argv[i], "-?" )) ||
  864.                   (!strcmp(argv[i], "--help"))) Usage(*argv);
  865.           else
  866.           {
  867.             fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
  868.             Usage(*argv);
  869.           }
  870.         }
  871.         else
  872.         {
  873.           /* Process file */
  874.  
  875.           if(argv[i][0] == '?') Usage(*argv);
  876.           else
  877.           {
  878.             if(clibname){
  879.                 FILE *file=fopen(clibname,"r");
  880.                 size_t size;
  881.                 if(!file){
  882.                     fprintf(stderr, "Couldn't open <%s>!\n",clibname);
  883.                     exit(EXIT_FAILURE);
  884.                 }
  885.                 if(fseek(file,0,SEEK_END)) exit(EXIT_FAILURE);
  886.                 size=ftell(file);
  887.                 if(fseek(file,0,SEEK_SET)) exit(EXIT_FAILURE);
  888.                 clibtext=malloc(size+1);
  889.                 if(!clibtext){
  890.                     fprintf(stderr,"Out of memory!\n");
  891.                     exit(EXIT_FAILURE);
  892.                 }
  893.                 clibtext[fread(clibtext,1,size,file)]=0;
  894.                 fclose(file);
  895.             }
  896.             ProcessFD(argv[i], mode, outdir, outform);
  897.             if(clibname){
  898.                 free(clibtext);
  899.                 clibname=clibtext=0;
  900.             }
  901.             filesdone ++;
  902.           }
  903.         }
  904.       }
  905.     }
  906.  
  907.     if(!filesdone) ProcessFD(NULL, mode, outdir, outform);
  908.  
  909.     return(erg);
  910. }
  911.