Example #1
0
stmt_ty *
stmt_if_alloc(blob_list_ty *condition, stmt_ty *then_clause,
    stmt_ty *else_clause)
{
    stmt_if_ty      *result;
    blob_list_ty    *c2;
    table_ty        *tp;

    trace(("stmt_if_alloc()\n{\n"));
    result = (stmt_if_ty *)stmt_alloc(&method);

    assert(condition->length >= 1);
    for (tp = table; tp < ENDOF(table); ++tp)
    {
        if (!tp->fast)
            tp->fast = str_from_c(tp->name);
        if (str_equal(condition->list[0]->text, tp->fast))
            break;
    }
    assert(tp < ENDOF(table));
    if (tp >= ENDOF(table))
        tp = &table[0];
    c2 = tp->rewrite(condition, &result->ref);
    blob_list_free(condition);

    result->condition = c2;
    result->then_clause = then_clause;
    result->else_clause = else_clause;

    stmt_variable_merge((stmt_ty *)result, then_clause);
    if (else_clause)
        stmt_variable_merge((stmt_ty *)result, else_clause);
    trace(("}\n"));
    return (stmt_ty *)result;
}
Example #2
0
static void
version_copyright()
{
	static char *text[] =
	{
		"All rights reserved.",
		"",
		"The %s program comes with ABSOLUTELY NO WARRANTY;",
		"for details use the '%s -VERSion License' command.",
		"The %s program is free software, and you are welcome",
		"to redistribute it under certain conditions; for",
		"details use the '%s -VERSion License' command.",
	};

	char		**cpp;
	char		*progname;

	progname = progname_get();
	printf("%s version %s\n", progname, version_stamp());
	printf("Copyright (C) %s Peter Miller;\n", copyright_years());
	for (cpp = text; cpp < ENDOF(text); ++cpp)
	{
		printf(*cpp, progname);
		fputc('\n', stdout);
	}
}
Example #3
0
bool		json_t_parse_string(t_json_parser *p,
				t_json_t_value const *t, void *data)
{
	t_sub		val_string;
	t_sub		*value;

	if (p->token != JSON_VALUE || p->value_type != JSON_VALUE_STRING)
		return (ft_json_fail(p, SUBC("Expecting string")));
	val_string = JSON_VAL_STRING(p);
	value = MALLOC(sizeof(t_sub) + val_string.length);
	*value = SUB(ENDOF(value), val_string.length);
	memcpy(ENDOF(value), val_string.str, val_string.length);
	*(t_sub**)data = value;
	return (true);
	(void)t;
}
Example #4
0
t_file_in		*ft_in_fdopen(int fd)
{
	t_file_in		*in;

	in = MALLOC(sizeof(t_file_in) + F_IN_BUFF_SIZE);
	*in = F_IN(fd, ENDOF(in), F_IN_BUFF_SIZE);
	return (in);
}
Example #5
0
void
builtin_initialize(void)
{
    builtin_ty      **fpp;
    string_ty       *s;

    for (fpp = func; fpp < ENDOF(func); ++fpp)
    {
        s = str_from_c((*fpp)->name);
        symtab_assign(id_global_stp(), s, id_builtin_new(*fpp));
        str_free(s);
    }
}
Example #6
0
t_texture const	*load_texture1(uint32_t color, uint32_t flags)
{
	t_hmap *const	cache = texture_cache();
	uint32_t		key[2];
	t_texture		*tmp;

	key[0] = flags;
	key[1] = color;
	if ((tmp = ft_hmapget(cache, SUBV(key)).value) != NULL)
		return (tmp);
	tmp = ft_hmapput(cache, SUBV(key), NULL,
		sizeof(t_texture) + sizeof(uint32_t)).value;
	ft_logf(LOG_DEBUG, "Solid texture created: #%.8x", color);
	*tmp = (t_texture){&texture_solid, (t_img){ENDOF(tmp), 1, 1}};
	*tmp->img.data = color;
	if (flags & TEXTURE_GAMMA)
		correct_gamma(&tmp->img);
	return (tmp);
}
Example #7
0
char *
arglex_token_name(arglex_token_ty n)
{
    arglex_table_ty *tp;

    switch (n)
    {
    case arglex_token_eoln:
        return "end of command line";

    case arglex_token_number:
        return "number";

    case arglex_token_option:
        return "option";

    case arglex_token_stdio:
        return "standard input or output";

    case arglex_token_string:
        return "string";

    default:
        break;
    }
    for (tp = table; tp < ENDOF(table); tp++)
    {
        if (tp->token == n)
            return tp->name;
    }
    if (utable)
    {
        for (tp = utable; tp->name; tp++)
        {
            if (tp->token == n)
                return tp->name;
        }
    }

    assert(0);
    return "unknown command line token";
}
Example #8
0
/*
 * lexescape - parse an ARE backslash escape (backslash already eaten)
 * Note slightly nonstandard use of the CCLASS type code.
 */
static int						/* not actually used, but convenient for RETV */
lexescape(struct vars * v)
{
	chr			c;
	static const chr alert[] = {
		CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
	};
	static const chr esc[] = {
		CHR('E'), CHR('S'), CHR('C')
	};
	const chr  *save;

	assert(v->cflags & REG_ADVF);

	assert(!ATEOS());
	c = *v->now++;
	if (!iscalnum(c))
		RETV(PLAIN, c);

	NOTE(REG_UNONPOSIX);
	switch (c)
	{
		case CHR('a'):
			RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007')));
			break;
		case CHR('A'):
			RETV(SBEGIN, 0);
			break;
		case CHR('b'):
			RETV(PLAIN, CHR('\b'));
			break;
		case CHR('B'):
			RETV(PLAIN, CHR('\\'));
			break;
		case CHR('c'):
			NOTE(REG_UUNPORT);
			if (ATEOS())
				FAILW(REG_EESCAPE);
			RETV(PLAIN, (chr) (*v->now++ & 037));
			break;
		case CHR('d'):
			NOTE(REG_ULOCALE);
			RETV(CCLASS, 'd');
			break;
		case CHR('D'):
			NOTE(REG_ULOCALE);
			RETV(CCLASS, 'D');
			break;
		case CHR('e'):
			NOTE(REG_UUNPORT);
			RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033')));
			break;
		case CHR('f'):
			RETV(PLAIN, CHR('\f'));
			break;
		case CHR('m'):
			RET('<');
			break;
		case CHR('M'):
			RET('>');
			break;
		case CHR('n'):
			RETV(PLAIN, CHR('\n'));
			break;
		case CHR('r'):
			RETV(PLAIN, CHR('\r'));
			break;
		case CHR('s'):
			NOTE(REG_ULOCALE);
			RETV(CCLASS, 's');
			break;
		case CHR('S'):
			NOTE(REG_ULOCALE);
			RETV(CCLASS, 'S');
			break;
		case CHR('t'):
			RETV(PLAIN, CHR('\t'));
			break;
		case CHR('u'):
			c = lexdigits(v, 16, 4, 4);
			if (ISERR())
				FAILW(REG_EESCAPE);
			RETV(PLAIN, c);
			break;
		case CHR('U'):
			c = lexdigits(v, 16, 8, 8);
			if (ISERR())
				FAILW(REG_EESCAPE);
			RETV(PLAIN, c);
			break;
		case CHR('v'):
			RETV(PLAIN, CHR('\v'));
			break;
		case CHR('w'):
			NOTE(REG_ULOCALE);
			RETV(CCLASS, 'w');
			break;
		case CHR('W'):
			NOTE(REG_ULOCALE);
			RETV(CCLASS, 'W');
			break;
		case CHR('x'):
			NOTE(REG_UUNPORT);
			c = lexdigits(v, 16, 1, 255);		/* REs >255 long outside spec */
			if (ISERR())
				FAILW(REG_EESCAPE);
			RETV(PLAIN, c);
			break;
		case CHR('y'):
			NOTE(REG_ULOCALE);
			RETV(WBDRY, 0);
			break;
		case CHR('Y'):
			NOTE(REG_ULOCALE);
			RETV(NWBDRY, 0);
			break;
		case CHR('Z'):
			RETV(SEND, 0);
			break;
		case CHR('1'):
		case CHR('2'):
		case CHR('3'):
		case CHR('4'):
		case CHR('5'):
		case CHR('6'):
		case CHR('7'):
		case CHR('8'):
		case CHR('9'):
			save = v->now;
			v->now--;			/* put first digit back */
			c = lexdigits(v, 10, 1, 255);		/* REs >255 long outside spec */
			if (ISERR())
				FAILW(REG_EESCAPE);
			/* ugly heuristic (first test is "exactly 1 digit?") */
			if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp))
			{
				NOTE(REG_UBACKREF);
				RETV(BACKREF, (chr) c);
			}
			/* oops, doesn't look like it's a backref after all... */
			v->now = save;
			/* and fall through into octal number */
		case CHR('0'):
			NOTE(REG_UUNPORT);
			v->now--;			/* put first digit back */
			c = lexdigits(v, 8, 1, 3);
			if (ISERR())
				FAILW(REG_EESCAPE);
			if (c > 0xff)
			{
				/* out of range, so we handled one digit too much */
				v->now--;
				c >>= 3;
			}
			RETV(PLAIN, c);
			break;
		default:
			assert(iscalpha(c));
			FAILW(REG_EESCAPE); /* unknown alphabetic escape */
			break;
	}
Example #9
0
/*
 * next - get next token
 */
static int						/* 1 normal, 0 failure */
next(struct vars * v)
{
	chr			c;

	/* errors yield an infinite sequence of failures */
	if (ISERR())
		return 0;				/* the error has set nexttype to EOS */

	/* remember flavor of last token */
	v->lasttype = v->nexttype;

	/* REG_BOSONLY */
	if (v->nexttype == EMPTY && (v->cflags & REG_BOSONLY))
	{
		/* at start of a REG_BOSONLY RE */
		RETV(SBEGIN, 0);		/* same as \A */
	}

	/* if we're nested and we've hit end, return to outer level */
	if (v->savenow != NULL && ATEOS())
	{
		v->now = v->savenow;
		v->stop = v->savestop;
		v->savenow = v->savestop = NULL;
	}

	/* skip white space etc. if appropriate (not in literal or []) */
	if (v->cflags & REG_EXPANDED)
		switch (v->lexcon)
		{
			case L_ERE:
			case L_BRE:
			case L_EBND:
			case L_BBND:
				skip(v);
				break;
		}

	/* handle EOS, depending on context */
	if (ATEOS())
	{
		switch (v->lexcon)
		{
			case L_ERE:
			case L_BRE:
			case L_Q:
				RET(EOS);
				break;
			case L_EBND:
			case L_BBND:
				FAILW(REG_EBRACE);
				break;
			case L_BRACK:
			case L_CEL:
			case L_ECL:
			case L_CCL:
				FAILW(REG_EBRACK);
				break;
		}
		assert(NOTREACHED);
	}

	/* okay, time to actually get a character */
	c = *v->now++;

	/* deal with the easy contexts, punt EREs to code below */
	switch (v->lexcon)
	{
		case L_BRE:				/* punt BREs to separate function */
			return brenext(v, c);
			break;
		case L_ERE:				/* see below */
			break;
		case L_Q:				/* literal strings are easy */
			RETV(PLAIN, c);
			break;
		case L_BBND:			/* bounds are fairly simple */
		case L_EBND:
			switch (c)
			{
				case CHR('0'):
				case CHR('1'):
				case CHR('2'):
				case CHR('3'):
				case CHR('4'):
				case CHR('5'):
				case CHR('6'):
				case CHR('7'):
				case CHR('8'):
				case CHR('9'):
					RETV(DIGIT, (chr) DIGITVAL(c));
					break;
				case CHR(','):
					RET(',');
					break;
				case CHR('}'):	/* ERE bound ends with } */
					if (INCON(L_EBND))
					{
						INTOCON(L_ERE);
						if ((v->cflags & REG_ADVF) && NEXT1('?'))
						{
							v->now++;
							NOTE(REG_UNONPOSIX);
							RETV('}', 0);
						}
						RETV('}', 1);
					}
					else
						FAILW(REG_BADBR);
					break;
				case CHR('\\'):	/* BRE bound ends with \} */
					if (INCON(L_BBND) && NEXT1('}'))
					{
						v->now++;
						INTOCON(L_BRE);
						RET('}');
					}
					else
						FAILW(REG_BADBR);
					break;
				default:
					FAILW(REG_BADBR);
					break;
			}
			assert(NOTREACHED);
			break;
		case L_BRACK:			/* brackets are not too hard */
			switch (c)
			{
				case CHR(']'):
					if (LASTTYPE('['))
						RETV(PLAIN, c);
					else
					{
						INTOCON((v->cflags & REG_EXTENDED) ?
								L_ERE : L_BRE);
						RET(']');
					}
					break;
				case CHR('\\'):
					NOTE(REG_UBBS);
					if (!(v->cflags & REG_ADVF))
						RETV(PLAIN, c);
					NOTE(REG_UNONPOSIX);
					if (ATEOS())
						FAILW(REG_EESCAPE);
					(DISCARD) lexescape(v);
					switch (v->nexttype)
					{			/* not all escapes okay here */
						case PLAIN:
							return 1;
							break;
						case CCLASS:
							switch (v->nextvalue)
							{
								case 'd':
									lexnest(v, brbackd, ENDOF(brbackd));
									break;
								case 's':
									lexnest(v, brbacks, ENDOF(brbacks));
									break;
								case 'w':
									lexnest(v, brbackw, ENDOF(brbackw));
									break;
								default:
									FAILW(REG_EESCAPE);
									break;
							}
							/* lexnest done, back up and try again */
							v->nexttype = v->lasttype;
							return next(v);
							break;
					}
					/* not one of the acceptable escapes */
					FAILW(REG_EESCAPE);
					break;
				case CHR('-'):
					if (LASTTYPE('[') || NEXT1(']'))
						RETV(PLAIN, c);
					else
						RETV(RANGE, c);
					break;
				case CHR('['):
					if (ATEOS())
						FAILW(REG_EBRACK);
					switch (*v->now++)
					{
						case CHR('.'):
							INTOCON(L_CEL);
							/* might or might not be locale-specific */
							RET(COLLEL);
							break;
						case CHR('='):
							INTOCON(L_ECL);
							NOTE(REG_ULOCALE);
							RET(ECLASS);
							break;
						case CHR(':'):
							INTOCON(L_CCL);
							NOTE(REG_ULOCALE);
							RET(CCLASS);
							break;
						default:		/* oops */
							v->now--;
							RETV(PLAIN, c);
							break;
					}
					assert(NOTREACHED);
					break;
				default:
					RETV(PLAIN, c);
					break;
			}
			assert(NOTREACHED);
			break;
		case L_CEL:				/* collating elements are easy */
			if (c == CHR('.') && NEXT1(']'))
			{
				v->now++;
				INTOCON(L_BRACK);
				RETV(END, '.');
			}
			else
				RETV(PLAIN, c);
			break;
		case L_ECL:				/* ditto equivalence classes */
			if (c == CHR('=') && NEXT1(']'))
			{
				v->now++;
				INTOCON(L_BRACK);
				RETV(END, '=');
			}
			else
				RETV(PLAIN, c);
			break;
		case L_CCL:				/* ditto character classes */
			if (c == CHR(':') && NEXT1(']'))
			{
				v->now++;
				INTOCON(L_BRACK);
				RETV(END, ':');
			}
			else
				RETV(PLAIN, c);
			break;
		default:
			assert(NOTREACHED);
			break;
	}

	/* that got rid of everything except EREs and AREs */
	assert(INCON(L_ERE));

	/* deal with EREs and AREs, except for backslashes */
	switch (c)
	{
		case CHR('|'):
			RET('|');
			break;
		case CHR('*'):
			if ((v->cflags & REG_ADVF) && NEXT1('?'))
			{
				v->now++;
				NOTE(REG_UNONPOSIX);
				RETV('*', 0);
			}
			RETV('*', 1);
			break;
		case CHR('+'):
			if ((v->cflags & REG_ADVF) && NEXT1('?'))
			{
				v->now++;
				NOTE(REG_UNONPOSIX);
				RETV('+', 0);
			}
			RETV('+', 1);
			break;
		case CHR('?'):
			if ((v->cflags & REG_ADVF) && NEXT1('?'))
			{
				v->now++;
				NOTE(REG_UNONPOSIX);
				RETV('?', 0);
			}
			RETV('?', 1);
			break;
		case CHR('{'):			/* bounds start or plain character */
			if (v->cflags & REG_EXPANDED)
				skip(v);
			if (ATEOS() || !iscdigit(*v->now))
			{
				NOTE(REG_UBRACES);
				NOTE(REG_UUNSPEC);
				RETV(PLAIN, c);
			}
			else
			{
				NOTE(REG_UBOUNDS);
				INTOCON(L_EBND);
				RET('{');
			}
			assert(NOTREACHED);
			break;
		case CHR('('):			/* parenthesis, or advanced extension */
			if ((v->cflags & REG_ADVF) && NEXT1('?'))
			{
				NOTE(REG_UNONPOSIX);
				v->now++;
				if (ATEOS())
					FAILW(REG_BADRPT);
				switch (*v->now++)
				{
					case CHR(':'):		/* non-capturing paren */
						RETV('(', 0);
						break;
					case CHR('#'):		/* comment */
						while (!ATEOS() && *v->now != CHR(')'))
							v->now++;
						if (!ATEOS())
							v->now++;
						assert(v->nexttype == v->lasttype);
						return next(v);
						break;
					case CHR('='):		/* positive lookahead */
						NOTE(REG_ULOOKAROUND);
						RETV(LACON, LATYPE_AHEAD_POS);
						break;
					case CHR('!'):		/* negative lookahead */
						NOTE(REG_ULOOKAROUND);
						RETV(LACON, LATYPE_AHEAD_NEG);
						break;
					case CHR('<'):
						if (ATEOS())
							FAILW(REG_BADRPT);
						switch (*v->now++)
						{
							case CHR('='):		/* positive lookbehind */
								NOTE(REG_ULOOKAROUND);
								RETV(LACON, LATYPE_BEHIND_POS);
								break;
							case CHR('!'):		/* negative lookbehind */
								NOTE(REG_ULOOKAROUND);
								RETV(LACON, LATYPE_BEHIND_NEG);
								break;
							default:
								FAILW(REG_BADRPT);
								break;
						}
						assert(NOTREACHED);
						break;
					default:
						FAILW(REG_BADRPT);
						break;
				}
				assert(NOTREACHED);
			}
			if (v->cflags & REG_NOSUB)
				RETV('(', 0);	/* all parens non-capturing */
			else
				RETV('(', 1);
			break;
		case CHR(')'):
			if (LASTTYPE('('))
				NOTE(REG_UUNSPEC);
			RETV(')', c);
			break;
		case CHR('['):			/* easy except for [[:<:]] and [[:>:]] */
			if (HAVE(6) && *(v->now + 0) == CHR('[') &&
				*(v->now + 1) == CHR(':') &&
				(*(v->now + 2) == CHR('<') ||
				 *(v->now + 2) == CHR('>')) &&
				*(v->now + 3) == CHR(':') &&
				*(v->now + 4) == CHR(']') &&
				*(v->now + 5) == CHR(']'))
			{
				c = *(v->now + 2);
				v->now += 6;
				NOTE(REG_UNONPOSIX);
				RET((c == CHR('<')) ? '<' : '>');
			}
			INTOCON(L_BRACK);
			if (NEXT1('^'))
			{
				v->now++;
				RETV('[', 0);
			}
			RETV('[', 1);
			break;
		case CHR('.'):
			RET('.');
			break;
		case CHR('^'):
			RET('^');
			break;
		case CHR('$'):
			RET('$');
			break;
		case CHR('\\'): /* mostly punt backslashes to code below */
			if (ATEOS())
				FAILW(REG_EESCAPE);
			break;
		default:				/* ordinary character */
			RETV(PLAIN, c);
			break;
	}

	/* ERE/ARE backslash handling; backslash already eaten */
	assert(!ATEOS());
	if (!(v->cflags & REG_ADVF))
	{							/* only AREs have non-trivial escapes */
		if (iscalnum(*v->now))
		{
			NOTE(REG_UBSALNUM);
			NOTE(REG_UUNSPEC);
		}
		RETV(PLAIN, *v->now++);
	}
	(DISCARD) lexescape(v);
	if (ISERR())
		FAILW(REG_EESCAPE);
	if (v->nexttype == CCLASS)
	{							/* fudge at lexical level */
		switch (v->nextvalue)
		{
			case 'd':
				lexnest(v, backd, ENDOF(backd));
				break;
			case 'D':
				lexnest(v, backD, ENDOF(backD));
				break;
			case 's':
				lexnest(v, backs, ENDOF(backs));
				break;
			case 'S':
				lexnest(v, backS, ENDOF(backS));
				break;
			case 'w':
				lexnest(v, backw, ENDOF(backw));
				break;
			case 'W':
				lexnest(v, backW, ENDOF(backW));
				break;
			default:
				assert(NOTREACHED);
				FAILW(REG_ASSERT);
				break;
		}
		/* lexnest done, back up and try again */
		v->nexttype = v->lasttype;
		return next(v);
	}
	/* otherwise, lexescape has already done the work */
	return !ISERR();
}
Example #10
0
/*
 * lexword - interpolate a bracket expression for word characters
 * Possibly ought to inquire whether there is a "word" character class.
 */
static void
lexword(struct vars * v)
{
	lexnest(v, backw, ENDOF(backw));
}
Example #11
0
static int
reserved(string_ty *s)
{
    typedef struct table_ty table_ty;
    struct table_ty
    {
        char            *name;
        int             token;
    };

    static table_ty table[] =
    {
        { "override", OVERRIDE },
        { "include", INCLUDE2 },
        { "-include", INCLUDE3 },
        { ".include", INCLUDE },
        { "vpath", VPATH },
        { "VPATH", VPATH2 },
        { "ifdef", IF },
        { "ifndef", IF },
        { "ifeq", IF },
        { "ifneq", IF },
        { "else", ELSE },
        { "endif", ENDIF },
        { "endef", ENDDEF },
        { "define", DEFINE },
        { "export", EXPORT },
        { "unexport", UNEXPORT },
    };

    static symtab_ty *symtab;
    int             *data;
    string_ty       *name;
    char            *cp;

    if (!symtab)
    {
        table_ty        *tp;

        symtab = symtab_alloc(SIZEOF(table));
        for (tp = table; tp < ENDOF(table); ++tp)
        {
            name = str_from_c(tp->name);
            symtab_assign(symtab, name, &tp->token);
            str_free(name);
        }
    }

    cp = strchr(s->str_text, '(');
    if (cp)
    {
        name = str_n_from_c(s->str_text, cp - s->str_text);
        data = symtab_query(symtab, name);
        str_free(name);
    }
    else
        data = symtab_query(symtab, s);
    if (data)
        return *data;
    return 0;
}
Example #12
0
arglex_token_ty
arglex(void)
{
    arglex_table_ty *tp;
    int             j;
    arglex_table_ty *hit[20];
    int             nhit;
    char            *arg;
    static char     *pushback[3];
    static int      pushback_depth;

    trace(("arglex()\n{\n"));
    if (pushback_depth)
    {
        /*
         * the second half of a "-foo=bar" style argument.
         */
        arg = pushback[--pushback_depth];
    }
    else
    {
        if (argc <= 0)
        {
            arglex_token = arglex_token_eoln;
            arg = "";
            goto done;
        }
        arg = argv[0];
        argc--;
        argv++;

        /*
         * See if it looks like a GNU "-foo=bar" option.
         * Split it at the '=' to make it something the
         * rest of the code understands.
         */
        if (arg[0] == '-' && arg[1] != '=')
        {
            char           *eqp;

            eqp = strchr(arg, '=');
            if (eqp)
            {
                pushback[pushback_depth++] = eqp + 1;
                *eqp = 0;
            }
        }

        /*
         * Turn the GNU-style leading "--"
         * into "-" if necessary.
         */
        if (arg[0] == '-' && arg[1] == '-' && arg[2] && !is_a_number(arg + 1))
            ++arg;
    }

    /*
     * see if it is a number
     */
    if (is_a_number(arg))
    {
        arglex_token = arglex_token_number;
        goto done;
    }

    /*
     * scan the tables to see what it matches
     */
    nhit = 0;
    partial = 0;
    for (tp = table; tp < ENDOF(table); tp++)
    {
        if (arglex_compare(tp->name, arg))
            hit[nhit++] = tp;
    }
    if (utable)
    {
        for (tp = utable; tp->name; tp++)
        {
            if (arglex_compare(tp->name, arg))
                hit[nhit++] = tp;
        }
    }

    /*
     * deal with unknown or ambiguous options
     */
    switch (nhit)
    {
    case 0:
        /*
         * not found in the tables
         */
        if (*arg == '-')
            arglex_token = arglex_token_option;
        else
            arglex_token = arglex_token_string;
        break;

    case 1:
        if (partial)
            pushback[pushback_depth++] = (char *)partial;
        arg = hit[0]->name;
        arglex_token = hit[0]->token;
        break;

    default:
    {
        string_ty      *s1;
        string_ty      *s2;
        sub_context_ty *scp;

        s1 = str_from_c(hit[0]->name);
        for (j = 1; j < nhit; ++j)
        {
            s2 = str_format("%s, %s", s1->str_text, hit[j]->name);
            str_free(s1);
            s1 = s2;
        }
        scp = sub_context_new();
        sub_var_set_charstar(scp, "Name", arg);
        sub_var_set_string(scp, "Guess", s1);
        fatal_intl(scp, i18n("option \"$name\" ambiguous ($guess)"));
        /* NOTREACHED */
    }
    }

    /*
     * here for all exits
     */
  done:
    arglex_value.alv_string = arg;
    trace(("return %d; /* \"%s\" */\n", arglex_token, arg));
    trace(("}\n"));
    return arglex_token;
}