/*
 *  util.c -- general utility functions.
 */

#include <ctype.h>
#include "..\h\config.h"
#include "general.h"
#include "tproto.h"
#include "..\h\cpuconf.h"
#include "globals.h"
#include "trans.h"
#include "tree.h"


extern int optind;

extern char *ofile;

/*
 * The following code is operating-system dependent [@util.01].  Define the
 *  characters that terminate a file name prefix.
 */

#if PORT
#define Prefix "/"
Deliberate Syntax Error
#endif					/* PORT */

#if AMIGA
#define Prefix "/:"
#endif					/* AMIGA */

#if ATARI_ST
#define Prefix "/:\\"
#endif					/* ATARI_ST */

#if HIGHC_386 || MSDOS || OS2
#define Prefix "/:\\"
#endif					/* HIGHC_386 || MSDOS || OS2 */

#if MACINTOSH
#define Prefix ":"
#endif					/* MACINTOSH */

#if MVS || VM
#define Prefix ""
#endif					/* MVS || VM */

#if UNIX
#define Prefix "/"
#endif					/* UNIX */

#if VMS
#define Prefix "]:"
#endif					/* VMS */

/*
 * End of operating-system specific code.
 */

/*
 * Information about Icon functions.
 */

/*
 * Number of arguments.
 */


/*
 * Names of Icon functions.
 */
char *ftable[] = {
#define FncDef(p,n) Lit(p),
#define FncDefV(p) Lit(p),
#include "..\h\fdefs.h"
#undef FncDef
#undef FncDefV
   };

int ftbsize = sizeof(ftable)/sizeof(char *);

/*
 * alloc - allocate n bytes
 */

pointer alloc(n)
unsigned int n;
   {
   pointer a;

   if (!(a = malloc((msize)n)))
      quit("out of memory");
   return a;
   }

/*
 * salloc - allocate and initialize string 
 */

char *salloc(s)
char *s;
   {

   return strcpy((char *)alloc((unsigned int)(strlen(s)+1)),s);
   }

/*
 * tcalloc - allocate and zero m*n bytes
 */
pointer tcalloc(m,n)
unsigned int m, n;
   {
   pointer a;

   if (!(a = calloc(m,n)))
      quit("out of memory");
   return a;
   }

/*
 * fparse - break a file name down into component parts.
 *  Result is a pointer to a struct of static pointers good until the next call.
 */
struct fileparts *fparse(s)
char *s;
   {
   static char buf[MaxFileName+2];
   static struct fileparts fp;
   int n;
   char *p, *q;
   char *index();

#if MVS         /* for any compiler which takes member names */
   static char extbuf [MaxFileName+2] ;

   p = index(s, '(');
   if (p) {
      fp.member = p+1;
      memcpy(extbuf, s, p-s);
      extbuf [p-s]  = '\0';
      s = extbuf;
   }
   else fp.member = s + strlen(s);
#endif					/* MVS */

   q = s;
   fp.ext = p = s + strlen(s);
   while (--p >= s) {
      if (*p == '.' && *fp.ext == '\0')
         fp.ext = p;
      else if (index(Prefix,*p)) {
         q = p+1;
         break;
         }
      }
   fp.dir = buf;
   n = q - s;
   strncpy(fp.dir,s,n);
   fp.dir[n] = '\0';
   fp.name = buf + n + 1;
   n = fp.ext - q;
   strncpy(fp.name,q,n);
   fp.name[n] = '\0';
   return &fp;
   }

/*
 * makename - make a file name, optionally substituting a new dir and/or ext
 */
char *makename(dest,d,name,e)
char *dest, *d, *name, *e;
   {
   struct fileparts fp;
   fp = *fparse(name);
   if (d != NULL)
      fp.dir = d;
   if (e != NULL)
      fp.ext = e;

#if MVS
   if (*fp.member)
      sprintf(dest,"%s%s%s(%s", fp.dir, fp.name, fp.ext, fp.member);
   else
#endif					/* MVS */

   sprintf(dest,"%s%s%s",fp.dir,fp.name,fp.ext);
   return dest;
   }

/*
 * quit - immediate exit with error message
 */

novalue quit(msg)
char *msg;
   {
   quitf(msg,"");
   }

/*
 * quitf - immediate exit with message format and argument
 */
novalue quitf(msg,arg)
char *msg, *arg;
   {


   extern char *progname;
   fprintf(stderr,"%s: ",progname);
   fprintf(stderr,msg,arg);
   fprintf(stderr,"\n");

#ifndef VarTran
   if (ofile)
      unlink(ofile);			/* remove bad icode file */
#endif					/* VarTran */

   exit(ErrorExit);
   }

/*
 * tsyserr is called for fatal errors.  The message s is produced and the
 *  translator exits.
 */
novalue tsyserr(s)
char *s;
   {


   if (tok_loc.n_file)
      fprintf(stderr, "File %s; ", tok_loc.n_file);
   fprintf(stderr, "Line %d # %s\n", in_line, s);

   exit(ErrorExit);
   }


/*
 * round2 - round an integer up to the next power of 2.
 */
unsigned int round2(n)
unsigned int n;
   {
   unsigned int b = 1;
   while (b < n)
      b <<= 1;
   return b;
   }


/*
 * sizearg - process -S command option.
 */

struct keyptr {			/* structure for listing option chars */
   char *cmd;				/* option character(s) */
   unsigned int *valp;			/* pointer to value word */
   };

static struct keyptr keytable[] = {	/* maps keys to store addresses */

#define Size(cmd,vname,defalt) cmd, &vname,
#define MinSize(x,y,z)
#include "sizes.h"			\* initialize from "sizes.h" data *\
#undef Size
#undef MinSize
   0, 0,				/* terminate with null entry */
   };

novalue sizearg(arg,argv)
char *arg;
char **argv;
   {
   struct keyptr *k;			/* key table pointer */
   char *s;				/* value string pointer */
   int v;				/* option value */

   for (k = keytable; k->cmd; k++)	/* search for key match */
      if (arg[0] == k->cmd[0] && (arg[0] != 'h' || arg[1] == k->cmd[1]))
         break;

   if (k->cmd == NULL)			/* abort if not found */
      quitf("unrecognized -S option: -S%s",arg);

   if (arg[0] == 'h')
      s = &arg[2];			/* find value */
   else
      s = &arg[1];
      
   if (*s == '\0') {			/* if value is in next arg */
      s = argv[optind++];
      if (s == NULL)
         quitf("missing value: -S%s", arg);
      }

   v = (int)atol(s);				/* convert integer -- check */
   if (v <= 0)
      quitf("illegal value: -S%s", arg);
   *k->valp = v;			/* store result */
   }


/*
 * smatch - case-insensitive string match - returns nonzero if they match
 */
int smatch(s,t)
char *s, *t;
   {
   char a, b;
   for (;;) {
      while (*s == *t)
         if (*s++ == '\0')
            return 1;
         else
            t++;
      a = *s++;
      b = *t++;
      if (isupper(a))  a = tolower(a);
      if (isupper(b))  b = tolower(b);
      if (a != b)
         return 0;
      }
   }
