/*
   SAS/C frontend with
   GCC-style options

   bf 11-14-96
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <proto/dos.h>
#include <proto/exec.h>

typedef struct Node Node;
typedef struct List List;

#define LBUFSIZE   1024
#define MAXPATHLEN 1024

const char *version = "\0$VER: scc 1.1 (11-17-96)\n";
List LibList;

void
cleanup (void)
{
  Node *node, *next;

  for (next = node = LibList.lh_Head; next = node -> ln_Succ; node = next)
  {
    if (node -> ln_Name)
      free (node -> ln_Name);
    free (node);
  }
}

void
add_library_dir (char *path)
{
  Node *ln;

  if (!(ln = (Node *) malloc (sizeof (Node))))
    goto cleanup;

  ln -> ln_Name = NULL;
  AddHead (&LibList, ln);

  if (!(ln -> ln_Name = malloc (strlen (path) + 1)))
    goto cleanup;
  
  strcpy (ln -> ln_Name, path);
  return;  

  cleanup:

  printf ("Out of memory.\n");
  exit (20);
}

char *
locate_library (char *lib)
{
  static char dir[MAXPATHLEN];
  Node *node, *next;
  BPTR lock;

  for (next = node = LibList.lh_Head; next = node -> ln_Succ; node = next)
  {
    strcpy (dir, node -> ln_Name);
    AddPart (dir, lib, MAXPATHLEN);
    strcat (dir, ".lib");
    if (lock = Lock (dir, ACCESS_READ))
    {
      UnLock (lock);
      return dir;
    }
  }
  return NULL;
}

char *
translate_path (char *path)
{
  static char s[MAXPATHLEN];
  char *f, *t, *p, *e;
  int len, dbl_slash = 0;

  p = path-1;
  t = s;
  e = path + strlen (path);

  while (p < e)
  {
   if (p = strchr (f=p+1, '/'))
     *p = '\0';
   else
     p = e;

   if (!(len = (int) p - (int) f))
     continue;

   if (len <= 3 && *f == '.')
   {
      if (len == 1)
        continue;
      if (*(f+1) == '.')
      {
        if (t != s && *(t-1) != '/')
        {
          dbl_slash = 1;
          *t = '/';
          t++;
        }
        *t = '/';
        t++;
        continue;
      }
    }
    if (t != s && *(t-1) != '/')
    {
      *t = '/';
      t++;
    }
    t = stpcpy (t, f);
    dbl_slash = 0;
  }
  if (dbl_slash)
    *(t-1) = '\0';
  if (t == s)
    strcpy (s, "\"\"");
  return s;
}

char *
option_argument (int argc, char *argv[], int *i)
{
  int t = *i;
  char *arg;

  if (argv[t][2] != '\0')
    arg = &argv[t][2];
  else
  {
    if (!argv[++(*i)])
    {
      printf ("%s: Option requires argument: '-%c'.\n", argv[0], argv[t][1]);
      exit (20);
    }
    arg = argv[*i];
  }
  return arg;
}

#define TTABSIZE 5

char *
translate_long_option (int argc, char *argv[], int *i)
{
  const struct {
    const char *from;
    const char *to;
  } TransTab[TTABSIZE] =
  {
    { "pedantic",		"ansi strict" },
    { "pedantic-errors",	"ansi err=all strict" },
    { "ansi",			"ansi" },
    { "Werror",			"err=all" },
    { "Wall",			"warn=all" }
  };
  char *opt = &argv[*i][1];
  int t;

  for (t=0; t<TTABSIZE; t++)
  {
    if (strcmp (opt, TransTab[t].from) == 0)
      return TransTab[t].to;
  }
  return NULL;
}

int
is_object_module (char *file)
{
  int len = strlen (file);

  if (file[len-2] == '.' && file[len-1] == 'o')
    return 1;
  return 0;
}

int
main (int argc, char *argv[])
{
  char *p, s[LBUFSIZE], *t, *l;
  int dont_link = 0, i, verbose = 0;

  NewList (&LibList);
  atexit (cleanup);
                     /* GCC has 18 versions of [__](amiga[dos]|mc68000)[__] */
  p = stpcpy (s, "sc DEF=__mc68000__=1 DEF=__amigados__=1 DEF=__AMIGA__=1 ");

  for (i=1; i<argc; i++)
  {
    if (argv[i][0] == '-')
    {
      switch (argv[i][1])
      {
        case '?':
          printf ("SAS/C frontend with gcc-style options.\n"
                  "Usage: %s [-EvgDOocILl][<long options>] <files>\n"
                  "  (-pedantic -pedantic-errors -ansi -Werror -Wall)\n", argv[0]);
          exit (0);

        case 'E':
          p = stpcpy (p, "PPONLY"); /* SAS/C's .p-file should go to SCC's stdout */
          break;
          
        case 'v':
          p = stpcpy (p, "VERBOSE");
          verbose = 1;        
          break;

        case 'g':
          p = stpcpy (p, "DEBUG=FF");
          break;

        case 'D':
          p = stpcpy (p, "DEF=");
          p = stpcpy (p, option_argument (argc, argv, &i));
          break;

        case 'O':
          p = stpcpy (p, "OPT");
          break;

        case 'o':
          if (is_object_module (t = translate_path (option_argument (argc, argv, &i))))
          {
            dont_link = 1;
            continue;
          }
          p = stpcpy (p, "TO ");
          p = stpcpy (p, t);
          break;

        case 'c':
          dont_link = 1;
          continue;

        case 'I':
          p = stpcpy (p, "IDIR=");
          p = stpcpy (p, translate_path (option_argument (argc, argv, &i)));
          break;

        case 'L':
          add_library_dir (translate_path (option_argument (argc, argv, &i)));
          continue;

        case 'l':
          l = translate_path (option_argument (argc, argv, &i));
          if (!(t = locate_library (l)))
          {
            printf ("%s: Library not found: %s.lib.\n", argv[0], l);
            exit (20);
          }
          p = stpcpy (p, "LIB=");
          p = stpcpy (p, t);
          break;

        default:
          if (t = translate_long_option (argc, argv, &i))
          {
            p = stpcpy (p, t);
            break;
          }
          printf ("Option ignored: %s.\n", argv[i]);
          continue;
      }
    }
    else
      p = stpcpy (p, argv[i]);

    p = stpcpy (p, " ");
  }
  if (!dont_link)
  {
    p = stpcpy (p, "LINK ");
  }
  if (*(--p) == ' ')
  {
    *p = '\0';
  }
  if (verbose)
    printf ("%s.\n", s);
  if (i = system (s))
    printf ("%s: SAS/C compiler returned %d.\n", argv[0], i);
  exit (i);
}
