/*
 * oclh_cc.c
 *
 *  Created on: Jun 1, 2015
 *      Author: havock
 */
#include <string.h>
#include <oclh_cc.h>
#include <oclh.h>

int32_t main(int32_t argc, char *argv[]) {
    int32_t err=0;
    char *pcOutputPrefix  = NULL,
         *pcOCLBuildOpts  = NULL,
        **ppcSrcFilenames = NULL;
    _GHT_LOG Log=_ghf_declLog();
    _GHT_AWSS AWSs=_ghf_declAWSs(_GHE_LOG_ALL,
                                 _GHE_BUILD_LOG_IN_SEPARATED_FILES);
    _GHT_DEVLIST_DESC DevLstDesc=_ghf_declDevLstDesc();
    _GHE_OUTNAME_TYPE OutNameType=_GHE_VOLATILE_OUTPUT_NAME;
    {
        uint64_t i=1ul;
        for(i=1ul; i<(uint64_t)argc; i++) {
            if(argv[i][0]=='-') { /* key-value */
                if(argv[i][1]=='o' ||
                   !strncmp(argv[i],"--dev-idxs=",11ul) ||
                   !strncmp(argv[i],"--dev-name=",11ul) ||
                   !strncmp(argv[i],"--verbatim-output-name",22ul)   ) {
                    if(argv[i][1]=='o') { /* output prefix */
                        if(!argv[i][2]) { pcOutputPrefix=argv[++i]; }
                        else { pcOutputPrefix=argv[i]+2ul; }
                    }
                    if(!strncmp(argv[i],"--dev-idxs=",11ul)) {
                        uint64_t b=0ul, e=1ul;
                        char cPrev='s', *pcDevIdxs=NULL;
                        if(argv[i][11]) { pcDevIdxs=&argv[i][11]; }
                        else { pcDevIdxs=argv[++i]; }
                        while(cPrev) {
                            while(pcDevIdxs[e] && pcDevIdxs[e]!=',') e++;
                            cPrev=pcDevIdxs[e];
                            pcDevIdxs[e]='\0';
                            err|=_ghf_addDevIdxToDevLstDesc(&DevLstDesc,
                                                  (cl_uint)atoi(&pcDevIdxs[b]));
                            b=e+1; e=b;
                        }
                    }
                    if(!strncmp(argv[i],"--dev-name=",11ul)) {
                        if(argv[i][11]) {
                            err|=_ghf_setDevLstDesc_DevNameWC(&DevLstDesc,
                                                              &argv[i][11]);
                        } else {
                            err|=_ghf_setDevLstDesc_DevNameWC(&DevLstDesc,
                                                              argv[++i]);
                        }
                    }
                    if(!strncmp(argv[i],"--verbatim-output-name",22ul))
                        OutNameType=_GHE_VERBATIM_OUTPUT_NAME;
                } else { /* compiler and linker options */
                    err=__ghf_concatHeapStrAndCharPtr(&pcOCLBuildOpts,
                                                       argv[i]);
#if defined(__OCLH_BUILDER_FLAG) || defined(__OCLH_COMPILER_ONLY_FLAG)
                    if((argv[i][1]=='D' || argv[i][1]=='I') && !argv[i][2]) {
                        err|=__ghf_concatHeapStrAndCharPtr(&pcOCLBuildOpts,
                                                           argv[++i]);
                    }
#endif /* defined(__OCLH_BUILDER_FLAG) || defined(__OCLH_COMPILER_ONLY_FLAG) */
                }
            } else err=_ghf_addCharPtrToCharPtrList(&ppcSrcFilenames,argv[i]);
            if(err) {
                fprintf(stderr,
                        "Unable to add item \"%s\" to compiler options list\n",
                        argv[i]);
                _ghf_wipeDevLstDesc(&DevLstDesc);
                _ghf_wipeCharPtrList(&ppcSrcFilenames);
                _ghf_freeHostZ(&pcOCLBuildOpts);
                return(err);
            }
        }
    }
    if(pcOutputPrefix) {
        __ghf_removePreNPostSpacesFromCharPtr(pcOutputPrefix);
        __ghf_replaceSpacesWithUnderscoreInCharPtr(pcOutputPrefix);
    }
    if(ppcSrcFilenames) {
        uint64_t i=0ul;
        for(i=0ul; ppcSrcFilenames[i]; i++)
            __ghf_removePreNPostSpacesFromCharPtr(ppcSrcFilenames[i]);
    } else {
        _ghf_wipeDevLstDesc(&DevLstDesc);
        _ghf_wipeCharPtrList(&ppcSrcFilenames);
        _ghf_freeHostZ(&pcOCLBuildOpts);
        fprintf(stderr, "No source files specified\n");
        return(1);
    }
    err=_ghf_genrLog(&Log,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                     _GHM_OCLH_COMPILER_LOG_FILENAME
#endif /* defined(__OCLH_COMPILER_ONLY_FLAG) */
#if defined(__OCLH_LINKER_ONLY_FLAG)
                     _GHM_OCLH_LINKER_LOG_FILENAME
#endif /* defined(__OCLH_LINKER_ONLY_FLAG) */
#if defined(__OCLH_BUILDER_FLAG)
                     _GHM_OCLH_BUILDER_LOG_FILENAME
#endif /* defined(__OCLH_BUILDER_FLAG) */
                    );
    if(err) {
        _ghf_wipeDevLstDesc(&DevLstDesc);
        _ghf_wipeCharPtrList(&ppcSrcFilenames);
        _ghf_freeHostZ(&pcOCLBuildOpts);
        _ghf_wipeLog(&Log);
        fprintf(stderr,"Unable to open the log file %s\n",
                _GHM_OCLH_BUILDER_LOG_FILENAME);
        return(err);
    }
    {
        char** ppcSources=NULL;
        uint64_t i=0ul;
        while(ppcSrcFilenames[i]) {
            err|=_ghf_addFileToCharPtrListWithSizes(&ppcSources,
                                                    ppcSrcFilenames[i],
#if defined(__OCLH_BUILDER_FLAG) || defined(__OCLH_COMPILER_ONLY_FLAG)
                                                    8);
#else
                                                    1);
#endif /* defined(__OCLH_BUILDER_FLAG) || defined(__OCLH_COMPILER_ONLY_FLAG) */
            i++;
        }
        err=_ghf_genrAWSs(&AWSs,Log,DevLstDesc,ppcSources,
#if defined(__OCLH_BUILDER_FLAG) || defined(__OCLH_COMPILER_ONLY_FLAG)
                          _GHE_HL_LISTINGS,
#endif /* defined(__OCLH_BUILDER_FLAG) || defined(__OCLH_COMPILER_ONLY_FLAG) */
#if defined(__OCLH_LINKER_ONLY_FLAG)
                          _GHE_SEPARATED_OBJECTS,
#endif /* defined(__OCLH_LINKER_ONLY_FLAG) */
                          pcOCLBuildOpts, pcOutputPrefix);
        _ghf_wipeDevLstDesc(&DevLstDesc);
        _ghf_wipeCharPtrList(&ppcSrcFilenames);
        _ghf_wipeCharPtrListWithSizes(&ppcSources);
        _ghf_freeHostZ(&pcOCLBuildOpts);
        if(err) fprintf(stderr,"Check the log file\n");
    }
    {
        uint64_t i=0ul;
        for(i=0ul; i<AWSs.u64NofWSs; i++)
            _ghf_saveWS_ProgramBinaries(AWSs.pWSet[i],
                                        pcOutputPrefix, OutNameType);
    }
    _ghf_wipeAWSs(&AWSs);
    _ghf_wipeLog(&Log);
    return(err);
}
