/*
 * Interface between our RenderWare makefile and the horribly
 * non standard compiler for SH4.  Translates parameters, and
 * puts them in a sub command file to eliminate the command line
 * parameter overflow problem.
 * 
 * Usage: sh4int <compiler_name> [[option]|option...]
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char rcsid[] = "@@(#)$Id: sh4int.c,v 1.8 2000/06/27 09:05:36 johns Exp $";

/*************************************************************************
 *
 * Main entry point
 *
 ************************************************************************/

int 
main(int argc, char **argv )
{
    ++argv, --argc;  /* skip over program name */

    if (argc--)
    {
        char    *program_path = NULL;

        program_path = *argv++;

        if (argc--)
        {
            char    *subcom_path = NULL;
            FILE    *fptr = NULL;

            subcom_path = *argv++;

            fptr = fopen(subcom_path, "wt");

            if (fptr)
            {
                int     sysRet;
                char    buffer[200];

                if (strstr(program_path, "lbr.exe"))
                {
                    /* Do parameter conversion for librarian */

                    while (argc--)
                    {
                        char    *opt = *argv++;
                        char    *p;

                        /* Replace /s with \s */
                        while (p = strchr(opt, '/'))
                            *p = '\\';

                        if (opt[0] == '-')
                        {
                            switch (opt[1])
                            {
                                case ('f'): case ('F'):
                                {
                                    switch (opt[2])
                                    {
                                        case ('a'): case ('A'):
                                        {
                                            /* It's an append operation */
                                            fprintf(fptr, "LIBRARY %s\n", &opt[3]);
                                            break;
                                        }
                                        case ('c'): case ('C'):
                                        {
                                            /* It's a create option */
                                            fprintf(fptr, "CREATE %s\n", &opt[3]);
                                            break;
                                        }
                                        default:
                                        {
                                            /* Unknown option */
                                            break;
                                        }
                                    }
                                }
                                default:
                                {
                                    /* Unknown option */
                                    break;
                                }
                            }
                        }
                        else
                        {
                            /* Add it as a file */
                            fprintf(fptr, "ADD %s\n", opt);
                        }
                    }

                    /* Command to end it all */
                    fprintf(fptr, "EXIT\n");

                    fclose(fptr);

                    /* Assemble a command line */
                    sprintf(buffer, "%s -subcommand=%s", program_path, subcom_path);

                    /* Shell out to run the librarian */
                    sysRet = system(buffer);
                    if (sysRet)
                    {
                        fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                        return (sysRet);
                    }

                    /* Success */
                    return (0);
                }
                else if (strstr(program_path, "asmsh.exe"))
                {
                    char    *objConvert;
                    char    *objFile;
                    char    *srcFile;
                    int     cdebug = 0;
                    char    *defines[100], *includes[100];
                    int     numDefines = 0;
                    int     numIncludes = 0;
                    int     metrowerks = 0;

                    /* Do parameter conversion for assembler */
                    if (!argc)
                    {
                        /* No converter */
                        fclose(fptr);
                        fprintf(stderr, "Could not find object converter name\n");
                        return (-1);
                    }

                    /* Pull off object conversion util for debug build */
                    objConvert = *argv++;

                    while (argc--)
                    {
                        char    *opt = *argv++;
                        char    *p;

                        /* Replace /s with \s */
                        while (p = strchr(opt, '/'))
                            *p = '\\';

                        if (opt[0] == '-')
                        {
                            switch (opt[1])
                            {
                                case ('a'): case ('A'):
                                {
                                    /* Turn on debugging info */
                                    cdebug = 1;
                                    break;
                                }
                                case ('b'): case ('B'):
                                {
                                    /* Covert to metrowerks */
                                    metrowerks = 1;
                                    break;
                                }
                                case ('c'):
                                {
                                    break;
                                }

                                case ('D'): case ('d'):
                                {
                                    /* Store the address of the define */
                                    defines[numDefines++] = &opt[2];
                                    break;
                                }

                                case ('F'): case ('f'):
                                {
                                    switch (opt[2])
                                    {
                                        case ('O'): case ('o'):
                                        {
                                            objFile = &opt[3];
                                            break;
                                        }
                                        default:
                                        {
                                            break;
                                        }
                                    }
                                    break;
                                }
                                case ('I'): case ('i'):
                                {
                                    /* Store the address of the define */
                                    includes[numIncludes++] = &opt[2];
                                    break;
                                }
                                default:
                                {
                                    fprintf(fptr, "%s\n", opt);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            srcFile = opt;
                            break;
                        }
                    }

                    if (srcFile)
                    {
                        fprintf(fptr, "%s\n", srcFile);
                    }

                    if (objFile)
                    {
                        fprintf(fptr, "-object=%s\n", objFile);
                    }

                    if (cdebug)
                    {
                        fprintf(fptr, "-debug\n");
                    }
                    else
                    {
                        fprintf(fptr, "-nodebug\n");
                    }

                    if (numDefines)
                    {
                        fprintf(fptr, "-define=");
                        while (numDefines--)
                        {
                            fprintf(fptr, defines[numDefines]);
                            if (numDefines)
                            {
                                fprintf(fptr, ",");
                            }
                        }
                        fprintf(fptr, "\n");
                    }

                    if (numIncludes)
                    {
                        fprintf(fptr, "-include=");
                        while (numIncludes--)
                        {
                            fprintf(fptr, includes[numIncludes]);
                            if (numIncludes)
                            {
                                fprintf(fptr, ",");
                            }
                        }
                        fprintf(fptr, "\n");
                    }

                    /* Other miscellaneous options */
                    fprintf(fptr, "-cpu=SH4\n");
                    fprintf(fptr, "-endian=little\n");
                    fprintf(fptr, "-nolist\n");

                    fclose(fptr);

                    /* Assemble a command line */
                    sprintf(buffer, "%s -subcommand=%s", program_path, subcom_path);

                    /* Shell out to run the assembler */
                    sysRet = system(buffer);
                    if (sysRet)
                    {
                        fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                        return (sysRet);
                    }

                    if (cdebug && !metrowerks)
                    {
                        char    tempObj[200];
                        /* We need to run the debug info conversion tool */

                        /* Construct a temporary name - add an x to the name (assumes non 8.3 format possible) */
                        sprintf(tempObj, "%sx", objFile);

                        /* Run the util */
                        sprintf(buffer, "%s -sysrof=%s %s", objConvert, tempObj, objFile);
                        sysRet = system(buffer);
                        if (sysRet)
                        {
                            fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                            return (sysRet);
                        }

                        /* Remove the old file */
                        sysRet = remove(objFile);
                        if (sysRet)
                        {
                            fprintf(stderr, "Failed to remove file <%s>, return code %d\n", objFile, sysRet);
                            return (sysRet);
                        }

                        /* Move the new file into place */
                        sysRet = rename(tempObj, objFile);
                        if (sysRet)
                        {
                            fprintf(stderr, "Failed to rename file <%s> to <%s>, return code: %d\n", tempObj, objFile, sysRet);
                            return (sysRet);
                        }
                    }

                    if (metrowerks)
                    {
                        if (strstr(objFile, ".obj"))
                        {
                            char    tempObj[200];
                            /* We need to convert to mterowerks */

                            /* Construct a temporary name - add an x to the name (assumes non 8.3 format possible) */
                            sprintf(tempObj, "%s.elf", objFile);

                            /* Construct a temporary name - add an x to the name (assumes non 8.3 format possible) */
                            sprintf(buffer, "elfcnv %s %s", objFile, tempObj);

                            /* Run the util */
                            sysRet = system(buffer);
                            if (sysRet)
                            {
                                fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                                return (sysRet);
                            }

                            /* Remove the old file */
                            sysRet = remove(objFile);
                            if (sysRet)
                            {
                                fprintf(stderr, "Failed to remove file <%s>, return code %d\n", objFile, sysRet);
                                return (sysRet);
                            }

                            /* Move the new file into place */
                            sysRet = rename(tempObj, objFile);
                            if (sysRet)
                            {
                                fprintf(stderr, "Failed to rename file <%s> to <%s>, return code: %d\n", tempObj, objFile, sysRet);
                                return (sysRet);
                            }
                        }
                    }

                    /* Success */
                    return (0);
                }
                else if (strstr(program_path, "shc.exe"))
                {
                    char    *objConvert;
                    char    *objFile;
                    char    *defines[100], *includes[100];
                    int     numDefines = 0;
                    int     numIncludes = 0;
                    int     optimize = 0;
                    int     cdebug = 0;
                    int     makingObj = 1;
                    int     metrowerks = 0;

                    /* Do parameter conversion for compiler */
                    if (!argc)
                    {
                        /* No converter */
                        fclose(fptr);
                        fprintf(stderr, "Could not find object converter name\n");
                        return(-1);
                    }

                    /* Pull off object conversion util for debug build */
                    objConvert = *argv++;

                    while (argc--)
                    {
                        char    *opt = *argv++;
                        char    *p;

                        /* Replace /s with \s */
                        while (p = strchr(opt, '/'))
                            *p = '\\';

                        if (opt[0] == '-')
                        {
                            switch (opt[1])
                            {
                                case ('a'): case ('A'):
                                {
                                    /* Turn on c debugging info */
                                    cdebug = 1;
                                    break;
                                }
                                case ('b'): case ('B'):
                                {
                                    /* Covert to metrowerks */
                                    metrowerks = 1;
                                    break;
                                }
                                case ('c'):
                                {
                                    break;
                                }
                                case ('D'): case('d'):
                                {
                                    /* Store the address of the define */
                                    defines[numDefines++] = &opt[2];
                                    break;
                                }
                                case ('F'): case ('f'):
                                {
                                    switch (opt[2])
                                    {
                                        case ('O'): case ('o'):
                                        {
                                            objFile = &opt[3];
                                            fprintf(fptr, "-objectfile=%s\n", objFile);
                                            break;
                                        }
                                        default:
                                        {
                                            break;
                                        }
                                    }
                                    break;
                                }
                                case ('I'): case('i'):
                                {
                                    /* Store the address of the include path */
                                    includes[numIncludes++] = &opt[2];
                                    break;
                                }
                                case ('O'): case ('o'):
                                {
                                    /* Turn on optimisation */
                                    optimize = 1;
                                    break;
                                }
                                case ('S'): case ('s'):
                                {
                                    fprintf(fptr, "-code=Asmcode\n");
                                    makingObj = 0;
                                    break;
                                }
                                default:
                                {
                                    fprintf(fptr, "%s\n", opt);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            fprintf(fptr, "%s\n", opt);
                            break;
                        }
                    }

                    if (numDefines)
                    {
                        fprintf(fptr, "-define=");
                        while (numDefines--)
                        {
                            fprintf(fptr, defines[numDefines]);
                            if (numDefines)
                            {
                                fprintf(fptr, ",");
                            }
                        }
                        fprintf(fptr, "\n");
                    }

                    if (numIncludes)
                    {
                        fprintf(fptr, "-include=");
                        while (numIncludes--)
                        {
                            fprintf(fptr, includes[numIncludes]);
                            if (numIncludes)
                            {
                                fprintf(fptr, ",");
                            }
                        }
                        fprintf(fptr, "\n");
                    }

                    fprintf(fptr, "-optimize=%d\n", optimize);

                    if (cdebug)
                    {
                        fprintf(fptr, "-debug\n");
                    }
                    else
                    {
                        fprintf(fptr, "-nodebug\n");
                    }

                    /* Other miscellaneous options */
                    fprintf(fptr, "-section=p=P,c=C,d=D,b=B\n");
                    fprintf(fptr, "-show=noobj,source,expansion,w=80,l=0\n");
                    fprintf(fptr, "-comment=nonest\n");
                    fprintf(fptr, "-cpu=sh4\n");
                    fprintf(fptr, "-division=cpu\n");
                    fprintf(fptr, "-fpu=single\n");
                    fprintf(fptr, "-endian=little\n");
                    fprintf(fptr, "-extra=a=800\n");            /* God knows what this does!! */
                    fprintf(fptr, "-pic=0\n");
                    fprintf(fptr, "-macsave=0\n");
                    fprintf(fptr, "-speed\n");
					fprintf(fptr, "-loop\n");
                    fprintf(fptr, "-sjis\n");
                    fprintf(fptr, "-string=const\n");

                    fclose(fptr);

                    /* Assemble a command line */
                    sprintf(buffer, "%s -subcommand=%s", program_path, subcom_path);

                    /* Shell out to run the compiler */
                    sysRet = system(buffer);
                    if (sysRet)
                    {
                        fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                        return (sysRet);
                    }

                    if (cdebug && makingObj && !metrowerks)
                    {
                        char    tempObj[200];
                        /* We need to run the debug info conversion tool */

                        /* Construct a temporary name - add an x to the name (assumes non 8.3 format possible) */
                        sprintf(tempObj, "%sx", objFile);

                        /* Run the util */
                        sprintf(buffer, "%s -sysrof=%s %s", objConvert, tempObj, objFile);
                        sysRet = system(buffer);
                        if (sysRet)
                        {
                            fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                            return (sysRet);
                        }

                        /* Remove the old file */
                        sysRet = remove(objFile);
                        if (sysRet)
                        {
                            fprintf(stderr, "Failed to remove file <%s>, return code %d\n", objFile, sysRet);
                            return (sysRet);
                        }

                        /* Move the new file into place */
                        sysRet = rename(tempObj, objFile);
                        if (sysRet)
                        {
                            fprintf(stderr, "Failed to rename file <%s> to <%s>, return code: %d\n", tempObj, objFile, sysRet);
                            return (sysRet);
                        }
                    }

                    if (metrowerks)
                    {
                        if (strstr(objFile, ".obj"))
                        {
                            char    tempObj[200];
                            /* We need to convert to mterowerks */

                            /* Construct a temporary name - add an x to the name (assumes non 8.3 format possible) */
                            sprintf(tempObj, "%s.elf", objFile);

                            /* Construct a temporary name - add an x to the name (assumes non 8.3 format possible) */
                            sprintf(buffer, "elfcnv %s %s", objFile, tempObj);

                            /* Run the util */
                            sysRet = system(buffer);
                            if (sysRet)
                            {
                                fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                                return (sysRet);
                            }

                            /* Remove the old file */
                            sysRet = remove(objFile);
                            if (sysRet)
                            {
                                fprintf(stderr, "Failed to remove file <%s>, return code %d\n", objFile, sysRet);
                                return (sysRet);
                            }

                            /* Move the new file into place */
                            sysRet = rename(tempObj, objFile);
                            if (sysRet)
                            {
                                fprintf(stderr, "Failed to rename file <%s> to <%s>, return code: %d\n", tempObj, objFile, sysRet);
                                return (sysRet);
                            }
                        }
                    }

                    /* Success */
                    return (0);
                }
                else  if (strstr(program_path, "lnk.exe"))
                {
                    char    *objs[100], *libs[100];
                    char    string[100];
                    char    *output = NULL;
                    char    *cp;
                    int     numObjs = 0;
                    int     numLibs = 0;
                    int     cdebug = 0;
                    int     i;

                    /* Do parameter conversion for compiler */
                    if (!argc)
                    {
                        /* No converter */
                        fclose(fptr);
                        fprintf(stderr, "Could not find object converter name\n");
                        return(-1);
                    }

                    while (argc--)
                    {
                        char    *opt = *argv++;
                        char    *p;

                        /* Replace /s with \s */
                        while (p = strchr(opt, '/'))
                            *p = '\\';

                        if (opt[0] == '-')
                        {
                            switch (opt[1])
                            {
                                case ('d'): case ('D'):
                                {
                                    /* Turn on c debugging info */
                                    cdebug = 1;
                                    break;
                                }

                                default:
                                {
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (strstr(opt, ".obj")) /* .obj */
                            {
                                objs[numObjs++] = opt;
                            }
                            else if (strstr(opt, ".lib")) /* lib */
                            {
                                libs[numLibs++] = opt;
                            }
                            else if (strstr(opt, ".elf")) /* elf */
                            {
                                output = opt;
                            }
                        }
                    }

                    if (cdebug)
                    {
                        fprintf(fptr, "debug\n");
                    }
                    else
                    {
                        fprintf(fptr, "nodebug\n");
                    }

                    fprintf(fptr, "align_section\n");
                    fprintf(fptr, "elf\n");
                    fprintf(fptr, "output %s\n", output); /* .elf */

                    /* libs */
                    for (i = 0; i < numLibs; i++)
                    {
                        fprintf(fptr, "library %s\n", libs[i]);
                    }

                    /* objs */
                    for (i = 0; i < numObjs; i++)
                    {
                        fprintf(fptr, "input %s\n", objs[i]);
                    }

                    strcpy(string, output);
                    cp = string;
                    while (*cp != '.') cp++;

                    strcpy(cp, ".map\0");

                    fprintf(fptr, "print %s\n", string);
                    fprintf(fptr, "form a\n");
                    fprintf(fptr, "entry SG_SEC\n");
                    fprintf(fptr, "start IP(8C008000),DSGLH(8C010000)\n");
                    fprintf(fptr, "exit");

                    fclose(fptr);

                    /* Assemble a command line */
                    sprintf(buffer, "%s -sub=%s", program_path, subcom_path);

                    /* Shell out to run the linker */
                    sysRet = system(buffer);
                    if (sysRet)
                    {
                        fprintf(stderr, "<%s> failed, return code: %d\n", buffer, sysRet);
                        return (sysRet);
                    }

                    /* Success */
                    return (0);
                }
                else
                {
                    fprintf(stderr, "Bollox");
                }
            }

            fprintf(stderr, "Failed to open subcommand file\n");
            return (-1);
        }
    }

    fprintf(stderr, "Usage: sh4int <compiler_name> [[option]|option...]\n");
    return (-1);
}
