Skip to content

Commit

Permalink
Determine if simple command names are declaration utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
magicant committed Jan 5, 2025
1 parent 85a64cf commit 61c96c3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 15 deletions.
38 changes: 25 additions & 13 deletions builtin.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* builtin.c: built-in commands */
/* (C) 2007-2022 magicant */
/* (C) 2007-2025 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -77,16 +77,28 @@ void init_builtin(void)
ht_initwithcapacity(&builtins, hashstr, htstrcmp, 53);

#if YASH_ENABLE_HELP
# define DEFBUILTIN(name,func,type,help,syntax,options) \
do { \
static const builtin_T bi = { func, type, help, syntax, options, }; \
ht_set(&builtins, name, &bi); \
# define DEFBUILTIN(name,func,type,help,syntax,options) \
do { \
static const builtin_T bi = \
{ func, type, false, help, syntax, options, }; \
ht_set(&builtins, name, &bi); \
} while (0)
# define DEFDECLUTIL(name,func,type,help,syntax,options) \
do { \
static const builtin_T bi = \
{ func, type, true, help, syntax, options, }; \
ht_set(&builtins, name, &bi); \
} while (0)
#else
# define DEFBUILTIN(name,func,type,help,syntax,options) \
do { \
static const builtin_T bi = { func, type, }; \
ht_set(&builtins, name, &bi); \
# define DEFBUILTIN(name,func,type,help,syntax,options) \
do { \
static const builtin_T bi = { func, type, false, }; \
ht_set(&builtins, name, &bi); \
} while (0)
# define DEFDECLUTIL(name,func,type,help,syntax,options) \
do { \
static const builtin_T bi = { func, type, true, }; \
ht_set(&builtins, name, &bi); \
} while (0)
#endif

Expand Down Expand Up @@ -121,13 +133,13 @@ void init_builtin(void)
unalias_syntax, all_help_options);

/* defined in "variable.c" */
DEFBUILTIN("typeset", typeset_builtin, BI_ELECTIVE, typeset_help,
DEFDECLUTIL("typeset", typeset_builtin, BI_ELECTIVE, typeset_help,
typeset_syntax, typeset_options);
DEFBUILTIN("export", typeset_builtin, BI_SPECIAL, export_help,
DEFDECLUTIL("export", typeset_builtin, BI_SPECIAL, export_help,
export_syntax, typeset_options);
DEFBUILTIN("local", typeset_builtin, BI_ELECTIVE, local_help,
DEFDECLUTIL("local", typeset_builtin, BI_ELECTIVE, local_help,
local_syntax, local_options);
DEFBUILTIN("readonly", typeset_builtin, BI_SPECIAL, readonly_help,
DEFDECLUTIL("readonly", typeset_builtin, BI_SPECIAL, readonly_help,
readonly_syntax, typeset_options);
#if YASH_ENABLE_ARRAY
DEFBUILTIN("array", array_builtin, BI_EXTENSION, array_help, array_syntax,
Expand Down
3 changes: 2 additions & 1 deletion builtin.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Yash: yet another shell */
/* builtin.h: built-in commands */
/* (C) 2007-2022 magicant */
/* (C) 2007-2025 magicant */

/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -36,6 +36,7 @@ typedef enum builtintype_T {
typedef struct builtin_T {
main_T *body;
builtintype_T type;
_Bool isdeclutil;
#if YASH_ENABLE_HELP
const char *help_text, *syntax_text;
const struct xgetopt_T *options;
Expand Down
28 changes: 27 additions & 1 deletion parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <wchar.h>
#include <wctype.h>
#include "alias.h"
#include "builtin.h"
#include "expand.h"
#include "input.h"
#include "option.h"
Expand Down Expand Up @@ -663,6 +664,8 @@ static redir_T *tryparse_redirect(parsestate_T *ps)
__attribute__((nonnull,malloc,warn_unused_result));
static void validate_redir_operand(parsestate_T *ps)
__attribute__((nonnull));
static bool is_declaration_utility(void *const *words)
__attribute__((nonnull,pure,warn_unused_result));
static command_T *parse_compound_command(parsestate_T *ps)
__attribute__((nonnull,malloc,warn_unused_result));
static command_T *parse_group(parsestate_T *ps)
Expand Down Expand Up @@ -2098,7 +2101,7 @@ command_T *parse_command(parsestate_T *ps)
result->c_redirs = NULL;
result->c_words = parse_simple_command_tokens(
ps, &result->c_assigns, &result->c_redirs);
result->c_isdeclutil = false; // TODO FIXME
result->c_isdeclutil = is_declaration_utility(result->c_words);

if (result->c_words[0] == NULL && result->c_assigns == NULL &&
result->c_redirs == NULL) {
Expand Down Expand Up @@ -2386,6 +2389,29 @@ void validate_redir_operand(parsestate_T *ps)
} while (psubstitute_alias(ps, 0));
}

/* Determines if the command name is a declaration utility.
* `words` must point to a NULL-terminated array of pointers to `wordunit_T's.
* This function usually examines only the first word, but may scan remaining
* words if a word delegates to the next one. */
bool is_declaration_utility(void *const *words)
{
for (; *words != NULL; words++) {
const wordunit_T *w = *words;
if (!is_single_string_word(w))
return false;
if (wcscmp(w->wu_string, L"command") == 0)
continue;

char *name = malloc_wcstombs(w->wu_string);
if (name == NULL)
return false;
const builtin_T *bi = get_builtin(name);
free(name);
return bi != NULL && bi->isdeclutil;
}
return false;
}

/* Parses a compound command.
* `command' is the name of the command to parse such as "(" and "if".
* Returns NULL iff the current token does not start a compound command. */
Expand Down

0 comments on commit 61c96c3

Please sign in to comment.