/*
 * Simple tool for generating dependencies from .c/.h files.
 * Requires djgpp or MingW.
 *
 * Notes: This isn't a C-preprocessor, so it doesn't correctly handle
 * "#include" files inside "#if" blocks. Output dependencies are always
 * written in lower case.
 */

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

#include "sysdep.h"

#define TRACE(level, fmt, ...)                  \
        do {                                    \
          if (verbose >= level) {               \
            printf ("# line %u: "fmt, __LINE__, \
                    ##__VA_ARGS__);             \
          }                                     \
        } while (0)

#ifdef __MINGW32__
int _dowildcard = 1; /* Required for MinGW-64 to glob the cmd-line. */
#endif

char  include[]  = "#include";
char  exclude[]  = "@NO_DEP";
char *obj_prefix = "";
char *obj_suffix = ".$(O)";

int usage (const char *who_am_i)
{
  printf ("syntax: %s [-v] [-p obj-prefix] [-s obj-suffix] "
          ".c/.h-files | @resp\n", who_am_i);
  return (-1);
}

void print_deps (const char *ipath, char *fname)
{
}

int main (int argc, char **argv)
{
  int   ch, idx;
  int   num_files = 0;
  int   num_includes = 0;
  int   num_deps = 0;
  int   verbose = 0;
  char *prog = argv[0];
  char *fname;

  while ((ch = getopt(argc,argv,"vp:s:")) != EOF)
     switch (ch)
     {
       case 'v': verbose = 1;
                 break;
       case 'p': obj_prefix = optarg;
                 break;
       case 's': obj_suffix = optarg;
                 break;
       case '?':
       default:  return usage (prog);
     }

  argc -= optind;
  argv += optind;

  if (argc < 1)
     return usage (prog);

  printf ("#\n# Generated by %s. DO NOT EDIT\n#\n", prog);

  for (idx = 0; idx < argc && (fname = argv[idx]) != NULL; idx++)
  {
    char  buf[512], *dot, *slash;
    int   c_file, h_file;
    int   rvalue;
    FILE *fin;

    fname = strdup (fname);
    strlwr (fname);
    dot = strrchr (fname, '.');
    if (!dot)
    {
      TRACE (0, "`%s' is not a .c or .h-file\n", fname);
      continue;
    }

    TRACE (1, "Processing `%s'\n", fname);

    c_file = (stricmp(dot,".c") == 0);
    h_file = (stricmp(dot,".h") == 0);

    if (!c_file && !h_file)
    {
      TRACE (0, "`%s' is not a .c or .h-file\n", fname);
      continue;
    }

    fin = fopen (fname, "rt");
    if (!fin)
    {
      TRACE (0, "Cannot open `%s'\n", fname);
      return (-1);
    }

    slash = strrchr (fname, '/');
    rvalue = 0;
    num_deps = 0;

    while (fgets(buf,sizeof(buf),fin))
    {
      char *cp, *cp1 = buf;

      while (isspace(*cp1))
            cp1++;

      if (*cp1 != '#' || ++cp1 == '\0')
         continue;

      while (isspace(*cp1))
            cp1++;

      if (!*cp1 ||
          strnicmp(cp1,"include",7) ||
          (cp = strchr(cp1,'\"')) == NULL)
         continue;

      cp++;
      if (!*cp || (cp1 = strchr(cp, '\"')) == NULL)   /* find right '"' */
         continue;

      /* Only accept .c/.h files
       */
      if (cp1[-2] != '.' || (cp1[-1] != 'c' && cp1[-1] != 'h'))
         continue;

      if (strstr(cp,exclude))
      {
        TRACE (1, "Excluding line %s\n", buf);
        continue;
      }

      num_includes++;
      num_deps++;

      if (!rvalue)  /* processing left side of dependency */
      {
        if (c_file)
             printf ("%s%.*s%s: %s", obj_prefix, dot-fname, fname, obj_suffix, fname);
        else printf ("%s:", fname);
        rvalue = 1;
      }

      /* now print the right side */
      *cp1 = '\0';
      if (slash && c_file)
           printf (" %.*s%s", slash-fname, fname, cp);
      else printf (" %s", cp);

#if 0
      /* Try to follow the include_path */
      for (ipath = inc_path; ipath; ipath++)
        print_deps (ipath, fname);
#endif
    }

    if (rvalue)
       putchar ('\n');
    fclose (fin);

    num_files++;
    if (num_deps > 0)
       TRACE (1, "  %d dependant(s)\n", num_deps);
  }

  TRACE (1, "Processed %d files with %d include files\n",
         num_files, num_includes);

  return (num_files > 0 ? 0 : 1);
}

