Parse(buf, bufl, args, argl)
char *buf, **args;
int bufl, *argl;
{
  register char *p = buf, **ap = args, *pp;
  register int delim, argc;
  int *lp = argl;

  debug2("Parse %d %s\n", bufl, buf);
  argc = 0;
  pp = buf;
  delim = 0;
  for (;;)
    {
      *lp = 0;
      while (*p && (*p == ' ' || *p == '\t'))
	++p;
#ifdef PSEUDOS
      if (argc == 0 && *p == '!')
	{
	  *ap++ = "exec";
	  *lp++ = 4;
	  p++;
	  argc++;
	  continue;
        }
#endif
      if (*p == '\0' || *p == '#' || *p == '\n')
	{
	  *p = '\0';
	  for (delim = 0; delim < argc; delim++)
	    debug1("-- %s\n", args[delim]);
	  args[argc] = 0;
	  return argc;
	}
      if (++argc >= MAXARGS)
	{
	  Msg(0, "%s: too many tokens.", rc_name);
	  return 0;
	}
      *ap++ = pp;

      debug1("- new arg %s\n", p);
      while (*p)
	{
	  if (*p == delim)
	    delim = 0;
	  else if (delim != '\'' && *p == '\\' && (p[1] == 'n' || p[1] == 'r' || p[1] == 't' || p[1] == '\'' || p[1] == '"' || p[1] == '\\' || p[1] == '$' || p[1] == '#' || p[1] == '^' || (p[1] >= '0' && p[1] <= '7')))
	    {
	      p++;
	      if (*p >= '0' && *p <= '7')
		{
		  *pp = *p - '0';
		  if (p[1] >= '0' && p[1] <= '7')
		    {
		      p++;
		      *pp = (*pp << 3) | (*p - '0');
		      if (p[1] >= '0' && p[1] <= '7')
			{
			  p++;
			  *pp = (*pp << 3) | (*p - '0');
			}
		    }
		  pp++;
		}
	      else
		{
		  switch (*p)
		    {
		      case 'n': *pp = '\n'; break;
		      case 'r': *pp = '\r'; break;
		      case 't': *pp = '\t'; break;
		      default: *pp = *p; break;
		    }
		  pp++;
		}
	    }
	  else if (delim != '\'' && *p == '$' && (p[1] == '{' || p[1] == ':' || (p[1] >= 'a' && p[1] <= 'z') || (p[1] >= 'A' && p[1] <= 'Z') || (p[1] >= '0' && p[1] <= '9') || p[1] == '_'))

	    {
	      char *ps, *pe, op, *v, xbuf[11], path[MAXPATHLEN];
	      int vl;

	      ps = ++p;
	      debug1("- var %s\n", ps);
	      p++;
	      while (*p)
		{
		  if (*ps == '{' && *p == '}')
		    break;
		  if (*ps == ':' && *p == ':')
		    break;
		  if (*ps != '{' && *ps != ':' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && *p != '_')
		    break;
		  p++;
		}
	      pe = p;
	      if (*ps == '{' || *ps == ':')
		{
		  if (!*p)
		    {
		      Msg(0, "%s: bad variable name.", rc_name);
		      return 0;
		    }
		  p++;
		}
	      op = *pe;
	      *pe = 0;
	      debug1("- var is '%s'\n", ps);
	      if (*ps == ':')
		v = gettermcapstring(ps + 1);
	      else
		{
		  if (*ps == '{')
		    ps++;
		  v = xbuf;
		  if (!strcmp(ps, "TERM"))
		    v = display ? D_termname : "unknown";
		  else if (!strcmp(ps, "COLUMNS"))
		    sprintf(xbuf, "%d", display ? D_width : -1);
		  else if (!strcmp(ps, "LINES"))
		    sprintf(xbuf, "%d", display ? D_height : -1);
		  else if (!strcmp(ps, "PID"))
		    sprintf(xbuf, "%d", getpid());
		  else if (!strcmp(ps, "PWD"))
		    {
		      if (getcwd(path, sizeof(path) - 1) == 0)
			v = "?";
		      else
			v = path;
		    }
		  else if (!strcmp(ps, "STY"))
		    {
		      if ((v = strchr(SockName, '.')))	/* Skip the PID */
			v++;
		      else
			v = SockName;
		    }
		  else
		    v = getenv(ps);
		}
	      *pe = op;
	      vl = v ? strlen(v) : 0;
	      if (vl)
		{
		  debug1("- sub is '%s'\n", v);
		  if (p - pp < vl)
		    {
		      int right = buf + bufl - (p + strlen(p) + 1);
		      if (right > 0)
			{
			  bcopy(p, p + right, strlen(p) + 1);
			  p += right;
			}
		    }
		  if (p - pp < vl)
		    {
		      Msg(0, "%s: no space left for variable expansion.", rc_name);
		      return 0;
		    }
		  bcopy(v, pp, vl);
		  pp += vl;
		}
	      continue;
	    }
	  else if (delim != '\'' && *p == '^' && p[1])
	    {
	      p++;
	      *pp++ = *p == '?' ? '\177' : *p & 0x1f;
	    }
	  else if (delim == 0 && (*p == '\'' || *p == '"'))
	    delim = *p;
	  else if (delim == 0 && (*p == ' ' || *p == '\t' || *p == '\n'))
	    break;
	  else
	    *pp++ = *p;
	  p++;
	}
      if (delim)
	{
	  Msg(0, "%s: Missing %c quote.", rc_name, delim);
	  return 0;
	}
      if (*p)
	p++;
      *pp = 0;
      debug2("- arg done, '%s' rest %s\n", ap[-1], p);
      *lp++ = pp - ap[-1];
      pp++;
    }
}
Parse(buf, bufl, args, argl)
char *buf, **args;
int bufl, *argl;
{
  register char *p = buf, **ap = args, *pp;
  register int delim, argc;
  int *lp = argl;

  debug2("Parse %d %s\n", bufl, buf);
  argc = 0;
  pp = buf;
  delim = 0;
  for (;;)
    {
      *lp = 0;
      while (*p && (*p == ' ' || *p == '\t'))
	++p;
#ifdef PSEUDOS
      if (argc == 0 && *p == '!')
	{
	  *ap++ = "exec";
	  *lp++ = 4;
	  p++;
	  argc++;
	  continue;
        }
#endif
      if (*p == '\0' || *p == '#' || *p == '\n')
	{
	  *p = '\0';
	  for (delim = 0; delim < argc; delim++)
	    debug1("-- %s\n", args[delim]);
	  args[argc] = 0;
	  return argc;
	}
      if (++argc >= MAXARGS)
	{
	  Msg(0, "%s: too many tokens.", rc_name);
	  return 0;
	}
      *ap++ = pp;

      debug1("- new arg %s\n", p);
      while (*p)
	{
	  if (*p == delim)
	    delim = 0;
	  else if (delim != '\'' && *p == '\\' && (p[1] == 'n' || p[1] == 'r' || p[1] == 't' || p[1] == '\'' || p[1] == '"' || p[1] == '\\' || p[1] == '$' || p[1] == '#' || p[1] == '^' || (p[1] >= '0' && p[1] <= '7')))
	    {
	      p++;
	      if (*p >= '0' && *p <= '7')
		{
		  *pp = *p - '0';
		  if (p[1] >= '0' && p[1] <= '7')
		    {
		      p++;
		      *pp = (*pp << 3) | (*p - '0');
		      if (p[1] >= '0' && p[1] <= '7')
			{
			  p++;
			  *pp = (*pp << 3) | (*p - '0');
			}
		    }
		  pp++;
		}
	      else
		{
		  switch (*p)
		    {
		      case 'n': *pp = '\n'; break;
		      case 'r': *pp = '\r'; break;
		      case 't': *pp = '\t'; break;
		      default: *pp = *p; break;
		    }
		  pp++;
		}
	    }
	  else if (delim != '\'' && *p == '$' && (p[1] == '{' || p[1] == ':' || (p[1] >= 'a' && p[1] <= 'z') || (p[1] >= 'A' && p[1] <= 'Z') || (p[1] >= '0' && p[1] <= '9') || p[1] == '_'))

	    {
	      char *ps, *pe, op, *v, xbuf[11], path[MAXPATHLEN];
	      int vl;

	      ps = ++p;
	      debug1("- var %s\n", ps);
	      p++;
	      while (*p)
		{
		  if (*ps == '{' && *p == '}')
		    break;
		  if (*ps == ':' && *p == ':')
		    break;
		  if (*ps != '{' && *ps != ':' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && *p != '_')
		    break;
		  p++;
		}
	      pe = p;
	      if (*ps == '{' || *ps == ':')
		{
		  if (!*p)
		    {
		      Msg(0, "%s: bad variable name.", rc_name);
		      return 0;
		    }
		  p++;
		}
	      op = *pe;
	      *pe = 0;
	      debug1("- var is '%s'\n", ps);
	      if (*ps == ':')
		v = gettermcapstring(ps + 1);
	      else
		{
		  if (*ps == '{')
		    ps++;
		  v = xbuf;
		  if (!strcmp(ps, "TERM"))
		    v = display ? D_termname : "unknown";
		  else if (!strcmp(ps, "COLUMNS"))
		    sprintf(xbuf, "%d", display ? D_width : -1);
		  else if (!strcmp(ps, "LINES"))
		    sprintf(xbuf, "%d", display ? D_height : -1);
		  else if (!strcmp(ps, "PID"))
		    sprintf(xbuf, "%d", getpid());
		  else if (!strcmp(ps, "PWD"))
		    {
		      if (getcwd(path, sizeof(path) - 1) == 0)
			v = "?";
		      else
			v = path;
		    }
		  else if (!strcmp(ps, "STY"))
		    {
		      if ((v = strchr(SockName, '.')))	 
			v++;
		      else
			v = SockName;
		    }
		  else
		    v = getenv(ps);
		}
	      *pe = op;
	      vl = v ? strlen(v) : 0;
	      if (vl)
		{
		  debug1("- sub is '%s'\n", v);
		  if (p - pp < vl)
		    {
		      int right = buf + bufl - (p + strlen(p) + 1);
		      if (right > 0)
			{
			  bcopy(p, p + right, strlen(p) + 1);
			  p += right;
			}
		    }
		  if (p - pp < vl)
		    {
		      Msg(0, "%s: no space left for variable expansion.", rc_name);
		      return 0;
		    }
		  bcopy(v, pp, vl);
		  pp += vl;
		}
	      continue;
	    }
	  else if (delim != '\'' && *p == '^' && p[1])
	    {
	      p++;
	      *pp++ = *p == '?' ? '\177' : *p & 0x1f;
	    }
	  else if (delim == 0 && (*p == '\'' || *p == '"'))
	    delim = *p;
	  else if (delim == 0 && (*p == ' ' || *p == '\t' || *p == '\n'))
	    break;
	  else
	    *pp++ = *p;
	  p++;
	}
      if (delim)
	{
	  Msg(0, "%s: Missing %c quote.", rc_name, delim);
	  return 0;
	}
      if (*p)
	p++;
      *pp = 0;
      debug2("- arg done, '%s' rest %s\n", ap[-1], p);
      *lp++ = pp - ap[-1];
      pp++;
    }
}