예제 #1
0
파일: extoken.c 프로젝트: aosm/graphviz
int
extoken_fn(register Expr_t* ex)
{
	register int	c;
	register char*	s;
	register int	q;
	char*		e;

	if (ex->eof || ex->errors)
		return 0;
 again:
	for (;;) switch (c = lex(ex))
	{
	case 0:
		goto eof;
	case '/':
		switch (q = lex(ex))
		{
		case '*':
			for (;;) switch (lex(ex))
			{
			case '\n':
				BUMP (error_info.line);
				continue;
			case '*':
				switch (lex(ex))
				{
				case 0:
					goto eof;
				case '\n':
					BUMP (error_info.line);
					break;
				case '*':
					exunlex(ex, '*');
					break;
				case '/':
					goto again;
				}
				break;
			}
			break;
		case '/':
			while ((c = lex(ex)) != '\n')
				if (!c)
					goto eof;
			break;
		default:
			goto opeq;
		}
		/*FALLTHROUGH*/
	case '\n':
		BUMP (error_info.line);
		/*FALLTHROUGH*/
	case ' ':
	case '\t':
		break;
	case '(':
	case '{':
	case '[':
		ex->input->nesting++;
		return exlval.op = c;
	case ')':
	case '}':
	case ']':
		ex->input->nesting--;
		return exlval.op = c;
	case '+':
	case '-':
		if ((q = lex(ex)) == c)
			return exlval.op = c == '+' ? INC : DEC;
		goto opeq;
	case '*':
	case '%':
	case '^':
		q = lex(ex);
	opeq:
		exlval.op = c;
		if (q == '=')
			c = '=';
		else if (q == '%' && c == '%')
		{
			if (ex->input->fp)
				ex->more = (const char*)ex->input->fp;
			else ex->more = ex->input->sp;
			goto eof;
		}
		else exunlex(ex, q);
		return c;
	case '&':
	case '|':
		if ((q = lex(ex)) == '=')
		{
			exlval.op = c;
			return '=';
		}
		if (q == c)
			c = c == '&' ? AND : OR;
		else exunlex(ex, q);
		return exlval.op = c;
	case '<':
	case '>':
		if ((q = lex(ex)) == c)
		{
			exlval.op = c = c == '<' ? LS : RS;
			if ((q = lex(ex)) == '=')
				c = '=';
			else exunlex(ex, q);
			return c;
		}
		goto relational;
	case '=':
	case '!':
		q = lex(ex);
	relational:
		if (q == '=') switch (c)
		{
		case '<':
			c = LE;
			break;
		case '>':
			c = GE;
			break;
		case '=':
			c = EQ;
			break;
		case '!':
			c = NE;
			break;
		}
		else exunlex(ex, q);
		return exlval.op = c;
	case '#':
		if (!ex->linewrap && !(ex->disc->flags & EX_PURE))
		{
			s = ex->linep - 1;
			while (s > ex->line && isspace(*(s - 1)))
				s--;
			if (s == ex->line)
			{
				switch (extoken_fn(ex))
				{
				case DYNAMIC:
				case ID:
				case NAME:
					s = exlval.id->name;
					break;
				default:
					s = "";
					break;
				}
				if (streq(s, "include"))
				{
					if (extoken_fn(ex) != STRING)
						exerror("#%s: string argument expected", s);
					else if (!expush(ex, exlval.string, 1, NiL, NiL))
					{
						setcontext(ex);
						goto again;
					}
				}
				else exerror("unknown directive");
			}
		}
		return exlval.op = c;
	case '\'':
	case '"':
		q = c;
		sfstrset(ex->tmp, 0);
		ex->input->nesting++;
		while ((c = lex(ex)) != q)
		{
			if (c == '\\')
			{
				sfputc(ex->tmp, c);
				c = lex(ex);
			}
			if (!c)
			{
				exerror("unterminated %c string", q);
				goto eof;
			}
			if (c == '\n')
			{
				BUMP (error_info.line);
			}
			sfputc(ex->tmp, c);
		}
		ex->input->nesting--;
		s = sfstruse(ex->tmp);
		if (q == '"' || (ex->disc->flags & EX_CHARSTRING))
		{
			if (!(exlval.string = vmstrdup(ex->vm, s)))
				goto eof;
			stresc(exlval.string);
			return STRING;
		}
		exlval.integer = chrtoi(s);
		return INTEGER;
	case '.':
		if (isdigit(c = lex(ex)))
		{
			sfstrset(ex->tmp, 0);
			sfputc(ex->tmp, '0');
			sfputc(ex->tmp, '.');
			goto floating;
		}
		exunlex(ex, c);
		return exlval.op = '.';
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		sfstrset(ex->tmp, 0);
		sfputc(ex->tmp, c);
		q = INTEGER;
		if ((c = lex(ex)) == 'x' || c == 'X')
		{
			sfputc(ex->tmp, c);
			for (;;)
			{
				switch (c = lex(ex))
				{
				case '0': case '1': case '2': case '3': case '4':
				case '5': case '6': case '7': case '8': case '9':
				case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': 
				case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': 
					sfputc(ex->tmp, c);
					continue;
				}
				break;
			}
		}
		else
		{
			while (isdigit(c))
			{
				sfputc(ex->tmp, c);
				c = lex(ex);
			}
			if (c == '#')
			{
				sfputc(ex->tmp, c);
				/* s = sfstruse(ex->tmp); */
				/* b = strtol(s, NiL, 10); */
				do
				{
					sfputc(ex->tmp, c);
				} while (isalnum(c = lex(ex)));
			}
			else
			{
				if (c == '.')
				{
				floating:
					q = FLOATING;
					sfputc(ex->tmp, c);
					while (isdigit(c = lex(ex)))
						sfputc(ex->tmp, c);
				}
				if (c == 'e' || c == 'E')
				{
					q = FLOATING;
					sfputc(ex->tmp, c);
					if ((c = lex(ex)) == '-' || c == '+')
					{
						sfputc(ex->tmp, c);
						c = lex(ex);
					}
					while (isdigit(c))
					{
						sfputc(ex->tmp, c);
						c = lex(ex);
					}
				}
			}
		}
		s = sfstruse(ex->tmp);
		if (q == FLOATING)
			exlval.floating = strtod(s, &e);
		else
		{
			if (c == 'u' || c == 'U')
			{
				q = UNSIGNED;
				c = lex(ex);
				exlval.integer = strToL(s, &e);
			}
			else
				exlval.integer = strToL(s, &e);
			if (*e)
			{
				*--e = 1;
				exlval.integer *= strton(e, &e, NiL, 0);
			}
		}
		exunlex(ex, c);
		if (*e || isalpha(c) || c == '_' || c == '$')
		{
			exerror("%s: invalid numeric constant", s);
			goto eof;
		}
		return q;
	default:
		if (isalpha(c) || c == '_' || c == '$')
		{
			sfstrset(ex->tmp, 0);
			sfputc(ex->tmp, c);
			while (isalnum(c = lex(ex)) || c == '_' || c == '$')
				sfputc(ex->tmp, c);
			exunlex(ex, c);
			s = sfstruse(ex->tmp);
			if (!(exlval.id = (Exid_t*)dtmatch(ex->symbols, s)))
			{
				if (!(exlval.id = newof(0, Exid_t, 1, strlen(s) - EX_NAMELEN + 1)))
				{
					exerror("out of space");
					goto eof;
				}
				strcpy(exlval.id->name, s);
				exlval.id->lex = NAME;
				dtinsert((ex->formals || !ex->symbols->view) ? ex->symbols : ex->symbols->view, exlval.id);
			}

			/*
			 * lexical analyzer state controlled by the grammar
			 */

			switch (exlval.id->lex)
			{
			case DECLARE:
				if (exlval.id->index == CHAR)
				{
					/*
					 * `char*' === `string'
					 * the * must immediately follow char
					 */

					if (c == '*')
					{
						lex(ex);
						exlval.id = id_string;
					}
				}
				break;
			case NAME:
				/*
				 * action labels are disambiguated from ?:
				 * through the expr.nolabel grammar hook
				 * the : must immediately follow labels
				 */

				if (c == ':' && !expr.nolabel)
					return LABEL;
				break;
			case PRAGMA:
				/*
				 * user specific statement stripped and
				 * passed as string
				 */

				{
					int	b;
					int	n;
					int	pc = 0;
					int	po;
					int	t;

					/*UNDENT...*/
	sfstrset(ex->tmp, 0);
	b = 1;
	n = 0;
	po = 0;
	t = 0;
	for (c = t = lex(ex);; c = lex(ex))
	{
		switch (c)
		{
		case 0:
			goto eof;
		case '/':
			switch (q = lex(ex))
			{
			case '*':
				for (;;)
				{
					switch (lex(ex))
					{
					case '\n':
						BUMP (error_info.line);
						continue;
					case '*':
						switch (lex(ex))
						{
						case 0:
							goto eof;
						case '\n':
							BUMP (error_info.line);
							continue;
						case '*':
							exunlex(ex, '*');
							continue;
						case '/':
							break;
						default:
							continue;
						}
						break;
					}
					if (!b++)
						goto eof;
					sfputc(ex->tmp, ' ');
					break;
				}
				break;
			case '/':
				while ((c = lex(ex)) != '\n')
					if (!c)
						goto eof;
				BUMP (error_info.line);
				b = 1;
				sfputc(ex->tmp, '\n');
				break;
			default:
				b = 0;
				sfputc(ex->tmp, c);
				sfputc(ex->tmp, q);
				break;
			}
			continue;
		case '\n':
			BUMP (error_info.line);
			b = 1;
			sfputc(ex->tmp, '\n');
			continue;
		case ' ':
		case '\t':
			if (!b++)
				goto eof;
			sfputc(ex->tmp, ' ');
			continue;
		case '(':
		case '{':
		case '[':
			b = 0;
			if (!po)
			{
				switch (po = c)
				{
				case '(':
					pc = ')';
					break;
				case '{':
					pc = '}';
					break;
				case '[':
					pc = ']';
					break;
				}
				n++;
			}
			else if (c == po)
				n++;
			sfputc(ex->tmp, c);
			continue;
		case ')':
		case '}':
		case ']':
			b = 0;
			if (!po)
			{
				exunlex(ex, c);
				break;
			}
			sfputc(ex->tmp, c);
			if (c == pc && --n <= 0)
			{
				if (t == po)
					break;
				po = 0;
			}
			continue;
		case ';':
			b = 0;
			if (!n)
				break;
			sfputc(ex->tmp, c);
			continue;
		case '\'':
		case '"':
			b = 0;
			sfputc(ex->tmp, c);
			ex->input->nesting++;
			q = c;
			while ((c = lex(ex)) != q)
			{
				if (c == '\\')
				{
					sfputc(ex->tmp, c);
					c = lex(ex);
				}
				if (!c)
				{
					exerror("unterminated %c string", q);
					goto eof;
				}
				if (c == '\n')
				{
					BUMP (error_info.line);
				}
				sfputc(ex->tmp, c);
			}
			ex->input->nesting--;
			continue;
		default:
			b = 0;
			sfputc(ex->tmp, c);
			continue;
		}
		break;
	}
	(*ex->disc->reff)(ex, NiL, exlval.id, NiL, sfstruse(ex->tmp), 0, ex->disc);

					/*..INDENT*/
				}
				goto again;
			}
			return exlval.id->lex;
		}
		return exlval.op = c;
	}
 eof:
	ex->eof = 1;
	return exlval.op = ';';
}
예제 #2
0
파일: ssd.c 프로젝트: ISLEcode/kornshell
int
main(int argc, char** argv)
{
	register int	n;
	register int	i;
	register long	v;
	char*		s;
	char*		e;
	char*		data;
	int		uf;
	int		wf;
	int		idlecmd;
	int		usercount;
	unsigned long	t;
	unsigned long	toss;
	unsigned long	usertime;
	unsigned long	now;
	unsigned long	then;
	Proc_t*		proc;
	CSSTAT		ss;
	struct stat	st;
	char		cmd[PATH_MAX];
	char		buf[PATH_MAX];
	char		tmp[PATH_MAX / 4];
	char*		av[4];
	char*		iv[3];
#if NAMELIST
	DIR*		root;
	struct dirent*	entry;
	int		kf;
#endif

	NoP(argc);
	error_info.id = CS_STAT_DAEMON;
	if (!pathpath(error_info.id, argv[0], PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, cmd, sizeof(cmd)))
		error(ERROR_SYSTEM|3, "cannot locate daemon executable");
	if (!pathpath(CS_STAT_DIR, argv[0], PATH_EXECUTE, buf, sizeof(buf)))
		error(3, "%s: cannot locate data directory", CS_STAT_DIR);
	if (stat(buf, &st))
		error(ERROR_SYSTEM|3, "%s: stat error", buf);
	if (st.st_uid != geteuid())
		error(3, "%s: effective uid mismatch", buf);
	if (chdir(buf))
		error(ERROR_SYSTEM|3, "%s: chdir error", buf);
	data = csname(0);
	if (argv[1] && strcmp(argv[1], data))
	{
		/*
		 * start remote status daemon
		 */

		data = argv[1];
		if (!csaddr(data))
			error(3, "%s: unknown host", data);
		if (!stat(data, &st) && (long)(CSTIME() - (unsigned long)st.st_ctime) < CS_STAT_DOWN)
			exit(0);
		sfsprintf(buf, sizeof(buf), "./%s", data);
		csstat(buf, &ss);
		if (s = csattr(CS_HOST_LOCAL, "type"))
		{
			strcpy(tmp, s);
			if (s = csattr(data, "type"))
				pathrepl(cmd, sizeof(cmd), tmp, s);
		}

		/*
		 * loop until remote status daemon starts
		 * check for competing startup daemon
		 */

		if (csdaemon(0))
			exit(1);
		umask(S_IRWXU|S_IRWXG|S_IRWXO);
		av[0] = CS_REMOTE_SHELL;
		av[1] = data;
		av[2] = cmd;
		av[3] = 0;
		for (;;)
		{
			update(data, 0, 0, &ss);
			if (!(remote = procopen(av[0], av, NiL, NiL, PROC_UID|PROC_GID)))
				break;
			while (!kill(remote->pid, 0))
				update(data, 0, CS_STAT_FREQ + (CS_STAT_DOWN - CS_STAT_FREQ) / 2, &ss);
			procclose(remote);
			remote = 0;
			if (ss.up > 0)
				ss.up = -ss.up;
		}
		for (;;) update(data, 0, CS_STAT_FREQ + (CS_STAT_DOWN - CS_STAT_FREQ) / 2, &ss);
	}
	remove(data);
	if ((n = open(data, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0)) < 0)
		error(ERROR_SYSTEM|3, "%s: cannot update", data);
	for (i = 0; i < elementsof(usrfiles); i++)
		if ((uf = open(usrfile = usrfiles[i], O_RDONLY)) >= 0) break;
	if (uf < 0)
		error(ERROR_SYSTEM|3, "%s: cannot read", usrfiles[0]);

	/*
	 * final initialization
	 */

	if (csdaemon((1<<2)|(1<<n)|(1<<uf)))
		error(ERROR_SYSTEM|3, "cannot dive into background");
	umask(S_IRWXU|S_IRWXG|S_IRWXO);
	close(2);
	dup(n);
	close(n);
	error_info.id = data;
	av[0] = "uptime";
	av[1] = 0;
	toss = getpid();
	for (s = data; *s; s++)
		CSTOSS(toss, *s);
	usertime = 0;
#if NAMELIST
	for (n = 0; n < elementsof(symbols); n++)
		names[n].n_name = symbols[n].name;
	if ((kf = open(memfile, O_RDONLY)) >= 0)
	{
		if (chdir("/"))
			error(ERROR_SYSTEM|3, "/: chdir error");
		s = 0;
		for (i = 0; i < elementsof(sysfiles); i++)
			if (!access(sysfiles[i], F_OK))
			{
				s = sysfiles[i];
				break;
			}
		if (!s)
		{
			if (!(root = opendir(".")))
				error(ERROR_SYSTEM|3, "/: cannot read");
			while (entry = readdir(root))
			{
				if ((i = strlen(entry->d_name) - 2) > 0 && entry->d_name[i] == 'i' && entry->d_name[i + 1] == 'x' && !stat(entry->d_name, &st) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
				{
					s = entry->d_name;
					break;
				}
			}
			closedir(root);
		}
		nlist(s, names);
		for (n = 0; n < elementsof(symbols); n++)
			if (!names[n].n_type)
			{
				error(1, "%s: %s not in nlist", s, names[n].n_name);
				close(kf);
				kf = -1;
			}
		if (chdir(buf))
			error(ERROR_SYSTEM|3, "%s: chdir error", buf);
	}
	if (kf < 0)
#endif
	{
		sfsprintf(buf, sizeof(buf), "%s/%s%s%s", WHODIR, WHOPRE, data, WHOSUF);
		if ((wf = open(buf, O_RDONLY)) >= 0)
		{
			if (read(wf, &who, sizeof(who)) != sizeof(who) || who.wd_vers != WHOVERS || who.wd_type != WHOTYPE)
			{
				error(1, "%s: rwhod protocol mismatch", buf);
				close(wf);
				wf = -1;
			}
			else whofile = strdup(buf);
		}
	}
	strcpy(cmd + strlen(cmd), ".idle");
	if (eaccess(cmd, X_OK)) idlecmd = 0;
	else
	{
		idlecmd = 1;
		iv[0] = cmd;
		iv[1] = data;
		iv[2] = 0;
	}

	/*
	 * the daemon loop
	 */

	ss.idle = 4 * 60 * 60;
	now = CSTIME();
	for (;;)
	{
		then = now;
		now = CSTIME();

		/*
		 * update logged in user stats
		 */

		if (fstat(uf, &st))
			error(ERROR_SYSTEM|3, "%s: stat error", usrfile);
		if (usertime != (unsigned long)st.st_mtime)
		{
			usertime = st.st_mtime;
			if (lseek(uf, 0L, 0))
				error(ERROR_SYSTEM|3, "%s: seek error", usrfile);
			if ((n = read(uf, usrs, sizeof(usrs))) < 0)
				error(ERROR_SYSTEM|3, "%s: read error", usrfile);
			usercount = n / sizeof(struct utmp);
		}

		/*
		 * count the interesting users
		 * find the min user idle time
		 */

		if (idlecmd)
		{
			/*
			 * check idle command
			 */

			if (!(proc = procopen(iv[0], iv, NiL, NiL, PROC_READ|PROC_UID|PROC_GID)))
				idlecmd = 0;
			else
			{
				idlecmd = 1;
				n = read(proc->rfd, buf, sizeof(buf));
				if (procclose(proc) || n < 0)
					idlecmd = 0;
				else
				{
					if (n > 0)
						n--;
					buf[n] = 0;
					if (isdigit(buf[0]))
						ss.idle = strtol(buf, NiL, 10);
					else if (streq(buf, "busy"))
						ss.idle = 0;
					else if (streq(buf, "free"))
						ss.idle = ~0;
					else if (streq(buf, "idle"))
					{
						n = since(then);
						if ((ss.idle + n) < ss.idle) ss.idle = ~0;
						else ss.idle += n;
					}
					else idlecmd = -1;
				}
			}
		}
		if (idlecmd <= 0)
			ss.idle = ~0;
		ss.users = 0;
		for (i = 0; i < usercount; i++)
			if (usrs[i].ut_name[0] && usrs[i].ut_line[0])
			{
				sfsprintf(buf, sizeof(buf), "/dev/%s", usrs[i].ut_line);
				if (stat(buf, &st)) usrs[i].ut_name[0] = 0;
				else
				{
					v = since(st.st_atime);
					if (v < CS_STAT_IGNORE)
						ss.users++;
					if (idlecmd <= 0 && v < ss.idle)
						ss.idle = v;
				}
			}
		if (idlecmd <= 0 || !ss.users)
		{
			/*
			 * check devices for min idle time
			 */

			for (i = 0; i < elementsof(devfiles); i++)
				if (devfiles[i])
				{
					if (stat(devfiles[i], &st)) devfiles[i] = 0;
					else
					{
						v = since(st.st_atime);
						if (!ss.users && v < CS_STAT_IGNORE)
							ss.users++;
						if (idlecmd <= 0 && v < ss.idle)
							ss.idle = v;
					}
				}
		}

		/*
		 * get the hard stuff
		 */

#if NAMELIST
		if (kf >= 0)
		{
			/*
			 * update memfile symbol values
			 */

			for (n = 0; n < elementsof(symbols); n++)
				if (symbols[n].once >= 0)
				{
					if (lseek(kf, (long)names[n].n_value, 0) != (long)names[n].n_value)
						error(ERROR_SYSTEM|3, "%s: %s seek error", memfile, names[n].n_name);
					if (read(kf, symbols[n].addr, symbols[n].size) != symbols[n].size)
						error(ERROR_SYSTEM|3, "%s: %s read error", memfile, names[n].n_name);
					if (symbols[n].once) symbols[n].once = -1;
				}
#ifdef CP_TIME
			for (i = 0; i < CPUSTATES; i++)
				cp_time[i] = 0;
			for (n = 0; n <= maxcpu; n++)
				if (CPUFOUND(n))
					for (i = 0; i < CPUSTATES; i++)
						cp_time[i] += CP_TIME(n)[i];
#endif
			ss.load = (avenrun * 100) / FSCALE;
		}
		else
#endif
		if (wf >= 0)
		{
			if (lseek(wf, 0L, 0))
				error(ERROR_SYSTEM|3, "%s: seek error", whofile);
			read(wf, &who, sizeof(who));
			ss.load = who.wd_loadav[0];
			boottime = who.wd_boottime;
			for (i = 0; i < elementsof(cp_time); i++)
				cp_time[i] = 100;
		}
		else if (!(proc = procopen(av[0], av, NiL, NiL, PROC_READ|PROC_UID|PROC_GID)))
			error(ERROR_SYSTEM|3, "%s: exec error", av[0]);
		else
		{
			/*
			 * defer to process with memfile access
			 */

			n = read(proc->rfd, buf, sizeof(buf) - 1);
			if (procclose(proc) || n <= 0)
				error(3, "%s: invalid", av[0]);
			buf[n] = 0;
			if (!(s = strrchr(buf, ':')))
				error(3, "%s: invalid output", av[0]);
			ss.load = strton(s + 1, NiL, NiL, 100);
			n = 0;
			if ((s = strchr(buf, 'u')) && *++s == 'p')
			{
				n = strtol(s + 1, &e, 10) * 60 * 60;
				s = e;
				while (isspace(*s)) s++;
				if (*s == 'd')
				{
					n *= 24;
					while (*s && !isdigit(*s)) s++;
					n += strtol(s, &e, 10) * 60 * 60;
					s = e;
				}
				if (*s == ':') n += strtol(s + 1, NiL, 10) * 60;
			}
			boottime = since(n);
			for (i = 0; i < elementsof(cp_time); i++)
				cp_time[i] = 0;
		}

		/*
		 * finalize the new stat info
		 */

		t = 0;
		for (i = 0; i < elementsof(cp_time); i++)
		{
			if ((cp_diff[i] = cp_time[i] - cp_prev[i]) < 0) cp_diff[i] = -cp_diff[i];
			t += cp_diff[i];
			cp_prev[i] = cp_time[i];
		}
		if (!t) t = 1;
		ss.pctsys = (cp_diff[CP_SYS] * 100) / t;
		ss.pctusr = ((cp_diff[CP_USER] + cp_diff[CP_NICE]) * 100) / t;
		ss.up = since(boottime);
		update(data, now, (4 * CS_STAT_FREQ + 2 * (CSTOSS(toss, 0) % (CS_STAT_FREQ + 1))) / 5, &ss);
	}
}
예제 #3
0
Recfmt_t
recstr(register const char* s, char** e)
{
    char*	t;
    int	n;
    long	v;
    int	a[6];

    while (*s == ' ' || *s == '\t' || *s == ',')
        s++;
    switch (*s)
    {
    case 'd':
    case 'D':
        if (!*s)
            n = '\n';
        else
        {
            if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))
                n = (int)strtol(s, &t, 0);
            else
                n = chresc(s, &t);
            s = (const char*)t;
        }
        if (e)
            *e = (char*)s;
        return REC_D_TYPE(n);
    case 'f':
    case 'F':
        while (*++s == ' ' || *s == '\t' || *s == ',');
    /*FALLTHROUGH*/
    case '+':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        n = strton(s, &t, NiL, 0);
        if (n > 0 && t > (char*)s)
        {
            if (e)
                *e = t;
            return REC_F_TYPE(n);
        }
        break;
    case 'm':
    case 'M':
        while (*++s == ' ' || *s == '\t' || *s == ',');
        for (t = (char*)s; *t && *t != ' ' && *t != '\t' && *t != ','; t++);
        if ((t - s) == 4)
        {
            if (strneq(s, "data", 4))
            {
                if (e)
                    *e = t;
                return REC_M_TYPE(REC_M_data);
            }
            else if (strneq(s, "path", 4))
            {
                if (e)
                    *e = t;
                return REC_M_TYPE(REC_M_path);
            }
        }

        /*
         * TBD: look up name in method libraries
         *	and assign an integer index
         */

        break;
    case 'u':
    case 'U':
        while (*++s == ' ' || *s == '\t' || *s == ',');
        n = strtol(s, &t, 0);
        if (n < 0 || n > 15 || *t++ != '.')
            break;
        v = strtol(t, &t, 0);
        if (*t)
            break;
        if (e)
            *e = t;
        return REC_U_TYPE(n, v);
    case 'v':
    case 'V':
        a[0] = 0;
        a[1] = 4;
        a[2] = 0;
        a[3] = 2;
        a[4] = 0;
        a[5] = 1;
        n = 0;
        for (;;)
        {
            switch (*++s)
            {
            case 0:
                break;
            case 'm':
            case 'M':
                n = 0;
                continue;
            case 'h':
            case 'H':
                n = 1;
                continue;
            case 'o':
            case 'O':
                n = 2;
                continue;
            case 'z':
            case 'Z':
                n = 3;
                continue;
            case 'b':
            case 'B':
                n = 4;
                a[n++] = 0;
                continue;
            case 'l':
            case 'L':
                n = 4;
                a[n++] = 1;
                continue;
            case 'n':
            case 'N':
                n = 0;
                a[5] = 0;
                continue;
            case 'i':
            case 'I':
                n = 0;
                a[5] = 1;
                continue;
            case ' ':
            case '\t':
            case ',':
            case '-':
            case '+':
                continue;
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                v = 0;
                a[n++] = strtol(s, &t, 0);
                s = (const char*)t - 1;
                continue;
            }
            break;
        }
        if (e)
            *e = (char*)s;
        if (a[3] > (a[1] - a[2]))
            a[3] = a[1] - a[2];
        return REC_V_RECORD(REC_V_TYPE(a[1], a[2], a[3], a[4], a[5]), a[0]);
    case '%':
        if (e)
            *e = (char*)s + 1;
        return REC_M_TYPE(REC_M_path);
    case '-':
    case '?':
        if (e)
            *e = (char*)s + 1;
        return REC_M_TYPE(REC_M_data);
    }
    if (e)
        *e = (char*)s;
    return REC_N_TYPE();
}