/* mkmake.c -- Martin Hohl -- 28.Dez.1991 -- All rights reserved */
/********************************************************************/
/* Name:  mkmake.c                                                  */
/* Zweck: Makefile-Generator für MS-DOS und AmigaDOS        |    |  */
/*                                                          |    |  */
/* Autor: Martin Hohl                                       |\__/`  */
/*        Robert-Leicht-Strasse 132                         |       */
/*        D-7000 Stuttgart 80                               |       */
/*        F.R.Germany                                               */
/* Version:  0.2 vom 07.05.1992                                     */
/* Compiler: AmigaDOS: SAS/C 5.10                                   */
/* Letzte Modifikation:  07.05.1992                                 */
/* Status: Freeware, (C)opyright by Martin Hohl                     */
/********************************************************************/

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

#ifdef __TURBOC__
#include <dos.h>
#include <dir.h>
#define MSDOS

#define OBJEXT "OBJ"
#define OBJEXTLC "obj"
#define LIBRARIAN "tlib"
#endif

#ifdef AMIGA
#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

#define OBJEXT "O"
#define OBJEXTLC "o"
#define LIBRARIAN "oml"

extern struct DosLibrary *DOSBase;

#define DosVersion (DOSBase->dl_lib.lib_Version)

#define NAMESIZE 128
#endif

#ifdef AZTEC_C
#include <functions.h>
#endif

#ifdef LATTICE_50
#include <proto/exec.h>
#include <proto/dos.h>

/* these were unimplemented until dos 36.147 */

BOOL ParsePatternNoCase( UBYTE *pat, UBYTE *buf, long buflen );
BOOL MatchPatternNoCase( UBYTE *pat, UBYTE *str );

#pragma libcall DOSBase ParsePatternNoCase 3C6 32103
#pragma libcall DOSBase MatchPatternNoCase 3CC 2102
#endif

#ifdef MSDOS
#define NAMESIZE 14
#endif

void AddToNameList(struct NameList **, char *);
void FreeNameList(struct NameList **);
void MakeExt(char *, char *, char *);
void MakeBasename(char *, char *);
void strlcpy(register char *, register char *);
void mputn(FILE *, char *, unsigned);
int iswild(char *);
void scandir(char *, struct NameList **);
int exists(char *);
int tolower(int);
#ifdef AMIGA
int match(char *, char *);
char *parsepath(char *, char **);
void cleanup(UBYTE *, USHORT, struct FileInfoBlock *, BPTR);
#endif

struct NameList {
  struct NameList *Next;
  char Name[NAMESIZE];
};

/* Name in Liste einfuegen */
void AddToNameList(list,name)
struct NameList **list;
char *name;
{
  register struct NameList *ptr;
 
  if ((ptr=(struct NameList *)malloc(sizeof(struct NameList)))==0L) {
    printf("not enough memory for malloc()\n");
    exit(-1);
  };
  strncpy(ptr->Name,name,NAMESIZE);
  ptr->Next = *list;
  *list=ptr;
}
 
/* Liste komplett freigeben */
void FreeNameList(ptr)
struct NameList **ptr;
{
  register struct NameList *workptr, *nextptr;
 
  workptr = *ptr;
  while (workptr!=0L) {
    nextptr=workptr->Next;
    free(workptr);
    workptr=nextptr;
  };
  *ptr=0L;
}

/* (Neue) Extension an Filenamen anhängen */
void MakeExt(NewName,filename,newext)
register char *NewName;
register char *filename;
register char *newext;
{
  while ((*filename != '.') && (*filename != '\0')) {
    *NewName++ = *filename++;
  };
  *NewName++ = '.';
  while (*newext != '\0') {
    *NewName++ = *newext++;
  };
  *NewName = '\0';
}

/* Base-Name aus Dateinamen erzeugen, Parameter-Reihenfolge wie bei strcpy */
void MakeBasename(Basename,Filename)
register char *Basename;
register char *Filename;
{
  while ((*Filename != '.') && (*Filename != '\0')) {
    *Basename++ = *Filename++;
  };
  *Basename = '\0';
}

/* String-Kopieren mit Umwandlung in lowercase */
void strlcpy(register char *dest, register char *src)
{
  char c;

  while (*src != '\0') {
    c = tolower(*src);
    *dest++ = c;
    src++;
  };
  *dest = '\0';
}

#ifdef TEST
void mputn(FILE * fp, char *str, unsigned max)
{
  unsigned i;

  i=max;
  while ((i != 0) && (*str != '\0')) {
    putc(*str,fp);
    str++;
    i--;
  };
  while (i != 0) {
    putc(' ',fp);
    i--;
  };
}
#endif

/*--------SYSTEM DEPENDENT FUNCTION SECTION---------------------*/
/* Prüfen, ob Name ein Wildcard-Muster enthält */
int iswild(char *Pattern)
{
  int rc;
#ifdef MSDOS
  rc = (strchr(Pattern,'*') != 0L) || (strchr(Pattern,'?') != 0L);
#endif
#ifdef AMIGA
  rc = 0;
  while (*Pattern != '\0') {
    switch(*Pattern) {
      case '#':
      case '?':
      case '|':
      case '(':
      case ')':
      case '[':
      case ']':
        rc = ~0;
        break;
    };
    Pattern++;
  };
#endif
  return rc;
}

#ifdef AMIGA
/* Pfadname zerlegen */
char *parsepath(char *pathname, char **Pattern)
{
  register char *s,*d, *Path;

  s = strrchr(pathname,'/');
  if (s == 0L) s = strrchr(pathname,':');
  if (s != 0L) {
    Path = d = malloc((unsigned)(s-pathname)+1);
    while ((*pathname != '\0') && (pathname != s)) {
      *d++ = *pathname++;
    };
    if (pathname == s) *d++ = *pathname;
    *d = '\0';
    s++;
    *Pattern = strdup(s);
  }
  else {
    Path = malloc(1);
    *Path = '\0';
    *Pattern = strdup(pathname);
  };
  { register unsigned char *s;
  s = *Pattern;
  while (*s != '\0') {
    if ((*s >='a') && (*s <= 'z')) *s &= 0xDF;
    s++;
  };
  }
  return Path;
}

void cleanup(UBYTE *PBuf, USHORT PBufLen, struct FileInfoBlock *FIB, BPTR DirLock)
{
  if (PBuf != 0L) FreeMem(PBuf, PBufLen);
  if (FIB != 0L) FreeMem(FIB, sizeof(struct FileInfoBlock));
  if (DirLock != 0L) UnLock(DirLock);
}
#endif

/* scan the directory given by pathname */
void scandir(char *pathname, struct NameList **rootptr)
{
#ifdef MSDOS
  int attrmask,rc;
  struct NameList *work;
  struct ffblk *dirp;
  if ((dirp = malloc(sizeof(struct ffblk))) == NULL) {
    fputs("Cannot allocate memory\n",stderr);
    exit(0);
  };
  memset(dirp,0,sizeof(struct ffblk));

  attrmask = FA_DIREC | FA_ARCH | FA_RDONLY;
  rc = findfirst(pathname, dirp, attrmask);
  while (rc == 0) {
    if (!(dirp->ff_attrib & FA_DIREC)) { /* normale Datei */
      AddToNameList(rootptr,dirp->ff_name);
    }; /* if ... FA_DIREC */
    rc = findnext(dirp);
  }; /* while */
  free(dirp);
#endif
#ifdef AMIGA
  UBYTE *PBuf = 0L;
  USHORT PBufLen = 0;
  BPTR DirLock = 0L;
  ULONG success;
  struct FileInfoBlock *FIB = 0L;
  char *Pattern, *Path;
  char fullname[128];

  Path = parsepath(pathname,&Pattern);

  PBufLen = (strlen(Pattern)+1)*3;
  if ((PBuf = AllocMem((ULONG)PBufLen, MEMF_PUBLIC | MEMF_CLEAR)) == 0L) {
    fputs("not enough memory\n",stderr);
    exit(0);
  };

  if (DosVersion >= 37) {
    int IsWild = ParsePatternNoCase(Pattern,PBuf,(ULONG)PBufLen);
    if (IsWild==-1) {
      fputs("Pech gehabt ! Puffer für ParsePattern war zu klein.\n",stderr);
      cleanup(PBuf,PBufLen,FIB,DirLock);
      exit(0);
    };
  };

  if ((FIB = AllocMem((ULONG)sizeof(struct FileInfoBlock),MEMF_PUBLIC)) == NULL) {
    fputs("not enough memory\n",stderr);
    cleanup(PBuf,PBufLen,FIB,DirLock);
    exit(0);
  };

  DirLock = Lock(Path,SHARED_LOCK);
  if (DirLock==NULL) {
    fputs("Cannot get a lock for ",stderr);
    fputs(pathname,stderr);
    putc('\n',stderr);
    cleanup(PBuf,PBufLen,FIB,DirLock);
    exit(0);
  };

  if (success = Examine(DirLock, FIB)) {
    if (DosVersion >= 37) {
      while (success) {
        if (FIB->fib_DirEntryType < 0 ) {
          if (MatchPatternNoCase(PBuf,FIB->fib_FileName)) {
#ifdef TEST
            mputn(stderr,FIB->fib_FileName,40);
            putc('\r',stderr);
            fflush(stderr);
#endif
            if (*Path != '\0') {
              strncpy(fullname,Path,128);
              strcat(fullname,FIB->fib_FileName);
              AddToNameList(rootptr, fullname);
            }
            else AddToNameList(rootptr, FIB->fib_FileName);
          };
        }; /* if */
        success = ExNext(DirLock, FIB);
      }; /* while */
    }
    else {
      while (success) {
        if (FIB->fib_DirEntryType < 0 ) {
          if (match(FIB->fib_FileName,Pattern)) {
#ifdef TEST
            mputn(stderr,FIB->fib_FileName,40);
            putc('\r',stderr);
            fflush(stderr);
#endif
            if (*Path != '\0') {
              strncpy(fullname,Path,128);
              strcat(fullname,FIB->fib_FileName);
              AddToNameList(rootptr, fullname);
            }
            else AddToNameList(rootptr, FIB->fib_FileName);
          };
        }; /* if */
        success = ExNext(DirLock, FIB);
      }; /* while */
    }
  }
  else {
    fputs("Cannot examine directory ",stderr);
    fputs(pathname,stderr);
    putc('\n',stderr);
    cleanup(PBuf,PBufLen,FIB,DirLock);
    exit(20);
  };

  UnLock(DirLock);
  DirLock = 0L;

  FreeMem(FIB, (ULONG)sizeof(struct FileInfoBlock));
  FIB = 0L;
  FreeMem(PBuf, (ULONG)PBufLen);
  PBuf = 0L;
#endif
}

/* Test whether a file exists */
int exists(char *filename)
{
  int rc;
  rc = access(filename,0);
  return(rc==0);
}

/*---END OF SYSTEM DEPENDENT FUNCTION SECTION---------------------*/

/* Hauptprogramm */
main(argc,argv)
int argc;
char *argv[];
{
  static char pathname[20][128];
  int i;
  static char objname[128];
  static char objext[12];
  static char mainfile[13];
  static char filename[13];
  static char libfile[13];

  int anzpn = 0;
  struct NameList *Root, *work;
  char allflag, librarian;
  int l,lf;

  char mainflag, lowercase = 0;
  register char *argstr;
  char *allstr;

  if (argc<=1) {
    fputs("Usage: ",stderr);
    fputs(argv[0],stderr);
    fputs(" [-o<objext>] [-m<mainfile>] [-aL] [-r<libfile>] fpattern\n",stderr);
  };
  strncpy(objext,OBJEXT,12);
  strncpy(mainfile,"",13);
  allflag = 0; librarian = 0;

  for (i=1; i<argc; i++) {
    argstr = argv[i];
    if (*argstr == '-') {
      argstr++;
      switch(*argstr) {
        case 'o': strncpy(objext,++argstr,12); break;
        case 'm': strncpy(mainfile,++argstr,12); break;
        case 'a': allflag = !0; break;
        case 'r': librarian = !0; strncpy(libfile,++argstr,12); break;
        case 'L': 
          lowercase = !0;
          strlcpy(objext,objext);
          break;
        default: 
          fputs("Unknown option -",stderr);
          putc(*argstr,stderr);
          fputs(" ignored\n",stderr);
      };
    }
    else strncpy(pathname[anzpn++],argv[i],128);
  };

  Root = 0L;
  for (i=0; i<anzpn; i++) { 
    if (iswild(pathname[i])) scandir(pathname[i],&Root);
    else {
      if (exists(pathname[i])) AddToNameList(&Root,pathname[i]);
    }
  }; /* for */

  if (allflag) {
    putchar('\n');
    if ((allstr = malloc(256)) == 0L) {
      fputs("not enough memory for malloc\n",stderr);
      exit(0);
    };
    strncpy(allstr,"SOURCES = ",256);
    for (work=Root; work != 0L; work=work->Next) {
      if (lowercase) strlcpy(filename,work->Name);
      else strcpy(filename,work->Name);
      l = strlen(allstr); 
      lf = strlen(filename);
      if (l+lf<78) {
        strcat(allstr,filename);
        l += lf;
      }
      else {
        fputs(allstr,stdout);
        fputs(" \\\n",stdout);
        strncpy(allstr,"          ",256);
        strcat(allstr,filename);
      };        
      if (work->Next != 0L) {
        strcat(allstr," ");
      }
      else {
        if (strcmp(allstr,"          ")!=0) {
          fputs(allstr,stdout);
          putchar('\n');
        };
        putchar('\n');
      };
    };
    strncpy(allstr,"OBJ = ",256);
    for (work=Root; work != 0L; work=work->Next) {
      if (lowercase) strlcpy(filename,work->Name);
      else strcpy(filename,work->Name);
      if (lowercase) MakeExt(objname,filename,OBJEXTLC);
      else MakeExt(objname,filename,OBJEXT);
      l = strlen(allstr); 
      lf = strlen(objname);
      if (l+lf<78) {
        strcat(allstr,objname);
        l += lf;
      }
      else {
        fputs(allstr,stdout);
        fputs(" \\\n",stdout);
        strncpy(allstr,"      ",256);
        strcat(allstr,objname);
      };        
      if (work->Next != 0L) {
        strcat(allstr," ");
      }
      else {
        if (strcmp(allstr,"      ")!=0) {
          fputs(allstr,stdout);
          putchar('\n');
        };
        putchar('\n');
      };
    };
    free(allstr); 
  };
  for (work=Root; work != 0L; work=work->Next) {
    if (lowercase) strlcpy(filename,work->Name);
    else strcpy(filename,work->Name);
    if (stricmp(filename,mainfile)==0) mainflag = !0;
    else mainflag = 0;
    if (mainflag) {
#ifdef MSDOS
      if (lowercase) MakeExt(objname,filename,"exe");
      else MakeExt(objname,filename,"EXE");
#else
      MakeBasename(objname,filename);
#endif
    }
    else {
      if (lowercase) MakeExt(objname,filename,objext);
      else MakeExt(objname,filename,objext);
    };
    fputs(objname,stdout);
    putchar(':');
    putchar(' ');
    fputs(filename,stdout);
    putchar('\n');
    fputs("\t$(CC) $(CFLAGS) ",stdout);
#ifndef AMIGA
    if (!mainflag) fputs("-c ",stdout);
#endif
    fputs(filename,stdout);
    putchar('\n');
    if (work->Next != 0L) putchar('\n'); 
  }
  if (librarian) {
    putchar('\n');
    if ((allstr = malloc(256)) == 0L) {
      fputs("not enough memory for malloc\n",stderr);
      exit(0);
    };
    if (libfile[0] == '\0') strcpy(libfile,"libtest.lib");
    fputs(libfile,stdout);
    fputs(": $(OBJ)\n",stdout);
#ifdef MSDOS
    strncpy(allstr,"\ttlib ",256);
#endif
#ifdef AMIGA
    strncpy(allstr,"\toml -v ",256);
#endif
    strcat(allstr,libfile);
#ifdef AMIGA
    strcat(allstr," r");
#endif
    for (work=Root; work != 0L; work=work->Next) {
      if (lowercase) strlcpy(filename,work->Name);
      else strcpy(filename,work->Name);
      if (lowercase) MakeExt(objname,filename,OBJEXTLC);
      else MakeExt(objname,filename,OBJEXT);
      l = strlen(allstr); 
      lf = strlen(objname);
      if (l+lf<100) {
#ifdef MSDOS
        strcat(allstr," +-");
        strcat(allstr,objname);
#endif
#ifdef AMIGA
        strcat(allstr," ");
        strcat(allstr,objname);
#endif
        l += lf;
      }
      else {
        fputs(allstr,stdout);
        putchar('\n');
#ifdef MSDOS
        strncpy(allstr,"\ttlib ",256);
        strcat(allstr,libfile);
        strcat(allstr," -+");
        strcat(allstr,objname);
#endif
#ifdef AMIGA
        strncpy(allstr,"\toml -v ",256);
        strcat(allstr,libfile);
        strcat(allstr," r ");
        strcat(allstr,objname);
#endif
      };        
      if (work->Next == 0L) {
        fputs(allstr,stdout);
        putchar('\n');
        putchar('\n');
      };
    };
  };
}
