Logo Search packages:      
Sourcecode: ksh version File versions

mam.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1989-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Bell Laboratories
 *
 * make abstract machine library
 */

static const char id[] = "\n@(#)$Id: libmam (AT&T Research) 1995-10-11 $\0\n";

static const char lib[] = "libmam:mam";

#include <mamlib.h>
#include <ctype.h>
#include <error.h>
#include <tok.h>

/*
 * free a rule
 */

static int
freerule(register struct rule* r)
{
      register struct list*   p;
      register struct list*   x;

      x = r->prereqs;
      while (p = x)
      {
            x = p->next;
            free(p);
      }
      free(r);
      return(0);
}

/*
 * get a process context
 */

static struct proc*
getproc(struct mam* mp, long pid)
{
      register struct proc*   pp;

      for (pp = mp->procs; pp; pp = pp->next)
            if (pp->pid == pid) return(pp);
      if (!(pp = newof(0, struct proc, 1, 0)) ||
          !(pp->bp = pp->fp = newof(0, struct frame, 1, 0)) ||
          !(pp->rules = hashalloc(0, HASH_set, HASH_ALLOCATE, HASH_free, freerule, HASH_name, "mam-rules", 0)) ||
          !(pp->vars = hashalloc(0, HASH_set, HASH_ALLOCATE, HASH_free, free, HASH_name, "mam-variables", 0)))
      {
            errorf(mp, mp, 2, "out of space");
            return(0);
      }
      pp->next = mp->procs;
      mp->procs = pp;
      pp->pid = pid;
      pp->fp->rule = pp->root = mamrule(pp, "");
      return(pp);
}

/*
 * allocate a mam scope
 */

struct mam*
mamalloc(void)
{
      register struct mam*    mp;

      if (!(mp = newof(0, struct mam, 1, 0))) return(0);
      mp->id = lib;
      if (!(mp->main = getproc(mp, 0)))
      {
            mamfree(mp);
            return(0);
      }
      return(mp);
}

/*
 * free a mam scope
 */

void
mamfree(register struct mam* mp)
{
      if (mp)
      {
            register struct proc*   pp;

            while (pp = mp->procs)
            {
                  mp->procs = pp->next;
                  if (pp->rules) hashfree(pp->rules);
                  if (pp->vars) hashfree(pp->vars);
                  if (pp->pwd) free(pp->pwd);
                  if (pp->view) free(pp->view);
                  if (pp->root) freerule(pp->root);
                  free(pp);
            }
            free(mp);
      }
}

/*
 * check for rule alias
 * this covers for an nmake mam output bug
 */

static struct rule*
alias(struct proc* pp, const char* name)
{
      char  buf[PATH_MAX];

      if (*name != '/' || *pp->fp->rule->name == '/' || !pp->pwd) return(0);
      sfsprintf(buf, sizeof(buf), "%s/%s", pp->pwd, pp->fp->rule->name);
      pathcanon(buf, 0);
      if (!streq(buf, name)) return(0);
      putrule(pp, name, pp->fp->rule);
      return(pp->fp->rule);
}

/*
 * set r attributes from s
 * prereq list pointer returned
 */

static struct list**
attributes(struct proc* pp, struct rule* r, char* s)
{
      char*       arg;
      struct list**     p = 0;

      while (tokscan(s, &s, " %s ", &arg) == 1)
      {
            if (streq(arg, "archive"))
                  r->attributes |= A_archive;
            else if (streq(arg, "dontcare"))
                  r->attributes |= A_dontcare;
            else if (streq(arg, "implicit"))
                  p = &pp->fp->rule->implicit;
            else if (streq(arg, "metarule"))
                  r->attributes |= A_metarule;
            else if (streq(arg, "virtual"))
                  r->attributes |= A_virtual;
      }
      return(p);
}

/*
 * scan a mam input stream
 */

int
mamscan(register struct mam* mp, const char* file)
{
      register struct proc*   pp;
      struct rule*            r;
      struct block*           a;
      char*             s;
      char*             op;
      char*             arg;
      char*             val;
      unsigned long           t;
      int               n;
      Sfio_t*                 input;
      char*             ofile;
      int               oline;
#if __sparc__ /* strcpy() and strcmp() bug() when '\0' is last byte in last page */
      char              buf[8096];
#endif

      if (!file) input = sfstdin;
      else if (!(input = sfopen(NiL, file, "r")))
      {
            errorf(mp, mp, 2, "%s: cannot read", file);
            return(-1);
      }
#if __sparc__
      sfsetbuf(input, buf, sizeof(buf));
#endif
      ofile = error_info.file;
      error_info.file = (char*)file;
      oline = error_info.line;
      error_info.line = 0;
      while (s = sfgetr(input, '\n', 1))
      {
            error_info.line++;
            if (tokscan(s, &s, " %s ", &op) != 1) continue;
            if (isdigit(*op))
            {
                  if (!(pp = getproc(mp, strtol(op, NiL, 10)))) return(-1);
                  if (tokscan(s, &s, " %s ", &op) != 1) continue;
            }
            else pp = mp->main;
            if (!pp->bp)
            {
                  errorf(mp, mp, 1, "%s: process %d is finished", op, pp->pid);
                  continue;
            }
            if (streq(op, "note"))
            {
                  /* comment */;
            }
            else if (streq(op, "setv"))
            {
                  tokscan(s, &val, " %s ", &arg);
                  while (isspace(*val)) val++;
                  mamvar(pp, arg, strdup(val));
            }
            else if ((n = streq(op, "make")) || streq(op, "prev"))
            {
                  tokscan(s, &s, " %s ", &arg);
                  if (n) r = mamrule(pp, arg);
                  else if (!(r = getrule(pp, arg)) && !(r = alias(pp, arg)))
                  {
                        errorf(mp, mp, 1, "%s: reference to undefined rule", arg);
                        continue;
                  }
                  mamprereq(pp, pp->fp->rule, r, attributes(pp, r, s));
                  if (n)
                  {
                        if (!pp->fp->next)
                        {
                              if (!(pp->fp->next = newof(0, struct frame, 1, 0)))
                              {
                                    errorf(mp, mp, 2, "out of space");
                                    return(-1);
                              }
                              pp->fp->next->prev = pp->fp;
                        }
                        pp->fp = pp->fp->next;
                        pp->fp->rule = r;
                  }
            }
            else if (streq(op, "exec"))
            {
                  tokscan(s, &s, " %s ", &arg);
                  if (streq(arg, "-"))
                  {
                        if (!pp->fp->prev) goto missing;
                        r = pp->fp->rule;
                  }
                  else r = mamrule(pp, arg);
                  while (isspace(*s)) s++;
                  if (!(a = newof(0, struct block, 1, 0)))
                  {
                        errorf(mp, mp, 2, "out of space");
                        return(-1);
                  }
                  a->data = strdup(s);
                  if (r->atail) r->atail->next = a;
                  else r->action = a;
                  r->atail = a;
            }
            else if (streq(op, "done"))
            {
                  if (!pp->fp->prev) goto missing;
                  tokscan(s, &s, " %s ", &arg);
                  if (!streq(pp->fp->rule->name, arg) && !alias(pp, arg))
                        errorf(mp, mp, 1, "%s: %s %s expected", arg, op, pp->fp->rule->name);
                  attributes(pp, pp->fp->rule, s);
                  pp->fp = pp->fp->prev;
            }
            else if (streq(op, "bind"))
            {
                  tokscan(s, NiL, " %s %lu %s ", &arg, &t, &val);
                  if (!(r = getrule(pp, arg)) && !(r = alias(pp, arg)))
                  {
                        errorf(mp, mp, 1, "%s: reference to undefined rule", arg);
                        continue;
                  }
                  if (val) r->bound = strdup(val);
                  r->time = t;
            }
            else if (streq(op, "code"))
            {
                  tokscan(s, NiL, " %s %d ", &arg, &n);
                  if (!(r = getrule(pp, arg)) && !(r = alias(pp, arg)))
                  {
                        errorf(mp, mp, 1, "%s: reference to undefined rule", arg);
                        continue;
                  }
                  r->status = n;
            }
            else if (streq(op, "info"))
            {
                  tokscan(s, &s, " %s ", &arg);
                  if (streq(arg, "mam"))
                  {
                        tokscan(s, NiL, " %s ", &arg);
                        if (mp->version) free(mp->version);
                        mp->version = strdup(arg);
                  }
                  else if (streq(arg, "start"))
                  {
                        tokscan(s, NiL, " %lu %d ", &pp->start, &n);
                        if (!pp->pid) pp->pid = n;
                        else if (pp->parent = getproc(mp, n)) 
                        {
                              register struct proc*   ppp = pp->parent;

                              if (!ppp->child) ppp->child = pp;
                              else if (!ppp->child->sibling) ppp->child->sibling = ppp->child->stail = pp;
                              else ppp->child->stail = ppp->child->stail->sibling = pp;
                        }
                  }
                  else if (streq(arg, "finish"))
                  {
                        register struct frame*  fp;

                        tokscan(s, NiL, " %lu %d ", &pp->finish, &pp->status);
                        if (pp->fp != pp->bp)
                              errorf(mp, mp, 1, "%s: not enough done ops", arg);
                        while (fp = pp->bp)
                        {
                              pp->bp = fp->next;
                              free(fp);
                        }
                  }
                  else if (streq(arg, "pwd"))
                  {
                        tokscan(s, NiL, " %s ", &val);
                        pp->pwd = strdup(val);
                  }
                  else if (streq(arg, "view"))
                  {
                        tokscan(s, NiL, " %s ", &val);
                        pp->view = strdup(val);
                  }
                  else errorf(mp, mp, 1, "%s: unknown %s attribute", arg, op);
            }
            else errorf(mp, mp, 1, "%s: unknown op ignored", op);
            continue;
      missing:
            errorf(mp, mp, 1, "%s: missing make op", op);
      }
      if (input != sfstdin) sfclose(input);
      error_info.file = ofile;
      error_info.line = oline;
      return(0);
}

/*
 * return old rule pointer if found
 * otherwise make a new rule
 */

struct rule*
mamrule(register struct proc* pp, const char* name)
{
      struct rule*            r;

      if (!(r = getrule(pp, name)) && (r = newof(0, struct rule, 1, 0)))
            r->name = putrule(pp, 0, r);
      return(r);
}

/*
 * return old var pointer if found
 * otherwise make a new var
 * if value!=0 then var value is set
 */

struct var*
mamvar(register struct proc* pp, const char* name, const char* value)
{
      struct var* v;

      if (!(v = getvar(pp, name)))
      {
            if (!(v = newof(0, struct var, 1, 0))) return(0);
            v->name = putvar(pp, 0, v);
      }
      if (value) v->value = (char*)value;
      return(v);
}

/*
 * add x to r prereq list
 */

void
mamprereq(struct proc* pp, struct rule* r, struct rule* x, struct list** p)
{
      struct list*      q;

      NoP(pp);
      if (x != r)
      {
            if (!p) p = &r->prereqs;
            if (q = *p)
            {
                  while (q)
                  {
                        if (x == q->rule) break;
                        if (!q->next)
                        {
                              if (!(q->next = newof(0, struct list, 1, 0))) return;
                              q->next->rule = x;
                              break;
                        }
                        q = q->next;
                  }
            }
            else if (!(*p = newof(0, struct list, 1, 0))) return;
            else (*p)->rule = x;
      }
}

Generated by  Doxygen 1.6.0   Back to index