/**************************************************************************
*
*   Copyright (C) 2000-2004, International Business Machines
*   Corporation and others.  All Rights Reserved.
*
***************************************************************************
*   file name:  make.c
*   encoding:   ANSI X3.4 (1968)
*   tab size:   8 (not used)
*   indentation:4
*
*   created on: 2000jul18
*   created by: Vladimir Weinstein
*   created on: 2000may17
*   created by: Steven \u24C7 Loomis
*   merged on: 2003sep14
*   merged by: George Rhoten
*   merged from nmake.c and gmake.c
*
* Emit a NMAKE or GNU makefile
*/

#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "makefile.h"
#include "cstring.h"
#include <stdio.h>

#ifdef U_MAKE_IS_NMAKE

char linebuf[2048];

/* Write any setup/initialization stuff */
void
pkg_mak_writeHeader(FileStream *f, const UPKGOptions *o)
{
    const char *appendVersion = NULL;
    if(o->version && !uprv_strstr(o->shortName,o->version)) { /* do not append version if 
                                                                 already contained in the name */
      appendVersion = o->version;
    }

    sprintf(linebuf, "## Makefile for %s (%s) created by pkgdata\n"
                    "## from ICU Version %s\n"
                    "\n",
                    o->shortName,
                    o->libName,
                    U_ICU_VERSION);
    T_FileStream_writeLine(f, linebuf);
    
    sprintf(linebuf, "NAME=%s%s\n"
                    "CNAME=%s\n"
                    "LIBNAME=%s\n"
                    "SRCDIR=%s\n"
                    "TARGETDIR=%s\n"
                    "TEMP_DIR=%s\n"
                    "MODE=%s\n"
                    "MAKEFILE=%s\n"
                    "ENTRYPOINT=%s\n"
                    "TARGET_VERSION=%s\n"
                    "MKINSTALLDIRS=mkdir\n"
                    "\n\n\n",
                    o->shortName,
                    (appendVersion ? appendVersion : ""),
                    o->cShortName,
                    o->libName,
                    o->srcDir,
                    o->targetDir,
                    o->tmpDir,
                    o->mode,
                    o->makeFile,
                    o->entryName,
                    o->version);
    T_FileStream_writeLine(f, linebuf);

    sprintf(linebuf, "## List files [%d] containing data files to process (note: - means stdin)\n"
        "LISTFILES= ",
        pkg_countCharList(o->fileListFiles));
    T_FileStream_writeLine(f, linebuf);

    pkg_writeCharListWrap(f, o->fileListFiles, " ", " \\\n", 0);

    T_FileStream_writeLine(f, "\n\n\n");

    sprintf(linebuf, "## Data Files [%d]\n"
        "DATAFILES= ",
        pkg_countCharList(o->files));

    T_FileStream_writeLine(f, linebuf);

    pkg_writeCharListWrap(f, o->files, " ", " \\\n", -1);

    T_FileStream_writeLine(f, "\n\n\n");

    sprintf(linebuf, "## Data File Paths [%d]\n"
        "DATAFILEPATHS= ",
        pkg_countCharList(o->filePaths));

    T_FileStream_writeLine(f, linebuf);

    pkg_writeCharListWrap(f, o->filePaths, " ", " \\\n", 1);

    T_FileStream_writeLine(f, "\n\n\n");

}

/* Write a stanza in the makefile, with specified   "target: parents...  \n\n\tcommands" [etc] */
void
pkg_mak_writeStanza(FileStream *f, const UPKGOptions *o, 
                    const char *target,
                    CharList* parents,
                    CharList* commands )
{
    T_FileStream_write(f, target, (int32_t)uprv_strlen(target));
    T_FileStream_write(f, " : ", 3);
    pkg_writeCharList(f, parents, " ",1);
    T_FileStream_write(f, "\n", 1);
    
    if(commands)
    {
        T_FileStream_write(f, "\t", 1);
        pkg_writeCharList(f, commands, "\n\t",0);
    }
    T_FileStream_write(f, "\n\n", 2);
}

/* write any cleanup/post stuff */
void
pkg_mak_writeFooter(FileStream *f, const UPKGOptions *o)
{
    char buf[256];
    sprintf(buf, "\n\n# End of makefile for %s [%s mode]\n\n", o->shortName, o->mode);
    T_FileStream_write(f, buf, (int32_t)uprv_strlen(buf));
}

#else   /* #ifdef WIN32 */

#include "cmemory.h"
#include "filestrm.h"
#include "toolutil.h"
#include "unewdata.h"
#include "uoptions.h"
#include "pkgtypes.h"
#include <string.h>

char linebuf[2048];

/* Write any setup/initialization stuff */
void
pkg_mak_writeHeader(FileStream *f, const UPKGOptions *o)
{
    sprintf(linebuf, "## Makefile for %s created by pkgdata\n"
                    "## from ICU Version %s\n"
                    "\n",
                    o->shortName,
                    U_ICU_VERSION);
    T_FileStream_writeLine(f, linebuf);
    
    sprintf(linebuf, "NAME=%s\n"
                     "LIBNAME=%s\n"
                    "CNAME=%s\n"
                    "TARGETDIR=%s\n"
                    "TEMP_DIR=%s\n"
                    "srcdir=$(TEMP_DIR)\n"
                    "SRCDIR=%s\n"
                    "MODE=%s\n"
                    "MAKEFILE=%s\n"
                    "ENTRYPOINT=%s\n"
                    "include %s\n"
                    "\n\n\n",
                    o->shortName,
                    o->libName,
                    o->cShortName,
                    o->targetDir,
                    o->tmpDir,
                    o->srcDir,
                    o->mode,
                    o->makeFile,
                    o->entryName,
                    o->options);
    T_FileStream_writeLine(f, linebuf);
    
    /* TEMP_PATH  and TARG_PATH will be empty if the respective dir is . */
    /* Avoid //'s and .'s which confuse make ! */
    if(!strcmp(o->tmpDir,"."))
    {
        T_FileStream_writeLine(f, "TEMP_PATH=\n");
    }
    else
    {
        T_FileStream_writeLine(f, "TEMP_PATH=$(TEMP_DIR)/\n");
    }
    
    if(!strcmp(o->targetDir,"."))
    {
        T_FileStream_writeLine(f, "TARG_PATH=\n");
    }
    else
    {
        T_FileStream_writeLine(f, "TARG_PATH=$(TARGETDIR)/\n");
    }

    sprintf(linebuf, "## List files [%u] containing data files to process (note: - means stdin)\n"
                    "LISTFILES= ",
                    (int)pkg_countCharList(o->fileListFiles));
    T_FileStream_writeLine(f, linebuf);

    pkg_writeCharListWrap(f, o->fileListFiles, " ", " \\\n",0);

    T_FileStream_writeLine(f, "\n\n\n");

    sprintf(linebuf, "## Data Files [%u]\n"
        "DATAFILES= ",
        (int)pkg_countCharList(o->files));

    T_FileStream_writeLine(f, linebuf);

    pkg_writeCharListWrap(f, o->files, " ", " \\\n",-1);

    T_FileStream_writeLine(f, "\n\n\n");

    sprintf(linebuf, "## Data File Paths [%u]\n"
                    "DATAFILEPATHS= ",
                    (int)pkg_countCharList(o->filePaths));

    T_FileStream_writeLine(f, linebuf);

    pkg_writeCharListWrap(f, o->filePaths, " ", " \\\n",0);

    T_FileStream_writeLine(f, "\n\n\n");

}

/* Write a stanza in the makefile, with specified   "target: parents...  \n\n\tcommands" [etc] */
void
pkg_mak_writeStanza(FileStream *f, const UPKGOptions *o, 
                    const char *target,
                    CharList* parents,
                    CharList* commands)
{
    T_FileStream_write(f, target, uprv_strlen(target));
    T_FileStream_write(f, " : ", 3);
    pkg_writeCharList(f, parents, " ",0);
    T_FileStream_write(f, "\n", 1);
    
    if(commands)
    {
        T_FileStream_write(f, "\t", 1);
        pkg_writeCharList(f, commands, "\n\t",0);
    }
    T_FileStream_write(f, "\n\n", 2);
}

/* write any cleanup/post stuff */
void
pkg_mak_writeFooter(FileStream *f, const UPKGOptions *o)
{
    T_FileStream_writeLine(f, "\nrebuild: clean all\n");
}


void
pkg_mak_writeObjRules(UPKGOptions *o,  FileStream *makefile, CharList **objects, const char* objSuffix)
{
    const char *p, *baseName;
    char *tmpPtr;
    char tmp[1024];
    char stanza[1024];
    char cfile[1024];
    CharList *oTail = NULL;
    CharList *infiles;
    CharList *parents = NULL, *commands = NULL;
    int32_t genFileOffset = 0;  /* offset from beginning of .c and .o file name, use to chop off package name for AS/400 */
    static int serNo = 0; /* counter for numeric file names */
    char serName[100];

    if(o->embed) {
      infiles = o->filePaths;
    } else {
      infiles = o->files; /* raw files - no paths other than tree paths */
    }
    
#if defined (OS400)
    if(infiles != NULL) {
        baseName = findBasename(infiles->str);
        p = uprv_strchr(baseName, '_');
        if(p != NULL) { 
            genFileOffset = (p-baseName)+1; /* "package_"  - name + underscore */
        }
    }
#endif
    
    for(;infiles;infiles = infiles->next) {
      if(o->embed) {
        baseName = findBasename(infiles->str); 
      } else {
        baseName = infiles->str; /* skip the icudt28b/ part */
      }
      p = uprv_strrchr(baseName, '.');
      if( (p == NULL) || (*p == '\0' ) ) {
        continue;
      }
      
      if(o->numeric) {
        sprintf(serName, "t%04x", serNo++);
        uprv_strcpy(tmp,serName);
        uprv_strcat(tmp, objSuffix);
      } else {
        uprv_strncpy(tmp, baseName, p-baseName);
        p++;
        
        uprv_strcpy(tmp+(p-1-baseName), "_"); /* to append */
        uprv_strcat(tmp, p);
        uprv_strcat(tmp, objSuffix );
        
        /* iSeries cannot have '-' in the .o objects. */
        for( tmpPtr = tmp; *tmpPtr; tmpPtr++ ) {
          if ( *tmpPtr == U_FILE_SEP_CHAR ) { /* map tree names with underscores */
            *tmpPtr = '_';
          }
          if ( *tmpPtr == '-' ) {
            *tmpPtr = '_';
          }
        }
      }
      
      *objects = pkg_appendToList(*objects, &oTail, uprv_strdup(tmp + genFileOffset)); /* Offset for AS/400 */
      
      /* write source list */
      uprv_strcpy(cfile,tmp);
      uprv_strcpy(cfile+uprv_strlen(cfile)-uprv_strlen(objSuffix), ".c" ); /* replace .o with .c */
      
      /* Make up parents.. */
      if(!o->embed) {
        char *parentPath;
        parentPath = uprv_malloc(1+uprv_strlen(baseName) + uprv_strlen("$(SRCDIR)/"));
        sprintf(parentPath, "$(SRCDIR)/%s", baseName);
        parents = pkg_appendToList(parents, NULL, parentPath);
      } else {
        parents = pkg_appendToList(parents, NULL, uprv_strdup(infiles->str));
      }
      
      /* make up commands.. */
      if(!o->embed) {
        /* search for tree.. */
        const char *tchar;
        char tree[1024];
        if((tchar=uprv_strchr(baseName, '/'))) {
          tree[0]='_';
          strncpy(tree+1,baseName,tchar-baseName);
          tree[tchar-baseName+1]=0;
        } else {
          tree[0] = 0;
        }
#ifdef OS400
        sprintf(stanza, "$(INVOKE) $(GENCCODE) -n $(CNAME)%s -d $(TEMP_DIR) $(SRCDIR)/%s", tree, infiles->str);
#else
        sprintf(stanza, "$(INVOKE) $(GENCCODE) -n $(CNAME)%s -d $(TEMP_DIR) $<", tree);
#endif
      } else {
#ifdef OS400
        sprintf(stanza, "$(INVOKE) $(GENCCODE) -d $(TEMP_DIR) %s", infiles->str);
#else
        sprintf(stanza, "$(INVOKE) $(GENCCODE) -d $(TEMP_DIR) $<");
#endif
      }
      
      if(o->numeric) {
        strcat(stanza, " -f ");
        strcat(stanza,serName);
      } else if(!o->embed && uprv_strchr(baseName, '/')) {
        /* append actual file - ex:   coll_en_res  otherwise the tree name will be lost */
        strcat(stanza, " -f ");
        strncat(stanza, tmp, (strlen(tmp)-strlen(objSuffix)));
      }
      
      commands = pkg_appendToList(commands, NULL, uprv_strdup(stanza));
      
#ifdef OS400
      /* This builds the file into one .c file */
      sprintf(stanza, "@cat $(TEMP_PATH)%s >> $(TEMP_PATH)/$(NAME)all.c", cfile);
      commands = pkg_appendToList(commands, NULL, uprv_strdup(stanza));

      sprintf(stanza, "@$(RMV) $(TEMP_DIR)/%s", cfile);
      commands = pkg_appendToList(commands, NULL, uprv_strdup(stanza));
        
      T_FileStream_write(makefile, "\t", 1);
      pkg_writeCharList(makefile, commands, "\n\t",0);
      T_FileStream_write(makefile, "\n\n", 2);
#else
      if(genFileOffset > 0) {    /* for AS/400 */
        sprintf(stanza, "@mv $(TEMP_PATH)%s $(TEMP_PATH)%s", cfile, cfile+genFileOffset);
        commands = pkg_appendToList(commands, NULL, uprv_strdup(stanza));
      }
      
      sprintf(stanza, "@$(COMPILE.c) -o $@ $(TEMP_DIR)/%s", cfile+genFileOffset); /* for AS/400 */
      commands = pkg_appendToList(commands, NULL, uprv_strdup(stanza));
      
      sprintf(stanza, "@$(RMV) $(TEMP_DIR)/%s", cfile+genFileOffset);
      commands = pkg_appendToList(commands, NULL, uprv_strdup(stanza));
      
      sprintf(stanza, "$(TEMP_PATH)%s", tmp+genFileOffset); /* for AS/400 */
      pkg_mak_writeStanza(makefile, o, stanza, parents, commands);
#endif
      
      pkg_deleteList(parents);
      pkg_deleteList(commands);
      parents = NULL;
      commands = NULL;
    }   
}

#endif  /* #ifdef WIN32 */

void
pkg_mak_writeAssemblyHeader(FileStream *f, const UPKGOptions *o)
{
    T_FileStream_writeLine(f, "\n");
    T_FileStream_writeLine(f, "ifneq ($(GENCCODE_ASSEMBLY),)\n");
    T_FileStream_writeLine(f, "\n");
    T_FileStream_writeLine(f, "BASE_OBJECTS=$(NAME)_dat.o\n");
    T_FileStream_writeLine(f, "\n");
    T_FileStream_writeLine(f, "$(TEMP_DIR)/$(NAME).dat: $(CMNLIST) $(DATAFILEPATHS)\n");
    if(!o->embed) {
      T_FileStream_writeLine(f, "\t$(INVOKE) $(GENCMN) -c -e $(ENTRYPOINT) -n $(NAME) -s $(SRCDIR) -t dat -d $(TEMP_DIR) 0 $(CMNLIST)\n");
    } else {
      T_FileStream_writeLine(f, "\t$(INVOKE) $(GENCMN) -c -e $(ENTRYPOINT) -n $(NAME) -E -t dat -d $(TEMP_DIR) 0 $(CMNLIST)\n");
    }
    T_FileStream_writeLine(f, "\n");
    T_FileStream_writeLine(f, "$(TEMP_DIR)/$(NAME)_dat.o : $(TEMP_DIR)/$(NAME).dat\n");
    T_FileStream_writeLine(f, "\t$(INVOKE) $(GENCCODE) $(GENCCODE_ASSEMBLY) -n $(NAME) -e $(ENTRYPOINT) -d $(TEMP_DIR) $<\n");
    T_FileStream_writeLine(f, "\t$(COMPILE.c) $(DYNAMICCPPFLAGS) $(DYNAMICCXXFLAGS) -o $@ $(TEMP_DIR)/$(NAME)_dat"ASM_SUFFIX"\n");
    T_FileStream_writeLine(f, "\t$(RMV) $(TEMP_DIR)/$(NAME)_dat"ASM_SUFFIX"\n");
    T_FileStream_writeLine(f, "\n");
    T_FileStream_writeLine(f, "else\n");
    T_FileStream_writeLine(f, "\n");
}

void
pkg_mak_writeAssemblyFooter(FileStream *f, const UPKGOptions *o)
{
    T_FileStream_writeLine(f, "\nendif\n");
}

