home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 215.lha / GlueMaker_v1.0 / GlueMaker.c < prev    next >
C/C++ Source or Header  |  1996-02-15  |  19KB  |  706 lines

  1. /*****************************************************************
  2.  *  GlueMaker - makes glue routines from .fd files - by Talin    *
  3.  *  Copyright (c) 1989 Elf Tech                                  *
  4.  *****************************************************************
  5.  *  Revision History:                                            *
  6.  *    Version 1.0 - Released 4 Feb 1989                          *
  7.  *****************************************************************/
  8.  
  9. #include "exec/types.h"
  10. #include "exec/memory.h"
  11. #include "libraries/dosextens.h"
  12. #include "setjmp.h"
  13. #include "stdio.h"
  14.  
  15. #define    NEWLINE            0x0a
  16. #define RETURN            0x0d
  17. #define TAB                0x09
  18.  
  19. #define MEM_SIZE        30000        /* 30 K */
  20.  
  21. /* file buffer variables */
  22.  
  23. void                    *AllocMem();
  24. APTR                     Open();
  25. LONG                    in_size;                /* size of input file (.fd) */
  26. char                     *memstart=NULL,            /* start of file in memory */
  27.                         *memend;                /* end of file in memory */
  28.  
  29. /* parsing variables */
  30.  
  31. char                    *scan,                    /* current scan point in source */
  32.                         *put,                    /* address of string to insert */
  33.                         *name,
  34.                         *line_start,            /* start of current line */
  35.                         *find_line_end();        /* find ending CR */
  36. LONG                    nval,                    /* numeric value parsed */
  37.                         txlen,                    /* text string parsed */
  38.                         digits,                    /* # of digits parsed */
  39.                         linenum;                /* current line number */
  40.  
  41. UBYTE                    priv_flag,                /* ##private flag */
  42.                         jump_flag;                /* jump flag */
  43.  
  44. short                    reg_num,        /* register number, 0-15 */
  45.                         regs_saved,        /* number of registers saved on stack */
  46.                         arg_count;
  47.  
  48. UWORD                    regs_used;        /* registers used, flag bits */
  49.  
  50. BYTE                    reg_args[16],    /* registers passed as parameters */
  51.                         reg_sizes[16],    /* and what size the args were */
  52.                         reg_type[16];    /* if we needed an lea */
  53.  
  54. UBYTE                    savestring[50];    /* movem register list for save/restore */
  55. UBYTE                    argstring[50];    /* movem register list for unstack */
  56.  
  57. /* te following table defines which regs may be used, which need to be restored,
  58.     etc. It may be changed to alter the register model.
  59. */
  60.  
  61. #define REG_SCRATCH        0                /* ok to use this register as scratch */
  62. #define REG_PRESERVE    1                /* preserve this register */
  63. #define    REG_SPECIAL        2                /* leave this register alone */
  64.  
  65. UBYTE reg_protect[] = {
  66.     REG_SCRATCH,                        /* d0 */
  67.     REG_SCRATCH,                        /* d1 */
  68.     REG_SCRATCH,                        /* d2 */
  69.     REG_SCRATCH,                        /* d3 */
  70.     REG_PRESERVE,                        /* d4 */
  71.     REG_PRESERVE,                        /* d5 */
  72.     REG_PRESERVE,                        /* d6 */
  73.     REG_PRESERVE,                        /* d7 */
  74.     REG_SCRATCH,                        /* a0 */
  75.     REG_SCRATCH,                        /* a1 */
  76.     REG_PRESERVE,                        /* a2 */
  77.     REG_PRESERVE,                        /* a3 */
  78.     REG_PRESERVE,                        /* a4 */
  79.     REG_PRESERVE,                        /* a5 */
  80.     REG_SPECIAL,                        /* a6 */
  81.     REG_SPECIAL,                        /* a7 */
  82. };
  83.  
  84. jmp_buf env;                            /* setjmp for errors */
  85.  
  86. UBYTE    boldstring[] = { 0x1b, '[' };    /* to print boldface on CON: */
  87. UBYTE    unboldstring[] = { 0x1b, '[' };    /* to print normal on CON: */
  88.  
  89. #define SCAT    goto exit_pgm;            /* standard exit macro */
  90. #define EOB(x)    (x >= memend)            /* end of buffer */
  91.  
  92. char *seek_char(), *reg_string(),*rindex();
  93.  
  94. APTR    gluefile=NULL;                    /* file handle of current output file */
  95. extern int Enable_Abort;                /* used by Chk_Abort */
  96.  
  97. main(argc, argv) LONG argc; UBYTE **argv;
  98. {    APTR                infile=NULL, makefile=NULL, vectorfile=NULL, lvofile=NULL;
  99.     short                jmp=0,
  100.                         length;
  101.  
  102.     static char        /*    yn[2],    */            /* yes or no */
  103.                         libname[40],        /* name of library we are gluemaking */
  104.                         lvoname[40],        /* name of lvo file */
  105.                         filename[80],
  106.                         funcname[40],        /* name of current .fd function */
  107.                         basename[40],        /* name of library base */
  108.                         jumpname[40],        /* for ##jump directive */
  109.                         vectorfilename[80],    /* pathname of 'vector.i' file */
  110.                         gluefilepath[80],    /* path for glue files */
  111.                         gluefilename[120];    /* name of current output file */
  112.  
  113.     LONG                flength,            /* lengths of above strings */
  114.                         mflength,
  115.                         vflength,
  116.                         gplength=0;
  117.  
  118.     if (!Input()) return 0;                    /* can't run from workbench */
  119.  
  120.     Enable_Abort = 0;                        /* don't abort, let me handle it */
  121.  
  122.     if (jmp = setjmp(env)) SCAT;            /* set jump for error */
  123.  
  124.     if (argc != 2)
  125.     {    puts("GlueMaker - By Talin.");
  126.         puts("Usage: GlueMaker <input file>");
  127.         puts("");
  128.         puts("The glue file has 5 parameters:");
  129.         puts("FDFILE=filename         (name of funcdef file, '.fd' added.)");
  130.         puts("OUTDIR=dirname          (name of directory to put asm routines)");
  131.         puts("LIBFILE=filename        (name of resulting link library, '.lib' added)");
  132.         puts("PROTECT                 (use this to preserve d2/d3 in glue routines)");
  133.         puts("");
  134.         SCAT;
  135.     }
  136.  
  137.     {    FILE *fd = fopen(argv[1],"r");
  138.         char inbuf[128],*c;
  139.  
  140.         if (!fd) error("Cannot open input file.");
  141.  
  142.         while (fgets(inbuf,128,fd))
  143.         {    if (inbuf[0])
  144.             {    if (c = rindex(inbuf,'\n')) *c = 0;
  145.                 if (!strncmp(inbuf,"FDFILE=",7)) strcpy(filename,&inbuf[7]);
  146.                 else if (!strncmp(inbuf,"OUTDIR=",7)) strcpy(gluefilepath,&inbuf[7]);
  147.                 else if (!strncmp(inbuf,"LIBFILE=",8)) strcpy(libname,&inbuf[8]);
  148.                 else if (!strncmp(inbuf,"PROTECT",7))
  149.                 {    reg_protect[2] = reg_protect[3] = REG_PRESERVE; }
  150.                 else error("Unrecognized option");
  151.             }
  152.         }
  153.         gplength = strlen(gluefilepath);
  154.  
  155.         fclose(fd);
  156.     }
  157.     
  158.     if (gplength > 0 && gluefilepath[gplength-1] != ':')
  159.         strcat(gluefilepath,"/");
  160.  
  161.     strcat(filename,".fd");                    /* name of input file */
  162.  
  163.     if (!(memstart = AllocMem(MEM_SIZE,0))) error("Not Enough Memory.");
  164.     if (!(infile = Open(filename,MODE_OLDFILE))) error("Couldn't open input file.");
  165.  
  166.     in_size = Read(infile,memstart,MEM_SIZE);
  167.     Close(infile); infile = NULL;
  168.  
  169.     if (in_size >= MEM_SIZE) error("Input File Too Big.");
  170.     printf("Read %ld bytes from source file.\n",in_size);
  171.  
  172.     line_start = scan = memstart;
  173.     memend = memstart + in_size;
  174.  
  175.     priv_flag = jump_flag = FALSE;
  176.  
  177.     /* now build the LVO file path string */
  178.  
  179.     strcpy(gluefilename,gluefilepath);
  180.     strcat(gluefilename,libname);
  181.     strcat(gluefilename,"_lvo.asm");
  182.  
  183.     if (!(lvofile = Open(gluefilename,MODE_NEWFILE)))
  184.         error("Couldn't open lvo file.");
  185.  
  186.     strcpy(vectorfilename,gluefilepath);
  187.     strcat(vectorfilename,libname);
  188.     strcat(vectorfilename,"_lvo.i");
  189.  
  190.     if (!(vectorfile = Open(vectorfilename,MODE_NEWFILE)))
  191.         error("Couldn't open vector file.");
  192.  
  193.     strcpy(gluefilename,gluefilepath);
  194.     strcat(gluefilename,"makefile");
  195.  
  196.     if (!(makefile = Open(gluefilename,MODE_NEWFILE)))
  197.         error("Couldn't open make file.");
  198.  
  199.     /* now, start parsing the file */
  200.  
  201.     APrintf(makefile,"#\n# makefile for %s.lib - created by GlueMaker\n#\n\n",libname);
  202.     APrintf(makefile,".asm.o:\n        as -D -C -o $@ $*.asm\n\n");
  203.     APrintf(makefile,"OBS=");
  204.  
  205.     APrintf(vectorfile,"* Vector list for glue routines.\n\n");
  206.  
  207.     while (TRUE)
  208.     {    abortcheck();
  209.         if (match_word("##base"))
  210.         {    /* get the global base variable... */
  211.             whitespace();
  212.             put = basename;
  213.             if (!get_symbol(40)) fatal("Base name too long.");
  214.             if (txlen == 0) fatal("Invalid base name.");
  215.             printf("Library Base Pointer is <%s>.\n",basename);
  216.         }
  217.         else if (match_word("##jump"))
  218.         {    whitespace();
  219.             put = jumpname;
  220.             if (!get_symbol(40)) fatal("Jump name too long.");
  221.             if (txlen == 0) jump_flag = FALSE; else jump_flag = TRUE;
  222.         }
  223.         else if (match_word("##bias"))
  224.         {    get_number();
  225.             /* get the library bias... */
  226.             /* I don't know how the library bias is used, so... */
  227.             printf("Bias is: <%ld>.\n",nval);
  228.         }
  229.         else if (match_word("##private"))
  230.         {    /* set the 'private' flag.. (don't generate glue files) */
  231.             priv_flag = TRUE;
  232.         }
  233.         else if (match_word("##public")) priv_flag = FALSE;        /* set private off */
  234.         else if (match_word("##end")) break;                    /* done */
  235.         else if (match_word("*")) { ; }                            /* comment */
  236.         else
  237.         {    /* it's a definition */
  238.             put = funcname;
  239.             if (!get_symbol(40)) fatal("Function name too long.");
  240.             if (txlen == 0) fatal("Invalid symbol name.");
  241.             printf("Defining %s.\n",funcname);
  242.             if (match_char('('))            /* function arguments... */
  243.             {    short i;
  244.                 if (seek_char(')'))            /* look for closing paren */
  245.                 {    regs_saved = 0;
  246.                     regs_used = NULL;
  247.                     arg_count = 0;
  248.  
  249.                     if (match_char('('))    /* registers used */
  250.                     {    while (TRUE)
  251.                         {    if (match_char(')')) break;
  252.                             reg_sizes[arg_count] = 4;            /* size = longword */
  253.                             reg_type[arg_count] = 0;            /* normal */
  254.                             if (match_char('&')) reg_type[arg_count] = 1;
  255.  
  256.                             if (get_register())
  257.                             {    if (match_word(".l") || match_word(".L"))
  258.                                     reg_sizes[arg_count] = 4;
  259.                                 else if (match_word(".w") || match_word(".W"))
  260.                                     reg_sizes[arg_count] = 2;
  261.                                 else if (match_word(".b") || match_word(".B"))
  262.                                     reg_sizes[arg_count] = 1;
  263.  
  264.                                 reg_args[arg_count++] = reg_num;
  265.                                 if (arg_count >= 16) fatal("Too many arguments");
  266.                                 if (reg_protect[reg_num] == REG_SPECIAL)
  267.                                     fatal("Can't use that register.");
  268.                                 else if (regs_used & (1<<reg_num))
  269.                                     fatal("Already used that register");
  270.  
  271.                                 regs_used |= 1<<reg_num;
  272.                                 if (reg_protect[reg_num] == REG_PRESERVE)
  273.                                     regs_saved++;
  274.  
  275.                                 /* now get the delimeter... */
  276.                                 if (match_char('/') || match_char(',')) ;
  277.                             }
  278.                             else fatal ("Delimeter Expected.");
  279.                         }
  280.                      }
  281.  
  282.                     /* now, write out the routine...*/
  283.  
  284.                     abortcheck();
  285.  
  286.                     APrintf(vectorfile,"            LIBVEC    %s\n",funcname);
  287.  
  288.                     if (priv_flag) goto priv;
  289.  
  290.                     APrintf(makefile,"    %s.o \\\n",funcname);
  291.  
  292.                     strcpy(gluefilename,gluefilepath);
  293.                     strcat(gluefilename,funcname);
  294.                     strcat(gluefilename,".asm");
  295.  
  296.                     if (!(gluefile = Open(gluefilename,MODE_NEWFILE)))
  297.                         error("Couldn't open glue source file.");
  298.  
  299. /*                    APrintf(gluefile,"\n**** Glue File: %s.c ****\n",funcname); */
  300.                     APrintf(gluefile,"* Glue routine for %s() - created by GlueMaker\n",funcname);
  301.                     APrintf(gluefile,"*\n");
  302.                     APrintf(gluefile,"*    ");
  303.                     Write(gluefile,line_start,scan-line_start);
  304.                     APrintf(gluefile,"\n*\n");
  305.                     APrintf(gluefile,"            xref    %s,_LVO%s\n",
  306.                         basename,funcname);
  307.                     APrintf(gluefile,"            xdef    _%s\n",funcname);
  308.                     if (jump_flag) APrintf(gluefile,"            xref    %s\n",
  309.                         jumpname);
  310.                     APrintf(gluefile,"_%s:\n",funcname);
  311.                     if (regs_saved > 1)
  312.                     {    reg_move_string();            /* create movem string */
  313.                         APrintf(gluefile,"            movem.l    %s,-(sp)\n",savestring);
  314.                     }
  315.                     else if (regs_saved)
  316.                     {    reg_move_string();
  317.                         APrintf(gluefile,"            move.l    %s,-(sp)\n",savestring);
  318.                     }
  319.  
  320.                     reg_params(4+4*regs_saved);
  321.  
  322.                     APrintf(gluefile,"            move.l    %s,a6\n",basename);
  323.                     if (regs_saved)
  324.                     {    APrintf(gluefile,"            jsr        _LVO%s(a6)\n",funcname);
  325.  
  326.                         if (regs_saved==1)
  327.                         {    APrintf(gluefile,"\t\t\tmove.l    (sp)+,%s\n",savestring);
  328.                         }
  329.                         else APrintf(gluefile,"\t\t\tmovem.l    (sp)+,%s\n",savestring);
  330.                         if (jump_flag)
  331.                             APrintf(gluefile,"\t\t\tbra        %s\n",jumpname);
  332.                         else APrintf(gluefile,"\t\t\trts\n");
  333.                     }
  334.                     else
  335.                     {    if (jump_flag)
  336.                             APrintf(gluefile,"\t\t\tpea        %s\n",jumpname);
  337.                         APrintf(gluefile,"\t\t\tjmp        _LVO%s(a6)\n",funcname);
  338.                     }
  339.  
  340.                     Close(gluefile);
  341.                     gluefile = NULL;
  342.  
  343.                     priv: ;
  344.                 }
  345.                 else fatal("Matching parenthesis needed");
  346.             }
  347.             else fatal("Arguments not defined.");
  348.             /* now, skip the arguments */
  349.             /* and get to the registers... (if any) */
  350.         }
  351.         /* skip to the next line - check for garbage on line? */
  352.         seek_eol();
  353.     }
  354.     APrintf(makefile,"\n\nall: $(OBS) %s_lvo.o\n        lb %s.lib $(OBS) %s_lvo.o\n\n",libname,libname,libname);
  355.  
  356.     APrintf(lvofile,
  357.         "* ======================================================================\n");
  358.     APrintf(lvofile,
  359.         "* Library Vector File for %s.lib\n",libname);
  360.     APrintf(lvofile,
  361.         "* Created By GlueMaker\n");
  362.     APrintf(lvofile,
  363.         "* ======================================================================\n");
  364.     APrintf(lvofile,"\n");
  365.     APrintf(lvofile,"\t\t\tINCLUDE\t\"exec/types.i\"\n");
  366.     APrintf(lvofile,"\t\t\tINCLUDE\t\"exec/libraries.i\"\n");
  367.     APrintf(lvofile,"\n");
  368.     APrintf(lvofile,"LIBVEC\t\tMACRO\n");
  369.     APrintf(lvofile,"\t\t\txdef\t_LVO\\1\n");
  370.     APrintf(lvofile,"_LVO\\1\t\tequ\t\tCOUNT_LIB\n");
  371.     APrintf(lvofile,"COUNT_LIB\tset\t\tCOUNT_LIB-LIB_VECTSIZE\n");
  372.     APrintf(lvofile,"\t\t\tendm\n");
  373.     APrintf(lvofile,"\n");
  374.     APrintf(lvofile,"\t\t\tLIBINIT\n");
  375.     APrintf(lvofile,"\n");
  376.     APrintf(lvofile,"\t\t\tinclude\t\t\"%s_lvo.i\"\n",libname);
  377.     APrintf(lvofile,"\n");
  378.     APrintf(lvofile,"\t\t\tend\n");
  379.  
  380.     puts("Exiting.");
  381. exit_pgm:
  382.     if (gluefile) Close(gluefile);
  383.     if (lvofile) Close(lvofile);
  384.     if (makefile) Close(makefile);
  385.     if (vectorfile) Close(vectorfile);
  386.     if (memstart) FreeMem(memstart,MEM_SIZE);
  387. }
  388.  
  389. /* print fatal global error message */
  390.  
  391. error(message) char *message;
  392. {    printf("ERROR: %s.\n",message);
  393.     longjmp(env,1);
  394. }
  395.  
  396. abortcheck()
  397. {    if (Chk_Abort())
  398.     {    puts("Aborted.");
  399.         longjmp(env,1);
  400.     }
  401. }
  402.  
  403. /* print fatal error message caused by specific line */
  404.  
  405. fatal(message) char *message;
  406. {    char *current;
  407.     current = scan;
  408.     skip_line();
  409.     offending_line(current,scan);
  410.     printf("ERROR: %s on line %ld.\n",message,linenum);
  411.     longjmp(env,2);
  412. }
  413.  
  414. /* print warning message */
  415.  
  416. warn(message) char *message;
  417. {    char *end;
  418.     end = find_line_end();
  419.     offending_line(scan,end);
  420.     printf("WARNING: %s on line %ld.\n",message,linenum);
  421. }
  422.  
  423. char underline_on[] = { 0x9b,'4','m',0 };
  424. char underline_off[] = { 0x9b,'0','m',0 };
  425.  
  426. /* string copy with limits; works slightly different from strncpy() */
  427.  
  428. char *scpy(str1,str2,n) register char *str1,*str2; register long n;
  429. {    char *hold;
  430.     hold = str1;
  431.     while (n-- && (*str1++ = *str2++)) ;
  432.     *str1 = '\0';
  433.     return (hold);
  434. }
  435.  
  436. /* print out the line that caused the error */
  437.  
  438. offending_line(a,b) char *a,*b;
  439. {    char stuff[80];
  440.     int i,j;
  441.     i = a - line_start;
  442.     j = b - a;
  443.     if (i > 79)
  444.     {    scpy(stuff,line_start,79);
  445.         printf("%s$\n",stuff);
  446.         return;
  447.     }
  448.     scpy(stuff,line_start,i);
  449.     printf("%s%s",stuff,underline_on);
  450.     if (i+j > 79)
  451.     {    scpy(stuff,a,79-i);
  452.         printf("%s$",stuff);
  453.     }
  454.     else
  455.     {    scpy(stuff,a,j);
  456.         printf(stuff);
  457.     }
  458.     printf("%s\n",underline_off);
  459. }
  460.  
  461. match_char(c) char c;
  462. {    whitespace();
  463.     if (*scan == c) { scan++; return TRUE; }
  464.     return FALSE;
  465. }
  466.  
  467. /* match a word, case sensitive */
  468.  
  469. match_word(p) char *p;
  470. {    char *s;
  471.  
  472.     whitespace();
  473.     s = scan;
  474.     while (*p) if (*s++ != *p++) return FALSE;
  475.     scan = s;
  476.     return TRUE;
  477. }
  478.  
  479. /* parse a number */
  480.  
  481. get_number()
  482. {    whitespace();
  483.     digits = nval = 0;
  484.     while (*scan >= '0' && *scan <= '9')
  485.     {    nval = nval * 10 + (*scan++ - '0');
  486.         digits++;
  487.     }
  488. }
  489.  
  490. /* expect a symbol name */
  491.  
  492. get_symbol(maxlen) short maxlen;
  493. {    txlen = 0;
  494.     while ( (*scan >= 'a' && *scan <= 'z') ||
  495.             (*scan >= 'A' && *scan <= 'Z') ||
  496.             (*scan >= '0' && *scan <= '9') ||
  497.              *scan == '_' )
  498.     {    if (txlen >= maxlen-2) { *put++=0; return FALSE; }
  499.         *put++=*scan++; txlen++;
  500.     }
  501.     *put++ = 0;
  502.     return TRUE;
  503. }
  504.  
  505. /* skip until a certain character is found */
  506.  
  507. char *seek_char(c) char c;
  508. {    char *s;
  509.     s = scan;
  510.     while (!EOB(s) && *s != RETURN && *s != NEWLINE && *s != ';')
  511.     {    if (*s++ == c) return scan=s; }
  512.     return NULL;
  513. }
  514.  
  515. /* skip over blank characters */
  516.  
  517. whitespace()
  518. {    while (*scan == ' ' || *scan == TAB) scan++;
  519. }
  520.  
  521. /* skip this line, maintain error-handling info */
  522.  
  523. seek_eol()
  524. {    while (!(EOB(scan)))
  525.     {    if (*scan == RETURN || *scan == NEWLINE)
  526.         {    linenum++;
  527.             line_start = scan + 1;
  528.             scan++;
  529.             break;
  530.         }
  531.         else scan++;
  532.     }
  533. }
  534.  
  535. skipcomma()
  536. {    whitespace();
  537.     if (*scan == ',') scan++;
  538. }
  539.  
  540. skip()
  541. {    while (!EOB(scan) && *scan != NEWLINE && *scan != RETURN) scan++;
  542. }
  543.  
  544. skip_line()
  545. {    scan = find_line_end();
  546. }
  547.  
  548. /* find end of line, do not change error-handling info */
  549.  
  550. char *find_line_end()
  551. {    char *at;
  552.     at = scan;
  553.     while (*at != RETURN && *at != NEWLINE) at++;
  554.     return at;
  555. }
  556.  
  557. /* parse a register name */
  558.  
  559. get_register()
  560. {    char c;
  561.     if (match_char('a') || match_char('A')) reg_num = 8;
  562.     else if (match_char('d') || match_char('D')) reg_num = 0;
  563.     else return FALSE;
  564.     c = *scan++;
  565.     if (c >= '0' && c <= '9') reg_num += (c - '0');
  566.     else return FALSE;
  567.     return TRUE;
  568. }
  569.  
  570. char    rstring[3] = "A0";
  571.  
  572. /* return a register name, given the number */
  573.  
  574. char *reg_string(regnum) short regnum;
  575. {    ins_regname(regnum,rstring);
  576.     return rstring;
  577. }
  578.  
  579. /* insert a register name into a byte array */
  580.  
  581. ins_regname(regnum,string) short regnum; char *string;
  582. {    if (regnum & 8) *string++ = 'A'; else *string++ = 'D';
  583.     *string++ = '0' + (regnum & 7);
  584. }
  585.  
  586. /* generate a 'movem'-style register string. */
  587.  
  588. UBYTE    regbuf[17];            /* 16 registers */
  589.  
  590. /* I use 17 as a sentinel case */
  591.  
  592. reg_move_string()
  593. {    short         i, reg, runstart, runlength, runflag;
  594.     UBYTE        *str=savestring;
  595.  
  596.         /* first, clear all the elements in the array to zero */
  597.  
  598.     for (i=0; i<17; i++) regbuf[i] = 0;
  599.  
  600.         /* now, mark off the registers that need to be saved */
  601.  
  602.     for (i=0; i<arg_count; i++)
  603.     {    reg = reg_args[i];            /* get the register that was used */
  604.         if (reg_protect[reg] == REG_PRESERVE)
  605.         {    regbuf[reg] = 1;
  606.         }
  607.     }
  608.  
  609.         /* now, figure out which ones have runs... */
  610.  
  611.     runstart = -1;            /* not in a run */
  612.     for (i=0; i<17; i++)
  613.     {    /* start of run */
  614.         if (runstart >= 0)
  615.         {    if (regbuf[i] == 0 || i == 8)    /* cut off run starting at A0 */
  616.             {    runlength = i - runstart;
  617.                 if (str != savestring) *str++ = '/';    /* seperator */
  618.                 if (runlength==1) { ins_regname(runstart,str); str += 2; }
  619.                 else
  620.                 {    ins_regname(runstart,str); str+=2;
  621.                     *str++ = '-';
  622.                     ins_regname(i-1,str); str+=2;
  623.                 }
  624.                 runstart = -1;
  625.             }
  626.         }
  627.         if (runstart < 0 && regbuf[i]) { runstart = i; }
  628.     }
  629.     *str++ = 0;
  630. }
  631.  
  632. /* see which parameters can be filled via 'movem' */
  633.  
  634. reg_params(offset)
  635. {    short        i, last, runlength, reg;
  636.     UBYTE        *str=argstring;
  637.  
  638.     last = -1;                        /* last register pushed (none) */
  639.     runlength = 0;
  640.  
  641.     if (arg_count == 0) return;
  642.  
  643.     for (i=0; i<arg_count; i++)
  644.     {    reg = reg_args[i];
  645.         if (reg > last && !reg_type[i] && runlength >= 0) runlength++;
  646.         else
  647.         {    *str++ = 0;
  648.  
  649.             if (runlength < 0)
  650.                 APrintf(gluefile,"\t\t\tlea.l    %ld(sp),%s\n",offset,argstring);
  651.             else if (runlength)
  652.                 APrintf(gluefile,"\t\t\tmovem.l    %ld(sp),%s\n",offset,argstring);
  653.             else APrintf(gluefile,"\t\t\tmove.l    %ld(sp),%s\n",offset,argstring);
  654.  
  655.             if (runlength < 0) offset += 4;
  656.             else offset += (runlength * 4);
  657.             str = argstring;
  658.  
  659.             if (reg_type[i]) runlength = -1;
  660.             else runlength = 1;
  661.         }
  662.  
  663.         if (runlength>1) *str++ = '/';
  664.         ins_regname(reg,str); str+=2;
  665.         
  666.         last = reg;
  667.     }
  668.  
  669.     *str++ = 0;
  670.  
  671.     if (runlength < 0) APrintf(gluefile,"\t\t\tlea.l    %ld(sp),%s\n",offset,argstring);
  672.     else if (runlength) APrintf(gluefile,"\t\t\tmovem.l    %ld(sp),%s\n",offset,argstring);
  673.     else APrintf(gluefile,"\t\t\tmove.l    %ld(sp),%s\n",offset,argstring);
  674. }
  675.  
  676. #define MAXLINE        128
  677.  
  678. APTR        afile;
  679. UWORD        APrint_size;
  680. char        abuf[MAXLINE+1];
  681.  
  682. a_put_char(c) char c;
  683. {    abuf[APrint_size++] = c;
  684.     if (APrint_size >= MAXLINE || c == '\n')
  685.     {    Write(afile,abuf,APrint_size);
  686.         APrint_size = 0;
  687.     }
  688. }
  689.  
  690. /* APrintf - printfs into AmigaDOS file handle */
  691.  
  692. APrintf(file,string,args) APTR file; char *string; LONG args;
  693. {    APrint_size = 0;                            /* start at zero */
  694.     afile = file;
  695.     format(a_put_char,string,&args);                    /* format the string */
  696.     if (APrint_size) { Write(file,abuf,APrint_size); APrint_size = 0; }
  697. }
  698.  
  699. GetLine(string,length) char *string; short length;
  700. {    char *c;
  701.     fgets(string,length,stdin);
  702.     if (c = rindex(string,'\n')) *c = 0;
  703.     abortcheck();
  704.     return strlen(string);
  705. }
  706.