-関数の __attribute__ の位置を変更
gettext 対応
#endif
#endif /* COMMON_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
# parse options
for i in "$@"
do
- case "$i" in
- -h|--help)
- help="yes" ;;
- -d|--debug)
- debug="yes" ;;
- --without-readline)
- readline="no" ;;
- --with-readline=*)
- readline="${i#--with-readline=}" ;;
- --with-readline)
- readline="yes" ;;
- --prefix=*)
- prefix="${i#--prefix=}" ;;
- --exec-prefix=*)
- execprefix="${i#--exec-prefix=}" ;;
- --bindir=*)
- bindir="${i#--bindir=}" ;;
- *)
- echo "$0: $i: unknown option" >&2
- exit 1
- esac
+ case "$i" in
+ -h|--help)
+ help="yes" ;;
+ -d|--debug)
+ debug="yes" ;;
+ --without-readline)
+ readline="no" ;;
+ --with-readline=*)
+ readline="${i#--with-readline=}" ;;
+ --with-readline)
+ readline="yes" ;;
+ --prefix=*)
+ prefix="${i#--prefix=}" ;;
+ --exec-prefix=*)
+ execprefix="${i#--exec-prefix=}" ;;
+ --bindir=*)
+ bindir="${i#--bindir=}" ;;
+ *)
+ echo "$0: $i: unknown option" >&2
+ exit 1
+ esac
done
if [ x"${help}" = x"yes" ]
then
- cat <<END
+ cat <<END
Usage: ./configure [options...]
Available options:
Influential environment variables:
CC, CFLAGS, CADDS, LDFLAGS, LDADDS, LDLIBS, INSTALL_PROGRAM
END
- exit 0
+ exit 0
fi
echo "/* ${configh}: generated by configure */" >&6
checking () {
- printf "%s" "checking $1... "
- echo >&5
- echo "# checking $1..." >&5
+ printf "%s" "checking $1... "
+ echo >&5
+ echo "# checking $1..." >&5
}
checkby () {
- echo "%" "$@" >&5
- eval "$@" '>&5 2>&1'
+ echo "%" "$@" >&5
+ eval "$@" '>&5 2>&1'
}
trycompile () {
- echo "%" ${cc} ${cflags} ${CADDS} ${ldflags} ${LDADDS} -o "${tempout}" \
- "${tempsrc}" "$@" ${ldlibs} >&5
- ${cc} ${cflags} ${CADDS} ${ldflags} ${LDADDS} -o "${tempout}" \
- "${tempsrc}" "$@" ${ldlibs} >&5 2>&1
+ echo "%" ${cc} ${cflags} ${CADDS} ${ldflags} ${LDADDS} -o "${tempout}" \
+ "${tempsrc}" "$@" ${ldlibs} >&5
+ ${cc} ${cflags} ${CADDS} ${ldflags} ${LDADDS} -o "${tempout}" \
+ "${tempsrc}" "$@" ${ldlibs} >&5 2>&1
}
checked () {
- echo "$1"
- echo "# result: $1" >&5
+ echo "$1"
+ echo "# result: $1" >&5
}
defconfigh () {
- echo "#define" $1 ${2:-1} >&6
- echo "# defining $1=${2:-1} in ${configh}" >&5
+ echo "#define" $1 ${2:-1} >&6
+ echo "# defining $1=${2:-1} in ${configh}" >&5
}
# check whether GCC is available
if [ x"${gcc}" = x"yes" ]
then
- cc="${CC:-gcc}"
- if [ x"${debug}" = x"yes" ]
- then
- cflags="-std=c99 -O1 -ggdb -Wall -Wextra"
- else
- cflags="-std=c99 -O2 -g"
- defconfigh "NDEBUG"
- fi
-else
- if [ x"${debug}" = x"yes" ]
- then
- echo "--debug option specified but GCC unavailable" 2>&1
- debug="no"
- fi
+ cc="${CC:-gcc}"
+ if [ x"${debug}" = x"yes" ]
+ then
+ cflags="-std=c99 -O1 -ggdb -Wall -Wextra"
+ else
+ cflags="-std=c99 -O2 -g"
defconfigh "NDEBUG"
+ fi
+else
+ if [ x"${debug}" = x"yes" ]
+ then
+ echo "--debug option specified but GCC unavailable" 2>&1
+ debug="no"
+ fi
+ defconfigh "NDEBUG"
fi
# check whether GNU Readline is available
if [ x"${readline}" = x"check" -o x"${readline}" = x"yes" ]
then
- if [ x"${readline}" = x"yes" ]
- then
- defconfigh "USE_READLINE"
- fi
- checking "whether GNU Readline is available"
- cat >"${tempsrc}" <<END
+ if [ x"${readline}" = x"yes" ]
+ then
+ defconfigh "USE_READLINE"
+ fi
+ checking "whether GNU Readline is available"
+ cat >"${tempsrc}" <<END
#include <stdio.h>
#include <readline/readline.h>
/* check some features to exclude old libedit */
void *y = &rl_attempted_completion_over;
int main() { readline(""); return 0; }
END
- if [ -r libreadline.a ]
- then
- rllib="libreadline.a"
- else
- rllib="-l readline"
- fi
- if trycompile ${rllib}
- then
- checked "yes"
- ldlibs="${rllib} ${ldlibs}"
+ if [ -r libreadline.a ]
+ then
+ rllib="libreadline.a"
+ else
+ rllib="-l readline"
+ fi
+ if trycompile ${rllib}
+ then
+ checked "yes"
+ ldlibs="${rllib} ${ldlibs}"
+ readline="ok"
+ else
+ for i in ${rlldflagcand}
+ do
+ if trycompile ${rllib} -l $i
+ then
+ checked "with $i library"
+ ldlibs="${rllib} -l $i ${ldlibs}"
readline="ok"
- else
- for i in ${rlldflagcand}
- do
- if trycompile ${rllib} -l $i
- then
- checked "with $i library"
- ldlibs="${rllib} -l $i ${ldlibs}"
- readline="ok"
- break
- fi
- done
- fi
- if [ x"${readline}" = x"ok" ]
- then
- defconfigh "HAVE_LIBREADLINE"
- else
- checked "no"
- readline="no"
- fi
+ break
+ fi
+ done
+ fi
+ if [ x"${readline}" = x"ok" ]
+ then
+ defconfigh "HAVE_LIBREADLINE"
+ else
+ checked "no"
+ readline="no"
+ fi
fi
# check for strnlen
END
if trycompile
then
- checked "yes"
- defconfigh "HAVE_STRNLEN"
+ checked "yes"
+ defconfigh "HAVE_STRNLEN"
else
- checked "no"
+ checked "no"
fi
# check for wcsnlen
END
if trycompile
then
- checked "yes"
- defconfigh "HAVE_WCSNLEN"
+ checked "yes"
+ defconfigh "HAVE_WCSNLEN"
else
- checked "no"
+ checked "no"
fi
# check for mkstemp
END
if trycompile
then
- checked "yes"
- defconfigh "HAVE_MKSTEMP"
+ checked "yes"
+ defconfigh "HAVE_MKSTEMP"
else
- checked "no"
+ checked "no"
fi
# check for strsignal
END
if trycompile
then
- checked "yes"
- defconfigh "HAVE_STRSIGNAL"
+ checked "yes"
+ defconfigh "HAVE_STRSIGNAL"
else
- checked "no"
+ checked "no"
fi
rm -f "${tempsrc}" "${tempout}"
+
+
+# vim: set ts=8 sts=4 sw=4 noet:
/* コマンドの実行のしかたを表す */
typedef enum {
- execnormal, /* 普通に実行 */
- execasync, /* 非同期的に実行 */
- execself, /* 自分自身のプロセスで実行 */
+ execnormal, /* 普通に実行 */
+ execasync, /* 非同期的に実行 */
+ execself, /* 自分自身のプロセスで実行 */
} exec_T;
/* パイプのファイルディスクリプタの情報 */
typedef struct pipeinfo_T {
- int pi_fromprevfd; /* 前のプロセスとのパイプ */
- int pi_tonextfds[2]; /* 次のプロセスとのパイプ */
- int pi_loopoutfd; /* ループパイプの書き込み側 */
+ int pi_fromprevfd; /* 前のプロセスとのパイプ */
+ int pi_tonextfds[2]; /* 次のプロセスとのパイプ */
+ int pi_loopoutfd; /* ループパイプの書き込み側 */
} pipeinfo_T;
/* 使用しない部分は無効な値として -1 を入れる。 */
#define PIDX_IN 0 /* パイプの読み込み側の FD のインデックス */
static void exec_commands(command_T *c, exec_T type, bool looppipe);
__attribute__((nonnull))
static pid_t exec_process(
- command_T *c, exec_T type, pipeinfo_T *pi, pid_t pgid);
+ command_T *c, exec_T type, pipeinfo_T *pi, pid_t pgid);
static pid_t fork_and_reset(pid_t pgid, bool fg);
* finally_exit: true なら実行後そのまま終了する。 */
void exec_and_or_lists(and_or_T *a, bool finally_exit)
{
- while (a) {
- if (!a->ao_async)
- exec_pipelines(a->ao_pipelines, finally_exit && !a->next);
- else
- exec_pipelines_async(a->ao_pipelines);
-
- a = a->next;
- }
- if (finally_exit)
- exit(laststatus);
+ while (a) {
+ if (!a->ao_async)
+ exec_pipelines(a->ao_pipelines, finally_exit && !a->next);
+ else
+ exec_pipelines_async(a->ao_pipelines);
+
+ a = a->next;
+ }
+ if (finally_exit)
+ exit(laststatus);
}
/* パイプラインたちを実行する。 */
static void exec_pipelines(pipeline_T *p, bool finally_exit)
{
- while (p) {
- exec_commands(p->pl_commands,
- (finally_exit && !p->next && !p->pl_neg) ? execself : execnormal,
- p->pl_loop);
- if (p->pl_neg)
- laststatus = !laststatus;
-
- if (p->pl_next_cond == !!laststatus)
- break;
- p = p->next;
- }
- if (finally_exit)
- exit(laststatus);
+ while (p) {
+ exec_commands(p->pl_commands,
+ (finally_exit && !p->next && !p->pl_neg) ? execself : execnormal,
+ p->pl_loop);
+ if (p->pl_neg)
+ laststatus = !laststatus;
+
+ if (p->pl_next_cond == !!laststatus)
+ break;
+ p = p->next;
+ }
+ if (finally_exit)
+ exit(laststatus);
}
/* パイプラインたちを非同期的に実行する。 */
static void exec_pipelines_async(pipeline_T *p)
{
- (void) p;
- xerror(0,0,"%s: NOT IMPLEMENTED", __func__);
- // TODO exec.c: exec_pipelines_async
+ (void) p;
+ xerror(0,0,"%s: NOT IMPLEMENTED", __func__);
+ // TODO exec.c: exec_pipelines_async
}
/* if コマンドを実行する */
static void exec_if(command_T *c, bool finally_exit)
{
- // TODO exec.c: exec_if: 未実装
- (void) c;
- laststatus = 0;
- if (finally_exit)
- exit(laststatus);
+ // TODO exec.c: exec_if: 未実装
+ (void) c;
+ laststatus = 0;
+ if (finally_exit)
+ exit(laststatus);
}
/* for コマンドを実行する */
static void exec_for(command_T *c, bool finally_exit)
{
- // TODO exec.c: exec_for: 未実装
- (void) c;
- laststatus = 0;
- if (finally_exit)
- exit(laststatus);
+ // TODO exec.c: exec_for: 未実装
+ (void) c;
+ laststatus = 0;
+ if (finally_exit)
+ exit(laststatus);
}
/* while コマンドを実行する */
static void exec_while(command_T *c, bool finally_exit)
{
- // TODO exec.c: exec_while: 未実装
- (void) c;
- laststatus = 0;
- if (finally_exit)
- exit(laststatus);
+ // TODO exec.c: exec_while: 未実装
+ (void) c;
+ laststatus = 0;
+ if (finally_exit)
+ exit(laststatus);
}
/* case コマンドを実行する */
static void exec_case(command_T *c, bool finally_exit)
{
- // TODO exec.c: exec_case: 未実装
- (void) c;
- laststatus = 0;
- if (finally_exit)
- exit(laststatus);
+ // TODO exec.c: exec_case: 未実装
+ (void) c;
+ laststatus = 0;
+ if (finally_exit)
+ exit(laststatus);
}
/* exec_commands 関数で使うサブルーチン */
* 成功すると true、エラーがあると false を返す。 */
static inline void next_pipe(pipeinfo_T *pi, bool next)
{
- if (pi->pi_fromprevfd >= 0)
- xclose(pi->pi_fromprevfd);
- if (pi->pi_tonextfds[PIDX_OUT] >= 0)
- xclose(pi->pi_tonextfds[PIDX_OUT]);
- pi->pi_fromprevfd = pi->pi_tonextfds[PIDX_IN];
- if (next) {
- /* ファイルディスクリプタ 0 または 1 が未使用の場合は、ダミーのパイプを
- * 開くことで実際のパイプのファイルディスクリプタを 2 以上にする。
- * こうしないと、後でパイプを標準入出力に繋ぎ変える時に他のパイプを
- * 上書きしてしまう。 */
- int dummy[2];
- bool usedummy = (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF)
- || (fcntl(STDOUT_FILENO, F_GETFD) == -1 && errno == EBADF);
-
- if (usedummy && pipe(dummy) < 0)
- goto fail;
- if (pipe(pi->pi_tonextfds) < 0)
- goto fail;
- if (usedummy) {
- xclose(dummy[PIDX_IN]);
- xclose(dummy[PIDX_OUT]);
- }
- } else {
- pi->pi_tonextfds[PIDX_IN] = -1;
- pi->pi_tonextfds[PIDX_OUT] = pi->pi_loopoutfd;
- pi->pi_loopoutfd = -1;
+ if (pi->pi_fromprevfd >= 0)
+ xclose(pi->pi_fromprevfd);
+ if (pi->pi_tonextfds[PIDX_OUT] >= 0)
+ xclose(pi->pi_tonextfds[PIDX_OUT]);
+ pi->pi_fromprevfd = pi->pi_tonextfds[PIDX_IN];
+ if (next) {
+ /* ファイルディスクリプタ 0 または 1 が未使用の場合は、ダミーのパイプを
+ * 開くことで実際のパイプのファイルディスクリプタを 2 以上にする。
+ * こうしないと、後でパイプを標準入出力に繋ぎ変える時に他のパイプを
+ * 上書きしてしまう。 */
+ int dummy[2];
+ bool usedummy = (fcntl(STDIN_FILENO, F_GETFD) == -1 && errno == EBADF)
+ || (fcntl(STDOUT_FILENO, F_GETFD) == -1 && errno == EBADF);
+
+ if (usedummy && pipe(dummy) < 0)
+ goto fail;
+ if (pipe(pi->pi_tonextfds) < 0)
+ goto fail;
+ if (usedummy) {
+ xclose(dummy[PIDX_IN]);
+ xclose(dummy[PIDX_OUT]);
}
- return;
+ } else {
+ pi->pi_tonextfds[PIDX_IN] = -1;
+ pi->pi_tonextfds[PIDX_OUT] = pi->pi_loopoutfd;
+ pi->pi_loopoutfd = -1;
+ }
+ return;
fail:
- pi->pi_tonextfds[PIDX_IN] = pi->pi_tonextfds[PIDX_OUT] = -1;
- xerror(0, errno, Ngt("cannot open pipe"));
+ pi->pi_tonextfds[PIDX_IN] = pi->pi_tonextfds[PIDX_OUT] = -1;
+ xerror(0, errno, Ngt("cannot open pipe"));
}
/* 一つのパイプラインを構成する各コマンドを実行する
* looppipe: パイプをループ状にするかどうか */
static void exec_commands(command_T *c, exec_T type, bool looppipe)
{
- size_t count;
- pid_t pgid;
- command_T *cc;
- job_T *job;
- process_T *ps;
- pipeinfo_T pinfo = PIPEINFO_INIT;
-
- /* コマンドの数を数える */
- count = 0;
- for (cc = c; cc; cc = cc->next)
- count++;
- assert(count > 0);
-
- if (looppipe) { /* 最初と最後を繋ぐパイプを用意する */
- int fds[2];
- if (pipe(fds) < 0) {
- xerror(0, errno, Ngt("cannot open pipe"));
- } else {
- pinfo.pi_tonextfds[PIDX_IN] = fds[PIDX_IN];
- pinfo.pi_loopoutfd = fds[PIDX_OUT];
- }
- }
-
- job = xmalloc(sizeof *job + count * sizeof *job->j_procs);
- ps = job->j_procs;
-
- /* 各コマンドを実行 */
- pgid = 0;
- cc = c;
- for (size_t i = 0; i < count; i++) {
- pid_t pid;
-
- next_pipe(&pinfo, i < count - 1);
- pid = exec_process(cc,
- (type == execself && i < count - 1) ? execnormal : type,
- &pinfo, pgid);
- if (pid < 0)
- goto fail;
- ps[i].pr_pid = pid;
- ps[i].pr_status = JS_RUNNING;
- ps[i].pr_waitstatus = 0;
- ps[i].pr_name = NULL; /* 最初は名無し: 名前は後で付ける */
- if (pgid == 0)
- pgid = pid;
- cc = cc->next;
- }
- assert(cc == NULL);
- assert(type != execself); /* execself なら exec_process は返らない */
- assert(pinfo.pi_tonextfds[PIDX_IN] < 0);
- assert(pinfo.pi_loopoutfd < 0);
- if (pinfo.pi_fromprevfd >= 0)
- xclose(pinfo.pi_fromprevfd); /* 残ったパイプを閉じる */
- if (pinfo.pi_tonextfds[PIDX_OUT] >= 0)
- xclose(pinfo.pi_tonextfds[PIDX_OUT]); /* 残ったパイプを閉じる */
-
- if (pgid == 0) { /* fork しなかったらもうやることはない */
- free(job);
- return;
- }
-
- set_active_job(job);
- if (type == execnormal) { /* ジョブの終了を待つ */
- job->j_pgid = do_job_control ? pgid : 0;
- job->j_status = JS_RUNNING;
- job->j_statuschanged = true;
- job->j_loop = looppipe;
- job->j_pcount = count;
- wait_for_job(ACTIVE_JOBNO, do_job_control);
- laststatus = calc_status_of_job(job);
- handle_traps();
- if (job->j_status == JS_DONE) {
- remove_job(ACTIVE_JOBNO);
- return;
- }
+ size_t count;
+ pid_t pgid;
+ command_T *cc;
+ job_T *job;
+ process_T *ps;
+ pipeinfo_T pinfo = PIPEINFO_INIT;
+
+ /* コマンドの数を数える */
+ count = 0;
+ for (cc = c; cc; cc = cc->next)
+ count++;
+ assert(count > 0);
+
+ if (looppipe) { /* 最初と最後を繋ぐパイプを用意する */
+ int fds[2];
+ if (pipe(fds) < 0) {
+ xerror(0, errno, Ngt("cannot open pipe"));
} else {
- laststatus = EXIT_SUCCESS;
- }
-
- /* バックグラウンドジョブをジョブリストに追加する */
- cc = c;
- for (size_t i = 0; i < count; i++) { /* 各プロセスの名前を設定 */
- ps[i].pr_name = command_to_wcs(cc);
- cc = cc->next;
+ pinfo.pi_tonextfds[PIDX_IN] = fds[PIDX_IN];
+ pinfo.pi_loopoutfd = fds[PIDX_OUT];
}
- add_job();
+ }
+
+ job = xmalloc(sizeof *job + count * sizeof *job->j_procs);
+ ps = job->j_procs;
+
+ /* 各コマンドを実行 */
+ pgid = 0;
+ cc = c;
+ for (size_t i = 0; i < count; i++) {
+ pid_t pid;
+
+ next_pipe(&pinfo, i < count - 1);
+ pid = exec_process(cc,
+ (type == execself && i < count - 1) ? execnormal : type,
+ &pinfo, pgid);
+ if (pid < 0)
+ goto fail;
+ ps[i].pr_pid = pid;
+ ps[i].pr_status = JS_RUNNING;
+ ps[i].pr_waitstatus = 0;
+ ps[i].pr_name = NULL; /* 最初は名無し: 名前は後で付ける */
+ if (pgid == 0)
+ pgid = pid;
+ cc = cc->next;
+ }
+ assert(cc == NULL);
+ assert(type != execself); /* execself なら exec_process は返らない */
+ assert(pinfo.pi_tonextfds[PIDX_IN] < 0);
+ assert(pinfo.pi_loopoutfd < 0);
+ if (pinfo.pi_fromprevfd >= 0)
+ xclose(pinfo.pi_fromprevfd); /* 残ったパイプを閉じる */
+ if (pinfo.pi_tonextfds[PIDX_OUT] >= 0)
+ xclose(pinfo.pi_tonextfds[PIDX_OUT]); /* 残ったパイプを閉じる */
+
+ if (pgid == 0) { /* fork しなかったらもうやることはない */
+ free(job);
return;
+ }
+
+ set_active_job(job);
+ if (type == execnormal) { /* ジョブの終了を待つ */
+ job->j_pgid = do_job_control ? pgid : 0;
+ job->j_status = JS_RUNNING;
+ job->j_statuschanged = true;
+ job->j_loop = looppipe;
+ job->j_pcount = count;
+ wait_for_job(ACTIVE_JOBNO, do_job_control);
+ laststatus = calc_status_of_job(job);
+ handle_traps();
+ if (job->j_status == JS_DONE) {
+ remove_job(ACTIVE_JOBNO);
+ return;
+ }
+ } else {
+ laststatus = EXIT_SUCCESS;
+ }
+
+ /* バックグラウンドジョブをジョブリストに追加する */
+ cc = c;
+ for (size_t i = 0; i < count; i++) { /* 各プロセスの名前を設定 */
+ ps[i].pr_name = command_to_wcs(cc);
+ cc = cc->next;
+ }
+ add_job();
+ return;
fail:
- laststatus = -2;
- if (pinfo.pi_fromprevfd >= 0)
- xclose(pinfo.pi_fromprevfd);
- if (pinfo.pi_tonextfds[PIDX_IN] >= 0)
- xclose(pinfo.pi_tonextfds[PIDX_IN]);
- if (pinfo.pi_tonextfds[PIDX_OUT] >= 0)
- xclose(pinfo.pi_tonextfds[PIDX_OUT]);
- if (pinfo.pi_loopoutfd >= 0)
- xclose(pinfo.pi_loopoutfd);
- free(job);
+ laststatus = -2;
+ if (pinfo.pi_fromprevfd >= 0)
+ xclose(pinfo.pi_fromprevfd);
+ if (pinfo.pi_tonextfds[PIDX_IN] >= 0)
+ xclose(pinfo.pi_tonextfds[PIDX_IN]);
+ if (pinfo.pi_tonextfds[PIDX_OUT] >= 0)
+ xclose(pinfo.pi_tonextfds[PIDX_OUT]);
+ if (pinfo.pi_loopoutfd >= 0)
+ xclose(pinfo.pi_loopoutfd);
+ free(job);
}
/* 一つのコマンドを実行する。
* パイプを一方でも繋いだら、必ず fork する。この時 type == execself は不可。 */
static pid_t exec_process(command_T *c, exec_T type, pipeinfo_T *pi, pid_t pgid)
{
- bool need_fork; /* fork するかどうか */
- bool finally_exit; /* true なら最後に exit してこの関数から返らない */
-
- switch (c->c_type) {
- case CT_SIMPLE:
- // exec.c: exec_process: CT_SIMPLE の実行
- need_fork = finally_exit = false;
- break;
- case CT_SUBSHELL:
- need_fork = finally_exit = true;
- break;
- default:
- need_fork = finally_exit = false;
- break;
- }
-
- if (type == execself) {
- need_fork = false; finally_exit = true;
- assert(!is_interactive_now);
- } else if (type == execasync
- || pi->pi_fromprevfd >= 0 || pi->pi_tonextfds[PIDX_OUT] >= 0) {
- /* 非同期実行またはパイプを繋ぐ場合は必ず fork */
- need_fork = finally_exit = true;
- }
-
- assert(!need_fork || finally_exit); /* fork すれば必ず子プロセスは exit */
- if (need_fork) {
- pid_t cpid = fork_and_reset(pgid, type == execnormal);
- if (cpid != 0)
- return cpid;
- }
- if (finally_exit)
- reset_signals(!do_job_control && type == execasync);
-
- /* パイプを繋ぎ、余ったパイプを閉じる */
- if (pi->pi_fromprevfd >= 0) {
- xdup2(pi->pi_fromprevfd, STDIN_FILENO);
- xclose(pi->pi_fromprevfd);
- }
- if (pi->pi_tonextfds[PIDX_OUT] >= 0) {
- xdup2(pi->pi_tonextfds[PIDX_OUT], STDOUT_FILENO);
- xclose(pi->pi_tonextfds[PIDX_OUT]);
- }
- if (pi->pi_tonextfds[PIDX_IN] >= 0)
- xclose(pi->pi_tonextfds[PIDX_IN]);
- if (pi->pi_loopoutfd >= 0)
- xclose(pi->pi_loopoutfd);
-
- /* リダイレクトを開く */
- // TODO exec.c: exec_process: redirect
-
- /* 非対話的シェルで非同期実行する場合は stdin を /dev/null にリダイレクト */
- if (type == execasync && !is_interactive && pi->pi_fromprevfd < 0
- /* TODO exec.c: && !is_stdin_redirected */) {
- }
-
- /* 変数を代入する */
- // TODO exec.c: exec_process: assignment
-
- /* コマンドを実行する */
- switch (c->c_type) {
- case CT_SIMPLE:
- break;
- // TODO exec.c: exec_process: 単純コマンドの実行
- case CT_SUBSHELL:
- case CT_GROUP:
- exec_and_or_lists(c->c_subcmds, finally_exit);
- break;
- case CT_IF:
- exec_if(c, finally_exit);
- break;
- case CT_FOR:
- exec_for(c, finally_exit);
- break;
- case CT_WHILE:
- exec_while(c, finally_exit);
- break;
- case CT_CASE:
- exec_case(c, finally_exit);
- break;
- }
- if (finally_exit)
- exit(laststatus);
-
- fflush(NULL);
- // TODO exec.c: exec_process: 変数の一時代入を削除
- // TODO exec.c: exec_process: セーブしたリダイレクトを戻す
- return 0;
+ bool need_fork; /* fork するかどうか */
+ bool finally_exit; /* true なら最後に exit してこの関数から返らない */
+
+ switch (c->c_type) {
+ case CT_SIMPLE:
+ // exec.c: exec_process: CT_SIMPLE の実行
+ need_fork = finally_exit = false;
+ break;
+ case CT_SUBSHELL:
+ need_fork = finally_exit = true;
+ break;
+ default:
+ need_fork = finally_exit = false;
+ break;
+ }
+
+ if (type == execself) {
+ need_fork = false; finally_exit = true;
+ assert(!is_interactive_now);
+ } else if (type == execasync
+ || pi->pi_fromprevfd >= 0 || pi->pi_tonextfds[PIDX_OUT] >= 0) {
+ /* 非同期実行またはパイプを繋ぐ場合は必ず fork */
+ need_fork = finally_exit = true;
+ }
+
+ assert(!need_fork || finally_exit); /* fork すれば必ず子プロセスは exit */
+ if (need_fork) {
+ pid_t cpid = fork_and_reset(pgid, type == execnormal);
+ if (cpid != 0)
+ return cpid;
+ }
+ if (finally_exit)
+ reset_signals(!do_job_control && type == execasync);
+
+ /* パイプを繋ぎ、余ったパイプを閉じる */
+ if (pi->pi_fromprevfd >= 0) {
+ xdup2(pi->pi_fromprevfd, STDIN_FILENO);
+ xclose(pi->pi_fromprevfd);
+ }
+ if (pi->pi_tonextfds[PIDX_OUT] >= 0) {
+ xdup2(pi->pi_tonextfds[PIDX_OUT], STDOUT_FILENO);
+ xclose(pi->pi_tonextfds[PIDX_OUT]);
+ }
+ if (pi->pi_tonextfds[PIDX_IN] >= 0)
+ xclose(pi->pi_tonextfds[PIDX_IN]);
+ if (pi->pi_loopoutfd >= 0)
+ xclose(pi->pi_loopoutfd);
+
+ /* リダイレクトを開く */
+ // TODO exec.c: exec_process: redirect
+
+ /* 非対話的シェルで非同期実行する場合は stdin を /dev/null にリダイレクト */
+ if (type == execasync && !is_interactive && pi->pi_fromprevfd < 0
+ /* TODO exec.c: && !is_stdin_redirected */) {
+ }
+
+ /* 変数を代入する */
+ // TODO exec.c: exec_process: assignment
+
+ /* コマンドを実行する */
+ switch (c->c_type) {
+ case CT_SIMPLE:
+ break;
+ // TODO exec.c: exec_process: 単純コマンドの実行
+ case CT_SUBSHELL:
+ case CT_GROUP:
+ exec_and_or_lists(c->c_subcmds, finally_exit);
+ break;
+ case CT_IF:
+ exec_if(c, finally_exit);
+ break;
+ case CT_FOR:
+ exec_for(c, finally_exit);
+ break;
+ case CT_WHILE:
+ exec_while(c, finally_exit);
+ break;
+ case CT_CASE:
+ exec_case(c, finally_exit);
+ break;
+ }
+ if (finally_exit)
+ exit(laststatus);
+
+ fflush(NULL);
+ // TODO exec.c: exec_process: 変数の一時代入を削除
+ // TODO exec.c: exec_process: セーブしたリダイレクトを戻す
+ return 0;
}
/* fork して、いろいろ必要な設定を行う。
* 戻り値: fork の戻り値 */
static pid_t fork_and_reset(pid_t pgid, bool fg)
{
- fflush(NULL);
- xerror(0,0,"DEBUG: forking... (parent:%d)", (int) getpid());
-
- pid_t cpid = fork();
-
- if (cpid < 0) {
- /* fork 失敗 */
- xerror(0, errno, Ngt("fork: cannot make child process"));
- } else if (cpid > 0) {
- /* 親プロセス */
- if (do_job_control && pgid >= 0)
- setpgid(cpid, pgid);
- } else {
- /* 子プロセス */
- if (do_job_control && pgid >= 0) {
- setpgid(0, pgid);
- if (fg)
- (void) 0; // TODO exec: fork_and_reset: tcsetpgrp
- }
- // TODO exec: fork_and_reset: forget_original_pgrp
- remove_all_jobs();
- clear_traps();
- // TODO exec: fork_and_reset: clear_shellfds
- do_job_control = is_interactive_now = false;
-
- xerror(0,0,"DEBUG: forked (child:%d)", (int) getpid());
+ fflush(NULL);
+ xerror(0,0,"DEBUG: forking... (parent:%d)", (int) getpid());
+
+ pid_t cpid = fork();
+
+ if (cpid < 0) {
+ /* fork 失敗 */
+ xerror(0, errno, Ngt("fork: cannot make child process"));
+ } else if (cpid > 0) {
+ /* 親プロセス */
+ if (do_job_control && pgid >= 0)
+ setpgid(cpid, pgid);
+ } else {
+ /* 子プロセス */
+ if (do_job_control && pgid >= 0) {
+ setpgid(0, pgid);
+ if (fg)
+ (void) 0; // TODO exec: fork_and_reset: tcsetpgrp
}
- return cpid;
+ // TODO exec: fork_and_reset: forget_original_pgrp
+ remove_all_jobs();
+ clear_traps();
+ // TODO exec: fork_and_reset: clear_shellfds
+ do_job_control = is_interactive_now = false;
+
+ xerror(0,0,"DEBUG: forked (child:%d)", (int) getpid());
+ }
+ return cpid;
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
#endif /* EXEC_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
* 戻り値: 成功すると true、エラーがあると false。
* エラーがあった場合でも、途中結果が *argcp, *argvp に返される。 */
bool expand_line(void *const *restrict args,
- int *restrict argcp, void ***restrict argvp)
+ int *restrict argcp, void ***restrict argvp)
{
- plist_T list;
+ plist_T list;
- // TODO expand.c: expand_line: 未実装
- (void) args;
+ // TODO expand.c: expand_line: 未実装
+ (void) args;
- pl_init(&list);
- *argcp = list.length;
- *argvp = pl_toary(&list);
- return false;
+ pl_init(&list);
+ *argcp = list.length;
+ *argvp = pl_toary(&list);
+ return false;
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
__attribute__((nonnull))
bool expand_line(
- void *const *restrict args,
- int *restrict argcp,
- void ***restrict argvp);
+ void *const *restrict args,
+ int *restrict argcp,
+ void ***restrict argvp);
#endif /* EXPAND_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* struct hash_entry の定義 */
struct hash_entry {
- size_t next;
- unsigned long hash;
- kvpair_T kv;
+ size_t next;
+ unsigned long hash;
+ kvpair_T kv;
};
/* ハッシュエントリが有効かどうかは、kv.key が NULL でないかどうかで判別する。
* kv.key が NULL のとき、struct hash_entry 内の他のメンバは全て不定である。 */
* keycmp は二つのキーを比較する比較関数へのポインタである。
* 比較関数は、二つのキーが等しいとき 0 を、異なるときに非 0 を返す。 */
hashtable_T *ht_initwithcapacity(
- hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp,
- size_t capacity)
+ hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp,
+ size_t capacity)
{
- if (capacity == 0)
- capacity = 1;
-
- ht->count = 0;
- ht->capacity = capacity;
- ht->hashfunc = hashfunc;
- ht->keycmp = keycmp;
- ht->emptyindex = NOTHING;
- ht->tailindex = 0;
- ht->indices = xmalloc(capacity * sizeof *ht->indices);
- ht->entries = xmalloc(capacity * sizeof *ht->entries);
-
- for (size_t i = 0; i < capacity; i++) {
- ht->indices[i] = NOTHING;
- ht->entries[i].kv.key = NULL;
- }
-
- return ht;
+ if (capacity == 0)
+ capacity = 1;
+
+ ht->count = 0;
+ ht->capacity = capacity;
+ ht->hashfunc = hashfunc;
+ ht->keycmp = keycmp;
+ ht->emptyindex = NOTHING;
+ ht->tailindex = 0;
+ ht->indices = xmalloc(capacity * sizeof *ht->indices);
+ ht->entries = xmalloc(capacity * sizeof *ht->entries);
+
+ for (size_t i = 0; i < capacity; i++) {
+ ht->indices[i] = NOTHING;
+ ht->entries[i].kv.key = NULL;
+ }
+
+ return ht;
}
/* 初期化済みのハッシュテーブルを解放する。
* ハッシュテーブルに含まれる各キー・各値の解放は予め行っておくこと。 */
void ht_destroy(hashtable_T *ht)
{
- free(ht->indices);
- free(ht->entries);
+ free(ht->indices);
+ free(ht->entries);
}
/* ハッシュテーブルの容量を変更する。 */
static hashtable_T *ht_rehash(hashtable_T *ht, size_t newcapacity)
{
- assert(newcapacity > 0 && newcapacity >= ht->count);
-
- size_t oldcapacity = ht->capacity;
- size_t *oldindices = ht->indices;
- size_t *newindices = xmalloc(newcapacity * sizeof *ht->indices);
- struct hash_entry *oldentries = ht->entries;
- struct hash_entry *newentries = xmalloc(newcapacity * sizeof *ht->entries);
- size_t tail = 0;
-
- for (size_t i = 0; i < newcapacity; i++) {
- newindices[i] = NOTHING;
- newentries[i].kv.key = NULL;
- }
-
- /* oldentries から newentries にデータを移す */
- for (size_t i = 0; i < oldcapacity; i++) {
- void *key = oldentries[i].kv.key;
- if (key) {
- unsigned long hash = oldentries[i].hash;
- size_t newindex = (size_t) hash % newcapacity;
- newentries[tail] = (struct hash_entry) {
- .next = newindices[newindex],
- .hash = hash,
- .kv = oldentries[i].kv,
- };
- newindices[newindex] = tail;
- tail++;
- }
+ assert(newcapacity > 0 && newcapacity >= ht->count);
+
+ size_t oldcapacity = ht->capacity;
+ size_t *oldindices = ht->indices;
+ size_t *newindices = xmalloc(newcapacity * sizeof *ht->indices);
+ struct hash_entry *oldentries = ht->entries;
+ struct hash_entry *newentries = xmalloc(newcapacity * sizeof *ht->entries);
+ size_t tail = 0;
+
+ for (size_t i = 0; i < newcapacity; i++) {
+ newindices[i] = NOTHING;
+ newentries[i].kv.key = NULL;
+ }
+
+ /* oldentries から newentries にデータを移す */
+ for (size_t i = 0; i < oldcapacity; i++) {
+ void *key = oldentries[i].kv.key;
+ if (key) {
+ unsigned long hash = oldentries[i].hash;
+ size_t newindex = (size_t) hash % newcapacity;
+ newentries[tail] = (struct hash_entry) {
+ .next = newindices[newindex],
+ .hash = hash,
+ .kv = oldentries[i].kv,
+ };
+ newindices[newindex] = tail;
+ tail++;
}
-
- free(oldindices);
- free(oldentries);
- ht->capacity = newcapacity;
- ht->emptyindex = NOTHING;
- ht->tailindex = tail;
- ht->indices = newindices;
- ht->entries = newentries;
- return ht;
+ }
+
+ free(oldindices);
+ free(oldentries);
+ ht->capacity = newcapacity;
+ ht->emptyindex = NOTHING;
+ ht->tailindex = tail;
+ ht->indices = newindices;
+ ht->entries = newentries;
+ return ht;
}
/* ハッシュテーブルが少なくとも capacity 以上の容量を持つように拡張する。 */
inline hashtable_T *ht_ensurecapacity(hashtable_T *ht, size_t capacity)
{
- if (ht->capacity < capacity) {
- size_t newcapacity = ht->capacity;
- do
- newcapacity = newcapacity * 2 + 1;
- while (newcapacity < capacity);
- return ht_rehash(ht, newcapacity);
- } else {
- return ht;
- }
+ if (ht->capacity < capacity) {
+ size_t newcapacity = ht->capacity;
+ do
+ newcapacity = newcapacity * 2 + 1;
+ while (newcapacity < capacity);
+ return ht_rehash(ht, newcapacity);
+ } else {
+ return ht;
+ }
}
/* ハッシュテーブルの全エントリを削除する。freer が NULL でなければ、
* ハッシュテーブルの容量は変わらない。 */
hashtable_T *ht_clear(hashtable_T *ht, void freer(kvpair_T kv))
{
- size_t *indices = ht->indices;
- struct hash_entry *entries = ht->entries;
-
- for (size_t i = 0, cap = ht->capacity; i < cap; i++) {
- indices[i] = NOTHING;
- if (entries[i].kv.key) {
- if (freer)
- freer(entries[i].kv);
- entries[i].kv.key = NULL;
- }
+ size_t *indices = ht->indices;
+ struct hash_entry *entries = ht->entries;
+
+ for (size_t i = 0, cap = ht->capacity; i < cap; i++) {
+ indices[i] = NOTHING;
+ if (entries[i].kv.key) {
+ if (freer)
+ freer(entries[i].kv);
+ entries[i].kv.key = NULL;
}
+ }
- ht->count = 0;
- ht->emptyindex = NOTHING;
- ht->tailindex = 0;
- return ht;
+ ht->count = 0;
+ ht->emptyindex = NOTHING;
+ ht->tailindex = 0;
+ return ht;
}
/* ハッシュテーブルの値を取得する。
* key が NULL であるか、key に対応する要素がなければ { NULL, NULL } を返す。 */
kvpair_T ht_get(hashtable_T *ht, const void *key)
{
- if (key) {
- unsigned long hash = ht->hashfunc(key);
- size_t index = ht->indices[(size_t) hash % ht->capacity];
- while (index != NOTHING) {
- struct hash_entry *entry = &ht->entries[index];
- if (entry->hash == hash && ht->keycmp(entry->kv.key, key) == 0)
- return entry->kv;
- index = entry->next;
- }
+ if (key) {
+ unsigned long hash = ht->hashfunc(key);
+ size_t index = ht->indices[(size_t) hash % ht->capacity];
+ while (index != NOTHING) {
+ struct hash_entry *entry = &ht->entries[index];
+ if (entry->hash == hash && ht->keycmp(entry->kv.key, key) == 0)
+ return entry->kv;
+ index = entry->next;
}
- return (kvpair_T) { NULL, NULL, };
+ }
+ return (kvpair_T) { NULL, NULL, };
}
/* ハッシュテーブルにエントリを設定する。
* を返す。key が NULL ならば何もせずに { NULL, NULL } を返す。 */
kvpair_T ht_set(hashtable_T *ht, const void *key, const void *value)
{
- if (!key)
- return (kvpair_T) { NULL, NULL, };
-
- /* まず、key に等しいキーの既存のエントリがあるならそれを置き換える */
- unsigned long hash = ht->hashfunc(key);
- size_t mhash = (size_t) hash % ht->capacity;
- size_t index = ht->indices[mhash];
- while (index != NOTHING) {
- struct hash_entry *entry = &ht->entries[index];
- if (entry->hash == hash && ht->keycmp(entry->kv.key, key) == 0) {
- kvpair_T oldkv = entry->kv;
- entry->kv = (kvpair_T) { (void *) key, (void *) value, };
- return oldkv;
- }
- index = entry->next;
- }
+ if (!key)
+ return (kvpair_T) { NULL, NULL, };
- /* 既存のエントリがなかったので、新しいエントリを追加する。 */
- index = ht->emptyindex;
- if (index != NOTHING) {
- /* empty entry があればそこに追加する。 */
- struct hash_entry *entry = &ht->entries[index];
- ht->emptyindex = entry->next;
- *entry = (struct hash_entry) {
- .next = ht->indices[mhash],
- .hash = hash,
- .kv = (kvpair_T) { (void *) key, (void *) value, },
- };
- ht->indices[mhash] = index;
- } else {
- /* empty entry がなければ tail entry に追加する。 */
- ht_ensurecapacity(ht, ht->count + 1);
- mhash = (size_t) hash % ht->capacity;
- index = ht->tailindex;
- ht->entries[index] = (struct hash_entry) {
- .next = ht->indices[mhash],
- .hash = hash,
- .kv = (kvpair_T) { (void *) key, (void *) value, },
- };
- ht->indices[mhash] = index;
- ht->tailindex++;
+ /* まず、key に等しいキーの既存のエントリがあるならそれを置き換える */
+ unsigned long hash = ht->hashfunc(key);
+ size_t mhash = (size_t) hash % ht->capacity;
+ size_t index = ht->indices[mhash];
+ while (index != NOTHING) {
+ struct hash_entry *entry = &ht->entries[index];
+ if (entry->hash == hash && ht->keycmp(entry->kv.key, key) == 0) {
+ kvpair_T oldkv = entry->kv;
+ entry->kv = (kvpair_T) { (void *) key, (void *) value, };
+ return oldkv;
}
- ht->count++;
- return (kvpair_T) { NULL, NULL, };
+ index = entry->next;
+ }
+
+ /* 既存のエントリがなかったので、新しいエントリを追加する。 */
+ index = ht->emptyindex;
+ if (index != NOTHING) {
+ /* empty entry があればそこに追加する。 */
+ struct hash_entry *entry = &ht->entries[index];
+ ht->emptyindex = entry->next;
+ *entry = (struct hash_entry) {
+ .next = ht->indices[mhash],
+ .hash = hash,
+ .kv = (kvpair_T) { (void *) key, (void *) value, },
+ };
+ ht->indices[mhash] = index;
+ } else {
+ /* empty entry がなければ tail entry に追加する。 */
+ ht_ensurecapacity(ht, ht->count + 1);
+ mhash = (size_t) hash % ht->capacity;
+ index = ht->tailindex;
+ ht->entries[index] = (struct hash_entry) {
+ .next = ht->indices[mhash],
+ .hash = hash,
+ .kv = (kvpair_T) { (void *) key, (void *) value, },
+ };
+ ht->indices[mhash] = index;
+ ht->tailindex++;
+ }
+ ht->count++;
+ return (kvpair_T) { NULL, NULL, };
}
/* ハッシュテーブルから key に等しいキーのエントリを削除する。
* { NULL, NULL } を返す。 */
kvpair_T ht_remove(hashtable_T *ht, const void *key)
{
- if (key) {
- unsigned long hash = ht->hashfunc(key);
- size_t *indexp = &ht->indices[(size_t) hash % ht->capacity];
- while (*indexp != NOTHING) {
- size_t index = *indexp;
- struct hash_entry *entry = &ht->entries[index];
- if (entry->hash == hash && ht->keycmp(entry->kv.key, key) == 0) {
- kvpair_T oldkv = entry->kv;
- *indexp = entry->next;
- entry->next = ht->emptyindex;
- ht->emptyindex = index;
- entry->kv.key = NULL;
- ht->count--;
- return oldkv;
- }
- indexp = &entry->next;
- }
+ if (key) {
+ unsigned long hash = ht->hashfunc(key);
+ size_t *indexp = &ht->indices[(size_t) hash % ht->capacity];
+ while (*indexp != NOTHING) {
+ size_t index = *indexp;
+ struct hash_entry *entry = &ht->entries[index];
+ if (entry->hash == hash && ht->keycmp(entry->kv.key, key) == 0) {
+ kvpair_T oldkv = entry->kv;
+ *indexp = entry->next;
+ entry->next = ht->emptyindex;
+ ht->emptyindex = index;
+ entry->kv.key = NULL;
+ ht->count--;
+ return oldkv;
+ }
+ indexp = &entry->next;
}
- return (kvpair_T) { NULL, NULL, };
+ }
+ return (kvpair_T) { NULL, NULL, };
}
/* ハッシュテーブルの各エントリに対して、関数 f を一回ずつ呼び出す。
* この関数の実行中に ht のエントリを追加・削除してはならない。 */
int ht_each(hashtable_T *ht, int f(kvpair_T kv))
{
- struct hash_entry *entries = ht->entries;
-
- for (size_t i = 0, cap = ht->capacity; i < cap; i++) {
- kvpair_T kv = entries[i].kv;
- if (kv.key) {
- int r = f(kv);
- if (r)
- return r;
- }
+ struct hash_entry *entries = ht->entries;
+
+ for (size_t i = 0, cap = ht->capacity; i < cap; i++) {
+ kvpair_T kv = entries[i].kv;
+ if (kv.key) {
+ int r = f(kv);
+ if (r)
+ return r;
}
- return 0;
+ }
+ return 0;
}
/* ハッシュテーブルの内容を列挙する。
* 全ての列挙が終わると { NULL, NULL } が返る。 */
kvpair_T ht_next(hashtable_T *ht, size_t *indexp)
{
- while (*indexp < ht->capacity) {
- kvpair_T kv = ht->entries[*indexp].kv;
- (*indexp)++;
- if (kv.key)
- return kv;
- }
- return (kvpair_T) { NULL, NULL, };
+ while (*indexp < ht->capacity) {
+ kvpair_T kv = ht->entries[*indexp].kv;
+ (*indexp)++;
+ if (kv.key)
+ return kv;
+ }
+ return (kvpair_T) { NULL, NULL, };
}
* 使える。比較関数には strcmp を使うと良い。 */
unsigned long hashstr(const void *s)
{
- const char *c = s;
- unsigned long h = 0;
- while (*c)
- h = (h * 0x15uL + (unsigned long) *c++) ^ 0x55555555uL;
- return h;
+ const char *c = s;
+ unsigned long h = 0;
+ while (*c)
+ h = (h * 0x15uL + (unsigned long) *c++) ^ 0x55555555uL;
+ return h;
}
/* マルチバイト文字列の比較関数。引数を const char * にキャストし、strcmp 関数で
* 使える。ハッシュ関数には hashstr を使うと良い。 */
int htstrcmp(const void *s1, const void *s2)
{
- return strcmp((const char *) s1, (const char *) s2);
+ return strcmp((const char *) s1, (const char *) s2);
}
/* ワイド文字列に対するハッシュ関数。引数は const wchar_t * にキャストされ、
* 使える。比較関数には htwcscmp を使うと良い。 */
unsigned long hashwcs(const void *s)
{
- const wchar_t *c = s;
- unsigned long h = 0;
- while (*c)
- h = (h * 0x155uL + (unsigned long) *c++) ^ 0x55555555uL;
- return h;
+ const wchar_t *c = s;
+ unsigned long h = 0;
+ while (*c)
+ h = (h * 0x155uL + (unsigned long) *c++) ^ 0x55555555uL;
+ return h;
}
/* ワイド文字列の比較関数。引数を const wchar_t * にキャストし、wcscmp 関数で
* ハッシュ関数には hashwcs を使うと良い。 */
int htwcscmp(const void *s1, const void *s2)
{
- return wcscmp((const wchar_t *) s1, (const wchar_t *) s2);
+ return wcscmp((const wchar_t *) s1, (const wchar_t *) s2);
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
typedef unsigned long hashfunc_T(const void *key);
typedef int keycmp_T(const void *key1, const void *key2);
typedef struct hashtable_T {
- size_t count, capacity;
- hashfunc_T *hashfunc;
- keycmp_T *keycmp;
- size_t emptyindex, tailindex;
- size_t *indices;
- struct hash_entry *entries;
+ size_t count, capacity;
+ hashfunc_T *hashfunc;
+ keycmp_T *keycmp;
+ size_t emptyindex, tailindex;
+ size_t *indices;
+ struct hash_entry *entries;
} hashtable_T;
typedef struct kvpair_T {
- void *key, *value;
+ void *key, *value;
} kvpair_T;
__attribute__((nonnull))
static inline hashtable_T *ht_init(
- hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp);
+ hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp);
__attribute__((nonnull))
extern hashtable_T *ht_initwithcapacity(
- hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp,
- size_t capacity);
+ hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp,
+ size_t capacity);
__attribute__((nonnull))
extern void ht_destroy(hashtable_T *ht);
__attribute__((nonnull))
* keycmp は二つのキーを比較する比較関数へのポインタである。
* 比較関数は、二つのキーが等しいとき 0 を、異なるときに非 0 を返す。 */
static inline hashtable_T *ht_init(
- hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp)
+ hashtable_T *ht, hashfunc_T *hashfunc, keycmp_T *keycmp)
{
- return ht_initwithcapacity(
- ht, hashfunc, keycmp, HASHTABLE_DEFAULT_INIT_CAPACITY);
+ return ht_initwithcapacity(
+ ht, hashfunc, keycmp, HASHTABLE_DEFAULT_INIT_CAPACITY);
}
#endif /* HASHTABLE_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* joblist を初期化する。 */
void init_job(void)
{
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- pl_init(&joblist);
- pl_add(&joblist, NULL);
- }
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ pl_init(&joblist);
+ pl_add(&joblist, NULL);
+ }
}
/* アクティブジョブを設定する。 */
void set_active_job(job_T *job)
{
- assert(joblist.contents[ACTIVE_JOBNO] == NULL);
- joblist.contents[ACTIVE_JOBNO] = job;
+ assert(joblist.contents[ACTIVE_JOBNO] == NULL);
+ joblist.contents[ACTIVE_JOBNO] = job;
}
/* アクティブジョブをジョブリストに追加する。 */
void add_job(void)
{
- job_T *job = joblist.contents[ACTIVE_JOBNO];
+ job_T *job = joblist.contents[ACTIVE_JOBNO];
- assert(job != NULL);
- joblist.contents[ACTIVE_JOBNO] = NULL;
+ assert(job != NULL);
+ joblist.contents[ACTIVE_JOBNO] = NULL;
- /* 空いているジョブ番号があればそこに追加する。 */
- for (size_t i = 1; i < joblist.length; i++) {
- if (joblist.contents[i] == NULL) {
- joblist.contents[i] = job;
- return;
- }
+ /* 空いているジョブ番号があればそこに追加する。 */
+ for (size_t i = 1; i < joblist.length; i++) {
+ if (joblist.contents[i] == NULL) {
+ joblist.contents[i] = job;
+ return;
}
+ }
- /* 空いているジョブ番号がなければ最後に追加する。 */
- pl_add(&joblist, job);
+ /* 空いているジョブ番号がなければ最後に追加する。 */
+ pl_add(&joblist, job);
}
/* 指定した番号のジョブを無条件で削除する。
* 使われていないジョブ番号を指定しないこと。 */
void remove_job(size_t jobnumber)
{
- assert(jobnumber < joblist.length);
+ assert(jobnumber < joblist.length);
- job_T *job = joblist.contents[jobnumber];
- assert(job != NULL);
- joblist.contents[jobnumber] = NULL;
+ job_T *job = joblist.contents[jobnumber];
+ assert(job != NULL);
+ joblist.contents[jobnumber] = NULL;
- /* ジョブの領域を解放する */
- for (size_t i = 0; i < job->j_pcount; i++)
- free(job->j_procs[i].pr_name);
- free(job);
+ /* ジョブの領域を解放する */
+ for (size_t i = 0; i < job->j_pcount; i++)
+ free(job->j_procs[i].pr_name);
+ free(job);
}
/* 全てのジョブを無条件で削除する */
void remove_all_jobs(void)
{
- for (size_t i = 0; i < joblist.length; i++)
- if (joblist.contents[i])
- remove_job(i);
- /*
- pl_clear(&joblist);
- pl_add(&joblist, NULL);
- */
+ for (size_t i = 0; i < joblist.length; i++)
+ if (joblist.contents[i])
+ remove_job(i);
+ /*
+ pl_clear(&joblist);
+ pl_add(&joblist, NULL);
+ */
}
* この関数はブロックしない。 */
void do_wait(void)
{
- pid_t pid;
- int status;
+ pid_t pid;
+ int status;
#ifdef WIFCONTINUED
- static int waitopts = WUNTRACED | WCONTINUED | WNOHANG;
+ static int waitopts = WUNTRACED | WCONTINUED | WNOHANG;
#else
- static int waitopts = WUNTRACED | WNOHANG;
+ static int waitopts = WUNTRACED | WNOHANG;
#endif
start:
- pid = waitpid(-1, &status, waitopts);
- if (pid < 0) {
- switch (errno) {
- case EINTR:
- goto start; /* 単にやり直す */
- case ECHILD:
- return; /* 子プロセスが存在しなかった */
- case EINVAL:
+ pid = waitpid(-1, &status, waitopts);
+ if (pid < 0) {
+ switch (errno) {
+ case EINTR:
+ goto start; /* 単にやり直す */
+ case ECHILD:
+ return; /* 子プロセスが存在しなかった */
+ case EINVAL:
#ifdef WIFCONTINUED
- /* bash のソースによると、WCONTINUED が定義されていても
- * 使えない環境があるらしい。 → WCONTINUED なしで再挑戦 */
- if (waitopts & WCONTINUED) {
- waitopts = WUNTRACED | WNOHANG;
- goto start;
- }
-#endif
- /* falls thru! */
- default:
- xerror(0, errno, "waitpid");
- return;
+ /* bash のソースによると、WCONTINUED が定義されていても
+ * 使えない環境があるらしい。 → WCONTINUED なしで再挑戦 */
+ if (waitopts & WCONTINUED) {
+ waitopts = WUNTRACED | WNOHANG;
+ goto start;
}
- } else if (pid == 0) {
- /* もう状態変化を通知していない子プロセスは残っていなかった */
+#endif
+ /* falls thru! */
+ default:
+ xerror(0, errno, "waitpid");
return;
}
+ } else if (pid == 0) {
+ /* もう状態変化を通知していない子プロセスは残っていなかった */
+ return;
+ }
- size_t jobnumber, pnumber;
- job_T *job;
- process_T *pr;
+ size_t jobnumber, pnumber;
+ job_T *job;
+ process_T *pr;
- /* pid に対応する jobnumber, job, pr を特定する */
- for (jobnumber = 0; jobnumber < joblist.length; jobnumber++)
- if ((job = joblist.contents[jobnumber]))
- for (pnumber = 0; pnumber < job->j_pcount; pnumber++)
- if ((pr = &job->j_procs[pnumber])->pr_pid == pid)
- goto found;
+ /* pid に対応する jobnumber, job, pr を特定する */
+ for (jobnumber = 0; jobnumber < joblist.length; jobnumber++)
+ if ((job = joblist.contents[jobnumber]))
+ for (pnumber = 0; pnumber < job->j_pcount; pnumber++)
+ if ((pr = &job->j_procs[pnumber])->pr_pid == pid)
+ goto found;
- /* ジョブリスト内に pid が見付からなければ (これはジョブを disown した場合
- * などに起こりうる)、単に無視して start に戻る。 */
- goto start;
+ /* ジョブリスト内に pid が見付からなければ (これはジョブを disown した場合
+ * などに起こりうる)、単に無視して start に戻る。 */
+ goto start;
found:
- pr->pr_waitstatus = status;
- if (WIFEXITED(status) || WIFSIGNALED(status))
- pr->pr_status = JS_DONE;
- else if (WIFSTOPPED(status))
- pr->pr_status = JS_STOPPED;
+ pr->pr_waitstatus = status;
+ if (WIFEXITED(status) || WIFSIGNALED(status))
+ pr->pr_status = JS_DONE;
+ else if (WIFSTOPPED(status))
+ pr->pr_status = JS_STOPPED;
#ifdef WIFCONTINUED
- else if (WIFCONTINUED(status))
- pr->pr_status = JS_RUNNING;
+ else if (WIFCONTINUED(status))
+ pr->pr_status = JS_RUNNING;
#endif
- /* ジョブの各プロセスの状態を元に、ジョブ全体の状態を決める。
- * 少なくとも一つのプロセスが JS_RUNNING
- * -> ジョブ全体も JS_RUNNING
- * JS_RUNNING のプロセスはないが、JS_STOPPED のプロセスはある
- * -> ジョブ全体も JS_STOPPED
- * 全てのプロセスが JS_DONE
- * -> ジョブ全体も JS_DONE
- */
- jobstatus_T oldstatus = job->j_status;
- bool anyrunning = false, anystopped = false;
- /* job 内に一つでも実行中・停止中のプロセスが残っているかどうか調べる */
- for (size_t i = 0; i < job->j_pcount; i++) {
- switch (job->j_procs[i].pr_status) {
- case JS_RUNNING: anyrunning = true; goto out_of_loop;
- case JS_STOPPED: anystopped = true; break;
- default: break;
- }
+ /* ジョブの各プロセスの状態を元に、ジョブ全体の状態を決める。
+ * 少なくとも一つのプロセスが JS_RUNNING
+ * -> ジョブ全体も JS_RUNNING
+ * JS_RUNNING のプロセスはないが、JS_STOPPED のプロセスはある
+ * -> ジョブ全体も JS_STOPPED
+ * 全てのプロセスが JS_DONE
+ * -> ジョブ全体も JS_DONE
+ */
+ jobstatus_T oldstatus = job->j_status;
+ bool anyrunning = false, anystopped = false;
+ /* job 内に一つでも実行中・停止中のプロセスが残っているかどうか調べる */
+ for (size_t i = 0; i < job->j_pcount; i++) {
+ switch (job->j_procs[i].pr_status) {
+ case JS_RUNNING: anyrunning = true; goto out_of_loop;
+ case JS_STOPPED: anystopped = true; break;
+ default: break;
}
+ }
out_of_loop:
- job->j_status = anyrunning ? JS_RUNNING : anystopped ? JS_STOPPED : JS_DONE;
- if (job->j_status != oldstatus)
- job->j_statuschanged = true;
+ job->j_status = anyrunning ? JS_RUNNING : anystopped ? JS_STOPPED : JS_DONE;
+ if (job->j_status != oldstatus)
+ job->j_statuschanged = true;
- goto start;
+ goto start;
}
/* 指定した番号のジョブの状態変化を待つ。
* ジョブが既に終了 (または停止) していれば、待たずにすぐに返る。 */
void wait_for_job(size_t jobnumber, bool return_on_stop)
{
- job_T *job = joblist.contents[jobnumber];
-
- block_signals();
- for (;;) {
- do_wait();
- if (job->j_status == JS_DONE)
- break;
- if (return_on_stop && job->j_status == JS_STOPPED)
- break;
- wait_for_sigchld();
- }
- unblock_signals();
+ job_T *job = joblist.contents[jobnumber];
+
+ block_signals();
+ for (;;) {
+ do_wait();
+ if (job->j_status == JS_DONE)
+ break;
+ if (return_on_stop && job->j_status == JS_STOPPED)
+ break;
+ wait_for_sigchld();
+ }
+ unblock_signals();
}
/* waitpid が返したステータスから終了コードを算出する。 */
static int calc_status(int status)
{
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- if (WIFSIGNALED(status))
- return WTERMSIG(status);
- if (WIFSTOPPED(status))
- return WSTOPSIG(status);
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ if (WIFSIGNALED(status))
+ return WTERMSIG(status);
+ if (WIFSTOPPED(status))
+ return WSTOPSIG(status);
#ifdef WIFCONTINUED
- if (WIFCONTINUED(status))
- return 0;
+ if (WIFCONTINUED(status))
+ return 0;
#endif
- assert(false);
+ assert(false);
}
/* 指定したジョブの終了コードを求める。
* 状態が JS_RUNNING なジョブを指定しないこと。 */
int calc_status_of_job(job_T *job)
{
- switch (job->j_status) {
- case JS_DONE:
- return calc_status(job->j_procs[job->j_pcount - 1].pr_waitstatus);
- case JS_STOPPED:
- for (int i = job->j_pcount; --i >= 0; ) {
- if (job->j_procs[i].pr_status == JS_STOPPED)
- return calc_status(job->j_procs[i].pr_waitstatus);
- }
- /* falls thru! */
- default:
- assert(false);
+ switch (job->j_status) {
+ case JS_DONE:
+ return calc_status(job->j_procs[job->j_pcount - 1].pr_waitstatus);
+ case JS_STOPPED:
+ for (int i = job->j_pcount; --i >= 0; ) {
+ if (job->j_procs[i].pr_status == JS_STOPPED)
+ return calc_status(job->j_procs[i].pr_waitstatus);
}
+ /* falls thru! */
+ default:
+ assert(false);
+ }
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* ジョブ/プロセスの状態 */
typedef enum jobstatus_T {
- JS_RUNNING, JS_STOPPED, JS_DONE,
+ JS_RUNNING, JS_STOPPED, JS_DONE,
} jobstatus_T;
/* ジョブを構成するプロセスの情報 */
typedef struct process_T {
- pid_t pr_pid; /* プロセス ID */
- enum jobstatus_T pr_status; /* プロセスの状態 */
- int pr_waitstatus; /* 最後の wait の結果 */
- wchar_t *pr_name; /* 表示用のプロセス名 */
+ pid_t pr_pid; /* プロセス ID */
+ enum jobstatus_T pr_status; /* プロセスの状態 */
+ int pr_waitstatus; /* 最後の wait の結果 */
+ wchar_t *pr_name; /* 表示用のプロセス名 */
} process_T;
/* ジョブの情報 */
typedef struct job_T {
- pid_t j_pgid; /* プロセスグループ ID */
- enum jobstatus_T j_status; /* ジョブの状態 */
- bool j_statuschanged; /* 状態変化を報告していないなら true */
- bool j_loop; /* ループパイプかどうか */
- size_t j_pcount; /* j_procs の要素数 */
- struct process_T j_procs[]; /* 各プロセスの情報 */
+ pid_t j_pgid; /* プロセスグループ ID */
+ enum jobstatus_T j_status; /* ジョブの状態 */
+ bool j_statuschanged; /* 状態変化を報告していないなら true */
+ bool j_loop; /* ループパイプかどうか */
+ size_t j_pcount; /* j_procs の要素数 */
+ struct process_T j_procs[]; /* 各プロセスの情報 */
} job_T;
/* ジョブ制御無効時、ジョブのプロセスグループ ID はシェルと同じになるので、
* j_pgid は 0 となる。 */
#endif /* JOB_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
* を示す。 */
int input_mbs(struct xwcsbuf_T *buf, void *inputinfo)
{
- struct input_mbs_info *info = inputinfo;
- size_t initbuflen = buf->length;
- size_t count;
+ struct input_mbs_info *info = inputinfo;
+ size_t initbuflen = buf->length;
+ size_t count;
- if (!info->src)
- return EOF;
+ if (!info->src)
+ return EOF;
- while (info->srclen > 0) {
- wb_ensuremax(buf, buf->length + 1);
- count = mbrtowc(buf->contents + buf->length,
- info->src, info->srclen, &info->state);
- switch (count) {
- case 0: // L'\0' を読み取った
- info->src = NULL;
- info->srclen = 0;
- return (buf->length == initbuflen) ? EOF : 0;
- default: // L'\0' 以外の文字を読み取った
- info->src += count;
- info->srclen -= count;
- if (buf->contents[buf->length++] == '\n') {
- buf->contents[buf->length] = L'\0';
- return 0;
- }
- break;
- case (size_t) -2: // バイト列が途中で終わっている
- case (size_t) -1: // 不正なバイト列である
- goto err;
+ while (info->srclen > 0) {
+ wb_ensuremax(buf, buf->length + 1);
+ count = mbrtowc(buf->contents + buf->length,
+ info->src, info->srclen, &info->state);
+ switch (count) {
+ case 0: // L'\0' を読み取った
+ info->src = NULL;
+ info->srclen = 0;
+ return (buf->length == initbuflen) ? EOF : 0;
+ default: // L'\0' 以外の文字を読み取った
+ info->src += count;
+ info->srclen -= count;
+ if (buf->contents[buf->length++] == '\n') {
+ buf->contents[buf->length] = L'\0';
+ return 0;
}
+ break;
+ case (size_t) -2: // バイト列が途中で終わっている
+ case (size_t) -1: // 不正なバイト列である
+ goto err;
}
+ }
err:
+ xerror(0, errno,
+ Ngt("cannot convert multibyte character to wide character"));
+ return EOF;
+
+ /*
+ wb_ensuremax(buf, buf->length + 120);
+ count = mbsrtowcs(buf->contents + buf->length, &info->src,
+ buf->maxlength - buf->length + 1, &info->state);
+ if (count == (size_t) -1) {
xerror(0, errno,
- Ngt("cannot convert multibyte character to wide character"));
+ Ngt("cannot convert multibyte character to wide character"));
return EOF;
-
- /*
- wb_ensuremax(buf, buf->length + 120);
- count = mbsrtowcs(buf->contents + buf->length, &info->src,
- buf->maxlength - buf->length + 1, &info->state);
- if (count == (size_t) -1) {
- xerror(0, errno,
- Ngt("cannot convert multibyte character to wide character"));
- return EOF;
- }
- buf->length += count;
- return 0;
- */
+ }
+ buf->length += count;
+ return 0;
+ */
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* input_mbs の inputinfo として使う構造体 */
struct input_mbs_info {
- const char *src; /* 入力として返すソースコード */
- size_t srclen; /* 末尾の '\0' を含む src のバイト数 */
- mbstate_t state; /* ワイド文字列への変換の為のシフト状態 */
+ const char *src; /* 入力として返すソースコード */
+ size_t srclen; /* 末尾の '\0' を含む src のバイト数 */
+ mbstate_t state; /* ワイド文字列への変換の為のシフト状態 */
};
#endif /* LINEINPUT_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
echo "# dependencies resolved by makedepend"
for source in "$@"
do
- case "${source}" in
- *.c)
- {
- echo "${source%.c}.o:";
- sed -e '
- /^[[:blank:]]*#[[:blank:]]*include[[:blank:]]*"[^"]*"$/ {
- s/^[[:blank:]]*#[[:blank:]]*include[[:blank:]]*"\([^"]*\)"/\1/
- p
- }
- d
- ' "${source}"
- } | xargs
- esac
+ case "${source}" in
+ *.c)
+ {
+ echo "${source%.c}.o:";
+ sed -e '
+ /^[[:blank:]]*#[[:blank:]]*include[[:blank:]]*"[^"]*"$/ {
+ s/^[[:blank:]]*#[[:blank:]]*include[[:blank:]]*"\([^"]*\)"/\1/
+ p
+ }
+ d
+ ' "${source}"
+ } | xargs
+ esac
done
+
+
+# vim: set ts=8 sts=4 sw=4 noet:
typedef struct signal_T {
- int no;
- const char *name;
+ int no;
+ const char *name;
} signal_T;
const signal_T signals[] = {
- /* signals defined by POSIX.1-1990 */
- { SIGHUP, "HUP", }, { SIGINT, "INT", }, { SIGQUIT, "QUIT", },
- { SIGILL, "ILL", }, { SIGABRT, "ABRT", }, { SIGFPE, "FPE", },
- { SIGKILL, "KILL", }, { SIGSEGV, "SEGV", }, { SIGPIPE, "PIPE", },
- { SIGALRM, "ALRM", }, { SIGTERM, "TERM", }, { SIGUSR1, "USR1", },
- { SIGUSR2, "USR2", }, { SIGCHLD, "CHLD", }, { SIGCONT, "CONT", },
- { SIGSTOP, "STOP", }, { SIGTSTP, "TSTP", }, { SIGTTIN, "TTIN", },
- { SIGTTOU, "TTOU", },
- /* signals defined by SUSv2 & POSIX.1-2001 (SUSv3) */
- { SIGBUS, "BUS", }, { SIGPROF, "PROF", }, { SIGSYS, "SYS", },
- { SIGTRAP, "TRAP", }, { SIGURG, "URG", }, { SIGXCPU, "XCPU", },
- { SIGXFSZ, "XFSZ", },
+ /* signals defined by POSIX.1-1990 */
+ { SIGHUP, "HUP", }, { SIGINT, "INT", }, { SIGQUIT, "QUIT", },
+ { SIGILL, "ILL", }, { SIGABRT, "ABRT", }, { SIGFPE, "FPE", },
+ { SIGKILL, "KILL", }, { SIGSEGV, "SEGV", }, { SIGPIPE, "PIPE", },
+ { SIGALRM, "ALRM", }, { SIGTERM, "TERM", }, { SIGUSR1, "USR1", },
+ { SIGUSR2, "USR2", }, { SIGCHLD, "CHLD", }, { SIGCONT, "CONT", },
+ { SIGSTOP, "STOP", }, { SIGTSTP, "TSTP", }, { SIGTTIN, "TTIN", },
+ { SIGTTOU, "TTOU", },
+ /* signals defined by SUSv2 & POSIX.1-2001 (SUSv3) */
+ { SIGBUS, "BUS", }, { SIGPROF, "PROF", }, { SIGSYS, "SYS", },
+ { SIGTRAP, "TRAP", }, { SIGURG, "URG", }, { SIGXCPU, "XCPU", },
+ { SIGXFSZ, "XFSZ", },
#ifdef SIGPOLL
- { SIGPOLL, "POLL", },
+ { SIGPOLL, "POLL", },
#endif
#ifdef SIGVTALRM
- { SIGVTALRM, "VTALRM", },
+ { SIGVTALRM, "VTALRM", },
#endif
- /* other signals */
+ /* other signals */
#ifdef SIGIOT
- { SIGIOT, "IOT", },
+ { SIGIOT, "IOT", },
#endif
#ifdef SIGEMT
- { SIGEMT, "EMT", },
+ { SIGEMT, "EMT", },
#endif
#ifdef SIGSTKFLT
- { SIGSTKFLT, "STKFLT", },
+ { SIGSTKFLT, "STKFLT", },
#endif
#ifdef SIGIO
- { SIGIO, "IO", },
+ { SIGIO, "IO", },
#endif
#ifdef SIGCLD
- { SIGCLD, "CLD", },
+ { SIGCLD, "CLD", },
#endif
#ifdef SIGPWR
- { SIGPWR, "PWR", },
+ { SIGPWR, "PWR", },
#endif
#ifdef SIGINFO
- { SIGINFO, "INFO", },
+ { SIGINFO, "INFO", },
#endif
#ifdef SIGLOST
- { SIGLOST, "LOST", },
+ { SIGLOST, "LOST", },
#endif
#ifdef SIGMSG
- { SIGMSG, "MSG", },
+ { SIGMSG, "MSG", },
#endif
#ifdef SIGWINCH
- { SIGWINCH, "WINCH", },
+ { SIGWINCH, "WINCH", },
#endif
#ifdef SIGDANGER
- { SIGDANGER, "DANGER", },
+ { SIGDANGER, "DANGER", },
#endif
#ifdef SIGMIGRATE
- { SIGMIGRATE, "MIGRATE", },
+ { SIGMIGRATE, "MIGRATE", },
#endif
#ifdef SIGPRE
- { SIGPRE, "PRE", },
+ { SIGPRE, "PRE", },
#endif
#ifdef SIGVIRT
- { SIGVIRT, "VIRT", },
+ { SIGVIRT, "VIRT", },
#endif
#ifdef SIGKAP
- { SIGKAP, "KAP", },
+ { SIGKAP, "KAP", },
#endif
#ifdef SIGGRANT
- { SIGGRANT, "GRANT", },
+ { SIGGRANT, "GRANT", },
#endif
#ifdef SIGRETRACT
- { SIGRETRACT, "RETRACT", },
+ { SIGRETRACT, "RETRACT", },
#endif
#ifdef SIGSOUND
- { SIGSOUND, "SOUND", },
+ { SIGSOUND, "SOUND", },
#endif
#ifdef SIGUNUSED
- { SIGUNUSED, "UNUSED", },
+ { SIGUNUSED, "UNUSED", },
#endif
- { 0, NULL, },
+ { 0, NULL, },
};
int main(void)
{
- setlocale(LC_ALL, "");
-
- int min = 0;
-
- wprintf(L"/* signum.h: generated by mksignum */\n\n\n");
- wprintf(L"#include <stddef.h>\n\n");
-
- for (const signal_T *s = signals; s->no; s++)
- if (min < s->no)
- min = s->no;
-
- if (min < 100) {
- wprintf(L"/* injective function that returns an array index\n");
- wprintf(L" * corresponding to given signal number.\n");
- wprintf(L" * SIGNUM must not be a realtime signal number. */\n");
- wprintf(L"__attribute__((const))\n");
- wprintf(L"static inline size_t sigindex(int signum) {\n");
- wprintf(L" return (size_t) signum;\n");
- wprintf(L"}\n\n");
-
- wprintf(L"/* max index returned by sigindex + 1 */\n");
- wprintf(L"#define MAXSIGIDX %d\n\n", min + 1);
- } else {
- sigset_t ss;
- size_t v;
-
- wprintf(L"/* injective function that returns an array index\n");
- wprintf(L" * corresponding to given signal number.\n");
- wprintf(L" * SIGNUM must not be a realtime signal number. */\n");
- wprintf(L"__attribute__((const))\n");
- wprintf(L"static inline size_t sigindex(int signum) {\n");
- wprintf(L" switch (signum) {\n");
- wprintf(L" case 0 : return 0;\n");
-
- sigemptyset(&ss);
- v = 1;
- for (const signal_T *s = signals; s->no; s++) {
- if (!sigismember(&ss, s->no)) {
- sigaddset(&ss, s->no);
- wprintf(L" case SIG%-7s: return %zu;\n", s->name, v++);
- }
- }
-
- wprintf(L" }\n");
- wprintf(L"}\n\n");
-
- wprintf(L"/* max index returned by sigindex + 1 */\n");
- wprintf(L"#define MAXSIGIDX %zu\n\n", v);
+ setlocale(LC_ALL, "");
+
+ int min = 0;
+
+ wprintf(L"/* signum.h: generated by mksignum */\n\n\n");
+ wprintf(L"#include <stddef.h>\n\n");
+
+ for (const signal_T *s = signals; s->no; s++)
+ if (min < s->no)
+ min = s->no;
+
+ if (min < 100) {
+ wprintf(L"/* injective function that returns an array index\n");
+ wprintf(L" * corresponding to given signal number.\n");
+ wprintf(L" * SIGNUM must not be a realtime signal number. */\n");
+ wprintf(L"__attribute__((const))\n");
+ wprintf(L"static inline size_t sigindex(int signum) {\n");
+ wprintf(L" return (size_t) signum;\n");
+ wprintf(L"}\n\n");
+
+ wprintf(L"/* max index returned by sigindex + 1 */\n");
+ wprintf(L"#define MAXSIGIDX %d\n\n", min + 1);
+ } else {
+ sigset_t ss;
+ size_t v;
+
+ wprintf(L"/* injective function that returns an array index\n");
+ wprintf(L" * corresponding to given signal number.\n");
+ wprintf(L" * SIGNUM must not be a realtime signal number. */\n");
+ wprintf(L"__attribute__((const))\n");
+ wprintf(L"static inline size_t sigindex(int signum) {\n");
+ wprintf(L" switch (signum) {\n");
+ wprintf(L" case 0 : return 0;\n");
+
+ sigemptyset(&ss);
+ v = 1;
+ for (const signal_T *s = signals; s->no; s++) {
+ if (!sigismember(&ss, s->no)) {
+ sigaddset(&ss, s->no);
+ wprintf(L" case SIG%-7s: return %zu;\n", s->name, v++);
+ }
}
- wprintf(L"/* number of realtime signals that can be handled by yash */\n");
- wprintf(L"#define RTSIZE %d\n\n",
+ wprintf(L" }\n");
+ wprintf(L"}\n\n");
+
+ wprintf(L"/* max index returned by sigindex + 1 */\n");
+ wprintf(L"#define MAXSIGIDX %zu\n\n", v);
+ }
+
+ wprintf(L"/* number of realtime signals that can be handled by yash */\n");
+ wprintf(L"#define RTSIZE %d\n\n",
#if defined SIGRTMIN && defined SIGRTMAX
- SIGRTMAX - SIGRTMIN + 10
+ SIGRTMAX - SIGRTMIN + 10
#else
- 0
+ 0
#endif
- );
+ );
- return 0;
+ return 0;
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
void andorsfree(and_or_T *a)
{
- while (a) {
- pipesfree(a->ao_pipelines);
+ while (a) {
+ pipesfree(a->ao_pipelines);
- and_or_T *next = a->next;
- free(a);
- a = next;
- }
+ and_or_T *next = a->next;
+ free(a);
+ a = next;
+ }
}
static void pipesfree(pipeline_T *p)
{
- while (p) {
- comsfree(p->pl_commands);
+ while (p) {
+ comsfree(p->pl_commands);
- pipeline_T *next = p->next;
- free(p);
- p = next;
- }
+ pipeline_T *next = p->next;
+ free(p);
+ p = next;
+ }
}
static void comsfree(command_T *c)
{
- while (c) {
- redirsfree(c->c_redirs);
- switch (c->c_type) {
- case CT_SIMPLE:
- assignsfree(c->c_assigns);
- recfree(c->c_words, wordfree_vp);
- break;
- case CT_GROUP:
- case CT_SUBSHELL:
- andorsfree(c->c_subcmds);
- break;
- case CT_IF:
- ifcmdsfree(c->c_ifcmds);
- break;
- case CT_FOR:
- free(c->c_forname);
- recfree(c->c_forwords, wordfree_vp);
- andorsfree(c->c_forcmds);
- break;
- case CT_WHILE:
- andorsfree(c->c_whlcond);
- andorsfree(c->c_whlcmds);
- break;
- case CT_CASE:
- wordfree(c->c_casword);
- caseitemsfree(c->c_casitems);
- break;
- }
-
- command_T *next = c->next;
- free(c);
- c = next;
+ while (c) {
+ redirsfree(c->c_redirs);
+ switch (c->c_type) {
+ case CT_SIMPLE:
+ assignsfree(c->c_assigns);
+ recfree(c->c_words, wordfree_vp);
+ break;
+ case CT_GROUP:
+ case CT_SUBSHELL:
+ andorsfree(c->c_subcmds);
+ break;
+ case CT_IF:
+ ifcmdsfree(c->c_ifcmds);
+ break;
+ case CT_FOR:
+ free(c->c_forname);
+ recfree(c->c_forwords, wordfree_vp);
+ andorsfree(c->c_forcmds);
+ break;
+ case CT_WHILE:
+ andorsfree(c->c_whlcond);
+ andorsfree(c->c_whlcmds);
+ break;
+ case CT_CASE:
+ wordfree(c->c_casword);
+ caseitemsfree(c->c_casitems);
+ break;
}
+
+ command_T *next = c->next;
+ free(c);
+ c = next;
+ }
}
static void ifcmdsfree(ifcommand_T *i)
{
- while (i) {
- andorsfree(i->ic_condition);
- andorsfree(i->ic_commands);
+ while (i) {
+ andorsfree(i->ic_condition);
+ andorsfree(i->ic_commands);
- ifcommand_T *next = i->next;
- free(i);
- i = next;
- }
+ ifcommand_T *next = i->next;
+ free(i);
+ i = next;
+ }
}
static void caseitemsfree(caseitem_T *i)
{
- while (i) {
- recfree(i->ci_patterns, wordfree_vp);
- andorsfree(i->ci_commands);
+ while (i) {
+ recfree(i->ci_patterns, wordfree_vp);
+ andorsfree(i->ci_commands);
- caseitem_T *next = i->next;
- free(i);
- i = next;
- }
+ caseitem_T *next = i->next;
+ free(i);
+ i = next;
+ }
}
static void wordfree(wordunit_T *w)
{
- while (w) {
- switch (w->wu_type) {
- case WT_STRING:
- free(w->wu_string);
- break;
- case WT_PARAM:
- paramfree(w->wu_param);
- break;
- case WT_CMDSUB:
- free(w->wu_cmdsub);
- break;
- case WT_ARITH:
- wordfree(w->wu_arith);
- break;
- }
-
- wordunit_T *next = w->next;
- free(w);
- w = next;
+ while (w) {
+ switch (w->wu_type) {
+ case WT_STRING:
+ free(w->wu_string);
+ break;
+ case WT_PARAM:
+ paramfree(w->wu_param);
+ break;
+ case WT_CMDSUB:
+ free(w->wu_cmdsub);
+ break;
+ case WT_ARITH:
+ wordfree(w->wu_arith);
+ break;
}
+
+ wordunit_T *next = w->next;
+ free(w);
+ w = next;
+ }
}
static void wordfree_vp(void *w)
{
- wordfree((wordunit_T *) w);
+ wordfree((wordunit_T *) w);
}
static void paramfree(paramexp_T *p)
{
- if (p) {
- free(p->pe_name);
- wordfree(p->pe_match);
- wordfree(p->pe_subst);
- }
+ if (p) {
+ free(p->pe_name);
+ wordfree(p->pe_match);
+ wordfree(p->pe_subst);
+ }
}
static void assignsfree(assign_T *a)
{
- while (a) {
- free(a->name);
- wordfree(a->value);
+ while (a) {
+ free(a->name);
+ wordfree(a->value);
- assign_T *next = a->next;
- free(a);
- a = next;
- }
+ assign_T *next = a->next;
+ free(a);
+ a = next;
+ }
}
static void redirsfree(redir_T *r)
{
- while (r) {
- switch (r->rd_type) {
- case RT_INPUT: case RT_OUTPUT: case RT_CLOBBER: case RT_APPEND:
- case RT_INOUT: case RT_DUPIN: case RT_DUPOUT:
- wordfree(r->rd_filename);
- break;
- case RT_HERE: case RT_HERERT:
- free(r->rd_hereend);
- wordfree(r->rd_herecontent);
- break;
- }
-
- redir_T *next = r->next;
- free(r);
- r = next;
+ while (r) {
+ switch (r->rd_type) {
+ case RT_INPUT: case RT_OUTPUT: case RT_CLOBBER: case RT_APPEND:
+ case RT_INOUT: case RT_DUPIN: case RT_DUPOUT:
+ wordfree(r->rd_filename);
+ break;
+ case RT_HERE: case RT_HERERT:
+ free(r->rd_hereend);
+ wordfree(r->rd_herecontent);
+ break;
}
+
+ redir_T *next = r->next;
+ free(r);
+ r = next;
+ }
}
/* 引数が名前構成文字であるかどうか調べる */
static inline bool is_name_char(wchar_t c)
{
- switch (c) {
- case L'0': case L'1': case L'2': case L'3': case L'4':
- case L'5': case L'6': case L'7': case L'8': case L'9':
- case L'a': case L'b': case L'c': case L'd': case L'e': case L'f':
- case L'g': case L'h': case L'i': case L'j': case L'k': case L'l':
- case L'm': case L'n': case L'o': case L'p': case L'q': case L'r':
- case L's': case L't': case L'u': case L'v': case L'w': case L'x':
- case L'y': case L'z':
- case L'A': case L'B': case L'C': case L'D': case L'E': case L'F':
- case L'G': case L'H': case L'I': case L'J': case L'K': case L'L':
- case L'M': case L'N': case L'O': case L'P': case L'Q': case L'R':
- case L'S': case L'T': case L'U': case L'V': case L'W': case L'X':
- case L'Y': case L'Z': case L'_':
- return true;
- default:
- return false;
- }
+ switch (c) {
+ case L'0': case L'1': case L'2': case L'3': case L'4':
+ case L'5': case L'6': case L'7': case L'8': case L'9':
+ case L'a': case L'b': case L'c': case L'd': case L'e': case L'f':
+ case L'g': case L'h': case L'i': case L'j': case L'k': case L'l':
+ case L'm': case L'n': case L'o': case L'p': case L'q': case L'r':
+ case L's': case L't': case L'u': case L'v': case L'w': case L'x':
+ case L'y': case L'z':
+ case L'A': case L'B': case L'C': case L'D': case L'E': case L'F':
+ case L'G': case L'H': case L'I': case L'J': case L'K': case L'L':
+ case L'M': case L'N': case L'O': case L'P': case L'Q': case L'R':
+ case L'S': case L'T': case L'U': case L'V': case L'W': case L'X':
+ case L'Y': case L'Z': case L'_':
+ return true;
+ default:
+ return false;
+ }
}
/* s の先頭にある、識別子として正しい部分を飛ばして、残りの部分へのポインタを
* 返す。 */
static wchar_t *skip_name(const wchar_t *s)
{
- if (!iswdigit(*s))
- while (is_name_char(*s))
- s++;
- return (wchar_t *) s;
+ if (!iswdigit(*s))
+ while (is_name_char(*s))
+ s++;
+ return (wchar_t *) s;
}
static inline wordunit_T *parse_word(aliastype_T type)
{
- return parse_word_to(type, is_token_delimiter_char);
+ return parse_word_to(type, is_token_delimiter_char);
}
* この関数は再入不可能である。 */
int read_and_parse(parseinfo_T *restrict info, and_or_T **restrict result)
{
- cinfo = info;
- cerror = false;
- cindex = 0;
- wb_init(&cbuf);
- pl_init(&pending_heredocs);
- lastinputresult = cinfo->input(&cbuf, cinfo->inputinfo);
- if (lastinputresult == EOF) {
- return EOF;
- } else if (lastinputresult == 1) {
- *result = NULL;
- return 0;
- }
-
- and_or_T *r = parse_command_list();
-
- wb_destroy(&cbuf);
- pl_destroy(&pending_heredocs);
-
- if (!cerror) {
- assert(cindex == cbuf.length);
- *result = r;
- return 0;
- } else {
- andorsfree(r);
- return 1;
- }
+ cinfo = info;
+ cerror = false;
+ cindex = 0;
+ wb_init(&cbuf);
+ pl_init(&pending_heredocs);
+ lastinputresult = cinfo->input(&cbuf, cinfo->inputinfo);
+ if (lastinputresult == EOF) {
+ return EOF;
+ } else if (lastinputresult == 1) {
+ *result = NULL;
+ return 0;
+ }
+
+ and_or_T *r = parse_command_list();
+
+ wb_destroy(&cbuf);
+ pl_destroy(&pending_heredocs);
+
+ if (!cerror) {
+ assert(cindex == cbuf.length);
+ *result = r;
+ return 0;
+ } else {
+ andorsfree(r);
+ return 1;
+ }
}
/* 構文エラーメッセージを stderr に出力する。
* format はこの関数内で gettext に通す。format の最後に改行は不要。 */
static void serror(const char *restrict format, ...)
{
- va_list ap;
-
- if (cinfo->print_errmsg) {
- fflush(stdout);
- fprintf(stderr, gt("%s:%lu: syntax error: "),
- cinfo->filename ? cinfo->filename
- : yash_program_invocation_name,
- cinfo->lineno);
- va_start(ap, format);
- vfprintf(stderr, gt(format), ap);
- va_end(ap);
- fputc('\n', stderr);
- fflush(stderr);
- }
- cerror = true;
+ va_list ap;
+
+ if (cinfo->print_errmsg) {
+ fflush(stdout);
+ fprintf(stderr, gt("%s:%lu: syntax error: "),
+ cinfo->filename ? cinfo->filename
+ : yash_program_invocation_name,
+ cinfo->lineno);
+ va_start(ap, format);
+ vfprintf(stderr, gt(format), ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ fflush(stderr);
+ }
+ cerror = true;
}
/* 更なる入力を読み込む
* EOF: EOF に達したか、エラーがあった。(buf の内容は不定) */
static inline int read_more_input(void)
{
- if (lastinputresult == 0)
- lastinputresult = cinfo->input(&cbuf, cinfo->inputinfo);
- return lastinputresult;
+ if (lastinputresult == 0)
+ lastinputresult = cinfo->input(&cbuf, cinfo->inputinfo);
+ return lastinputresult;
}
/* cbuf.length >= cindex + n となるように、必要に応じて read_more_input する。
* 戻り値: lastinputresult */
static inline int ensure_buffer(size_t n)
{
- int lir = lastinputresult;
- while (lir == 0 && cbuf.length < cindex + n) {
- if (cbuf.length > 0 && cbuf.contents[cbuf.length - 1] == L'\n')
- break;
- lir = read_more_input();
- }
- return lir;
+ int lir = lastinputresult;
+ while (lir == 0 && cbuf.length < cindex + n) {
+ if (cbuf.length > 0 && cbuf.contents[cbuf.length - 1] == L'\n')
+ break;
+ lir = read_more_input();
+ }
+ return lir;
}
/* cindex を増やして blank・コメント・行連結を飛ばす。必要に応じて
static void skip_blanks_and_comment(void)
{
skipblanks: /* blank を飛ばす */
- while (iswblank(cbuf.contents[cindex]))
- cindex++;
- if (cbuf.contents[cindex] == L'\0' && read_more_input() == 0)
- goto skipblanks;
+ while (iswblank(cbuf.contents[cindex]))
+ cindex++;
+ if (cbuf.contents[cindex] == L'\0' && read_more_input() == 0)
+ goto skipblanks;
skiptonewline: /* コメントを飛ばす */
- if (cbuf.contents[cindex] == L'#') {
- do {
- cindex++;
- } while (cbuf.contents[cindex] != L'\n'
- && cbuf.contents[cindex] != L'\0');
- }
- if (cbuf.contents[cindex] == L'\0' && read_more_input() == 0)
- goto skiptonewline;
-
- /* 行連結を削除する */
- ensure_buffer(2);
- if (cbuf.contents[cindex] == L'\\' && cbuf.contents[cindex + 1] == L'\n') {
- wb_remove(&cbuf, cindex, 2);
- cinfo->lineno++;
- goto skipblanks;
- }
+ if (cbuf.contents[cindex] == L'#') {
+ do {
+ cindex++;
+ } while (cbuf.contents[cindex] != L'\n'
+ && cbuf.contents[cindex] != L'\0');
+ }
+ if (cbuf.contents[cindex] == L'\0' && read_more_input() == 0)
+ goto skiptonewline;
+
+ /* 行連結を削除する */
+ ensure_buffer(2);
+ if (cbuf.contents[cindex] == L'\\' && cbuf.contents[cindex + 1] == L'\n') {
+ wb_remove(&cbuf, cindex, 2);
+ cinfo->lineno++;
+ goto skipblanks;
+ }
}
/* 次のトークンに達するまで cindex を増やして blank 文字・改行文字・コメントを
* 戻り値: 一つ以上の NEWLINE トークンを飛ばしたかどうか */
static bool skip_to_next_token(void)
{
- bool newline = false;
+ bool newline = false;
+ skip_blanks_and_comment();
+ while (lastinputresult == 0 && cbuf.contents[cindex] == L'\n') {
+ newline = true;
+ next_line();
skip_blanks_and_comment();
- while (lastinputresult == 0 && cbuf.contents[cindex] == L'\n') {
- newline = true;
- next_line();
- skip_blanks_and_comment();
- }
- return newline;
+ }
+ return newline;
}
/* 現在位置が改行文字のとき、NEWLINE トークンとして解釈して次の行に進む。
* ヒアドキュメントの読み込みを控えているならそれも行う。 */
static void next_line(void)
{
- assert(cbuf.contents[cindex] == L'\n');
- cindex++;
- cinfo->lineno++;
- assert(cbuf.contents[cindex] == L'\0');
+ assert(cbuf.contents[cindex] == L'\n');
+ cindex++;
+ cinfo->lineno++;
+ assert(cbuf.contents[cindex] == L'\0');
- for (size_t i = 0; i < pending_heredocs.length; i++)
- read_heredoc_contents(pending_heredocs.contents[i]);
- pl_clear(&pending_heredocs);
- read_more_input();
+ for (size_t i = 0; i < pending_heredocs.length; i++)
+ read_heredoc_contents(pending_heredocs.contents[i]);
+ pl_clear(&pending_heredocs);
+ read_more_input();
}
/* 指定した文字がトークン区切り文字かどうかを調べる */
static bool is_token_delimiter_char(wchar_t c)
{
- return iswblank(c) || c == L'\0' || c == L'\n'
- || c == L';' || c == L'&' || c == L'|'
- || c == L'<' || c == L'>' || c == L'(' || c == L')';
+ return iswblank(c) || c == L'\0' || c == L'\n'
+ || c == L';' || c == L'&' || c == L'|'
+ || c == L'<' || c == L'>' || c == L'(' || c == L')';
}
/* 指定した文字が単純コマンドを区切る文字かどうかを調べる */
static bool is_command_delimiter_char(wchar_t c)
{
- return c == L'\0' || c == L'\n'
- || c == L';' || c == L'&' || c == L'|' || c == L'(' || c == L')';
+ return c == L'\0' || c == L'\n'
+ || c == L';' || c == L'&' || c == L'|' || c == L'(' || c == L')';
}
static bool is_slash_or_closing_brace(wchar_t c)
{
- return c == L'/' || c == L'}' || c == L'\0';
+ return c == L'/' || c == L'}' || c == L'\0';
}
static bool is_closing_brace(wchar_t c)
{
- return c == L'}' || c == L'\0';
+ return c == L'}' || c == L'\0';
}
/* cbuf の指定したインデックスにトークン token があるか調べる。
/* 予め ensure_buffer(wcslen(token)) を行っておくこと。 */
static bool is_token_at(const wchar_t *token, size_t index)
{
- wchar_t *c = matchwcsprefix(cbuf.contents + index, token);
- return c && is_token_delimiter_char(*c);
+ wchar_t *c = matchwcsprefix(cbuf.contents + index, token);
+ return c && is_token_delimiter_char(*c);
}
/* cbuf の指定したインデックスに ( や { や if などの「開く」トークンがあるか
* 調べる。あれば、そのトークンを示す文字列定数を返す。なければ NULL を返す。 */
static const wchar_t *check_opening_token_at(size_t index)
{
- ensure_buffer(6);
- if (cbuf.contents[index] == L'(') return L"(";
- if (is_token_at(L"{", index)) return L"{";
- if (is_token_at(L"if", index)) return L"if";
- if (is_token_at(L"for", index)) return L"for";
- if (is_token_at(L"while", index)) return L"while";
- if (is_token_at(L"until", index)) return L"until";
- if (is_token_at(L"case", index)) return L"case";
- return NULL;
+ ensure_buffer(6);
+ if (cbuf.contents[index] == L'(') return L"(";
+ if (is_token_at(L"{", index)) return L"{";
+ if (is_token_at(L"if", index)) return L"if";
+ if (is_token_at(L"for", index)) return L"for";
+ if (is_token_at(L"while", index)) return L"while";
+ if (is_token_at(L"until", index)) return L"until";
+ if (is_token_at(L"case", index)) return L"case";
+ return NULL;
}
/* cbuf の指定したインデックスに ) や } や fi などの「閉じる」トークンがあるか
* 「閉じる」トークンというのは、and/or リストを終わらせる印になるものである。*/
static const wchar_t *check_closing_token_at(size_t index)
{
- ensure_buffer(5);
- if (cbuf.contents[index] == L')') return L")";
- if (cbuf.contents[index] == L';' && cbuf.contents[index + 1] == L';')
- return L";;";
- if (is_token_at(L"}", index)) return L"}";
- if (is_token_at(L"then", index)) return L"then";
- if (is_token_at(L"else", index)) return L"else";
- if (is_token_at(L"elif", index)) return L"elif";
- if (is_token_at(L"fi", index)) return L"fi";
- if (is_token_at(L"do", index)) return L"do";
- if (is_token_at(L"done", index)) return L"done";
- if (is_token_at(L"esac", index)) return L"esac";
- return NULL;
+ ensure_buffer(5);
+ if (cbuf.contents[index] == L')') return L")";
+ if (cbuf.contents[index] == L';' && cbuf.contents[index + 1] == L';')
+ return L";;";
+ if (is_token_at(L"}", index)) return L"}";
+ if (is_token_at(L"then", index)) return L"then";
+ if (is_token_at(L"else", index)) return L"else";
+ if (is_token_at(L"elif", index)) return L"elif";
+ if (is_token_at(L"fi", index)) return L"fi";
+ if (is_token_at(L"do", index)) return L"do";
+ if (is_token_at(L"done", index)) return L"done";
+ if (is_token_at(L"esac", index)) return L"esac";
+ return NULL;
}
/* 区切りの良いところまで解析を進める。すなわち、少くとも一行の入力を読み取り、
* この関数を呼ぶ前に skip_blanks_and_comment をする必要はない。 */
static and_or_T *parse_command_list(void)
{
- and_or_T *first = NULL, **lastp = &first;
- bool separator = true;
- /* 二つ目以降のトークンを解析するにはセパレータ ('&', ';', または一つ以上の
- * 改行) が必要となる。 */
-
- while (!cerror) {
- skip_blanks_and_comment();
- if (cbuf.contents[cindex] == L'\0') {
- break;
- } else if (cbuf.contents[cindex] == L'\n') {
- next_line();
- break;
- } else if (!separator) {
- serror(Ngt("`;' or `&' missing"));
- break;
- }
-
- and_or_T *ao = parse_and_or_list();
- if (ao) {
- *lastp = ao;
- lastp = &ao->next;
- }
-
- separator = false;
- ensure_buffer(2);
- if (cbuf.contents[cindex] == L'&'
- || (cbuf.contents[cindex] == L';'
- && cbuf.contents[cindex + 1] != L';')) {
- cindex++;
- separator = true;
- }
+ and_or_T *first = NULL, **lastp = &first;
+ bool separator = true;
+ /* 二つ目以降のトークンを解析するにはセパレータ ('&', ';', または一つ以上の
+ * 改行) が必要となる。 */
+
+ while (!cerror) {
+ skip_blanks_and_comment();
+ if (cbuf.contents[cindex] == L'\0') {
+ break;
+ } else if (cbuf.contents[cindex] == L'\n') {
+ next_line();
+ break;
+ } else if (!separator) {
+ serror(Ngt("`;' or `&' missing"));
+ break;
+ }
+
+ and_or_T *ao = parse_and_or_list();
+ if (ao) {
+ *lastp = ao;
+ lastp = &ao->next;
+ }
+
+ separator = false;
+ ensure_buffer(2);
+ if (cbuf.contents[cindex] == L'&'
+ || (cbuf.contents[cindex] == L';'
+ && cbuf.contents[cindex + 1] != L';')) {
+ cindex++;
+ separator = true;
}
- return first;
+ }
+ return first;
}
/* 「閉じる」トークンが現れるまでコマンドを解析する。
* この関数を呼ぶ前に skip_to_next_token をする必要はない。 */
static and_or_T *parse_compound_list(void)
{
- and_or_T *first = NULL, **lastp = &first;
- bool savecerror = cerror;
- bool separator = true;
- /* 二つ目以降のトークンを解析するにはセパレータ ('&', ';', または一つ以上の
- * 改行) が必要となる。 */
-
- cerror = false;
- while (!cerror) {
- separator |= skip_to_next_token();
- if (!separator
- || cbuf.contents[cindex] == L'\0'
- || check_closing_token_at(cindex))
- break;
-
- and_or_T *ao = parse_and_or_list();
- if (ao) {
- *lastp = ao;
- lastp = &ao->next;
- }
-
- separator = false;
- ensure_buffer(2);
- if (cbuf.contents[cindex] == L'&'
- || (cbuf.contents[cindex] == L';'
- && cbuf.contents[cindex + 1] != L';')) {
- cindex++;
- separator = true;
- }
+ and_or_T *first = NULL, **lastp = &first;
+ bool savecerror = cerror;
+ bool separator = true;
+ /* 二つ目以降のトークンを解析するにはセパレータ ('&', ';', または一つ以上の
+ * 改行) が必要となる。 */
+
+ cerror = false;
+ while (!cerror) {
+ separator |= skip_to_next_token();
+ if (!separator
+ || cbuf.contents[cindex] == L'\0'
+ || check_closing_token_at(cindex))
+ break;
+
+ and_or_T *ao = parse_and_or_list();
+ if (ao) {
+ *lastp = ao;
+ lastp = &ao->next;
+ }
+
+ separator = false;
+ ensure_buffer(2);
+ if (cbuf.contents[cindex] == L'&'
+ || (cbuf.contents[cindex] == L';'
+ && cbuf.contents[cindex + 1] != L';')) {
+ cindex++;
+ separator = true;
}
- cerror |= savecerror;
- return first;
+ }
+ cerror |= savecerror;
+ return first;
}
/* 一つの and/or リストを解析する。
* なく '&'/';' そのもののインデックスを指した状態で返る。 */
static and_or_T *parse_and_or_list(void)
{
- and_or_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->ao_pipelines = parse_pipelines_in_and_or();
- result->ao_async = (cbuf.contents[cindex] == L'&');
- return result;
+ and_or_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->ao_pipelines = parse_pipelines_in_and_or();
+ result->ao_async = (cbuf.contents[cindex] == L'&');
+ return result;
}
/* and/or リスト内の全てのパイプラインを解析する。 */
static pipeline_T *parse_pipelines_in_and_or(void)
{
- pipeline_T *first = NULL, **lastp = &first;
+ pipeline_T *first = NULL, **lastp = &first;
- for (;;) {
- pipeline_T *p = parse_pipeline();
- if (p) {
- *lastp = p;
- lastp = &p->next;
- }
+ for (;;) {
+ pipeline_T *p = parse_pipeline();
+ if (p) {
+ *lastp = p;
+ lastp = &p->next;
+ }
- ensure_buffer(2);
- if (cbuf.contents[cindex] == L'&'
- && cbuf.contents[cindex+1] == L'&') {
- p->pl_next_cond = true;
- } else if (cbuf.contents[cindex] == L'|'
- && cbuf.contents[cindex+1] == L'|') {
- p->pl_next_cond = false;
- } else {
- break;
- }
- cindex += 2;
- skip_to_next_token();
+ ensure_buffer(2);
+ if (cbuf.contents[cindex] == L'&'
+ && cbuf.contents[cindex+1] == L'&') {
+ p->pl_next_cond = true;
+ } else if (cbuf.contents[cindex] == L'|'
+ && cbuf.contents[cindex+1] == L'|') {
+ p->pl_next_cond = false;
+ } else {
+ break;
}
- return first;
+ cindex += 2;
+ skip_to_next_token();
+ }
+ return first;
}
/* 一つのパイプライン ('|' で繋がった一つ以上のコマンド) を解析する。 */
static pipeline_T *parse_pipeline(void)
{
- pipeline_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->pl_next_cond = false;
-
- ensure_buffer(2);
- if (is_token_at(L"!", cindex)) {
- result->pl_neg = true;
- cindex++;
- skip_blanks_and_comment();
- } else {
- result->pl_neg = false;
- }
+ pipeline_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->pl_next_cond = false;
- ensure_buffer(2);
- if (!posixly_correct && cbuf.contents[cindex ] == L'|'
- && cbuf.contents[cindex + 1] != L'|') {
- result->pl_loop = true;
- cindex++;
- skip_blanks_and_comment();
- } else {
- result->pl_loop = false;
- }
+ ensure_buffer(2);
+ if (is_token_at(L"!", cindex)) {
+ result->pl_neg = true;
+ cindex++;
+ skip_blanks_and_comment();
+ } else {
+ result->pl_neg = false;
+ }
+
+ ensure_buffer(2);
+ if (!posixly_correct && cbuf.contents[cindex ] == L'|'
+ && cbuf.contents[cindex + 1] != L'|') {
+ result->pl_loop = true;
+ cindex++;
+ skip_blanks_and_comment();
+ } else {
+ result->pl_loop = false;
+ }
- result->pl_commands = parse_commands_in_pipeline();
- return result;
+ result->pl_commands = parse_commands_in_pipeline();
+ return result;
}
/* パイプラインの本体 (間を '|' で繋いた一つ以上のコマンド) を解析する。 */
static command_T *parse_commands_in_pipeline(void)
{
- command_T *first = NULL, **lastp = &first;
+ command_T *first = NULL, **lastp = &first;
- for (;;) {
- command_T *c = parse_command();
- if (c) {
- *lastp = c;
- lastp = &c->next;
- }
+ for (;;) {
+ command_T *c = parse_command();
+ if (c) {
+ *lastp = c;
+ lastp = &c->next;
+ }
- ensure_buffer(2);
- if (cbuf.contents[cindex] == L'|' && cbuf.contents[cindex+1] != L'|') {
- cindex++;
- skip_to_next_token();
- } else {
- break;
- }
+ ensure_buffer(2);
+ if (cbuf.contents[cindex] == L'|' && cbuf.contents[cindex+1] != L'|') {
+ cindex++;
+ skip_to_next_token();
+ } else {
+ break;
}
- return first;
+ }
+ return first;
}
/* 一つのコマンドを解析する。 */
static command_T *parse_command(void)
{
- /* Note: check_closing_token_at は ensure_buffer(5) を含む */
- const wchar_t *t = check_closing_token_at(cindex);
- if (t) {
- serror(get_errmsg_unexpected_token(t), t);
- return NULL;
- } else if (is_token_at(L"!", cindex)) {
- serror(get_errmsg_unexpected_token(L"!"), L"!");
- return NULL;
- } else if (is_token_at(L"in", cindex)) {
- serror(get_errmsg_unexpected_token(L"in"), L"in");
- return NULL;
- } else if (cbuf.contents[cindex] == L'(') {
- return parse_group(CT_SUBSHELL);
- } else if (is_command_delimiter_char(cbuf.contents[cindex])) {
- if (cbuf.contents[cindex] == L'\0')
- serror(Ngt("command missing at end of input"));
- else
- serror(Ngt("command missing before `%lc'"),
- (wint_t) cbuf.contents[cindex]);
- return NULL;
- }
+ /* Note: check_closing_token_at は ensure_buffer(5) を含む */
+ const wchar_t *t = check_closing_token_at(cindex);
+ if (t) {
+ serror(get_errmsg_unexpected_token(t), t);
+ return NULL;
+ } else if (is_token_at(L"!", cindex)) {
+ serror(get_errmsg_unexpected_token(L"!"), L"!");
+ return NULL;
+ } else if (is_token_at(L"in", cindex)) {
+ serror(get_errmsg_unexpected_token(L"in"), L"in");
+ return NULL;
+ } else if (cbuf.contents[cindex] == L'(') {
+ return parse_group(CT_SUBSHELL);
+ } else if (is_command_delimiter_char(cbuf.contents[cindex])) {
+ if (cbuf.contents[cindex] == L'\0')
+ serror(Ngt("command missing at end of input"));
+ else
+ serror(Ngt("command missing before `%lc'"),
+ (wint_t) cbuf.contents[cindex]);
+ return NULL;
+ }
- t = check_opening_token_at(cindex);
- if (t)
- return parse_compound_command(t);
+ t = check_opening_token_at(cindex);
+ if (t)
+ return parse_compound_command(t);
- // TODO parser.c: parse_command: 関数の解析
+ // TODO parser.c: parse_command: 関数の解析
- /* 普通の単純なコマンドを解析 */
- command_T *result = xmalloc(sizeof *result);
- redir_T **redirlastp;
+ /* 普通の単純なコマンドを解析 */
+ command_T *result = xmalloc(sizeof *result);
+ redir_T **redirlastp;
- result->next = NULL;
- result->c_lineno = cinfo->lineno;
- result->c_type = CT_SIMPLE;
- redirlastp = parse_assignments_and_redirects(result);
- result->c_words = parse_words_and_redirects(redirlastp, true);
+ result->next = NULL;
+ result->c_lineno = cinfo->lineno;
+ result->c_type = CT_SIMPLE;
+ redirlastp = parse_assignments_and_redirects(result);
+ result->c_words = parse_words_and_redirects(redirlastp, true);
- ensure_buffer(1);
- if (cbuf.contents[cindex] == L'(')
- serror(Ngt("invalid use of `%lc'"), (wint_t) cbuf.contents[cindex]);
- return result;
+ ensure_buffer(1);
+ if (cbuf.contents[cindex] == L'(')
+ serror(Ngt("invalid use of `%lc'"), (wint_t) cbuf.contents[cindex]);
+ return result;
}
/* 変数代入とリダイレクトを解析する。
* 結果を c->c_assigns と c->c_redirs に代入し、新しい redirlastp を返す。 */
static redir_T **parse_assignments_and_redirects(command_T *c)
{
- assign_T **assgnlastp = &c->c_assigns;
- redir_T **redirlastp = &c->c_redirs;
- assign_T *assgn;
- redir_T *redir;
-
- c->c_assigns = NULL;
- c->c_redirs = NULL;
- ensure_buffer(1);
- while (!is_command_delimiter_char(cbuf.contents[cindex])) {
- if ((redir = tryparse_redirect())) {
- *redirlastp = redir;
- redirlastp = &redir->next;
- } else if ((assgn = tryparse_assignment())) {
- *assgnlastp = assgn;
- assgnlastp = &assgn->next;
- } else {
- break;
- }
- ensure_buffer(1);
+ assign_T **assgnlastp = &c->c_assigns;
+ redir_T **redirlastp = &c->c_redirs;
+ assign_T *assgn;
+ redir_T *redir;
+
+ c->c_assigns = NULL;
+ c->c_redirs = NULL;
+ ensure_buffer(1);
+ while (!is_command_delimiter_char(cbuf.contents[cindex])) {
+ if ((redir = tryparse_redirect())) {
+ *redirlastp = redir;
+ redirlastp = &redir->next;
+ } else if ((assgn = tryparse_assignment())) {
+ *assgnlastp = assgn;
+ assgnlastp = &assgn->next;
+ } else {
+ break;
}
- return redirlastp;
+ ensure_buffer(1);
+ }
+ return redirlastp;
}
/* ワードとリダイレクトを解析する。
* first が true なら最初のワードは全ての種類のエイリアスを展開する。 */
static void **parse_words_and_redirects(redir_T **redirlastp, bool first)
{
- plist_T wordlist;
- redir_T *redir;
- wordunit_T *word;
-
- pl_init(&wordlist);
- ensure_buffer(1);
- while (!is_command_delimiter_char(cbuf.contents[cindex])) {
- if ((redir = tryparse_redirect())) {
- *redirlastp = redir;
- redirlastp = &redir->next;
- } else if ((word = parse_word(first ? anyalias : globalonly))) {
- pl_add(&wordlist, word);
- first = false;
- } else {
- break;
- }
- ensure_buffer(1);
+ plist_T wordlist;
+ redir_T *redir;
+ wordunit_T *word;
+
+ pl_init(&wordlist);
+ ensure_buffer(1);
+ while (!is_command_delimiter_char(cbuf.contents[cindex])) {
+ if ((redir = tryparse_redirect())) {
+ *redirlastp = redir;
+ redirlastp = &redir->next;
+ } else if ((word = parse_word(first ? anyalias : globalonly))) {
+ pl_add(&wordlist, word);
+ first = false;
+ } else {
+ break;
}
- return pl_toary(&wordlist);
+ ensure_buffer(1);
+ }
+ return pl_toary(&wordlist);
}
/* 0 個以上のリダイレクトを解析する。解析結果は *redirlastp に入る。
* *redirlastp は予め NULL を代入しておくこと。 */
static void parse_redirect_list(redir_T **lastp)
{
- redir_T *redir;
+ redir_T *redir;
- while ((redir = tryparse_redirect())) {
- *lastp = redir;
- lastp = &redir->next;
- }
+ while ((redir = tryparse_redirect())) {
+ *lastp = redir;
+ lastp = &redir->next;
+ }
}
/* 現在位置に変数代入があれば、それを解析して結果を返す。
* なければ、何もせず NULL を返す。 */
static assign_T *tryparse_assignment(void)
{
- size_t namelen;
+ size_t namelen;
- do
- namelen = skip_name(cbuf.contents + cindex) - (cbuf.contents + cindex);
- while (cbuf.contents[cindex + namelen] == L'\0' && read_more_input() == 0);
- if (namelen == 0 || cbuf.contents[cindex + namelen] != L'=')
- return NULL;
+ do
+ namelen = skip_name(cbuf.contents + cindex) - (cbuf.contents + cindex);
+ while (cbuf.contents[cindex + namelen] == L'\0' && read_more_input() == 0);
+ if (namelen == 0 || cbuf.contents[cindex + namelen] != L'=')
+ return NULL;
- assign_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->name = malloc_wcstombs(cbuf.contents + cindex, namelen);
- cindex += namelen + 1;
+ assign_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->name = malloc_wcstombs(cbuf.contents + cindex, namelen);
+ cindex += namelen + 1;
- ensure_buffer(1);
- if (is_token_delimiter_char(cbuf.contents[cindex])) {
- /* '=' の後は空文字列 */
- result->value = NULL;
- skip_blanks_and_comment();
- } else {
- result->value = parse_word(noalias);
- }
- return result;
+ ensure_buffer(1);
+ if (is_token_delimiter_char(cbuf.contents[cindex])) {
+ /* '=' の後は空文字列 */
+ result->value = NULL;
+ skip_blanks_and_comment();
+ } else {
+ result->value = parse_word(noalias);
+ }
+ return result;
}
/* 現在位置にリダイレクトがあれば、それを解析して結果を返す。
* なければ、何もせず NULL を返す。 */
static redir_T *tryparse_redirect(void)
{
- int fd;
+ int fd;
- ensure_buffer(2);
- if (iswdigit(cbuf.contents[cindex])) {
- wchar_t *endptr;
+ ensure_buffer(2);
+ if (iswdigit(cbuf.contents[cindex])) {
+ wchar_t *endptr;
reparse:
- errno = 0;
- fd = wcstol(cbuf.contents + cindex, &endptr, 10);
- if (errno)
- fd = -1; /* 無効な値 */
- if (!is_token_delimiter_char(*endptr)) {
- if (*endptr == L'\0' && read_more_input() == 0)
- goto reparse;
- else
- return NULL;
- } else if (*endptr != L'<' && *endptr != L'>') {
- return NULL;
- }
- cindex = endptr - cbuf.contents;
- } else if (cbuf.contents[cindex] == L'<') {
- fd = STDIN_FILENO;
- } else if (cbuf.contents[cindex] == L'>') {
- fd = STDOUT_FILENO;
- } else {
+ errno = 0;
+ fd = wcstol(cbuf.contents + cindex, &endptr, 10);
+ if (errno)
+ fd = -1; /* 無効な値 */
+ if (!is_token_delimiter_char(*endptr)) {
+ if (*endptr == L'\0' && read_more_input() == 0)
+ goto reparse;
+ else
return NULL;
+ } else if (*endptr != L'<' && *endptr != L'>') {
+ return NULL;
}
-
- redir_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->rd_fd = fd;
- ensure_buffer(3);
- assert(cbuf.contents[cindex] == L'<' || cbuf.contents[cindex] == L'>');
- if (cbuf.contents[cindex] == L'<') {
- switch (cbuf.contents[cindex + 1]) {
- case L'<':
- if (cbuf.contents[cindex + 2] == L'-') {
- result->rd_type = RT_HERERT; cindex += 3;
- } else {
- result->rd_type = RT_HERE; cindex += 2;
- }
- break;
- case L'>': result->rd_type = RT_INOUT; cindex += 2; break;
- case L'&': result->rd_type = RT_DUPIN; cindex += 2; break;
- default: result->rd_type = RT_INPUT; cindex += 1; break;
- }
- } else {
- switch (cbuf.contents[cindex + 1]) {
- case L'>': result->rd_type = RT_APPEND; cindex += 2; break;
- case L'|': result->rd_type = RT_CLOBBER; cindex += 2; break;
- case L'&': result->rd_type = RT_DUPOUT; cindex += 2; break;
- default: result->rd_type = RT_OUTPUT; cindex += 1; break;
- }
- }
- skip_blanks_and_comment();
- if (is_command_delimiter_char(cbuf.contents[cindex])) {
- serror(Ngt("redirect target not specified"));
- free(result);
- return NULL;
+ cindex = endptr - cbuf.contents;
+ } else if (cbuf.contents[cindex] == L'<') {
+ fd = STDIN_FILENO;
+ } else if (cbuf.contents[cindex] == L'>') {
+ fd = STDOUT_FILENO;
+ } else {
+ return NULL;
+ }
+
+ redir_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->rd_fd = fd;
+ ensure_buffer(3);
+ assert(cbuf.contents[cindex] == L'<' || cbuf.contents[cindex] == L'>');
+ if (cbuf.contents[cindex] == L'<') {
+ switch (cbuf.contents[cindex + 1]) {
+ case L'<':
+ if (cbuf.contents[cindex + 2] == L'-') {
+ result->rd_type = RT_HERERT; cindex += 3;
+ } else {
+ result->rd_type = RT_HERE; cindex += 2;
+ }
+ break;
+ case L'>': result->rd_type = RT_INOUT; cindex += 2; break;
+ case L'&': result->rd_type = RT_DUPIN; cindex += 2; break;
+ default: result->rd_type = RT_INPUT; cindex += 1; break;
}
- if (result->rd_type != RT_HERE && result->rd_type != RT_HERERT) {
- result->rd_filename = parse_word(globalonly);
- } else {
- size_t index = cindex;
- wchar_t *endofheredoc = parse_word_as_wcs();
- assert(index != cindex);
- if (wcschr(endofheredoc, L'\n'))
- serror(Ngt("end-of-heredoc indicator containing newline"));
- result->rd_hereend = endofheredoc;
- result->rd_herecontent = NULL;
+ } else {
+ switch (cbuf.contents[cindex + 1]) {
+ case L'>': result->rd_type = RT_APPEND; cindex += 2; break;
+ case L'|': result->rd_type = RT_CLOBBER; cindex += 2; break;
+ case L'&': result->rd_type = RT_DUPOUT; cindex += 2; break;
+ default: result->rd_type = RT_OUTPUT; cindex += 1; break;
}
- return result;
+ }
+ skip_blanks_and_comment();
+ if (is_command_delimiter_char(cbuf.contents[cindex])) {
+ serror(Ngt("redirect target not specified"));
+ free(result);
+ return NULL;
+ }
+ if (result->rd_type != RT_HERE && result->rd_type != RT_HERERT) {
+ result->rd_filename = parse_word(globalonly);
+ } else {
+ size_t index = cindex;
+ wchar_t *endofheredoc = parse_word_as_wcs();
+ assert(index != cindex);
+ if (wcschr(endofheredoc, L'\n'))
+ serror(Ngt("end-of-heredoc indicator containing newline"));
+ result->rd_hereend = endofheredoc;
+ result->rd_herecontent = NULL;
+ }
+ return result;
}
/* 現在位置のエイリアスを展開し、ワードを解析する。
* ワードがなくてもエラーを出さない。 */
static wordunit_T *parse_word_to(aliastype_T type, bool testfunc(wchar_t c))
{
- wordunit_T *first = NULL, **lastp = &first, *wu;
- bool indq = false; /* 二重引用符 " の中かどうか */
- size_t startindex = cindex;
+ wordunit_T *first = NULL, **lastp = &first, *wu;
+ bool indq = false; /* 二重引用符 " の中かどうか */
+ size_t startindex = cindex;
- // TODO parser.c: parse_word: エイリアス展開
- (void) type;
+ // TODO parser.c: parse_word: エイリアス展開
+ (void) type;
/* startindex から cindex の手前までの文字列を *lastp に追加する。 */
#define MAKE_WORDUNIT_STRING \
} \
} while (0)
- while (ensure_buffer(1),
- indq ? cbuf.contents[cindex] != L'\0'
- : !testfunc(cbuf.contents[cindex])) {
-
- switch (cbuf.contents[cindex]) {
- case L'\\':
- ensure_buffer(2);
- if (cbuf.contents[cindex + 1] == L'\n') { /* 行連結なら削除 */
- wb_remove(&cbuf, cindex, 2);
- cinfo->lineno++;
- continue;
- } else if (cbuf.contents[cindex + 1] != L'\0') {
- cindex += 2;
- continue;
- }
- break;
- case L'\n':
- cinfo->lineno++;
- read_more_input();
- break;
- case L'$':
- case L'`':
- MAKE_WORDUNIT_STRING;
- wu = parse_special_word_unit();
- startindex = cindex;
- if (wu) {
- *lastp = wu;
- lastp = &wu->next;
- continue;
- } else if (cbuf.contents[cindex] == L'\0') {
- continue;
- }
- break;
- case L'\'':
- if (!indq) {
- cindex++;
- skip_to_next_single_quote();
- }
- break;
- case L'"':
- indq = !indq;
- /* falls thru! */
- default:
- break;
- }
+ while (ensure_buffer(1),
+ indq ? cbuf.contents[cindex] != L'\0'
+ : !testfunc(cbuf.contents[cindex])) {
+
+ switch (cbuf.contents[cindex]) {
+ case L'\\':
+ ensure_buffer(2);
+ if (cbuf.contents[cindex + 1] == L'\n') { /* 行連結なら削除 */
+ wb_remove(&cbuf, cindex, 2);
+ cinfo->lineno++;
+ continue;
+ } else if (cbuf.contents[cindex + 1] != L'\0') {
+ cindex += 2;
+ continue;
+ }
+ break;
+ case L'\n':
+ cinfo->lineno++;
+ read_more_input();
+ break;
+ case L'$':
+ case L'`':
+ MAKE_WORDUNIT_STRING;
+ wu = parse_special_word_unit();
+ startindex = cindex;
+ if (wu) {
+ *lastp = wu;
+ lastp = &wu->next;
+ continue;
+ } else if (cbuf.contents[cindex] == L'\0') {
+ continue;
+ }
+ break;
+ case L'\'':
+ if (!indq) {
cindex++;
+ skip_to_next_single_quote();
+ }
+ break;
+ case L'"':
+ indq = !indq;
+ /* falls thru! */
+ default:
+ break;
}
- MAKE_WORDUNIT_STRING;
+ cindex++;
+ }
+ MAKE_WORDUNIT_STRING;
- if (indq)
- serror(Ngt("double-quote not closed"));
+ if (indq)
+ serror(Ngt("double-quote not closed"));
- skip_blanks_and_comment();
- return first;
+ skip_blanks_and_comment();
+ return first;
}
/* 次の単一引用符 ' が現れるまで cindex を増やして飛ばす。
* ' が見付からずに EOF に達したらエラーを出す。 */
static void skip_to_next_single_quote(void)
{
- for (;;) {
- ensure_buffer(1);
- switch (cbuf.contents[cindex]) {
- case L'\'':
- return;
- case L'\0':
- if (read_more_input() != 0) {
- serror(Ngt("single-quote not closed"));
- return;
- }
- break;
- case L'\n':
- cinfo->lineno++;
- /* falls thru! */
- default:
- break;
- }
- cindex++;
+ for (;;) {
+ ensure_buffer(1);
+ switch (cbuf.contents[cindex]) {
+ case L'\'':
+ return;
+ case L'\0':
+ if (read_more_input() != 0) {
+ serror(Ngt("single-quote not closed"));
+ return;
+ }
+ break;
+ case L'\n':
+ cinfo->lineno++;
+ /* falls thru! */
+ default:
+ break;
}
+ cindex++;
+ }
}
/* '$' または '`' で始まるパラメータ展開やコマンド置換を解析する。
* まま返る。さもなくば、cindex は少なくとも 1 以上増える。 */
static wordunit_T *parse_special_word_unit(void)
{
- switch (cbuf.contents[cindex++]) {
- case L'$':
- ensure_buffer(2);
- switch (cbuf.contents[cindex]) {
- case L'{':
- return parse_paramexp_in_brace();
- case L'(':
- if (cbuf.contents[cindex + 1] == L'(') {
- wordunit_T *wu = tryparse_arith();
- if (wu)
- return wu;
- }
- return parse_cmdsubst_in_paren();
- default:
- return parse_paramexp_raw();
- }
- case L'`':
- return parse_cmdsubst_in_backquote();
+ switch (cbuf.contents[cindex++]) {
+ case L'$':
+ ensure_buffer(2);
+ switch (cbuf.contents[cindex]) {
+ case L'{':
+ return parse_paramexp_in_brace();
+ case L'(':
+ if (cbuf.contents[cindex + 1] == L'(') {
+ wordunit_T *wu = tryparse_arith();
+ if (wu)
+ return wu;
+ }
+ return parse_cmdsubst_in_paren();
default:
- assert(false);
+ return parse_paramexp_raw();
}
+ case L'`':
+ return parse_cmdsubst_in_backquote();
+ default:
+ assert(false);
+ }
}
/* { } で囲んでいないパラメータを解析する。
* NULL を返す。 */
static wordunit_T *parse_paramexp_raw(void)
{
- paramexp_T *pe;
- size_t namelen; /* 変数名の長さ */
-
- ensure_buffer(1);
- switch (cbuf.contents[cindex]) {
- case L'@': case L'*': case L'#': case L'?':
- case L'-': case L'$': case L'!':
- namelen = 1;
- goto success;
- }
- if (!is_name_char(cbuf.contents[cindex]))
- goto fail;
-
- do
- namelen = skip_name(cbuf.contents + cindex) - (cbuf.contents + cindex);
- while (cbuf.contents[cindex + namelen] == L'\0' && read_more_input() == 0);
- if (namelen == 0) {
- assert(L'0' <= cbuf.contents[cindex] && cbuf.contents[cindex] <= L'9');
- namelen++;
- }
+ paramexp_T *pe;
+ size_t namelen; /* 変数名の長さ */
+
+ ensure_buffer(1);
+ switch (cbuf.contents[cindex]) {
+ case L'@': case L'*': case L'#': case L'?':
+ case L'-': case L'$': case L'!':
+ namelen = 1;
+ goto success;
+ }
+ if (!is_name_char(cbuf.contents[cindex]))
+ goto fail;
+
+ do
+ namelen = skip_name(cbuf.contents + cindex) - (cbuf.contents + cindex);
+ while (cbuf.contents[cindex + namelen] == L'\0' && read_more_input() == 0);
+ if (namelen == 0) {
+ assert(L'0' <= cbuf.contents[cindex] && cbuf.contents[cindex] <= L'9');
+ namelen++;
+ }
success:
- pe = xmalloc(sizeof *pe);
- pe->pe_type = PT_NONE;
- pe->pe_name = malloc_wcstombs(cbuf.contents + cindex, namelen);
- pe->pe_match = pe->pe_subst = NULL;
-
- wordunit_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->wu_type = WT_PARAM;
- result->wu_param = pe;
- cindex += namelen;
- return result;
+ pe = xmalloc(sizeof *pe);
+ pe->pe_type = PT_NONE;
+ pe->pe_name = malloc_wcstombs(cbuf.contents + cindex, namelen);
+ pe->pe_match = pe->pe_subst = NULL;
+
+ wordunit_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->wu_type = WT_PARAM;
+ result->wu_param = pe;
+ cindex += namelen;
+ return result;
fail:
- cindex--;
- return NULL;
+ cindex--;
+ return NULL;
}
/* "${" で始まるパラメータ展開を解析する。
* 指した状態で返る。 */
static wordunit_T *parse_paramexp_in_brace(void)
{
- paramexp_T *pe = xmalloc(sizeof *pe);
- pe->pe_type = 0;
- pe->pe_name = NULL;
- pe->pe_match = pe->pe_subst = NULL;
-
- wordunit_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->wu_type = WT_PARAM;
- result->wu_param = pe;
-
- assert(cbuf.contents[cindex] == L'{');
+ paramexp_T *pe = xmalloc(sizeof *pe);
+ pe->pe_type = 0;
+ pe->pe_name = NULL;
+ pe->pe_match = pe->pe_subst = NULL;
+
+ wordunit_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->wu_type = WT_PARAM;
+ result->wu_param = pe;
+
+ assert(cbuf.contents[cindex] == L'{');
+ cindex++;
+
+ /* PT_NUMBER を解析 */
+ ensure_buffer(3);
+ if (cbuf.contents[cindex] == L'#'
+ && cbuf.contents[cindex + 1] != L'}'
+ && (cbuf.contents[cindex + 1] != L'#'
+ || (cbuf.contents[cindex + 1] != L'\0'
+ && cbuf.contents[cindex + 2] == L'}'))) {
+ pe->pe_type |= PT_NUMBER;
cindex++;
-
- /* PT_NUMBER を解析 */
- ensure_buffer(3);
- if (cbuf.contents[cindex] == L'#'
- && cbuf.contents[cindex + 1] != L'}'
- && (cbuf.contents[cindex + 1] != L'#'
- || (cbuf.contents[cindex + 1] != L'\0'
- && cbuf.contents[cindex + 2] == L'}'))) {
- pe->pe_type |= PT_NUMBER;
- cindex++;
- }
-
- /* 変数名を取り出す */
- size_t namestartindex = cindex;
- switch (cbuf.contents[cindex]) {
- case L'@': case L'*': case L'#': case L'?':
- case L'-': case L'$': case L'!':
- cindex++;
- goto make_name;
- }
- do
- while (is_name_char(cbuf.contents[cindex]))
- cindex++;
- while (cbuf.contents[cindex] == L'\0' && read_more_input == 0);
- if (namestartindex == cindex) {
- serror(Ngt("parameter name missing"));
- goto fail;
- }
+ }
+
+ /* 変数名を取り出す */
+ size_t namestartindex = cindex;
+ switch (cbuf.contents[cindex]) {
+ case L'@': case L'*': case L'#': case L'?':
+ case L'-': case L'$': case L'!':
+ cindex++;
+ goto make_name;
+ }
+ do
+ while (is_name_char(cbuf.contents[cindex]))
+ cindex++;
+ while (cbuf.contents[cindex] == L'\0' && read_more_input == 0);
+ if (namestartindex == cindex) {
+ serror(Ngt("parameter name missing"));
+ goto fail;
+ }
make_name:
- pe->pe_name = malloc_wcstombs(
- cbuf.contents + namestartindex, cindex - namestartindex);
-
- /* PT_COLON を解析 */
- ensure_buffer(3);
- if (cbuf.contents[cindex] == L':') {
- pe->pe_type |= PT_COLON;
- cindex++;
- }
+ pe->pe_name = malloc_wcstombs(
+ cbuf.contents + namestartindex, cindex - namestartindex);
- /* '-' とか '+' とか '#' とかを解析 */
- switch (cbuf.contents[cindex]) {
- case L'-': pe->pe_type |= PT_MINUS; goto parse_subst;
- case L'+': pe->pe_type |= PT_PLUS; goto parse_subst;
- case L'=': pe->pe_type |= PT_ASSIGN; goto parse_subst;
- case L'?': pe->pe_type |= PT_ERROR; goto parse_subst;
- case L'#': pe->pe_type |= PT_MATCH | PT_MATCHHEAD; goto parse_match;
- case L'%': pe->pe_type |= PT_MATCH | PT_MATCHTAIL; goto parse_match;
- case L'/': pe->pe_type |= PT_SUBST | PT_MATCHLONGEST; goto parse_match;
- case L'}':
- pe->pe_type |= PT_NONE;
- if (pe->pe_type & PT_COLON)
- serror(Ngt("invalid use of `:' in parameter expansion"));
- goto check_closing_paren_and_finish;
- case L'\0': case L'\n':
- serror(Ngt("`%ls' missing"), L"}");
- goto fail;
- default:
- serror(Ngt("invalid character `%lc' in parameter expansion"),
- (wint_t) cbuf.contents[cindex]);
- goto fail;
- }
+ /* PT_COLON を解析 */
+ ensure_buffer(3);
+ if (cbuf.contents[cindex] == L':') {
+ pe->pe_type |= PT_COLON;
+ cindex++;
+ }
+
+ /* '-' とか '+' とか '#' とかを解析 */
+ switch (cbuf.contents[cindex]) {
+ case L'-': pe->pe_type |= PT_MINUS; goto parse_subst;
+ case L'+': pe->pe_type |= PT_PLUS; goto parse_subst;
+ case L'=': pe->pe_type |= PT_ASSIGN; goto parse_subst;
+ case L'?': pe->pe_type |= PT_ERROR; goto parse_subst;
+ case L'#': pe->pe_type |= PT_MATCH | PT_MATCHHEAD; goto parse_match;
+ case L'%': pe->pe_type |= PT_MATCH | PT_MATCHTAIL; goto parse_match;
+ case L'/': pe->pe_type |= PT_SUBST | PT_MATCHLONGEST; goto parse_match;
+ case L'}':
+ pe->pe_type |= PT_NONE;
+ if (pe->pe_type & PT_COLON)
+ serror(Ngt("invalid use of `:' in parameter expansion"));
+ goto check_closing_paren_and_finish;
+ case L'\0': case L'\n':
+ serror(Ngt("`%ls' missing"), L"}");
+ goto fail;
+ default:
+ serror(Ngt("invalid character `%lc' in parameter expansion"),
+ (wint_t) cbuf.contents[cindex]);
+ goto fail;
+ }
parse_match:
- if (pe->pe_type & PT_COLON) {
- if ((pe->pe_type & PT_MASK) != PT_SUBST)
- serror(Ngt("invalid use of `:' in parameter expansion"));
- cindex += 1;
- } else if (cbuf.contents[cindex] == cbuf.contents[cindex + 1]) {
- if ((pe->pe_type & PT_MASK) == PT_MATCH)
- pe->pe_type |= PT_MATCHLONGEST;
- else
- pe->pe_type |= PT_SUBSTALL;
- cindex += 2;
- } else if (cbuf.contents[cindex] == L'/') {
- if (cbuf.contents[cindex + 1] == L'#') {
- pe->pe_type |= PT_MATCHHEAD;
- cindex += 2;
- } else if (cbuf.contents[cindex + 1] == L'%') {
- pe->pe_type |= PT_MATCHTAIL;
- cindex += 2;
- } else {
- cindex += 1;
- }
- } else {
- cindex += 1;
- }
- if ((pe->pe_type & PT_MASK) == PT_MATCH) {
- pe->pe_match = parse_word_to(noalias, is_closing_brace);
- goto check_closing_paren_and_finish;
+ if (pe->pe_type & PT_COLON) {
+ if ((pe->pe_type & PT_MASK) != PT_SUBST)
+ serror(Ngt("invalid use of `:' in parameter expansion"));
+ cindex += 1;
+ } else if (cbuf.contents[cindex] == cbuf.contents[cindex + 1]) {
+ if ((pe->pe_type & PT_MASK) == PT_MATCH)
+ pe->pe_type |= PT_MATCHLONGEST;
+ else
+ pe->pe_type |= PT_SUBSTALL;
+ cindex += 2;
+ } else if (cbuf.contents[cindex] == L'/') {
+ if (cbuf.contents[cindex + 1] == L'#') {
+ pe->pe_type |= PT_MATCHHEAD;
+ cindex += 2;
+ } else if (cbuf.contents[cindex + 1] == L'%') {
+ pe->pe_type |= PT_MATCHTAIL;
+ cindex += 2;
} else {
- pe->pe_match = parse_word_to(noalias, is_slash_or_closing_brace);
+ cindex += 1;
}
-
- /* ensure_buffer(1); */
- if (cbuf.contents[cindex] != L'/')
- goto check_closing_paren_and_finish;
+ } else {
+ cindex += 1;
+ }
+ if ((pe->pe_type & PT_MASK) == PT_MATCH) {
+ pe->pe_match = parse_word_to(noalias, is_closing_brace);
+ goto check_closing_paren_and_finish;
+ } else {
+ pe->pe_match = parse_word_to(noalias, is_slash_or_closing_brace);
+ }
+
+ /* ensure_buffer(1); */
+ if (cbuf.contents[cindex] != L'/')
+ goto check_closing_paren_and_finish;
parse_subst:
- cindex++;
- pe->pe_subst = parse_word_to(noalias, is_closing_brace);
+ cindex++;
+ pe->pe_subst = parse_word_to(noalias, is_closing_brace);
check_closing_paren_and_finish:
- /* ensure_buffer(1); */
- if (cbuf.contents[cindex] == L'}')
- cindex++;
- else
- serror(Ngt("`%ls' missing"), L"}");
- if ((pe->pe_type & PT_NUMBER) && (pe->pe_type & PT_MASK) != PT_NONE)
- serror(Ngt("invalid use of `#' flag in parameter expansion"));
+ /* ensure_buffer(1); */
+ if (cbuf.contents[cindex] == L'}')
+ cindex++;
+ else
+ serror(Ngt("`%ls' missing"), L"}");
+ if ((pe->pe_type & PT_NUMBER) && (pe->pe_type & PT_MASK) != PT_NONE)
+ serror(Ngt("invalid use of `#' flag in parameter expansion"));
fail:
- return result;
+ return result;
}
/* "$(" で始まるコマンド置換を解析する。
* 返る。 */
static wordunit_T *parse_cmdsubst_in_paren(void)
{
- // TODO parser: parse_cmdsubst_in_paren: エイリアスを一時的に無効にする
- assert(cbuf.contents[cindex] == L'(');
+ // TODO parser: parse_cmdsubst_in_paren: エイリアスを一時的に無効にする
+ assert(cbuf.contents[cindex] == L'(');
- size_t startindex = ++cindex;
- andorsfree(parse_compound_list());
- assert(startindex <= cindex);
+ size_t startindex = ++cindex;
+ andorsfree(parse_compound_list());
+ assert(startindex <= cindex);
- wordunit_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->wu_type = WT_CMDSUB;
- result->wu_cmdsub = xwcsndup(
- cbuf.contents + startindex, cindex - startindex);
+ wordunit_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->wu_type = WT_CMDSUB;
+ result->wu_cmdsub = xwcsndup(
+ cbuf.contents + startindex, cindex - startindex);
- ensure_buffer(1);
- if (cbuf.contents[cindex] == L')')
- cindex++;
- else
- serror(Ngt("`%ls' missing"), L")");
- return result;
+ ensure_buffer(1);
+ if (cbuf.contents[cindex] == L')')
+ cindex++;
+ else
+ serror(Ngt("`%ls' missing"), L")");
+ return result;
}
/* '`' で始まるコマンド置換を解析する。
* 指した状態で返る。 */
static wordunit_T *parse_cmdsubst_in_backquote(void)
{
- xwcsbuf_T buf;
- wordunit_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->wu_type = WT_CMDSUB;
-
- assert(cbuf.contents[cindex - 1] == L'`');
- wb_init(&buf);
- for (;;) {
- ensure_buffer(1);
- switch (cbuf.contents[cindex]) {
- case L'`':
- cindex++;
- goto end;
- case L'\0':
- if (read_more_input() != 0) {
- serror(Ngt("backquoted command substitution not closed"));
- goto end;
- }
- break;
- case L'\\':
- cindex++;
- ensure_buffer(1);
- switch (cbuf.contents[cindex]) {
- case L'$': case L'`': case L'\\':
- goto default_;
- default:
- wb_wccat(&buf, L'\\');
- continue;
- }
- case L'\n':
- cinfo->lineno++;
- /* falls thru! */
- default: default_:
- wb_wccat(&buf, cbuf.contents[cindex]);
- cindex++;
- break;
- }
+ xwcsbuf_T buf;
+ wordunit_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->wu_type = WT_CMDSUB;
+
+ assert(cbuf.contents[cindex - 1] == L'`');
+ wb_init(&buf);
+ for (;;) {
+ ensure_buffer(1);
+ switch (cbuf.contents[cindex]) {
+ case L'`':
+ cindex++;
+ goto end;
+ case L'\0':
+ if (read_more_input() != 0) {
+ serror(Ngt("backquoted command substitution not closed"));
+ goto end;
+ }
+ break;
+ case L'\\':
+ cindex++;
+ ensure_buffer(1);
+ switch (cbuf.contents[cindex]) {
+ case L'$': case L'`': case L'\\':
+ goto default_;
+ default:
+ wb_wccat(&buf, L'\\');
+ continue;
+ }
+ case L'\n':
+ cinfo->lineno++;
+ /* falls thru! */
+ default: default_:
+ wb_wccat(&buf, cbuf.contents[cindex]);
+ cindex++;
+ break;
}
+ }
end:
- result->wu_cmdsub = wb_towcs(&buf);
- return result;
+ result->wu_cmdsub = wb_towcs(&buf);
+ return result;
}
/* "$((" で始まる数式展開を解析する。
* NULL を返す。 */
static wordunit_T *tryparse_arith(void)
{
- size_t savecindex = cindex;
- assert(cbuf.contents[cindex] == L'(' && cbuf.contents[cindex + 1] == L'(');
- cindex += 2;
+ size_t savecindex = cindex;
+ assert(cbuf.contents[cindex] == L'(' && cbuf.contents[cindex + 1] == L'(');
+ cindex += 2;
- wordunit_T *first = NULL, **lastp = &first, *wu;
- size_t startindex = cindex;
- int nestparen = 0;
-
- for (;;) {
- ensure_buffer(1);
- switch (cbuf.contents[cindex]) {
- case L'\\':
- ensure_buffer(2);
- if (cbuf.contents[cindex + 1] == L'\n') { /* 行連結なら削除 */
- wb_remove(&cbuf, cindex, 2);
- cinfo->lineno++;
- continue;
- } else if (cbuf.contents[cindex + 1] != L'\0') {
- cindex += 2;
- continue;
- }
- break;
- case L'$':
- case L'`':
- MAKE_WORDUNIT_STRING;
- wu = parse_special_word_unit();
- startindex = cindex;
- if (wu) {
- *lastp = wu;
- lastp = &wu->next;
- continue;
- } else if (cbuf.contents[cindex] == L'\0') {
- continue;
- }
- break;
- case L'(':
- nestparen++;
- break;
- case L')':
- nestparen--;
- if (nestparen < 0) {
- ensure_buffer(2);
- if (cbuf.contents[cindex + 1] == L')')
- goto end;
- else
- goto fail;
- }
- break;
- default:
- break;
- }
- cindex++;
+ wordunit_T *first = NULL, **lastp = &first, *wu;
+ size_t startindex = cindex;
+ int nestparen = 0;
+
+ for (;;) {
+ ensure_buffer(1);
+ switch (cbuf.contents[cindex]) {
+ case L'\\':
+ ensure_buffer(2);
+ if (cbuf.contents[cindex + 1] == L'\n') { /* 行連結なら削除 */
+ wb_remove(&cbuf, cindex, 2);
+ cinfo->lineno++;
+ continue;
+ } else if (cbuf.contents[cindex + 1] != L'\0') {
+ cindex += 2;
+ continue;
+ }
+ break;
+ case L'$':
+ case L'`':
+ MAKE_WORDUNIT_STRING;
+ wu = parse_special_word_unit();
+ startindex = cindex;
+ if (wu) {
+ *lastp = wu;
+ lastp = &wu->next;
+ continue;
+ } else if (cbuf.contents[cindex] == L'\0') {
+ continue;
+ }
+ break;
+ case L'(':
+ nestparen++;
+ break;
+ case L')':
+ nestparen--;
+ if (nestparen < 0) {
+ ensure_buffer(2);
+ if (cbuf.contents[cindex + 1] == L')')
+ goto end;
+ else
+ goto fail;
+ }
+ break;
+ default:
+ break;
}
+ cindex++;
+ }
end:
- MAKE_WORDUNIT_STRING;
- cindex += 2;
+ MAKE_WORDUNIT_STRING;
+ cindex += 2;
- wordunit_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->wu_type = WT_ARITH;
- result->wu_arith = first;
- return result;
+ wordunit_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->wu_type = WT_ARITH;
+ result->wu_arith = first;
+ return result;
fail:
- wordfree(first);
- cindex = savecindex;
- return NULL;
+ wordfree(first);
+ cindex = savecindex;
+ return NULL;
}
/* 現在位置にある WORD トークンを取り出す。
* cindex は次のトークンを指すように skip_blanks_and_comment した位置まで進む */
static wchar_t *parse_word_as_wcs(void)
{
- size_t index = cindex;
- wordfree(parse_word(globalonly));
+ size_t index = cindex;
+ wordfree(parse_word(globalonly));
- /* 元のインデックスと現在のインデックスの間にあるワードを取り出す */
- wchar_t *result = xwcsndup(cbuf.contents + index, cindex - index);
- /* ワード末尾の空白を除去 */
- index = cindex - index;
- while (index-- > 0 && iswblank(result[index]));
- result[++index] = L'\0';
- return result;
+ /* 元のインデックスと現在のインデックスの間にあるワードを取り出す */
+ wchar_t *result = xwcsndup(cbuf.contents + index, cindex - index);
+ /* ワード末尾の空白を除去 */
+ index = cindex - index;
+ while (index-- > 0 && iswblank(result[index]));
+ result[++index] = L'\0';
+ return result;
}
/* 複合コマンドを解析する。command はコマンド名。 */
* の呼出しおよびリダイレクトの解析をせずに戻る。 */
static command_T *parse_compound_command(const wchar_t *command)
{
- command_T *result;
- switch (command[0]) {
- case L'(':
- result = parse_group(CT_SUBSHELL);
- break;
- case L'{':
- result = parse_group(CT_GROUP);
- break;
- case L'i':
- result = parse_if();
- break;
- case L'f':
- result = parse_for();
- break;
- case L'w':
- result = parse_while(true);
- break;
- case L'u':
- result = parse_while(false);
- break;
- case L'c':
- result = parse_case();
- break;
- default:
- assert(false);
- }
- skip_blanks_and_comment();
- parse_redirect_list(&result->c_redirs);
- return result;
+ command_T *result;
+ switch (command[0]) {
+ case L'(':
+ result = parse_group(CT_SUBSHELL);
+ break;
+ case L'{':
+ result = parse_group(CT_GROUP);
+ break;
+ case L'i':
+ result = parse_if();
+ break;
+ case L'f':
+ result = parse_for();
+ break;
+ case L'w':
+ result = parse_while(true);
+ break;
+ case L'u':
+ result = parse_while(false);
+ break;
+ case L'c':
+ result = parse_case();
+ break;
+ default:
+ assert(false);
+ }
+ skip_blanks_and_comment();
+ parse_redirect_list(&result->c_redirs);
+ return result;
}
/* グループコマンドを解析する。type は CT_GROUP か CT_SUBSHELL。 */
static command_T *parse_group(commandtype_T type)
{
- const wchar_t *terminator;
+ const wchar_t *terminator;
- if (type == CT_GROUP) {
- assert(cbuf.contents[cindex] == L'{');
- terminator = L"}";
- } else if (type == CT_SUBSHELL) {
- assert(cbuf.contents[cindex] == L'(');
- terminator = L")";
- } else {
- assert(false);
- }
- cindex++;
-
- command_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->c_type = type;
- result->c_lineno = cinfo->lineno;
- result->c_redirs = NULL;
- result->c_subcmds = parse_compound_list();
- if (!result->c_subcmds)
- serror(Ngt("no commands in command group"));
- if (cbuf.contents[cindex] != terminator[0])
- print_errmsg_token_missing(terminator, cindex);
- cindex++;
- return result;
+ if (type == CT_GROUP) {
+ assert(cbuf.contents[cindex] == L'{');
+ terminator = L"}";
+ } else if (type == CT_SUBSHELL) {
+ assert(cbuf.contents[cindex] == L'(');
+ terminator = L")";
+ } else {
+ assert(false);
+ }
+ cindex++;
+
+ command_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->c_type = type;
+ result->c_lineno = cinfo->lineno;
+ result->c_redirs = NULL;
+ result->c_subcmds = parse_compound_list();
+ if (!result->c_subcmds)
+ serror(Ngt("no commands in command group"));
+ if (cbuf.contents[cindex] != terminator[0])
+ print_errmsg_token_missing(terminator, cindex);
+ cindex++;
+ return result;
}
/* if コマンドを解析する */
static command_T *parse_if(void)
{
- assert(is_token_at(L"if", cindex));
- cindex += 2;
-
- ifcommand_T *first = NULL, **lastp = &first;
- command_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->c_type = CT_IF;
- result->c_lineno = cinfo->lineno;
- result->c_redirs = NULL;
-
- bool els = false;
- while (!cerror) {
- ifcommand_T *ic = xmalloc(sizeof *ic);
- *lastp = ic;
- lastp = &ic->next;
- ic->next = NULL;
- if (!els) {
- ic->ic_condition = parse_compound_list();
- if (!ic->ic_condition)
- serror(Ngt("no commands between `if' and `then'"));
- ensure_buffer(5);
- if (is_token_at(L"then", cindex))
- cindex += 4;
- else
- print_errmsg_token_missing(L"then", cindex);
- } else {
- ic->ic_condition = NULL;
- }
- ic->ic_commands = parse_compound_list();
- if (!ic->ic_commands)
- serror(Ngt("no commands after `%ls'"), els ? L"else" : L"then");
- ensure_buffer(5);
- if (!els) {
- if (is_token_at(L"else", cindex)) {
- cindex += 4;
- els = true;
- } else if (is_token_at(L"elif", cindex)) {
- cindex += 4;
- } else if (is_token_at(L"fi", cindex)) {
- cindex += 2;
- break;
- } else {
- print_errmsg_token_missing(L"fi", cindex);
- }
- } else {
- if (is_token_at(L"fi", cindex))
- cindex += 2;
- else
- print_errmsg_token_missing(L"fi", cindex);
- break;
- }
+ assert(is_token_at(L"if", cindex));
+ cindex += 2;
+
+ ifcommand_T *first = NULL, **lastp = &first;
+ command_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->c_type = CT_IF;
+ result->c_lineno = cinfo->lineno;
+ result->c_redirs = NULL;
+
+ bool els = false;
+ while (!cerror) {
+ ifcommand_T *ic = xmalloc(sizeof *ic);
+ *lastp = ic;
+ lastp = &ic->next;
+ ic->next = NULL;
+ if (!els) {
+ ic->ic_condition = parse_compound_list();
+ if (!ic->ic_condition)
+ serror(Ngt("no commands between `if' and `then'"));
+ ensure_buffer(5);
+ if (is_token_at(L"then", cindex))
+ cindex += 4;
+ else
+ print_errmsg_token_missing(L"then", cindex);
+ } else {
+ ic->ic_condition = NULL;
}
- result->c_ifcmds = first;
- return result;
+ ic->ic_commands = parse_compound_list();
+ if (!ic->ic_commands)
+ serror(Ngt("no commands after `%ls'"), els ? L"else" : L"then");
+ ensure_buffer(5);
+ if (!els) {
+ if (is_token_at(L"else", cindex)) {
+ cindex += 4;
+ els = true;
+ } else if (is_token_at(L"elif", cindex)) {
+ cindex += 4;
+ } else if (is_token_at(L"fi", cindex)) {
+ cindex += 2;
+ break;
+ } else {
+ print_errmsg_token_missing(L"fi", cindex);
+ }
+ } else {
+ if (is_token_at(L"fi", cindex))
+ cindex += 2;
+ else
+ print_errmsg_token_missing(L"fi", cindex);
+ break;
+ }
+ }
+ result->c_ifcmds = first;
+ return result;
}
/* for コマンドを解析する */
static command_T *parse_for(void)
{
- assert(is_token_at(L"for", cindex));
- cindex += 3;
+ assert(is_token_at(L"for", cindex));
+ cindex += 3;
+ skip_blanks_and_comment();
+
+ command_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->c_type = CT_FOR;
+ result->c_lineno = cinfo->lineno;
+ result->c_redirs = NULL;
+ result->c_forname = parse_word_as_wcs();
+ if (result->c_forname[0] == L'\0' || *skip_name(result->c_forname) != L'\0')
+ serror(Ngt("`%ls' is not valid identifier"), result->c_forname);
+ skip_to_next_token();
+ ensure_buffer(3);
+ if (is_token_at(L"in", cindex)) {
+ redir_T *redirs = NULL;
+ cindex += 2;
skip_blanks_and_comment();
-
- command_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->c_type = CT_FOR;
- result->c_lineno = cinfo->lineno;
- result->c_redirs = NULL;
- result->c_forname = parse_word_as_wcs();
- if (result->c_forname[0] == L'\0' || *skip_name(result->c_forname) != L'\0')
- serror(Ngt("`%ls' is not valid identifier"), result->c_forname);
- skip_to_next_token();
- ensure_buffer(3);
- if (is_token_at(L"in", cindex)) {
- redir_T *redirs = NULL;
- cindex += 2;
- skip_blanks_and_comment();
- result->c_forwords = parse_words_and_redirects(&redirs, false);
- if (redirs) {
- serror(Ngt("redirections not allowed after `in'"));
- redirsfree(redirs);
- }
- } else {
- result->c_forwords = NULL;
+ result->c_forwords = parse_words_and_redirects(&redirs, false);
+ if (redirs) {
+ serror(Ngt("redirections not allowed after `in'"));
+ redirsfree(redirs);
}
- if (cbuf.contents[cindex] == L';')
- cindex++;
- skip_to_next_token();
- ensure_buffer(3);
- if (is_token_at(L"do", cindex))
- cindex += 2;
- else
- print_errmsg_token_missing(L"do", cindex);
- result->c_forcmds = parse_compound_list();
- if (!result->c_forcmds)
- serror(Ngt("no commands between `do' and `done'"));
- ensure_buffer(5);
- if (is_token_at(L"done", cindex))
- cindex += 4;
- else
- print_errmsg_token_missing(L"done", cindex);
- return result;
+ } else {
+ result->c_forwords = NULL;
+ }
+ if (cbuf.contents[cindex] == L';')
+ cindex++;
+ skip_to_next_token();
+ ensure_buffer(3);
+ if (is_token_at(L"do", cindex))
+ cindex += 2;
+ else
+ print_errmsg_token_missing(L"do", cindex);
+ result->c_forcmds = parse_compound_list();
+ if (!result->c_forcmds)
+ serror(Ngt("no commands between `do' and `done'"));
+ ensure_buffer(5);
+ if (is_token_at(L"done", cindex))
+ cindex += 4;
+ else
+ print_errmsg_token_missing(L"done", cindex);
+ return result;
}
/* while/until コマンドを解析する */
static command_T *parse_while(bool whltype)
{
- assert(is_token_at(whltype ? L"while" : L"until", cindex));
- cindex += 5;
-
- command_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->c_type = CT_WHILE;
- result->c_lineno = cinfo->lineno;
- result->c_redirs = NULL;
- result->c_whltype = whltype;
- result->c_whlcond = parse_compound_list();
- if (!result->c_whlcond)
- serror(Ngt("no commands after `%ls'"), whltype ? L"while" : L"until");
- ensure_buffer(3);
- if (is_token_at(L"do", cindex))
- cindex += 2;
- else
- print_errmsg_token_missing(L"do", cindex);
- result->c_whlcmds = parse_compound_list();
- if (!result->c_whlcmds)
- serror(Ngt("no commands between `do' and `done'"));
- ensure_buffer(5);
- if (is_token_at(L"done", cindex))
- cindex += 4;
- else
- print_errmsg_token_missing(L"done", cindex);
- return result;
+ assert(is_token_at(whltype ? L"while" : L"until", cindex));
+ cindex += 5;
+
+ command_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->c_type = CT_WHILE;
+ result->c_lineno = cinfo->lineno;
+ result->c_redirs = NULL;
+ result->c_whltype = whltype;
+ result->c_whlcond = parse_compound_list();
+ if (!result->c_whlcond)
+ serror(Ngt("no commands after `%ls'"), whltype ? L"while" : L"until");
+ ensure_buffer(3);
+ if (is_token_at(L"do", cindex))
+ cindex += 2;
+ else
+ print_errmsg_token_missing(L"do", cindex);
+ result->c_whlcmds = parse_compound_list();
+ if (!result->c_whlcmds)
+ serror(Ngt("no commands between `do' and `done'"));
+ ensure_buffer(5);
+ if (is_token_at(L"done", cindex))
+ cindex += 4;
+ else
+ print_errmsg_token_missing(L"done", cindex);
+ return result;
}
/* case コマンドを解析する */
static command_T *parse_case(void)
{
- assert(is_token_at(L"case", cindex));
+ assert(is_token_at(L"case", cindex));
+ cindex += 4;
+ skip_blanks_and_comment();
+
+ command_T *result = xmalloc(sizeof *result);
+ result->next = NULL;
+ result->c_type = CT_CASE;
+ result->c_lineno = cinfo->lineno;
+ result->c_redirs = NULL;
+ result->c_casword = parse_word(globalonly);
+ if (!result->c_casword)
+ serror(Ngt("no word after `%ls'"), L"case");
+ skip_to_next_token();
+ ensure_buffer(3);
+ if (is_token_at(L"in", cindex))
+ cindex += 2;
+ else
+ print_errmsg_token_missing(L"in", cindex);
+ result->c_casitems = parse_case_list();
+ ensure_buffer(5);
+ if (is_token_at(L"esac", cindex))
cindex += 4;
- skip_blanks_and_comment();
-
- command_T *result = xmalloc(sizeof *result);
- result->next = NULL;
- result->c_type = CT_CASE;
- result->c_lineno = cinfo->lineno;
- result->c_redirs = NULL;
- result->c_casword = parse_word(globalonly);
- if (!result->c_casword)
- serror(Ngt("no word after `%ls'"), L"case");
- skip_to_next_token();
- ensure_buffer(3);
- if (is_token_at(L"in", cindex))
- cindex += 2;
- else
- print_errmsg_token_missing(L"in", cindex);
- result->c_casitems = parse_case_list();
- ensure_buffer(5);
- if (is_token_at(L"esac", cindex))
- cindex += 4;
- else
- print_errmsg_token_missing(L"esac", cindex);
- return result;
+ else
+ print_errmsg_token_missing(L"esac", cindex);
+ return result;
}
/* case コマンドの本体 (`in' と `esac' の間) を解析する。
* この関数を呼ぶ前に skip_to_next_token は不要。 */
static caseitem_T *parse_case_list(void)
{
- caseitem_T *first = NULL, **lastp = &first;
-
- while (!cerror) {
- skip_to_next_token();
- ensure_buffer(5);
- if (is_token_at(L"esac", cindex))
- break;
-
- caseitem_T *ci = xmalloc(sizeof *ci);
- *lastp = ci;
- lastp = &ci->next;
- ci->next = NULL;
- ci->ci_patterns = parse_case_patterns();
- ci->ci_commands = parse_compound_list();
- /* for や while とは異なり、ci_commands は NULL でも良い。 */
- ensure_buffer(2);
- if (cbuf.contents[cindex] == L';' && cbuf.contents[cindex+1] == L';') {
- cindex += 2;
- } else {
- break;
- }
+ caseitem_T *first = NULL, **lastp = &first;
+
+ while (!cerror) {
+ skip_to_next_token();
+ ensure_buffer(5);
+ if (is_token_at(L"esac", cindex))
+ break;
+
+ caseitem_T *ci = xmalloc(sizeof *ci);
+ *lastp = ci;
+ lastp = &ci->next;
+ ci->next = NULL;
+ ci->ci_patterns = parse_case_patterns();
+ ci->ci_commands = parse_compound_list();
+ /* for や while とは異なり、ci_commands は NULL でも良い。 */
+ ensure_buffer(2);
+ if (cbuf.contents[cindex] == L';' && cbuf.contents[cindex+1] == L';') {
+ cindex += 2;
+ } else {
+ break;
}
- return first;
+ }
+ return first;
}
/* case 項目のパタン部分を解析する。
* 予め ensure_buffer(1), skip_blanks_and_comment しておくこと。 */
static void **parse_case_patterns(void)
{
- plist_T wordlist;
+ plist_T wordlist;
- pl_init(&wordlist);
- if (cbuf.contents[cindex] == L'(') { /* 最初の '(' は無視 */
- cindex++;
- skip_blanks_and_comment();
- }
- while (!cerror) {
- if (is_token_delimiter_char(cbuf.contents[cindex]))
- serror(Ngt("invalid character `%lc' in case pattern"),
- (wint_t) cbuf.contents[cindex]);
- pl_add(&wordlist, parse_word(globalonly));
- ensure_buffer(1);
- if (cbuf.contents[cindex] == L'|') {
- cindex++;
- } else if (cbuf.contents[cindex] == L')') {
- cindex++;
- break;
- } else {
- serror(Ngt("`%ls' missing"), L")");
- break;
- }
- skip_blanks_and_comment();
+ pl_init(&wordlist);
+ if (cbuf.contents[cindex] == L'(') { /* 最初の '(' は無視 */
+ cindex++;
+ skip_blanks_and_comment();
+ }
+ while (!cerror) {
+ if (is_token_delimiter_char(cbuf.contents[cindex]))
+ serror(Ngt("invalid character `%lc' in case pattern"),
+ (wint_t) cbuf.contents[cindex]);
+ pl_add(&wordlist, parse_word(globalonly));
+ ensure_buffer(1);
+ if (cbuf.contents[cindex] == L'|') {
+ cindex++;
+ } else if (cbuf.contents[cindex] == L')') {
+ cindex++;
+ break;
+ } else {
+ serror(Ngt("`%ls' missing"), L")");
+ break;
}
- return pl_toary(&wordlist);
+ skip_blanks_and_comment();
+ }
+ return pl_toary(&wordlist);
}
/* ヒアドキュメントの内容を読み込む。 */
static void read_heredoc_contents(redir_T *redir)
{
- wordunit_T *wu = xmalloc(sizeof *wu);
- wu->next = NULL;
- wu->wu_type = WT_STRING;
- wu->wu_string = xwcsdup(L"");
- redir->rd_herecontent = wu;
- // TODO parser.c: read_heredoc_contents: 未実装
+ wordunit_T *wu = xmalloc(sizeof *wu);
+ wu->next = NULL;
+ wu->wu_type = WT_STRING;
+ wu->wu_string = xwcsdup(L"");
+ redir->rd_herecontent = wu;
+ // TODO parser.c: read_heredoc_contents: 未実装
}
static const char *get_errmsg_unexpected_token(const wchar_t *token)
{
- switch (token[0]) {
- case L')': return Ngt("`%ls' without matching `('");
- case L'}': return Ngt("`%ls' without matching `{'");
- case L';': return Ngt("`%ls' used outside `case'");
- case L'!': return Ngt("`%ls' cannot be used as command name");
- case L'i': return Ngt("`%ls' cannot be used as command name");
- case L'f': return Ngt("`%ls' without matching `if'");
- case L't': return Ngt("`%ls' used without `if'");
- case L'd':
- assert(token[1] == L'o');
- if (token[2] == L'\0')
- return Ngt("`%ls' used without `for', `while', or `until'");
- else
- return Ngt("`%ls' without matching `do'");
- case L'e':
- if (token[1] == L's')
- return Ngt("`%ls' without matching `case'");
- else
- if (token[2] == L's')
- return Ngt("`%ls' used without `if'");
- else
- return Ngt("`%ls' used without `if'");
- default:
- assert(false);
- }
+ switch (token[0]) {
+ case L')': return Ngt("`%ls' without matching `('");
+ case L'}': return Ngt("`%ls' without matching `{'");
+ case L';': return Ngt("`%ls' used outside `case'");
+ case L'!': return Ngt("`%ls' cannot be used as command name");
+ case L'i': return Ngt("`%ls' cannot be used as command name");
+ case L'f': return Ngt("`%ls' without matching `if'");
+ case L't': return Ngt("`%ls' used without `if'");
+ case L'd':
+ assert(token[1] == L'o');
+ if (token[2] == L'\0')
+ return Ngt("`%ls' used without `for', `while', or `until'");
+ else
+ return Ngt("`%ls' without matching `do'");
+ case L'e':
+ if (token[1] == L's')
+ return Ngt("`%ls' without matching `case'");
+ else
+ if (token[2] == L's')
+ return Ngt("`%ls' used without `if'");
+ else
+ return Ngt("`%ls' used without `if'");
+ default:
+ assert(false);
+ }
}
static void print_errmsg_token_missing(const wchar_t *token, size_t index)
{
- const wchar_t *atoken = check_closing_token_at(index);
- if (atoken)
- serror(get_errmsg_unexpected_token(atoken), atoken);
- else
- serror(Ngt("`%ls' missing"), token);
+ const wchar_t *atoken = check_closing_token_at(index);
+ if (atoken)
+ serror(get_errmsg_unexpected_token(atoken), atoken);
+ else
+ serror(Ngt("`%ls' missing"), token);
}
__attribute__((nonnull(1)))
static void print_and_or_lists(
- xwcsbuf_T *restrict buf, const and_or_T *restrict andors,
- bool omit_last_semicolon);
+ xwcsbuf_T *restrict buf, const and_or_T *restrict andors,
+ bool omit_last_semicolon);
__attribute__((nonnull(1)))
static void print_pipelines(
- xwcsbuf_T *restrict buf, const pipeline_T *restrict pipelines);
+ xwcsbuf_T *restrict buf, const pipeline_T *restrict pipelines);
__attribute__((nonnull(1)))
static void print_commands(
- xwcsbuf_T *restrict buf, const command_T *restrict commands);
+ xwcsbuf_T *restrict buf, const command_T *restrict commands);
__attribute__((nonnull))
static void print_command_content(
- xwcsbuf_T *restrict buf, const command_T *restrict command);
+ xwcsbuf_T *restrict buf, const command_T *restrict command);
__attribute__((nonnull(1)))
static void print_caseitems(
- xwcsbuf_T *restrict buf, const caseitem_T *restrict caseitems);
+ xwcsbuf_T *restrict buf, const caseitem_T *restrict caseitems);
__attribute__((nonnull(1)))
static void print_assigns(
- xwcsbuf_T *restrict buf, const assign_T *restrict assigns);
+ xwcsbuf_T *restrict buf, const assign_T *restrict assigns);
__attribute__((nonnull(1)))
static void print_redirs(
- xwcsbuf_T *restrict buf, const redir_T *restrict redirs);
+ xwcsbuf_T *restrict buf, const redir_T *restrict redirs);
__attribute__((nonnull(1)))
static void print_word(
- xwcsbuf_T *restrict buf, const wordunit_T *restrict word);
+ xwcsbuf_T *restrict buf, const wordunit_T *restrict word);
__attribute__((nonnull))
static void print_paramexp(
- xwcsbuf_T *restrict buf, const paramexp_T *restrict param);
+ xwcsbuf_T *restrict buf, const paramexp_T *restrict param);
__attribute__((nonnull))
static void trim_end_of_buffer(xwcsbuf_T *buf);
* 戻り値は free 可能なワイド文字列へのポインタ。 */
wchar_t *commands_to_wcstring(const and_or_T *commands)
{
- xwcsbuf_T buf;
+ xwcsbuf_T buf;
- wb_init(&buf);
- print_and_or_lists(&buf, commands, true);
- trim_end_of_buffer(&buf);
- return wb_towcs(&buf);
+ wb_init(&buf);
+ print_and_or_lists(&buf, commands, true);
+ trim_end_of_buffer(&buf);
+ return wb_towcs(&buf);
}
#endif
* 戻り値は free 可能なワイド文字列へのポインタ。 */
wchar_t *command_to_wcs(const command_T *command)
{
- xwcsbuf_T buf;
+ xwcsbuf_T buf;
- wb_init(&buf);
- print_command_content(&buf, command);
- trim_end_of_buffer(&buf);
- return wb_towcs(&buf);
+ wb_init(&buf);
+ print_command_content(&buf, command);
+ trim_end_of_buffer(&buf);
+ return wb_towcs(&buf);
}
// TODO DEBUG parser.c: word_to_wcs
wchar_t *word_to_wcs(const wordunit_T *word)
{
- xwcsbuf_T buf;
- wb_init(&buf);
- print_word(&buf, word);
- trim_end_of_buffer(&buf);
- return wb_towcs(&buf);
+ xwcsbuf_T buf;
+ wb_init(&buf);
+ print_word(&buf, word);
+ trim_end_of_buffer(&buf);
+ return wb_towcs(&buf);
}
static void print_and_or_lists(
- xwcsbuf_T *restrict buf, const and_or_T *restrict c, bool omitsemicolon)
-{
- while (c) {
- print_pipelines(buf, c->ao_pipelines);
- assert(iswblank(buf->contents[buf->length - 1]));
- if (c->ao_async)
- wb_insert(buf, buf->length - 1, L"&");
- else if (!omitsemicolon || c->next)
- wb_insert(buf, buf->length - 1, L";");
- c = c->next;
- }
+ xwcsbuf_T *restrict buf, const and_or_T *restrict c, bool omitsemicolon)
+{
+ while (c) {
+ print_pipelines(buf, c->ao_pipelines);
+ assert(iswblank(buf->contents[buf->length - 1]));
+ if (c->ao_async)
+ wb_insert(buf, buf->length - 1, L"&");
+ else if (!omitsemicolon || c->next)
+ wb_insert(buf, buf->length - 1, L";");
+ c = c->next;
+ }
}
static void print_pipelines(
- xwcsbuf_T *restrict buf, const pipeline_T *restrict p)
-{
- while (p) {
- if (p->pl_neg)
- wb_cat(buf, L"! ");
- if (p->pl_loop)
- wb_cat(buf, L"| ");
- print_commands(buf, p->pl_commands);
- if (p->next)
- wb_cat(buf, p->pl_next_cond ? L"&& " : L"|| ");
- p = p->next;
- }
+ xwcsbuf_T *restrict buf, const pipeline_T *restrict p)
+{
+ while (p) {
+ if (p->pl_neg)
+ wb_cat(buf, L"! ");
+ if (p->pl_loop)
+ wb_cat(buf, L"| ");
+ print_commands(buf, p->pl_commands);
+ if (p->next)
+ wb_cat(buf, p->pl_next_cond ? L"&& " : L"|| ");
+ p = p->next;
+ }
}
static void print_commands(
- xwcsbuf_T *restrict buf, const command_T *restrict c)
-{
- while (c) {
- print_command_content(buf, c);
- print_redirs(buf, c->c_redirs);
- if (c->next)
- wb_cat(buf, L"| ");
- c = c->next;
- }
+ xwcsbuf_T *restrict buf, const command_T *restrict c)
+{
+ while (c) {
+ print_command_content(buf, c);
+ print_redirs(buf, c->c_redirs);
+ if (c->next)
+ wb_cat(buf, L"| ");
+ c = c->next;
+ }
}
static void print_command_content(
- xwcsbuf_T *restrict buf, const command_T *restrict c)
-{
- switch (c->c_type) {
- case CT_SIMPLE:
- print_assigns(buf, c->c_assigns);
- for (void **w = c->c_words; *w; w++) {
- print_word(buf, *w);
- wb_wccat(buf, L' ');
- }
- break;
- case CT_GROUP:
- wb_cat(buf, L"{ ");
- print_and_or_lists(buf, c->c_subcmds, false);
- wb_cat(buf, L"} ");
- break;
- case CT_SUBSHELL:
- wb_wccat(buf, L'(');
- print_and_or_lists(buf, c->c_subcmds, true);
- assert(iswblank(buf->contents[buf->length - 1]));
- wb_insert(buf, buf->length - 1, L")");
- break;
- case CT_IF:
- wb_cat(buf, L"if ");
- for (ifcommand_T *ic = c->c_ifcmds;;) {
- print_and_or_lists(buf, ic->ic_condition, false);
- wb_cat(buf, L"then ");
- print_and_or_lists(buf, ic->ic_commands, false);
- ic = ic->next;
- if (!ic) {
- break;
- } else if (!ic->ic_condition) {
- wb_cat(buf, L"else ");
- print_and_or_lists(buf, ic->ic_commands, false);
- break;
- } else {
- wb_cat(buf, L"elif ");
- }
- }
- wb_cat(buf, L"fi ");
- break;
- case CT_FOR:
- wb_cat(buf, L"for ");
- wb_cat(buf, c->c_forname);
- if (c->c_forwords) {
- wb_cat(buf, L" in");
- for (void **w = c->c_forwords; *w; w++) {
- wb_wccat(buf, L' ');
- print_word(buf, *w);
- }
- }
- wb_cat(buf, L"; do ");
- print_and_or_lists(buf, c->c_forcmds, false);
- wb_cat(buf, L"done ");
- break;
- case CT_WHILE:
- wb_cat(buf, c->c_whltype ? L"while " : L"until ");
- print_and_or_lists(buf, c->c_whlcond, false);
- wb_cat(buf, L"do ");
- print_and_or_lists(buf, c->c_whlcmds, false);
- wb_cat(buf, L"done ");
+ xwcsbuf_T *restrict buf, const command_T *restrict c)
+{
+ switch (c->c_type) {
+ case CT_SIMPLE:
+ print_assigns(buf, c->c_assigns);
+ for (void **w = c->c_words; *w; w++) {
+ print_word(buf, *w);
+ wb_wccat(buf, L' ');
+ }
+ break;
+ case CT_GROUP:
+ wb_cat(buf, L"{ ");
+ print_and_or_lists(buf, c->c_subcmds, false);
+ wb_cat(buf, L"} ");
+ break;
+ case CT_SUBSHELL:
+ wb_wccat(buf, L'(');
+ print_and_or_lists(buf, c->c_subcmds, true);
+ assert(iswblank(buf->contents[buf->length - 1]));
+ wb_insert(buf, buf->length - 1, L")");
+ break;
+ case CT_IF:
+ wb_cat(buf, L"if ");
+ for (ifcommand_T *ic = c->c_ifcmds;;) {
+ print_and_or_lists(buf, ic->ic_condition, false);
+ wb_cat(buf, L"then ");
+ print_and_or_lists(buf, ic->ic_commands, false);
+ ic = ic->next;
+ if (!ic) {
break;
- case CT_CASE:
- wb_cat(buf, L"case ");
- print_word(buf, c->c_casword);
- wb_cat(buf, L" in ");
- print_caseitems(buf, c->c_casitems);
- wb_cat(buf, L"esac ");
+ } else if (!ic->ic_condition) {
+ wb_cat(buf, L"else ");
+ print_and_or_lists(buf, ic->ic_commands, false);
break;
+ } else {
+ wb_cat(buf, L"elif ");
+ }
+ }
+ wb_cat(buf, L"fi ");
+ break;
+ case CT_FOR:
+ wb_cat(buf, L"for ");
+ wb_cat(buf, c->c_forname);
+ if (c->c_forwords) {
+ wb_cat(buf, L" in");
+ for (void **w = c->c_forwords; *w; w++) {
+ wb_wccat(buf, L' ');
+ print_word(buf, *w);
+ }
}
+ wb_cat(buf, L"; do ");
+ print_and_or_lists(buf, c->c_forcmds, false);
+ wb_cat(buf, L"done ");
+ break;
+ case CT_WHILE:
+ wb_cat(buf, c->c_whltype ? L"while " : L"until ");
+ print_and_or_lists(buf, c->c_whlcond, false);
+ wb_cat(buf, L"do ");
+ print_and_or_lists(buf, c->c_whlcmds, false);
+ wb_cat(buf, L"done ");
+ break;
+ case CT_CASE:
+ wb_cat(buf, L"case ");
+ print_word(buf, c->c_casword);
+ wb_cat(buf, L" in ");
+ print_caseitems(buf, c->c_casitems);
+ wb_cat(buf, L"esac ");
+ break;
+ }
}
static void print_caseitems(
- xwcsbuf_T *restrict buf, const caseitem_T *restrict i)
-{
- while (i) {
- bool first = true;
-
- wb_wccat(buf, L'(');
- for (void **w = i->ci_patterns; *w; w++) {
- if (!first)
- wb_wccat(buf, L'|');
- print_word(buf, *w);
- first = false;
- }
- wb_cat(buf, L") ");
- print_and_or_lists(buf, i->ci_commands, true);
- wb_cat(buf, L";; ");
-
- i = i->next;
+ xwcsbuf_T *restrict buf, const caseitem_T *restrict i)
+{
+ while (i) {
+ bool first = true;
+
+ wb_wccat(buf, L'(');
+ for (void **w = i->ci_patterns; *w; w++) {
+ if (!first)
+ wb_wccat(buf, L'|');
+ print_word(buf, *w);
+ first = false;
}
+ wb_cat(buf, L") ");
+ print_and_or_lists(buf, i->ci_commands, true);
+ wb_cat(buf, L";; ");
+
+ i = i->next;
+ }
}
static void print_assigns(
- xwcsbuf_T *restrict buf, const assign_T *restrict a)
+ xwcsbuf_T *restrict buf, const assign_T *restrict a)
{
- while (a) {
- wb_mbscat(buf, a->name);
- wb_wccat(buf, L'=');
- print_word(buf, a->value);
- wb_wccat(buf, L' ');
- a = a->next;
- }
+ while (a) {
+ wb_mbscat(buf, a->name);
+ wb_wccat(buf, L'=');
+ print_word(buf, a->value);
+ wb_wccat(buf, L' ');
+ a = a->next;
+ }
}
static void print_redirs(
- xwcsbuf_T *restrict buf, const redir_T *restrict r)
-{
- while (r) {
- const wchar_t *s;
- bool ishere;
-
- switch (r->rd_type) {
- case RT_INPUT: s = L"<"; ishere = false; break;
- case RT_OUTPUT: s = L">"; ishere = false; break;
- case RT_CLOBBER: s = L">|"; ishere = false; break;
- case RT_APPEND: s = L">>"; ishere = false; break;
- case RT_INOUT: s = L"<>"; ishere = false; break;
- case RT_DUPIN: s = L"<&"; ishere = false; break;
- case RT_DUPOUT: s = L">&"; ishere = false; break;
- case RT_HERE: s = L"<<"; ishere = true; break;
- case RT_HERERT: s = L"<<-"; ishere = true; break;
- default: assert(false);
- }
- wb_printf(buf, L"%d%ls", r->rd_fd, s);
- if (!ishere)
- print_word(buf, r->rd_filename);
- else
- wb_cat(buf, r->rd_hereend);
- wb_wccat(buf, L' ');
-
- r = r->next;
+ xwcsbuf_T *restrict buf, const redir_T *restrict r)
+{
+ while (r) {
+ const wchar_t *s;
+ bool ishere;
+
+ switch (r->rd_type) {
+ case RT_INPUT: s = L"<"; ishere = false; break;
+ case RT_OUTPUT: s = L">"; ishere = false; break;
+ case RT_CLOBBER: s = L">|"; ishere = false; break;
+ case RT_APPEND: s = L">>"; ishere = false; break;
+ case RT_INOUT: s = L"<>"; ishere = false; break;
+ case RT_DUPIN: s = L"<&"; ishere = false; break;
+ case RT_DUPOUT: s = L">&"; ishere = false; break;
+ case RT_HERE: s = L"<<"; ishere = true; break;
+ case RT_HERERT: s = L"<<-"; ishere = true; break;
+ default: assert(false);
}
+ wb_printf(buf, L"%d%ls", r->rd_fd, s);
+ if (!ishere)
+ print_word(buf, r->rd_filename);
+ else
+ wb_cat(buf, r->rd_hereend);
+ wb_wccat(buf, L' ');
+
+ r = r->next;
+ }
}
static void print_word(
- xwcsbuf_T *restrict buf, const wordunit_T *restrict w)
-{
- while (w) {
- switch (w->wu_type) {
- case WT_STRING:
- wb_cat(buf, w->wu_string);
- break;
- case WT_PARAM:
- print_paramexp(buf, w->wu_param);
- break;
- case WT_CMDSUB:
- wb_cat(buf, L"$(");
- wb_cat(buf, w->wu_cmdsub);
- wb_cat(buf, L")");
- break;
- case WT_ARITH:
- wb_cat(buf, L"$((");
- print_word(buf, w->wu_arith);
- wb_cat(buf, L"))");
- break;
- }
- w = w->next;
+ xwcsbuf_T *restrict buf, const wordunit_T *restrict w)
+{
+ while (w) {
+ switch (w->wu_type) {
+ case WT_STRING:
+ wb_cat(buf, w->wu_string);
+ break;
+ case WT_PARAM:
+ print_paramexp(buf, w->wu_param);
+ break;
+ case WT_CMDSUB:
+ wb_cat(buf, L"$(");
+ wb_cat(buf, w->wu_cmdsub);
+ wb_cat(buf, L")");
+ break;
+ case WT_ARITH:
+ wb_cat(buf, L"$((");
+ print_word(buf, w->wu_arith);
+ wb_cat(buf, L"))");
+ break;
}
+ w = w->next;
+ }
}
static void print_paramexp(
- xwcsbuf_T *restrict buf, const paramexp_T *restrict p)
-{
- wchar_t c;
-
- wb_cat(buf, L"${");
- if (p->pe_type & PT_NUMBER)
- wb_wccat(buf, L'#');
- wb_mbscat(buf, p->pe_name);
- if (p->pe_type & PT_COLON)
- wb_wccat(buf, L':');
- switch (p->pe_type & PT_MASK) {
- case PT_PLUS:
- wb_wccat(buf, L'+');
- goto append_subst;
- case PT_MINUS:
- wb_wccat(buf, L'-');
- goto append_subst;
- case PT_ASSIGN:
- wb_wccat(buf, L'=');
- goto append_subst;
- case PT_ERROR:
- wb_wccat(buf, L'?');
- goto append_subst;
- case PT_MATCH:
- if (p->pe_type & PT_MATCHHEAD) {
- c = L'#';
- } else {
- assert(p->pe_type & PT_MATCHTAIL);
- c = L'%';
- }
- wb_wccat(buf, c);
- if (p->pe_type & PT_MATCHLONGEST)
- wb_wccat(buf, c);
- print_word(buf, p->pe_match);
- break;
- case PT_SUBST:
- wb_wccat(buf, L'/');
- if (p->pe_type & PT_SUBSTALL)
- wb_wccat(buf, L'/');
- else if (p->pe_type & PT_MATCHHEAD)
- wb_wccat(buf, L'#');
- else if (p->pe_type & PT_MATCHTAIL)
- wb_wccat(buf, L'%');
- print_word(buf, p->pe_match);
- wb_wccat(buf, L'/');
- goto append_subst;
-append_subst:
- print_word(buf, p->pe_subst);
- break;
+ xwcsbuf_T *restrict buf, const paramexp_T *restrict p)
+{
+ wchar_t c;
+
+ wb_cat(buf, L"${");
+ if (p->pe_type & PT_NUMBER)
+ wb_wccat(buf, L'#');
+ wb_mbscat(buf, p->pe_name);
+ if (p->pe_type & PT_COLON)
+ wb_wccat(buf, L':');
+ switch (p->pe_type & PT_MASK) {
+ case PT_PLUS:
+ wb_wccat(buf, L'+');
+ goto append_subst;
+ case PT_MINUS:
+ wb_wccat(buf, L'-');
+ goto append_subst;
+ case PT_ASSIGN:
+ wb_wccat(buf, L'=');
+ goto append_subst;
+ case PT_ERROR:
+ wb_wccat(buf, L'?');
+ goto append_subst;
+ case PT_MATCH:
+ if (p->pe_type & PT_MATCHHEAD) {
+ c = L'#';
+ } else {
+ assert(p->pe_type & PT_MATCHTAIL);
+ c = L'%';
}
- wb_wccat(buf, L'}');
+ wb_wccat(buf, c);
+ if (p->pe_type & PT_MATCHLONGEST)
+ wb_wccat(buf, c);
+ print_word(buf, p->pe_match);
+ break;
+ case PT_SUBST:
+ wb_wccat(buf, L'/');
+ if (p->pe_type & PT_SUBSTALL)
+ wb_wccat(buf, L'/');
+ else if (p->pe_type & PT_MATCHHEAD)
+ wb_wccat(buf, L'#');
+ else if (p->pe_type & PT_MATCHTAIL)
+ wb_wccat(buf, L'%');
+ print_word(buf, p->pe_match);
+ wb_wccat(buf, L'/');
+ goto append_subst;
+append_subst:
+ print_word(buf, p->pe_subst);
+ break;
+ }
+ wb_wccat(buf, L'}');
}
static void trim_end_of_buffer(xwcsbuf_T *buf)
{
- size_t i = buf->length;
- while (i > 0 && iswblank(buf->contents[--i]));
- wb_remove(buf, i + 1, SIZE_MAX);
+ size_t i = buf->length;
+ while (i > 0 && iswblank(buf->contents[--i]));
+ wb_remove(buf, i + 1, SIZE_MAX);
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* and/or リストを表す */
typedef struct and_or_T {
- struct and_or_T *next;
- struct pipeline_T *ao_pipelines; /* リストを構成するパイプラインたち */
- bool ao_async; /* この and/or リストを非同期実行するか */
+ struct and_or_T *next;
+ struct pipeline_T *ao_pipelines; /* リストを構成するパイプラインたち */
+ bool ao_async; /* この and/or リストを非同期実行するか */
} and_or_T;
/* パイプラインを表す */
typedef struct pipeline_T {
- struct pipeline_T *next;
- struct command_T *pl_commands; /* パイプラインを構成するコマンドたち */
- bool pl_neg, pl_loop, pl_next_cond;
+ struct pipeline_T *next;
+ struct command_T *pl_commands; /* パイプラインを構成するコマンドたち */
+ bool pl_neg, pl_loop, pl_next_cond;
} pipeline_T;
/* pl_neg はパイプラインの終了ステータスを反転するかどうか。
* pl_loop はパイプラインが環状かどうか。
/* command_T の種類を表す */
typedef enum {
- CT_SIMPLE, /* シンプルコマンド */
- CT_GROUP, /* { } で囲んだコマンドグループ */
- CT_SUBSHELL, /* ( ) で囲んだサブシェルコマンドグループ */
- CT_IF, /* if コマンド */
- CT_FOR, /* for コマンド */
- CT_WHILE, /* while/until コマンド */
- CT_CASE, /* case コマンド */
+ CT_SIMPLE, /* シンプルコマンド */
+ CT_GROUP, /* { } で囲んだコマンドグループ */
+ CT_SUBSHELL, /* ( ) で囲んだサブシェルコマンドグループ */
+ CT_IF, /* if コマンド */
+ CT_FOR, /* for コマンド */
+ CT_WHILE, /* while/until コマンド */
+ CT_CASE, /* case コマンド */
} commandtype_T;
/* パイプラインを構成する一つのコマンドを表す */
typedef struct command_T {
- struct command_T *next;
- commandtype_T c_type;
- unsigned long c_lineno; /* このコマンドの行番号 */
- struct redir_T *c_redirs; /* このコマンドで行うリダイレクト */
- union {
- struct {
- struct assign_T *assigns; /* このコマンドで行う変数代入 */
- void **words; /* コマンド名と引数 */
- } simplecontent;
- struct and_or_T *subcmds; /* CT_GROUP, CT_SUBSHELL の内容 */
- struct ifcommand_T *ifcmds; /* if の内容 */
- struct {
- wchar_t *forname; /* for で回す変数名 */
- void **forwords; /* 代入する word のリスト */
- struct and_or_T *forcmds; /* for で実行するコマンド */
- } forcontent;
- struct {
- bool whltype; /* while なら 1、until なら 0 */
- struct and_or_T *whlcond; /* while/until の条件 */
- struct and_or_T *whlcmds; /* while/until で実行するコマンド */
- } whilecontent;
- struct {
- struct wordunit_T *casword; /* case で検索する word */
- struct caseitem_T *casitems; /* case の各項目 */
- } casecontent;
- } c_content;
+ struct command_T *next;
+ commandtype_T c_type;
+ unsigned long c_lineno; /* このコマンドの行番号 */
+ struct redir_T *c_redirs; /* このコマンドで行うリダイレクト */
+ union {
+ struct {
+ struct assign_T *assigns; /* このコマンドで行う変数代入 */
+ void **words; /* コマンド名と引数 */
+ } simplecontent;
+ struct and_or_T *subcmds; /* CT_GROUP, CT_SUBSHELL の内容 */
+ struct ifcommand_T *ifcmds; /* if の内容 */
+ struct {
+ wchar_t *forname; /* for で回す変数名 */
+ void **forwords; /* 代入する word のリスト */
+ struct and_or_T *forcmds; /* for で実行するコマンド */
+ } forcontent;
+ struct {
+ bool whltype; /* while なら 1、until なら 0 */
+ struct and_or_T *whlcond; /* while/until の条件 */
+ struct and_or_T *whlcmds; /* while/until で実行するコマンド */
+ } whilecontent;
+ struct {
+ struct wordunit_T *casword; /* case で検索する word */
+ struct caseitem_T *casitems; /* case の各項目 */
+ } casecontent;
+ } c_content;
} command_T;
#define c_assigns c_content.simplecontent.assigns
#define c_words c_content.simplecontent.words
/* if コマンドの条件とその条件が成り立つとき実行するコマンドを表す */
typedef struct ifcommand_T {
- struct ifcommand_T *next;
- struct and_or_T *ic_condition; /* 条件 */
- struct and_or_T *ic_commands; /* 実行するコマンド */
+ struct ifcommand_T *next;
+ struct and_or_T *ic_condition; /* 条件 */
+ struct and_or_T *ic_commands; /* 実行するコマンド */
} ifcommand_T;
/* else は next と ic_condition が NULL の ifcommand_T で表す。 */
/* case コマンドの一つの項目を表す */
typedef struct caseitem_T {
- struct caseitem_T *next;
- void **ci_patterns; /* 一致するか調べるパタンの配列 */
- struct and_or_T *ci_commands; /* 一致したときに実行するコマンド */
+ struct caseitem_T *next;
+ void **ci_patterns; /* 一致するか調べるパタンの配列 */
+ struct and_or_T *ci_commands; /* 一致したときに実行するコマンド */
} caseitem_T;
/* ci_patterns は wordunit_T へのポインタの NULL 終端配列へのポインタ */
/* wordunit_T の種類を表す */
typedef enum {
- WT_STRING, /* 文字列部分 (引用符を含む) */
- WT_PARAM, /* パラメータ展開 */
- WT_CMDSUB, /* コマンド置換 */
- WT_ARITH, /* 数式展開 */
+ WT_STRING, /* 文字列部分 (引用符を含む) */
+ WT_PARAM, /* パラメータ展開 */
+ WT_CMDSUB, /* コマンド置換 */
+ WT_ARITH, /* 数式展開 */
} wordunittype_T;
/* 単語展開の対象となる単語の構成要素を表す */
typedef struct wordunit_T {
- struct wordunit_T *next;
- wordunittype_T wu_type;
- union {
- wchar_t *string; /* 文字列部分 */
- struct paramexp_T *param; /* パラメータ展開の内容 */
- wchar_t *cmdsub; /* コマンド置換で実行するコマンド */
- struct wordunit_T *arith; /* 数式展開の内容 */
- } wu_value;
+ struct wordunit_T *next;
+ wordunittype_T wu_type;
+ union {
+ wchar_t *string; /* 文字列部分 */
+ struct paramexp_T *param; /* パラメータ展開の内容 */
+ wchar_t *cmdsub; /* コマンド置換で実行するコマンド */
+ struct wordunit_T *arith; /* 数式展開の内容 */
+ } wu_value;
} wordunit_T;
#define wu_string wu_value.string
#define wu_param wu_value.param
/* paramexp_T の種類を表す */
typedef enum {
- PT_NONE, /* 通常 */
- PT_MINUS, /* ${name-subst} */
- PT_PLUS, /* ${name+subst} */
- PT_ASSIGN, /* ${name=subst} */
- PT_ERROR, /* ${name?subst} */
- PT_MATCH, /* ${name#match}, ${name%match} */
- PT_SUBST, /* ${name/match/subst} */
- PT_NUMBER = 1 << 3, /* ${#name} */
- PT_COLON = 1 << 4, /* ${name:-subst}, ${name:+subst}, etc. */
- PT_MATCHHEAD = 1 << 5, /* 先頭のみにマッチ */
- PT_MATCHTAIL = 1 << 6, /* 末尾のみにマッチ */
- PT_MATCHLONGEST = 1 << 7, /* できるだけ長くマッチ */
- PT_SUBSTALL = 1 << 8, /* マッチしたもの全て置換 */
+ PT_NONE, /* 通常 */
+ PT_MINUS, /* ${name-subst} */
+ PT_PLUS, /* ${name+subst} */
+ PT_ASSIGN, /* ${name=subst} */
+ PT_ERROR, /* ${name?subst} */
+ PT_MATCH, /* ${name#match}, ${name%match} */
+ PT_SUBST, /* ${name/match/subst} */
+ PT_NUMBER = 1 << 3, /* ${#name} */
+ PT_COLON = 1 << 4, /* ${name:-subst}, ${name:+subst}, etc. */
+ PT_MATCHHEAD = 1 << 5, /* 先頭のみにマッチ */
+ PT_MATCHTAIL = 1 << 6, /* 末尾のみにマッチ */
+ PT_MATCHLONGEST = 1 << 7, /* できるだけ長くマッチ */
+ PT_SUBSTALL = 1 << 8, /* マッチしたもの全て置換 */
} paramexptype_T;
#define PT_MASK ((1 << 3) - 1)
/* type COLON MATCHH MATCHT MATCHL SUBSTA
/* パラメータ展開を表す */
typedef struct paramexp_T {
- paramexptype_T pe_type;
- char *pe_name;
- struct wordunit_T *pe_match, *pe_subst;
+ paramexptype_T pe_type;
+ char *pe_name;
+ struct wordunit_T *pe_match, *pe_subst;
} paramexp_T;
/* pe_name は変数名。
* pe_match は変数の内容とマッチさせる単語で、PT_MATCH, PT_SUBST で使う。
/* 代入を表す */
typedef struct assign_T {
- struct assign_T *next;
- char *name; /* 代入する変数名 */
- struct wordunit_T *value; /* 代入する値 */
+ struct assign_T *next;
+ char *name; /* 代入する変数名 */
+ struct wordunit_T *value; /* 代入する値 */
} assign_T;
/* value が NULL のとき、それは空文字列を表す。 */
/* リダイレクトの種類を表す */
typedef enum {
- RT_INPUT, /* <file */
- RT_OUTPUT, /* >file */
- RT_CLOBBER, /* >|file */
- RT_APPEND, /* >>file */
- RT_INOUT, /* <>file */
- RT_DUPIN, /* <&fd */
- RT_DUPOUT, /* >&fd */
- RT_HERE, /* <<END */
- RT_HERERT, /* <<-END */
+ RT_INPUT, /* <file */
+ RT_OUTPUT, /* >file */
+ RT_CLOBBER, /* >|file */
+ RT_APPEND, /* >>file */
+ RT_INOUT, /* <>file */
+ RT_DUPIN, /* <&fd */
+ RT_DUPOUT, /* >&fd */
+ RT_HERE, /* <<END */
+ RT_HERERT, /* <<-END */
} redirtype_T;
/* リダイレクトを表す */
typedef struct redir_T {
- struct redir_T *next;
- redirtype_T rd_type;
- int rd_fd; /* リダイレクトするファイル記述子 */
- union {
- struct wordunit_T *filename;
- struct {
- wchar_t *hereend; /* ヒアドキュメントの終わりを示すトークン */
- struct wordunit_T *herecontent; /* ヒアドキュメントの内容 */
- } heredoc;
- } rd_value;
+ struct redir_T *next;
+ redirtype_T rd_type;
+ int rd_fd; /* リダイレクトするファイル記述子 */
+ union {
+ struct wordunit_T *filename;
+ struct {
+ wchar_t *hereend; /* ヒアドキュメントの終わりを示すトークン */
+ struct wordunit_T *herecontent; /* ヒアドキュメントの内容 */
+ } heredoc;
+ } rd_value;
} redir_T;
#define rd_filename rd_value.filename
#define rd_hereend rd_value.heredoc.hereend
typedef int inputfunc_T(struct xwcsbuf_T *buf, void *inputinfo);
typedef struct parseinfo_T {
- bool print_errmsg; /* エラーメッセージを出力するかどうか */
- const char *filename; /* エラー表示で使うファイル名。NULL でも良い。 */
- unsigned long lineno; /* 行番号。最初は 1 にしておく。 */
- inputfunc_T *input; /* 入力関数 */
- void *inputinfo; /* 入力関数に渡す情報 */
+ bool print_errmsg; /* エラーメッセージを出力するかどうか */
+ const char *filename; /* エラー表示で使うファイル名。NULL でも良い。 */
+ unsigned long lineno; /* 行番号。最初は 1 にしておく。 */
+ inputfunc_T *input; /* 入力関数 */
+ void *inputinfo; /* 入力関数に渡す情報 */
} parseinfo_T;
__attribute__((nonnull))
extern int read_and_parse(
- parseinfo_T *restrict info, and_or_T **restrict result);
+ parseinfo_T *restrict info, and_or_T **restrict result);
/********** 構文木を文字列に戻すルーチン **********/
#endif /* PARSER_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
* 要素数を返す。(NULL 要素は戻り値に含めない) */
size_t plcount(void *const *list)
{
- size_t count = 0;
- while (*list++) count++;
- return count;
+ size_t count = 0;
+ while (*list++) count++;
+ return count;
}
/* ポインタの配列 *ary を、その要素であるポインタも含めて解放する。
* 要素である各ポインタ p に対して freer(p) した後、free(ary) する。 */
void recfree(void **ary, void freer(void *elem))
{
- if (ary) {
- for (void **a = ary; *a; a++) freer(*a);
- free(ary);
- }
+ if (ary) {
+ for (void **a = ary; *a; a++) freer(*a);
+ free(ary);
+ }
}
/* 未初期化のポインタリストを初期化する。 */
plist_T *pl_init(plist_T *list)
{
- list->contents = xmalloc((PLIST_INITSIZE + 1) * sizeof (void *));
- list->contents[0] = NULL;
- list->length = 0;
- list->maxlength = PLIST_INITSIZE;
- return list;
+ list->contents = xmalloc((PLIST_INITSIZE + 1) * sizeof (void *));
+ list->contents[0] = NULL;
+ list->length = 0;
+ list->maxlength = PLIST_INITSIZE;
+ return list;
}
/* 初期化済みのポインタリストの内容を削除し、未初期化状態に戻す。
* 配列の各要素は解放しないので注意。 */
void pl_destroy(plist_T *list)
{
- free(list->contents);
+ free(list->contents);
}
/* ポインタリストを解放し、内容を返す。ポインタリストを未初期化状態になる。
* することができる。 */
void **pl_toary(plist_T *list)
{
- if (list->maxlength - list->length > 10)
- pl_setmax(list, list->length);
- return list->contents;
+ if (list->maxlength - list->length > 10)
+ pl_setmax(list, list->length);
+ return list->contents;
}
/* ポインタリストのサイズ (list->maxlength) を変更する。
* 短くしすぎると、配列の末尾の要素はリストから消えてなくなる。 */
plist_T *pl_setmax(plist_T *list, size_t newmax)
{
- list->contents = xrealloc(list->contents, (newmax + 1) * sizeof (void *));
- list->maxlength = newmax;
- list->contents[newmax] = NULL;
- if (newmax < list->length)
- list->length = newmax;
- return list;
+ list->contents = xrealloc(list->contents, (newmax + 1) * sizeof (void *));
+ list->maxlength = newmax;
+ list->contents[newmax] = NULL;
+ if (newmax < list->length)
+ list->length = newmax;
+ return list;
}
/* list->maxlength が max 未満なら、max 以上になるようにメモリを再確保する。 */
inline plist_T *pl_ensuremax(plist_T *list, size_t max)
{
- if (list->maxlength < max) {
- size_t newmax = list->maxlength;
- do
- newmax = newmax * 2 + 1;
- while (newmax < max);
- return pl_setmax(list, newmax);
- } else {
- return list;
- }
+ if (list->maxlength < max) {
+ size_t newmax = list->maxlength;
+ do
+ newmax = newmax * 2 + 1;
+ while (newmax < max);
+ return pl_setmax(list, newmax);
+ } else {
+ return list;
+ }
}
/* ポインタリストの内容を空にする。リストの容量は変化しない。
* リストの各要素は解放しないので注意。 */
plist_T *pl_clear(plist_T *list)
{
- list->contents[list->length = 0] = NULL;
- return list;
+ list->contents[list->length = 0] = NULL;
+ return list;
}
/* ポインタリストの i 要素目から ln 要素を
* 特に、list->length <= i ならばリストの末尾に追加する。
* a は list->contents の一部であってはならない。 */
plist_T *pl_replace(
- plist_T *restrict list, size_t i, size_t ln,
- void *const *restrict a, size_t an)
+ plist_T *restrict list, size_t i, size_t ln,
+ void *const *restrict a, size_t an)
{
- if (i > list->length)
- i = list->length;
- if (ln > list->length - i)
- ln = list->length - i;
-
- size_t newlength = list->length - ln + an;
- pl_ensuremax(list, newlength);
- memmove(list->contents + i + an, list->contents + i + ln,
- (list->length - (i + ln) + 1) * sizeof (void *));
- memcpy(list->contents + i, a, an * sizeof (void *));
- list->length = newlength;
- return list;
+ if (i > list->length)
+ i = list->length;
+ if (ln > list->length - i)
+ ln = list->length - i;
+
+ size_t newlength = list->length - ln + an;
+ pl_ensuremax(list, newlength);
+ memmove(list->contents + i + an, list->contents + i + ln,
+ (list->length - (i + ln) + 1) * sizeof (void *));
+ memcpy(list->contents + i, a, an * sizeof (void *));
+ list->length = newlength;
+ return list;
}
/* ポインタリストの末尾に要素として p を追加する。
* p は NULL でも list そのものでも良い。 */
plist_T *pl_add(plist_T *list, void *p)
{
- pl_ensuremax(list, list->length + 1);
- list->contents[list->length++] = p;
- list->contents[list->length] = NULL;
- return list;
+ pl_ensuremax(list, list->length + 1);
+ list->contents[list->length++] = p;
+ list->contents[list->length] = NULL;
+ return list;
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
#include <stdint.h>
typedef struct plist_T {
- void **contents;
- size_t length, maxlength;
+ void **contents;
+ size_t length, maxlength;
} plist_T;
__attribute__((nonnull))
extern plist_T *pl_clear(plist_T *list);
__attribute__((nonnull))
extern plist_T *pl_replace(
- plist_T *restrict list, size_t i, size_t ln,
- void *const *restrict a, size_t an);
+ plist_T *restrict list, size_t i, size_t ln,
+ void *const *restrict a, size_t an);
__attribute__((nonnull))
static inline plist_T *pl_ninsert(
- plist_T *restrict list, size_t i, void *const *restrict a, size_t n);
+ plist_T *restrict list, size_t i, void *const *restrict a, size_t n);
__attribute__((nonnull))
static inline plist_T *pl_insert(
- plist_T *restrict list, size_t i, void *const *restrict a);
+ plist_T *restrict list, size_t i, void *const *restrict a);
__attribute__((nonnull))
static inline plist_T *pl_ncat(
- plist_T *restrict list, void *const *restrict a, size_t n);
+ plist_T *restrict list, void *const *restrict a, size_t n);
__attribute__((nonnull))
static inline plist_T *pl_cat(
- plist_T *restrict list, void *const *restrict a);
+ plist_T *restrict list, void *const *restrict a);
__attribute__((nonnull))
static inline plist_T *pl_remove(plist_T *list, size_t i, size_t n);
__attribute__((nonnull(1)))
* list->length <= i ならばリストの末尾に追加する。
* a は list->contents の一部であってはならない。 */
static inline plist_T *pl_ninsert(
- plist_T *restrict list, size_t i, void *const *restrict a, size_t n)
+ plist_T *restrict list, size_t i, void *const *restrict a, size_t n)
{
- return pl_replace(list, i, 0, a, n);
+ return pl_replace(list, i, 0, a, n);
}
/* ポインタの配列 a の要素をポインタリストの i 要素目の手前に挿入する。
* list->length <= i ならばリストの末尾に追加する。
* a は list->contents の一部であってはならない。 */
static inline plist_T *pl_insert(
- plist_T *restrict list, size_t i, void *const *restrict a)
+ plist_T *restrict list, size_t i, void *const *restrict a)
{
- return pl_replace(list, i, 0, a, plcount(a));
+ return pl_replace(list, i, 0, a, plcount(a));
}
/* ポインタの配列 a の最初の n 要素をポインタリストの末尾に追加する。
* a の要素に NULL があってもそれは特別扱いしない。
* a は list->contents の一部であってはならない。 */
static inline plist_T *pl_ncat(
- plist_T *restrict list, void *const *restrict a, size_t n)
+ plist_T *restrict list, void *const *restrict a, size_t n)
{
- return pl_replace(list, SIZE_MAX, 0, a, n);
+ return pl_replace(list, SIZE_MAX, 0, a, n);
}
/* ポインタの配列 a の要素をポインタリストの末尾に追加する。
* 挿入するのは、a 内の NULL の手前までの要素である。
* a は list->contents の一部であってはならない。 */
static inline plist_T *pl_cat(
- plist_T *restrict list, void *const *restrict a)
+ plist_T *restrict list, void *const *restrict a)
{
- return pl_replace(list, SIZE_MAX, 0, a, plcount(a));
+ return pl_replace(list, SIZE_MAX, 0, a, plcount(a));
}
/* リストの i 要素目から n 個の要素を削除する。
* 消される要素は勝手には解放されないので注意。 */
static inline plist_T *pl_remove(plist_T *list, size_t i, size_t n)
{
- return pl_replace(list, i, n, (void *[]) { NULL, }, 0);
+ return pl_replace(list, i, n, (void *[]) { NULL, }, 0);
}
#endif /* PLIST_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
* close が EINTR/EBADF 以外のエラーを返したら、エラーメッセージを出す。 */
int xclose(int fd)
{
- while (close(fd) < 0) {
- switch (errno) {
- case EINTR:
- continue;
- case EBADF:
- return 0;
- default:
- xerror(0, errno, Ngt("error in closing file descriptor %d"), fd);
- return -1;
- }
+ while (close(fd) < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EBADF:
+ return 0;
+ default:
+ xerror(0, errno, Ngt("error in closing file descriptor %d"), fd);
+ return -1;
}
- return 0;
+ }
+ return 0;
}
/* dup2 を確実に行う。(dup2 が EINTR を返したら、やり直す)
* この関数は事前に xclose(newfd) を行う。 */
int xdup2(int oldfd, int newfd)
{
- xclose(newfd);
- while (dup2(oldfd, newfd) < 0) {
- switch (errno) {
- case EINTR:
- continue;
- default:
- xerror(0, errno,
- Ngt("error in copying file descriptor %d to %d"),
- oldfd, newfd);
- return -1;
- }
+ xclose(newfd);
+ while (dup2(oldfd, newfd) < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ xerror(0, errno,
+ Ngt("error in copying file descriptor %d to %d"),
+ oldfd, newfd);
+ return -1;
}
- return newfd;
+ }
+ return newfd;
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
#endif /* REDIR_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* シグナルの情報を管理する構造体 */
typedef struct signal_T {
- int no;
- const char *name;
+ int no;
+ const char *name;
} signal_T;
/* シグナル情報の配列 */
static const signal_T signals[] = {
- /* POSIX.1-1990 で定義されたシグナル */
- { SIGHUP, "HUP", }, { SIGINT, "INT", }, { SIGQUIT, "QUIT", },
- { SIGILL, "ILL", }, { SIGABRT, "ABRT", }, { SIGFPE, "FPE", },
- { SIGKILL, "KILL", }, { SIGSEGV, "SEGV", }, { SIGPIPE, "PIPE", },
- { SIGALRM, "ALRM", }, { SIGTERM, "TERM", }, { SIGUSR1, "USR1", },
- { SIGUSR2, "USR2", }, { SIGCHLD, "CHLD", }, { SIGCONT, "CONT", },
- { SIGSTOP, "STOP", }, { SIGTSTP, "TSTP", }, { SIGTTIN, "TTIN", },
- { SIGTTOU, "TTOU", },
- /* SUSv2 & POSIX.1-2001 (SUSv3) で定義されたシグナル */
- { SIGBUS, "BUS", }, { SIGPROF, "PROF", }, { SIGSYS, "SYS", },
- { SIGTRAP, "TRAP", }, { SIGURG, "URG", }, { SIGXCPU, "XCPU", },
- { SIGXFSZ, "XFSZ", },
+ /* POSIX.1-1990 で定義されたシグナル */
+ { SIGHUP, "HUP", }, { SIGINT, "INT", }, { SIGQUIT, "QUIT", },
+ { SIGILL, "ILL", }, { SIGABRT, "ABRT", }, { SIGFPE, "FPE", },
+ { SIGKILL, "KILL", }, { SIGSEGV, "SEGV", }, { SIGPIPE, "PIPE", },
+ { SIGALRM, "ALRM", }, { SIGTERM, "TERM", }, { SIGUSR1, "USR1", },
+ { SIGUSR2, "USR2", }, { SIGCHLD, "CHLD", }, { SIGCONT, "CONT", },
+ { SIGSTOP, "STOP", }, { SIGTSTP, "TSTP", }, { SIGTTIN, "TTIN", },
+ { SIGTTOU, "TTOU", },
+ /* SUSv2 & POSIX.1-2001 (SUSv3) で定義されたシグナル */
+ { SIGBUS, "BUS", }, { SIGPROF, "PROF", }, { SIGSYS, "SYS", },
+ { SIGTRAP, "TRAP", }, { SIGURG, "URG", }, { SIGXCPU, "XCPU", },
+ { SIGXFSZ, "XFSZ", },
#ifdef SIGPOLL
- { SIGPOLL, "POLL", },
+ { SIGPOLL, "POLL", },
#endif
#ifdef SIGVTALRM
- { SIGVTALRM, "VTALRM", },
+ { SIGVTALRM, "VTALRM", },
#endif
- /* 他のシグナル */
+ /* 他のシグナル */
#ifdef SIGIOT
- { SIGIOT, "IOT", },
+ { SIGIOT, "IOT", },
#endif
#ifdef SIGEMT
- { SIGEMT, "EMT", },
+ { SIGEMT, "EMT", },
#endif
#ifdef SIGSTKFLT
- { SIGSTKFLT, "STKFLT", },
+ { SIGSTKFLT, "STKFLT", },
#endif
#ifdef SIGIO
- { SIGIO, "IO", },
+ { SIGIO, "IO", },
#endif
#ifdef SIGCLD
- { SIGCLD, "CLD", },
+ { SIGCLD, "CLD", },
#endif
#ifdef SIGPWR
- { SIGPWR, "PWR", },
+ { SIGPWR, "PWR", },
#endif
#ifdef SIGINFO
- { SIGINFO, "INFO", },
+ { SIGINFO, "INFO", },
#endif
#ifdef SIGLOST
- { SIGLOST, "LOST", },
+ { SIGLOST, "LOST", },
#endif
#ifdef SIGMSG
- { SIGMSG, "MSG", },
+ { SIGMSG, "MSG", },
#endif
#ifdef SIGWINCH
- { SIGWINCH, "WINCH", },
+ { SIGWINCH, "WINCH", },
#endif
#ifdef SIGDANGER
- { SIGDANGER, "DANGER", },
+ { SIGDANGER, "DANGER", },
#endif
#ifdef SIGMIGRATE
- { SIGMIGRATE, "MIGRATE", },
+ { SIGMIGRATE, "MIGRATE", },
#endif
#ifdef SIGPRE
- { SIGPRE, "PRE", },
+ { SIGPRE, "PRE", },
#endif
#ifdef SIGVIRT
- { SIGVIRT, "VIRT", },
+ { SIGVIRT, "VIRT", },
#endif
#ifdef SIGKAP
- { SIGKAP, "KAP", },
+ { SIGKAP, "KAP", },
#endif
#ifdef SIGGRANT
- { SIGGRANT, "GRANT", },
+ { SIGGRANT, "GRANT", },
#endif
#ifdef SIGRETRACT
- { SIGRETRACT, "RETRACT", },
+ { SIGRETRACT, "RETRACT", },
#endif
#ifdef SIGSOUND
- { SIGSOUND, "SOUND", },
+ { SIGSOUND, "SOUND", },
#endif
#ifdef SIGUNUSED
- { SIGUNUSED, "UNUSED", },
+ { SIGUNUSED, "UNUSED", },
#endif
- { 0, NULL, },
- /* 番号 0 のシグナルは存在しない (C99 7.14)
- * よってこれを配列の終わりの目印とする */
+ { 0, NULL, },
+ /* 番号 0 のシグナルは存在しない (C99 7.14)
+ * よってこれを配列の終わりの目印とする */
};
/* 各シグナルについて、受け取った後まだ処理していないことを示すフラグ */
* ものである。これらのシグナルに対して一度でもトラップが設定されると、
* そのシグナルの初期値は SIG_DFL に変更される。 */
static struct sigaction
- initsigchldaction, initsighupaction, initsigquitaction,
- initsigttouaction, initsigtstpaction,
- initsigtermaction, initsigintaction;
+ initsigchldaction, initsighupaction, initsigquitaction,
+ initsigttouaction, initsigtstpaction,
+ initsigtermaction, initsigintaction;
/* シグナルモジュールを初期化したかどうか
* これが true のとき、initsig{chld,hup,quit}action の値が有効である */
/* シグナルモジュールを初期化する */
void init_signal(void)
{
- struct sigaction action;
- sigset_t ss;
+ struct sigaction action;
+ sigset_t ss;
+
+ if (!initialized) {
+ initialized = true;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = sig_handler;
+ if (sigaction(SIGCHLD, &action, &initsigchldaction) < 0)
+ xerror(0, errno, "sigaction(SIGCHLD)");
+ if (sigaction(SIGHUP, &action, &initsighupaction) < 0)
+ xerror(0, errno, "sigaction(SIGHUP)");
+ if (sigaction(SIGQUIT, &action, &initsigquitaction) < 0)
+ xerror(0, errno, "sigaction(SIGQUIT)");
- if (!initialized) {
- initialized = true;
-
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- action.sa_handler = sig_handler;
- if (sigaction(SIGCHLD, &action, &initsigchldaction) < 0)
- xerror(0, errno, "sigaction(SIGCHLD)");
- if (sigaction(SIGHUP, &action, &initsighupaction) < 0)
- xerror(0, errno, "sigaction(SIGHUP)");
- if (sigaction(SIGQUIT, &action, &initsigquitaction) < 0)
- xerror(0, errno, "sigaction(SIGQUIT)");
-
- sigemptyset(&ss);
- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
- xerror(0, errno, "sigprocmask(SETMASK, nothing)");
- }
+ sigemptyset(&ss);
+ if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
+ xerror(0, errno, "sigprocmask(SETMASK, nothing)");
+ }
}
/* do_job_control と is_interactive_now に従ってシグナルを設定する。 */
void set_signals(void)
{
- struct sigaction action;
-
- if (do_job_control && !job_initialized) {
- job_initialized = true;
-
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- action.sa_handler = sig_handler;
- if (sigaction(SIGTTOU, &action, &initsigttouaction) < 0)
- xerror(0, errno, "sigaction(SIGTTOU)");
- if (sigaction(SIGTSTP, &action, &initsigtstpaction) < 0)
- xerror(0, errno, "sigaction(SIGTSTP)");
- }
- if (is_interactive_now && !interactive_initialized) {
- interactive_initialized = true;
-
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- action.sa_handler = sig_handler;
- if (sigaction(SIGINT, &action, &initsigintaction) < 0)
- xerror(0, errno, "sigaction(SIGINT)");
- if (sigaction(SIGTERM, &action, &initsigtermaction) < 0)
- xerror(0, errno, "sigaction(SIGTERM)");
- }
+ struct sigaction action;
+
+ if (do_job_control && !job_initialized) {
+ job_initialized = true;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = sig_handler;
+ if (sigaction(SIGTTOU, &action, &initsigttouaction) < 0)
+ xerror(0, errno, "sigaction(SIGTTOU)");
+ if (sigaction(SIGTSTP, &action, &initsigtstpaction) < 0)
+ xerror(0, errno, "sigaction(SIGTSTP)");
+ }
+ if (is_interactive_now && !interactive_initialized) {
+ interactive_initialized = true;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ action.sa_handler = sig_handler;
+ if (sigaction(SIGINT, &action, &initsigintaction) < 0)
+ xerror(0, errno, "sigaction(SIGINT)");
+ if (sigaction(SIGTERM, &action, &initsigtermaction) < 0)
+ xerror(0, errno, "sigaction(SIGTERM)");
+ }
}
/* シグナルハンドラを初期設定に戻す。
* qiignore: true なら、SIGQUIT と SIGINT はブロックしたままにする。 */
void reset_signals(bool qiignore)
{
- if (initialized) {
- if (sigaction(SIGCHLD, &initsigchldaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGCHLD)");
- if (sigaction(SIGHUP, &initsighupaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGHUP)");
- if (sigaction(SIGQUIT, &initsigquitaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGQUIT)");
- }
- if (job_initialized) {
- if (sigaction(SIGTTOU, &initsigttouaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGTTOU)");
- if (sigaction(SIGTSTP, &initsigtstpaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGTSTP)");
- }
- if (interactive_initialized) {
- if (sigaction(SIGINT, &initsigintaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGINT)");
- if (sigaction(SIGTERM, &initsigtermaction, NULL) < 0)
- xerror(0, errno, "sigaction(SIGTERM)");
- }
- if (qiignore) {
- sigset_t ss;
- sigemptyset(&ss);
- sigaddset(&ss, SIGQUIT);
- sigaddset(&ss, SIGINT);
- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
- xerror(0, errno, "sigprocmask(SETMASK, QUIT|INT)");
- }
+ if (initialized) {
+ if (sigaction(SIGCHLD, &initsigchldaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGCHLD)");
+ if (sigaction(SIGHUP, &initsighupaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGHUP)");
+ if (sigaction(SIGQUIT, &initsigquitaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGQUIT)");
+ }
+ if (job_initialized) {
+ if (sigaction(SIGTTOU, &initsigttouaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGTTOU)");
+ if (sigaction(SIGTSTP, &initsigtstpaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGTSTP)");
+ }
+ if (interactive_initialized) {
+ if (sigaction(SIGINT, &initsigintaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGINT)");
+ if (sigaction(SIGTERM, &initsigtermaction, NULL) < 0)
+ xerror(0, errno, "sigaction(SIGTERM)");
+ }
+ if (qiignore) {
+ sigset_t ss;
+ sigemptyset(&ss);
+ sigaddset(&ss, SIGQUIT);
+ sigaddset(&ss, SIGINT);
+ if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
+ xerror(0, errno, "sigprocmask(SETMASK, QUIT|INT)");
+ }
}
/* 汎用のシグナルハンドラ */
static void sig_handler(int signum)
{
#if defined SIGRTMIN && defined SIGRTMAX
- if (SIGRTMIN <= signum && signum <= SIGRTMAX) {
- size_t index = signum - SIGRTMIN;
- if (index < RTSIZE)
- rtsignal_received[index] = true;
- } else
+ if (SIGRTMIN <= signum && signum <= SIGRTMAX) {
+ size_t index = signum - SIGRTMIN;
+ if (index < RTSIZE)
+ rtsignal_received[index] = true;
+ } else
#endif
- {
- size_t index = sigindex(signum);
- assert(index < MAXSIGIDX);
- signal_received[index] = true;
-
- if (signum == SIGCHLD)
- sigchld_received = true;
- }
+ {
+ size_t index = sigindex(signum);
+ assert(index < MAXSIGIDX);
+ signal_received[index] = true;
+
+ if (signum == SIGCHLD)
+ sigchld_received = true;
+ }
}
/* wait_for_sigchld を呼ぶ前にこの関数を呼んで、
* SIGCHLD と SIGHUP をブロックする。 */
void block_signals(void)
{
- sigset_t ss;
+ sigset_t ss;
- sigemptyset(&ss);
- sigaddset(&ss, SIGCHLD);
- sigaddset(&ss, SIGHUP);
- if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
- xerror(0, errno, "sigprocmask(BLOCK, CHLD|HUP)");
+ sigemptyset(&ss);
+ sigaddset(&ss, SIGCHLD);
+ sigaddset(&ss, SIGHUP);
+ if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
+ xerror(0, errno, "sigprocmask(BLOCK, CHLD|HUP)");
}
/* wait_for_sigchld を呼んだ後にこの関数を呼んで、
* SIGCHLD と SIGHUP のブロックを解除する。 */
void unblock_signals(void)
{
- sigset_t ss;
+ sigset_t ss;
- sigemptyset(&ss);
- sigaddset(&ss, SIGCHLD);
- sigaddset(&ss, SIGHUP);
- if (sigprocmask(SIG_UNBLOCK, &ss, NULL) < 0)
- xerror(0, errno, "sigprocmask(UNBLOCK, CHLD|HUP)");
+ sigemptyset(&ss);
+ sigaddset(&ss, SIGCHLD);
+ sigaddset(&ss, SIGHUP);
+ if (sigprocmask(SIG_UNBLOCK, &ss, NULL) < 0)
+ xerror(0, errno, "sigprocmask(UNBLOCK, CHLD|HUP)");
}
/* SIGCHLD を受信するまで待機する。
* シェルを終了する。 */
void wait_for_sigchld(void)
{
- sigset_t ss;
-
- sigemptyset(&ss);
- for (;;) {
- if (signal_received[sigindex(SIGHUP)])
- (void) 0; // TODO sig.c: SIGHUP 受信時にシェルを終了する
- if (sigchld_received)
- break;
- if (sigsuspend(&ss) < 0 && errno != EINTR) {
- xerror(0, errno, "sigsuspend");
- break;
- }
+ sigset_t ss;
+
+ sigemptyset(&ss);
+ for (;;) {
+ if (signal_received[sigindex(SIGHUP)])
+ (void) 0; // TODO sig.c: SIGHUP 受信時にシェルを終了する
+ if (sigchld_received)
+ break;
+ if (sigsuspend(&ss) < 0 && errno != EINTR) {
+ xerror(0, errno, "sigsuspend");
+ break;
}
+ }
- sigchld_received = false;
+ sigchld_received = false;
}
/* トラップが設定されたシグナルを受信していたら、対応するコマンドを実行する。 */
void handle_traps(void)
{
- (void) trap_command;
- (void) rttrap_command;
- // TODO sig.c: handle_traps: 未実装
+ (void) trap_command;
+ (void) rttrap_command;
+ // TODO sig.c: handle_traps: 未実装
}
/* SIG_IGN 以外に設定したトラップを全て解除する */
void clear_traps(void)
{
- // TODO sig.c: clear_traps: 未実装
+ // TODO sig.c: clear_traps: 未実装
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
#endif /* SIG_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
/* 未初期化のマルチバイト文字列バッファ *buf を空文字列で初期化する。*/
xstrbuf_T *sb_init(xstrbuf_T *buf)
{
- buf->contents = xmalloc((XSTRBUF_INITSIZE + 1) * sizeof (char));
- buf->contents[0] = '\0';
- buf->length = 0;
- buf->maxlength = XSTRBUF_INITSIZE;
- return buf;
+ buf->contents = xmalloc((XSTRBUF_INITSIZE + 1) * sizeof (char));
+ buf->contents[0] = '\0';
+ buf->length = 0;
+ buf->maxlength = XSTRBUF_INITSIZE;
+ return buf;
}
/* 未初期化の文字列バッファ *buf をマルチバイト文字列 *s で初期化する。
* この関数で初期化するバッファの所有物となる。 */
xstrbuf_T *sb_initwith(xstrbuf_T *restrict buf, char *restrict s)
{
- buf->contents = s;
- buf->length = buf->maxlength = strlen(s);
- return buf;
+ buf->contents = s;
+ buf->length = buf->maxlength = strlen(s);
+ return buf;
}
/* マルチバイト文字列バッファ *buf を解放し、未初期化状態に戻す。 */
void sb_destroy(xstrbuf_T *buf)
{
- free(buf->contents);
+ free(buf->contents);
}
/* マルチバイト文字列バッファ *buf を解放し、バッファの内容だった文字列を返す。
* *buf は未初期化状態になる。戻り値は呼出し元が free すること。 */
char *sb_tostr(xstrbuf_T *buf)
{
- if (buf->maxlength - buf->length > 20)
- sb_setmax(buf, buf->length);
- return buf->contents;
+ if (buf->maxlength - buf->length > 20)
+ sb_setmax(buf, buf->length);
+ return buf->contents;
}
/* buf->maxlength を変更する。newmax < buf->length ならば末尾が消える。 */
xstrbuf_T *sb_setmax(xstrbuf_T *buf, size_t newmax)
{
- buf->contents = xrealloc(buf->contents, (newmax + 1) * sizeof (char));
- buf->maxlength = newmax;
- buf->contents[newmax] = '\0';
- if (newmax < buf->length)
- buf->length = newmax;
- return buf;
+ buf->contents = xrealloc(buf->contents, (newmax + 1) * sizeof (char));
+ buf->maxlength = newmax;
+ buf->contents[newmax] = '\0';
+ if (newmax < buf->length)
+ buf->length = newmax;
+ return buf;
}
/* buf->maxlength が max 未満なら、max 以上になるようにメモリを再確保する。 */
inline xstrbuf_T *sb_ensuremax(xstrbuf_T *buf, size_t max)
{
- if (buf->maxlength < max) {
- size_t newmax = buf->maxlength;
- do
- newmax = newmax * 2 + 1;
- while (newmax < max);
- return sb_setmax(buf, newmax);
- } else {
- return buf;
- }
+ if (buf->maxlength < max) {
+ size_t newmax = buf->maxlength;
+ do
+ newmax = newmax * 2 + 1;
+ while (newmax < max);
+ return sb_setmax(buf, newmax);
+ } else {
+ return buf;
+ }
}
/* マルチバイト文字列バッファを空にする。buf->maxlength は変わらない。 */
xstrbuf_T *sb_clear(xstrbuf_T *buf)
{
- buf->contents[buf->length = 0] = '\0';
- return buf;
+ buf->contents[buf->length = 0] = '\0';
+ return buf;
}
/* マルチバイト文字列バッファの i バイト目から bn バイトを
* 特に、buf->length <= i ならば文字列の末尾に追加する。
* s は buf->contents の一部であってはならない。 */
xstrbuf_T *sb_replace(
- xstrbuf_T *restrict buf, size_t i, size_t bn,
- const char *restrict s, size_t sn)
+ xstrbuf_T *restrict buf, size_t i, size_t bn,
+ const char *restrict s, size_t sn)
{
- sn = xstrnlen(s, sn);
- if (i > buf->length)
- i = buf->length;
- if (bn > buf->length - i)
- bn = buf->length - i;
-
- size_t newlength = buf->length - bn + sn;
- sb_ensuremax(buf, newlength);
- memmove(buf->contents + i + sn, buf->contents + i + bn,
- buf->length - (i + bn) + 1);
- memcpy(buf->contents + i, s, sn);
- buf->length = newlength;
- return buf;
+ sn = xstrnlen(s, sn);
+ if (i > buf->length)
+ i = buf->length;
+ if (bn > buf->length - i)
+ bn = buf->length - i;
+
+ size_t newlength = buf->length - bn + sn;
+ sb_ensuremax(buf, newlength);
+ memmove(buf->contents + i + sn, buf->contents + i + bn,
+ buf->length - (i + bn) + 1);
+ memcpy(buf->contents + i, s, sn);
+ buf->length = newlength;
+ return buf;
}
/* バッファの末尾にバイト c を追加する。 */
xstrbuf_T *sb_ccat(xstrbuf_T *buf, char c)
{
- sb_ensuremax(buf, buf->length + 1);
- buf->contents[buf->length++] = c;
- buf->contents[buf->length] = '\0';
- return buf;
+ sb_ensuremax(buf, buf->length + 1);
+ buf->contents[buf->length++] = c;
+ buf->contents[buf->length] = '\0';
+ return buf;
}
/* ワイド文字列をマルチバイト文字列に変換しバッファに追加する。
* エラーがあった場合でも、途中までは buf->contents に文字列が書き込まれる。
* s が NULL なら、シフト状態を初期状態に戻す文字列を追加する。 */
wchar_t *sb_wcscat(xstrbuf_T *restrict buf,
- const wchar_t *restrict s, mbstate_t *restrict ps)
+ const wchar_t *restrict s, mbstate_t *restrict ps)
{
- size_t count;
-
- if (s) {
- for (;;) {
- count = wcsrtombs(buf->contents + buf->length,
- (const wchar_t **) &s,
- buf->maxlength - buf->length + 1,
- ps);
- if (count == (size_t) -1)
- break;
- buf->length += count;
- if (!s)
- break;
- sb_ensuremax(buf, buf->maxlength * 2);
- }
- } else {
- mbstate_t saveps = *ps;
- count = wcrtomb(NULL, L'\0', &saveps);
- if (count == (size_t) -1)
- return NULL;
- sb_ensuremax(buf, buf->length + count - 1);
- count = wcrtomb(buf->contents + buf->length, L'\0', ps);
- assert(0 < count && count - 1 <= buf->maxlength - buf->length);
- buf->length += count - 1;
- }
+ size_t count;
- assert(buf->contents[buf->length] == '\0');
- return (wchar_t *) s;
+ if (s) {
+ for (;;) {
+ count = wcsrtombs(buf->contents + buf->length,
+ (const wchar_t **) &s,
+ buf->maxlength - buf->length + 1,
+ ps);
+ if (count == (size_t) -1)
+ break;
+ buf->length += count;
+ if (!s)
+ break;
+ sb_ensuremax(buf, buf->maxlength * 2);
+ }
+ } else {
+ mbstate_t saveps = *ps;
+ count = wcrtomb(NULL, L'\0', &saveps);
+ if (count == (size_t) -1)
+ return NULL;
+ sb_ensuremax(buf, buf->length + count - 1);
+ count = wcrtomb(buf->contents + buf->length, L'\0', ps);
+ assert(0 < count && count - 1 <= buf->maxlength - buf->length);
+ buf->length += count - 1;
+ }
+
+ assert(buf->contents[buf->length] == '\0');
+ return (wchar_t *) s;
}
/* 文字列をフォーマットして、文字列バッファの末尾に付け加える。
* format, ap 引数と戻り値の意味は vsprintf に準じる。 */
int sb_vprintf(xstrbuf_T *restrict buf, const char *restrict format, va_list ap)
{
- va_list saveap;
- va_copy(saveap, ap);
-
- ssize_t rest = buf->maxlength - buf->length + 1;
- int result = vsnprintf(buf->contents + buf->length, rest, format, ap);
-
- if (result >= rest) {
- /* バッファが足りなかった場合 */
- sb_ensuremax(buf, buf->length + result);
- rest = buf->maxlength - buf->length + 1;
- result = vsnprintf(buf->contents + buf->length, rest, format, saveap);
- }
- assert(result <= rest - 1);
- if (result >= 0)
- buf->length += result;
- assert(buf->contents[buf->length] == '\0');
- va_end(saveap);
- return result;
+ va_list saveap;
+ va_copy(saveap, ap);
+
+ ssize_t rest = buf->maxlength - buf->length + 1;
+ int result = vsnprintf(buf->contents + buf->length, rest, format, ap);
+
+ if (result >= rest) {
+ /* バッファが足りなかった場合 */
+ sb_ensuremax(buf, buf->length + result);
+ rest = buf->maxlength - buf->length + 1;
+ result = vsnprintf(buf->contents + buf->length, rest, format, saveap);
+ }
+ assert(result <= rest - 1);
+ if (result >= 0)
+ buf->length += result;
+ assert(buf->contents[buf->length] == '\0');
+ va_end(saveap);
+ return result;
}
/* 文字列をフォーマットして、文字列バッファの末尾に付け加える。
* format やそれ以降の引数と戻り値の意味は sprintf に準じる。 */
int sb_printf(xstrbuf_T *restrict buf, const char *restrict format, ...)
{
- va_list ap;
- int result;
+ va_list ap;
+ int result;
- va_start(ap, format);
- result = sb_vprintf(buf, format, ap);
- va_end(ap);
- return result;
+ va_start(ap, format);
+ result = sb_vprintf(buf, format, ap);
+ va_end(ap);
+ return result;
}
/* strftime の結果を文字列バッファの末尾に付け加える。
* format は、フォーマット結果が 0 文字となるようなものであってはならない。
* 戻り値: 増えた文字数 */
size_t sb_strftime(xstrbuf_T *restrict buf,
- const char *restrict format, const struct tm *restrict tm)
+ const char *restrict format, const struct tm *restrict tm)
{
- /* まず 40 バイトのバッファで変換できるか試す */
- char result[40];
- size_t count = strftime(result, sizeof result, format, tm);
- if (count) {
- sb_cat(buf, result);
- return count;
- }
-
- /* 結果が 40 文字を越える場合はバッファを増やしながらやり直す */
- size_t len = sizeof result;
- do {
- len *= 2;
- sb_ensuremax(buf, buf->length + len);
- count = strftime(buf->contents + buf->length,
- buf->maxlength - buf->length + 1,
- format,
- tm);
- } while (count == 0);
+ /* まず 40 バイトのバッファで変換できるか試す */
+ char result[40];
+ size_t count = strftime(result, sizeof result, format, tm);
+ if (count) {
+ sb_cat(buf, result);
return count;
+ }
+
+ /* 結果が 40 文字を越える場合はバッファを増やしながらやり直す */
+ size_t len = sizeof result;
+ do {
+ len *= 2;
+ sb_ensuremax(buf, buf->length + len);
+ count = strftime(buf->contents + buf->length,
+ buf->maxlength - buf->length + 1,
+ format,
+ tm);
+ } while (count == 0);
+ return count;
}
/* 未初期化のワイド文字列バッファ *buf を空文字列で初期化する。*/
xwcsbuf_T *wb_init(xwcsbuf_T *buf)
{
- buf->contents = xmalloc((XWCSBUF_INITSIZE + 1) * sizeof (wchar_t));
- buf->contents[0] = L'\0';
- buf->length = 0;
- buf->maxlength = XWCSBUF_INITSIZE;
- return buf;
+ buf->contents = xmalloc((XWCSBUF_INITSIZE + 1) * sizeof (wchar_t));
+ buf->contents[0] = L'\0';
+ buf->length = 0;
+ buf->maxlength = XWCSBUF_INITSIZE;
+ return buf;
}
/* 未初期化のワイド文字列バッファ *buf をワイド文字列 *s で初期化する。
* この関数で初期化するバッファの所有物となる。 */
xwcsbuf_T *wb_initwith(xwcsbuf_T *restrict buf, wchar_t *restrict s)
{
- buf->contents = s;
- buf->length = buf->maxlength = wcslen(s);
- return buf;
+ buf->contents = s;
+ buf->length = buf->maxlength = wcslen(s);
+ return buf;
}
/* ワイド文字列バッファ *buf を解放し、未初期化状態に戻す。 */
void wb_destroy(xwcsbuf_T *buf)
{
- free(buf->contents);
+ free(buf->contents);
}
/* ワイド文字列バッファ *buf を解放し、バッファの内容だった文字列を返す。
* *buf は未初期化状態になる。戻り値は呼出し元が free すること。 */
wchar_t *wb_towcs(xwcsbuf_T *buf)
{
- if (buf->maxlength - buf->length > 20)
- wb_setmax(buf, buf->length);
- return buf->contents;
+ if (buf->maxlength - buf->length > 20)
+ wb_setmax(buf, buf->length);
+ return buf->contents;
}
/* buf->maxlength を変更する。newmax < buf->length ならば末尾が消える。 */
xwcsbuf_T *wb_setmax(xwcsbuf_T *buf, size_t newmax)
{
- buf->contents = xrealloc(buf->contents, (newmax + 1) * sizeof (wchar_t));
- buf->maxlength = newmax;
- buf->contents[newmax] = L'\0';
- if (newmax < buf->length)
- buf->length = newmax;
- return buf;
+ buf->contents = xrealloc(buf->contents, (newmax + 1) * sizeof (wchar_t));
+ buf->maxlength = newmax;
+ buf->contents[newmax] = L'\0';
+ if (newmax < buf->length)
+ buf->length = newmax;
+ return buf;
}
/* ワイド文字列バッファを空にする。buf->maxlength は変わらない。 */
xwcsbuf_T *wb_clear(xwcsbuf_T *buf)
{
- buf->contents[buf->length = 0] = L'\0';
- return buf;
+ buf->contents[buf->length = 0] = L'\0';
+ return buf;
}
/* buf->maxlength が max 未満なら、max 以上になるようにメモリを再確保する。 */
inline xwcsbuf_T *wb_ensuremax(xwcsbuf_T *buf, size_t max)
{
- if (buf->maxlength < max) {
- size_t newmax = buf->maxlength;
- do
- newmax = newmax * 2 + 1;
- while (newmax < max);
- return wb_setmax(buf, newmax);
- } else {
- return buf;
- }
+ if (buf->maxlength < max) {
+ size_t newmax = buf->maxlength;
+ do
+ newmax = newmax * 2 + 1;
+ while (newmax < max);
+ return wb_setmax(buf, newmax);
+ } else {
+ return buf;
+ }
}
/* バッファの i 文字目から bn 文字をワイド文字列 s の最初の sn 文字に置換する。
* 特に、buf->length <= i ならば文字列の末尾に追加する。
* s は buf->contents の一部であってはならない。 */
xwcsbuf_T *wb_replace(
- xwcsbuf_T *restrict buf, size_t i, size_t bn,
- const wchar_t *restrict s, size_t sn)
+ xwcsbuf_T *restrict buf, size_t i, size_t bn,
+ const wchar_t *restrict s, size_t sn)
{
- sn = xwcsnlen(s, sn);
- if (i > buf->length)
- i = buf->length;
- if (bn > buf->length - i)
- bn = buf->length - i;
-
- size_t newlength = buf->length - bn + sn;
- wb_ensuremax(buf, newlength);
- wmemmove(buf->contents + i + sn, buf->contents + i + bn,
- buf->length - (i + bn) + 1);
- wmemcpy(buf->contents + i, s, sn);
- buf->length = newlength;
- return buf;
+ sn = xwcsnlen(s, sn);
+ if (i > buf->length)
+ i = buf->length;
+ if (bn > buf->length - i)
+ bn = buf->length - i;
+
+ size_t newlength = buf->length - bn + sn;
+ wb_ensuremax(buf, newlength);
+ wmemmove(buf->contents + i + sn, buf->contents + i + bn,
+ buf->length - (i + bn) + 1);
+ wmemcpy(buf->contents + i, s, sn);
+ buf->length = newlength;
+ return buf;
}
/* バッファの末尾にワイド文字 c を追加する。 */
xwcsbuf_T *wb_wccat(xwcsbuf_T *buf, wchar_t c)
{
- wb_ensuremax(buf, buf->length + 1);
- buf->contents[buf->length++] = c;
- buf->contents[buf->length] = L'\0';
- return buf;
+ wb_ensuremax(buf, buf->length + 1);
+ buf->contents[buf->length++] = c;
+ buf->contents[buf->length] = L'\0';
+ return buf;
}
/* マルチバイト文字列をワイド文字列に変換しバッファに追加する。
* エラーがあった場合でも、途中までは buf->contents に文字列が書き込まれる。 */
char *wb_mbscat(xwcsbuf_T *restrict buf, const char *restrict s)
{
- mbstate_t state;
- size_t count;
-
- memset(&state, 0, sizeof state); /* state を初期シフト状態で初期化 */
-
- for (;;) {
- count = mbsrtowcs(buf->contents + buf->length, (const char **) &s,
- buf->maxlength - buf->length + 1, &state);
- if (count == (size_t) -1)
- break;
- buf->length += count;
- if (!s)
- break;
- wb_ensuremax(buf, buf->maxlength * 2);
- }
-
- buf->contents[buf->length] = L'\0';
- return (char *) s;
+ mbstate_t state;
+ size_t count;
+
+ memset(&state, 0, sizeof state); /* state を初期シフト状態で初期化 */
+
+ for (;;) {
+ count = mbsrtowcs(buf->contents + buf->length, (const char **) &s,
+ buf->maxlength - buf->length + 1, &state);
+ if (count == (size_t) -1)
+ break;
+ buf->length += count;
+ if (!s)
+ break;
+ wb_ensuremax(buf, buf->maxlength * 2);
+ }
+
+ buf->contents[buf->length] = L'\0';
+ return (char *) s;
}
/* 文字列をフォーマットして、文字列バッファの末尾に付け加える。
* format やそれ以降の引数が buf->contents の一部であってはならない。
* format やそれ以降の引数と戻り値の意味は vswprintf に準じる。 */
int wb_vprintf(
- xwcsbuf_T *restrict buf, const wchar_t *restrict format, va_list ap)
+ xwcsbuf_T *restrict buf, const wchar_t *restrict format, va_list ap)
{
- va_list saveap;
- va_copy(saveap, ap);
+ va_list saveap;
+ va_copy(saveap, ap);
- ssize_t rest;
- int result;
+ ssize_t rest;
+ int result;
- for (int i = 0; i < 10; i++) {
- rest = buf->maxlength - buf->length + 1;
- result = vswprintf(buf->contents + buf->length, rest, format, ap);
+ for (int i = 0; i < 10; i++) {
+ rest = buf->maxlength - buf->length + 1;
+ result = vswprintf(buf->contents + buf->length, rest, format, ap);
- if (0 <= result && result < rest)
- break;
+ if (0 <= result && result < rest)
+ break;
- /* バッファが足りなかった場合、規格上負数が返ってくるはずなのだが、
- * (vsprintf と同様に) 必要なバッファの文字数を返すシステムもある。
- * (実際のところ、プログラマとしてはその方が嬉しかったりする) */
- wb_ensuremax(buf, buf->length + (result < 0 ? 2 * rest : result));
- va_end(ap);
- va_copy(ap, saveap);
- }
- if (result >= 0)
- buf->length += result;
- assert(buf->contents[buf->length] == L'\0');
+ /* バッファが足りなかった場合、規格上負数が返ってくるはずなのだが、
+ * (vsprintf と同様に) 必要なバッファの文字数を返すシステムもある。
+ * (実際のところ、プログラマとしてはその方が嬉しかったりする) */
+ wb_ensuremax(buf, buf->length + (result < 0 ? 2 * rest : result));
va_end(ap);
- va_end(saveap);
- return result;
+ va_copy(ap, saveap);
+ }
+ if (result >= 0)
+ buf->length += result;
+ assert(buf->contents[buf->length] == L'\0');
+ va_end(ap);
+ va_end(saveap);
+ return result;
}
/* 文字列をフォーマットして、文字列バッファの末尾に付け加える。
* format やそれ以降の引数と戻り値の意味は swprintf に準じる。 */
int wb_printf(xwcsbuf_T *restrict buf, const wchar_t *restrict format, ...)
{
- va_list ap;
- int result;
+ va_list ap;
+ int result;
- va_start(ap, format);
- result = wb_vprintf(buf, format, ap);
- va_end(ap);
- return result;
+ va_start(ap, format);
+ result = wb_vprintf(buf, format, ap);
+ va_end(ap);
+ return result;
}
* 変換の際にエラーがあると NULL を返す。 */
char *malloc_wcstombs(const wchar_t *s, size_t n)
{
- xstrbuf_T buf;
- mbstate_t state;
- wchar_t ss[n + 1];
- size_t nn = xwcsnlen(s, n);
-
- if (s[nn] != L'\0') {
- wcsncpy(ss, s, nn);
- ss[nn] = L'\0';
- s = ss;
- }
-
- sb_init(&buf);
- memset(&state, 0, sizeof state); /* 状態を初期状態で初期化 */
- if (sb_wcscat(&buf, s, &state) == NULL
- && sb_wcscat(&buf, NULL, &state) == NULL) {
- return sb_tostr(&buf);
- } else {
- sb_destroy(&buf);
- return NULL;
- }
+ xstrbuf_T buf;
+ mbstate_t state;
+ wchar_t ss[n + 1];
+ size_t nn = xwcsnlen(s, n);
+
+ if (s[nn] != L'\0') {
+ wcsncpy(ss, s, nn);
+ ss[nn] = L'\0';
+ s = ss;
+ }
+
+ sb_init(&buf);
+ memset(&state, 0, sizeof state); /* 状態を初期状態で初期化 */
+ if (sb_wcscat(&buf, s, &state) == NULL
+ && sb_wcscat(&buf, NULL, &state) == NULL) {
+ return sb_tostr(&buf);
+ } else {
+ sb_destroy(&buf);
+ return NULL;
+ }
}
/* マルチバイト文字列 s の先頭最大 n 文字をワイド文字列に変換し、
* 変換の際にエラーがあると NULL を返す。 */
wchar_t *malloc_mbstowcs(const char *s, size_t n)
{
- xwcsbuf_T buf;
- char ss[n + 1];
- size_t nn = xstrnlen(s, n);
-
- if (s[nn] != '\0') {
- strncpy(ss, s, nn);
- ss[nn] = '\0';
- s = ss;
- }
-
- wb_init(&buf);
- if (wb_mbscat(&buf, s) == NULL) {
- return wb_towcs(&buf);
- } else {
- wb_destroy(&buf);
- return NULL;
- }
+ xwcsbuf_T buf;
+ char ss[n + 1];
+ size_t nn = xstrnlen(s, n);
+
+ if (s[nn] != '\0') {
+ strncpy(ss, s, nn);
+ ss[nn] = '\0';
+ s = ss;
+ }
+
+ wb_init(&buf);
+ if (wb_mbscat(&buf, s) == NULL) {
+ return wb_towcs(&buf);
+ } else {
+ wb_destroy(&buf);
+ return NULL;
+ }
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
typedef struct xstrbuf_T {
- char *contents;
- size_t length, maxlength;
+ char *contents;
+ size_t length, maxlength;
} xstrbuf_T;
typedef struct xwcsbuf_T {
- wchar_t *contents;
- size_t length, maxlength;
+ wchar_t *contents;
+ size_t length, maxlength;
} xwcsbuf_T;
__attribute__((nonnull))
extern xstrbuf_T *sb_clear(xstrbuf_T *buf);
__attribute__((nonnull))
extern xstrbuf_T *sb_replace(
- xstrbuf_T *restrict buf, size_t i, size_t bn,
- const char *restrict s, size_t sn);
+ xstrbuf_T *restrict buf, size_t i, size_t bn,
+ const char *restrict s, size_t sn);
__attribute__((nonnull))
static inline xstrbuf_T *sb_ninsert(
- xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n);
+ xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n);
__attribute__((nonnull))
static inline xstrbuf_T *sb_insert(
- xstrbuf_T *restrict buf, size_t i, const char *restrict s);
+ xstrbuf_T *restrict buf, size_t i, const char *restrict s);
__attribute__((nonnull))
static inline xstrbuf_T *sb_ncat(
- xstrbuf_T *restrict buf, const char *restrict s, size_t n);
+ xstrbuf_T *restrict buf, const char *restrict s, size_t n);
__attribute__((nonnull))
static inline xstrbuf_T *sb_cat(
- xstrbuf_T *restrict buf, const char *restrict s);
+ xstrbuf_T *restrict buf, const char *restrict s);
__attribute__((nonnull))
static inline xstrbuf_T *sb_remove(xstrbuf_T *buf, size_t i, size_t n);
__attribute__((nonnull))
extern xstrbuf_T *sb_ccat(xstrbuf_T *buf, char c);
__attribute__((nonnull(1)))
extern wchar_t *sb_wcscat(
- xstrbuf_T *restrict buf,
- const wchar_t *restrict s, mbstate_t *restrict ps);
+ xstrbuf_T *restrict buf,
+ const wchar_t *restrict s, mbstate_t *restrict ps);
__attribute__((nonnull(1,2),format(printf,2,0)))
extern int sb_vprintf(
- xstrbuf_T *restrict buf, const char *restrict format, va_list ap);
+ xstrbuf_T *restrict buf, const char *restrict format, va_list ap);
__attribute__((nonnull(1,2),format(printf,2,3)))
extern int sb_printf(
- xstrbuf_T *restrict buf, const char *restrict format, ...);
+ xstrbuf_T *restrict buf, const char *restrict format, ...);
__attribute__((nonnull,format(strftime,2,0)))
extern size_t sb_strftime(
- xstrbuf_T *restrict buf,
- const char *restrict format, const struct tm *restrict tm);
+ xstrbuf_T *restrict buf,
+ const char *restrict format, const struct tm *restrict tm);
__attribute__((nonnull))
extern xwcsbuf_T *wb_init(xwcsbuf_T *buf);
extern xwcsbuf_T *wb_clear(xwcsbuf_T *buf);
__attribute__((nonnull))
extern xwcsbuf_T *wb_replace(
- xwcsbuf_T *restrict buf, size_t i, size_t bn,
- const wchar_t *restrict s, size_t sn);
+ xwcsbuf_T *restrict buf, size_t i, size_t bn,
+ const wchar_t *restrict s, size_t sn);
__attribute__((nonnull))
static inline xwcsbuf_T *wb_ninsert(
- xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n);
+ xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n);
__attribute__((nonnull))
static inline xwcsbuf_T *wb_insert(
- xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s);
+ xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s);
__attribute__((nonnull))
static inline xwcsbuf_T *wb_ncat(
- xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n);
+ xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n);
__attribute__((nonnull))
static inline xwcsbuf_T *wb_cat(
- xwcsbuf_T *restrict buf, const wchar_t *restrict s);
+ xwcsbuf_T *restrict buf, const wchar_t *restrict s);
__attribute__((nonnull))
static inline xwcsbuf_T *wb_remove(xwcsbuf_T *buf, size_t i, size_t n);
__attribute__((nonnull))
extern char *wb_mbscat(xwcsbuf_T *restrict buf, const char *restrict s);
__attribute__((nonnull(1,2)))
extern int wb_vprintf(
- xwcsbuf_T *restrict buf, const wchar_t *restrict format, va_list ap);
+ xwcsbuf_T *restrict buf, const wchar_t *restrict format, va_list ap);
__attribute__((nonnull(1,2)))
extern int wb_printf(
- xwcsbuf_T *restrict buf, const wchar_t *restrict format, ...);
+ xwcsbuf_T *restrict buf, const wchar_t *restrict format, ...);
__attribute__((nonnull,malloc,warn_unused_result))
extern char *malloc_wcstombs(const wchar_t *s, size_t n);
* buf->length <= i ならば文字列の末尾に追加する。
* s は buf->contents の一部であってはならない。 */
static inline xstrbuf_T *sb_ninsert(
- xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
+ xstrbuf_T *restrict buf, size_t i, const char *restrict s, size_t n)
{
- return sb_replace(buf, i, 0, s, n);
+ return sb_replace(buf, i, 0, s, n);
}
/* マルチバイト文字列 s をバッファの i バイト目の手前に挿入する。
* buf->length <= i ならば文字列の末尾に追加する。
* s は buf->contents の一部であってはならない。 */
static inline xstrbuf_T *sb_insert(
- xstrbuf_T *restrict buf, size_t i, const char *restrict s)
+ xstrbuf_T *restrict buf, size_t i, const char *restrict s)
{
- return sb_replace(buf, i, 0, s, SIZE_MAX);
+ return sb_replace(buf, i, 0, s, SIZE_MAX);
}
/* マルチバイト文字列 s の最初の n バイトを文字列バッファに追加する。
* strlen(s) < n ならば s 全体を追加する。
* s は buf->contents の一部であってはならない。 */
static inline xstrbuf_T *sb_ncat(
- xstrbuf_T *restrict buf, const char *restrict s, size_t n)
+ xstrbuf_T *restrict buf, const char *restrict s, size_t n)
{
- return sb_replace(buf, SIZE_MAX, 0, s, n);
+ return sb_replace(buf, SIZE_MAX, 0, s, n);
}
/* マルチバイト文字列 s を文字列バッファに追加する。
* s は buf->contents の一部であってはならない。 */
static inline xstrbuf_T *sb_cat(
- xstrbuf_T *restrict buf, const char *restrict s)
+ xstrbuf_T *restrict buf, const char *restrict s)
{
- return sb_replace(buf, SIZE_MAX, 0, s, SIZE_MAX);
+ return sb_replace(buf, SIZE_MAX, 0, s, SIZE_MAX);
}
/* マルチバイト文字列バッファの i バイト目から n バイトを削除する。
* buf->length <= i + n ならば i バイト目以降全てを削除する。 */
static inline xstrbuf_T *sb_remove(xstrbuf_T *buf, size_t i, size_t n)
{
- return sb_replace(buf, i, n, "", 0);
+ return sb_replace(buf, i, n, "", 0);
}
* buf->length <= i ならば文字列の末尾に追加する。
* s は buf->contents の一部であってはならない。 */
static inline xwcsbuf_T *wb_ninsert(
- xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
+ xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s, size_t n)
{
- return wb_replace(buf, i, 0, s, n);
+ return wb_replace(buf, i, 0, s, n);
}
/* ワイド文字列 s をバッファの i 文字目の手前に挿入する。
* buf->length <= i ならば文字列の末尾に追加する。
* s は buf->contents の一部であってはならない。 */
static inline xwcsbuf_T *wb_insert(
- xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s)
+ xwcsbuf_T *restrict buf, size_t i, const wchar_t *restrict s)
{
- return wb_replace(buf, i, 0, s, SIZE_MAX);
+ return wb_replace(buf, i, 0, s, SIZE_MAX);
}
/* ワイド文字列 s の最初の n 文字を文字列バッファに追加する。
* wcslen(s) < n ならば s 全体を追加する。
* s は buf->contents の一部であってはならない。 */
static inline xwcsbuf_T *wb_ncat(
- xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
+ xwcsbuf_T *restrict buf, const wchar_t *restrict s, size_t n)
{
- return wb_replace(buf, SIZE_MAX, 0, s, n);
+ return wb_replace(buf, SIZE_MAX, 0, s, n);
}
/* ワイド文字列 s を文字列バッファに追加する。
* s は buf->contents の一部であってはならない。 */
static inline xwcsbuf_T *wb_cat(
- xwcsbuf_T *restrict buf, const wchar_t *restrict s)
+ xwcsbuf_T *restrict buf, const wchar_t *restrict s)
{
- return wb_replace(buf, SIZE_MAX, 0, s, SIZE_MAX);
+ return wb_replace(buf, SIZE_MAX, 0, s, SIZE_MAX);
}
/* ワイド文字列バッファの i 文字目から n 文字を削除する。
* buf->length <= i + n ならば i 文字目以降全てを削除する。 */
static inline xwcsbuf_T *wb_remove(xwcsbuf_T *buf, size_t i, size_t n)
{
- return wb_replace(buf, i, n, L"", 0);
+ return wb_replace(buf, i, n, L"", 0);
}
#endif /* STRBUF_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
failed=0
for x in *.tests
do
- echo $x...
- if ! ${TESTEE} $x 2>&1 | diff - ${x%.tests}.right
- then
- failed=$(( ${failed} + 1 ))
- fi
+ echo $x...
+ if ! ${TESTEE} $x 2>&1 | diff - ${x%.tests}.right
+ then
+ failed=$(( ${failed} + 1 ))
+ fi
done
echo "${failed} test(s) failed."
test 0 -eq ${failed}
+
+
+# vim: set ts=8 sts=4 sw=4 noet:
/* Unused function
void *xcalloc(size_t nmemb, size_t size)
{
- void *result = calloc(nmemb, size);
- if (result)
- return result;
- xerror(2, ENOMEM, NULL);
- assert(false);
+ void *result = calloc(nmemb, size);
+ if (result)
+ return result;
+ xerror(2, ENOMEM, NULL);
+ assert(false);
}
*/
/* malloc を試みる。失敗したらプログラムを強制終了する。 */
void *xmalloc(size_t size)
{
- void *result = malloc(size);
- if (result)
- return result;
- xerror(2, ENOMEM, NULL);
- assert(false);
+ void *result = malloc(size);
+ if (result)
+ return result;
+ xerror(2, ENOMEM, NULL);
+ assert(false);
}
/* realloc を試みる。失敗したらプログラムを強制終了する。 */
void *xrealloc(void *ptr, size_t size)
{
- void *result = realloc(ptr, size);
- if (result)
- return result;
- xerror(2, ENOMEM, NULL);
- assert(false);
+ void *result = realloc(ptr, size);
+ if (result)
+ return result;
+ xerror(2, ENOMEM, NULL);
+ assert(false);
}
* len が s の実際の長さより大きければ s 全体を複製する */
char *xstrndup(const char *s, size_t len)
{
- len = xstrnlen(s, len);
+ len = xstrnlen(s, len);
- char *result = xmalloc(len + 1);
- result[len] = '\0';
- return memcpy(result, s, len);
+ char *result = xmalloc(len + 1);
+ result[len] = '\0';
+ return memcpy(result, s, len);
}
/* 文字列を新しく malloc した領域に複製する。
* len が s の実際の長さより大きければ s 全体を複製する */
wchar_t *xwcsndup(const wchar_t *s, size_t len)
{
- len = xwcsnlen(s, len);
+ len = xwcsnlen(s, len);
- wchar_t *result = xmalloc((len + 1) * sizeof(wchar_t));
- result[len] = L'\0';
- return wmemcpy(result, s, len);
+ wchar_t *result = xmalloc((len + 1) * sizeof(wchar_t));
+ result[len] = L'\0';
+ return wmemcpy(result, s, len);
}
/* 文字列 s が prefix で始まるなら、s 内の prefix を飛ばした最初の文字への
/* Unused function
char *matchstrprefix(const char *s, const char *prefix)
{
- while (*prefix) {
- if (*prefix != *s)
- return NULL;
- prefix++;
- s++;
- }
- return (char *) s;
+ while (*prefix) {
+ if (*prefix != *s)
+ return NULL;
+ prefix++;
+ s++;
+ }
+ return (char *) s;
}
*/
* ポインタを返し、さもなくば NULL を返す。 */
wchar_t *matchwcsprefix(const wchar_t *s, const wchar_t *prefix)
{
- while (*prefix) {
- if (*prefix != *s)
- return NULL;
- prefix++;
- s++;
- }
- return (wchar_t *) s;
+ while (*prefix) {
+ if (*prefix != *s)
+ return NULL;
+ prefix++;
+ s++;
+ }
+ return (wchar_t *) s;
}
* format == NULL && errno_ == 0 なら、"unknown error" を出力する。 */
void xerror(int status, int errno_, const char *restrict format, ...)
{
- va_list ap;
-
- yash_error_message_count++;
- fflush(stdout);
- fprintf(stderr, "%s: ", yash_program_invocation_name);
- if (format) {
- va_start(ap, format);
- vfprintf(stderr, gt(format), ap);
- va_end(ap);
- }
- if (errno_) {
- fprintf(stderr, format ? ": %s" : "%s", strerror(errno_));
- }
- if (format || errno_) {
- fputc('\n', stderr);
- } else {
- fputs(gt("unknown error\n"), stderr);
- }
- fflush(stderr);
- if (status)
- exit(status);
+ va_list ap;
+
+ yash_error_message_count++;
+ fflush(stdout);
+ fprintf(stderr, "%s: ", yash_program_invocation_name);
+ if (format) {
+ va_start(ap, format);
+ vfprintf(stderr, gt(format), ap);
+ va_end(ap);
+ }
+ if (errno_) {
+ fprintf(stderr, format ? ": %s" : "%s", strerror(errno_));
+ }
+ if (format || errno_) {
+ fputc('\n', stderr);
+ } else {
+ fputs(gt("unknown error\n"), stderr);
+ }
+ fflush(stderr);
+ if (status)
+ exit(status);
}
/* xgetopt_long で使う補助関数。argv[from] を argv[to] に持ってくる。 */
static void argshift(char **argv, int from, int to /* <= from */)
{
- char *s = argv[from];
+ char *s = argv[from];
- assert(from >= to);
- for (int i = from; i > to; i--)
- argv[i] = argv[i - 1];
- argv[to] = s;
+ assert(from >= to);
+ for (int i = from; i > to; i--)
+ argv[i] = argv[i - 1];
+ argv[to] = s;
}
/* GNU ライブラリにある getopt_long の自前の実装。
* この実装はマルチバイト文字には完全には対応していない。解析の対象となる文字は
* すべて初期シフト状態で解釈する。 */
int xgetopt_long(
- char **restrict argv,
- const char *restrict optstring,
- const struct xoption *restrict longopts,
- int *restrict longindex)
+ char **restrict argv,
+ const char *restrict optstring,
+ const struct xoption *restrict longopts,
+ int *restrict longindex)
{
- int initind;
- char *arg, *arg2, argchar;
- static int aindex;
- bool optionsfirst = posixly_correct, plusoptions = false;
-
- if (xoptind == 0) { /* 新しい解析を始めるためにリセット */
- aindex = 1;
- xoptind = 1;
- }
- if (*optstring == '+') {
- optionsfirst = true;
- optstring++;
- }
- if (*optstring == '*') {
- plusoptions = true;
- optstring++;
+ int initind;
+ char *arg, *arg2, argchar;
+ static int aindex;
+ bool optionsfirst = posixly_correct, plusoptions = false;
+
+ if (xoptind == 0) { /* 新しい解析を始めるためにリセット */
+ aindex = 1;
+ xoptind = 1;
+ }
+ if (*optstring == '+') {
+ optionsfirst = true;
+ optstring++;
+ }
+ if (*optstring == '*') {
+ plusoptions = true;
+ optstring++;
+ }
+
+ initind = xoptind;
+ while ((arg = argv[xoptind])) {
+ if ((arg[0] != '-' && (!plusoptions || (arg[0] != '+'))) || !arg[1]) {
+ /* arg はオプションではない */
+ if (optionsfirst)
+ break;
+ xoptind++;
+ continue;
}
- initind = xoptind;
- while ((arg = argv[xoptind])) {
- if ((arg[0] != '-' && (!plusoptions || (arg[0] != '+'))) || !arg[1]) {
- /* arg はオプションではない */
- if (optionsfirst)
- break;
- xoptind++;
- continue;
- }
-
- if (arg[0] == '-' && arg[1] == '-') {
- /* arg は "--" で始まる */
- goto tryparselongoption;
- } else {
- /* 一文字のオプションを解析 */
- goto tryparseshortoption;
- }
+ if (arg[0] == '-' && arg[1] == '-') {
+ /* arg は "--" で始まる */
+ goto tryparselongoption;
+ } else {
+ /* 一文字のオプションを解析 */
+ goto tryparseshortoption;
}
- xoptind = initind;
- return -1;
+ }
+ xoptind = initind;
+ return -1;
tryparseshortoption:
- argchar = arg[aindex];
- xoptopt = arg[0];
- optstring = strchr(optstring, argchar);
- if (!optstring) {
- xoptopt = argchar;
- goto nosuchoption;
+ argchar = arg[aindex];
+ xoptopt = arg[0];
+ optstring = strchr(optstring, argchar);
+ if (!optstring) {
+ xoptopt = argchar;
+ goto nosuchoption;
+ }
+
+ /* 有効なオプションが見付かった */
+ if (optstring[1] == ':') {
+ /* 引数を取るオプション */
+ xoptarg = &arg[aindex + 1];
+ aindex = 1;
+ if (!*xoptarg && optstring[2] != ':') {
+ /* -x arg のように分かれている場合 */
+ xoptarg = argv[xoptind + 1];
+ if (!xoptarg)
+ goto argumentmissing;
+ argshift(argv, xoptind, initind);
+ argshift(argv, xoptind + 1, initind + 1);
+ xoptind = initind + 2;
+ } else {
+ /* 引数が省略された場合 */
+ argshift(argv, xoptind, initind);
+ xoptind = initind + 1;
}
-
- /* 有効なオプションが見付かった */
- if (optstring[1] == ':') {
- /* 引数を取るオプション */
- xoptarg = &arg[aindex + 1];
- aindex = 1;
- if (!*xoptarg && optstring[2] != ':') {
- /* -x arg のように分かれている場合 */
- xoptarg = argv[xoptind + 1];
- if (!xoptarg)
- goto argumentmissing;
- argshift(argv, xoptind, initind);
- argshift(argv, xoptind + 1, initind + 1);
- xoptind = initind + 2;
- } else {
- /* 引数が省略された場合 */
- argshift(argv, xoptind, initind);
- xoptind = initind + 1;
- }
+ } else {
+ /* 引数を取らないオプション */
+ if (arg[aindex + 1]) {
+ aindex++;
+ argshift(argv, xoptind, initind);
+ xoptind = initind;
} else {
- /* 引数を取らないオプション */
- if (arg[aindex + 1]) {
- aindex++;
- argshift(argv, xoptind, initind);
- xoptind = initind;
- } else {
- argshift(argv, xoptind, initind);
- xoptind = initind + 1;
- }
+ argshift(argv, xoptind, initind);
+ xoptind = initind + 1;
}
- return argchar;
+ }
+ return argchar;
tryparselongoption:
- arg2 = &arg[2];
- if (!arg2[0]) {
- /* arg == "--" */
- argshift(argv, xoptind, initind);
- xoptind = initind + 1;
- return -1;
- }
- if (posixly_correct || !longopts)
- goto nosuchoption;
-
- /* 一致する長いオプションを探す */
- int matchindex = -1;
- size_t len = strcspn(arg2, "=");
- for (int i = 0; longopts[i].name; i++) {
- if (strncmp(longopts[i].name, arg2, len) == 0) {
- if (longopts[i].name[len]) {
- /* 部分一致 */
- if (matchindex < 0) {
- /* 初めての一致 */
- matchindex = i;
- continue;
- } else {
- /* すでに他にも一致したものがある */
- arg = arg2;
- goto ambiguousmatch;
- }
- } else {
- /* 完全一致 */
- matchindex = i;
- break;
- }
- }
- }
- if (matchindex < 0)
- goto nosuchoption;
-
- /* 長いオプションが見付かった */
- if (longindex)
- *longindex = matchindex;
- xoptopt = '-';
- if (longopts[matchindex].has_arg) {
- char *eq = strchr(arg2, '=');
- if (!eq) {
- /* --option arg のように分かれている場合 */
- xoptarg = argv[xoptind + 1];
- if (!xoptarg) {
- if (longopts[matchindex].has_arg == xrequired_argument)
- goto argumentmissing;
- argshift(argv, xoptind, initind);
- xoptind = initind + 1;
- } else {
- argshift(argv, xoptind, initind);
- argshift(argv, xoptind + 1, initind + 1);
- xoptind = initind + 2;
- }
+ arg2 = &arg[2];
+ if (!arg2[0]) {
+ /* arg == "--" */
+ argshift(argv, xoptind, initind);
+ xoptind = initind + 1;
+ return -1;
+ }
+ if (posixly_correct || !longopts)
+ goto nosuchoption;
+
+ /* 一致する長いオプションを探す */
+ int matchindex = -1;
+ size_t len = strcspn(arg2, "=");
+ for (int i = 0; longopts[i].name; i++) {
+ if (strncmp(longopts[i].name, arg2, len) == 0) {
+ if (longopts[i].name[len]) {
+ /* 部分一致 */
+ if (matchindex < 0) {
+ /* 初めての一致 */
+ matchindex = i;
+ continue;
} else {
- /* --option=arg のように '=' で引数を指定している場合 */
- xoptarg = eq + 1;
- argshift(argv, xoptind, initind);
- xoptind = initind + 1;
+ /* すでに他にも一致したものがある */
+ arg = arg2;
+ goto ambiguousmatch;
}
- } else {
- /* 引数を取らないオプション */
+ } else {
+ /* 完全一致 */
+ matchindex = i;
+ break;
+ }
+ }
+ }
+ if (matchindex < 0)
+ goto nosuchoption;
+
+ /* 長いオプションが見付かった */
+ if (longindex)
+ *longindex = matchindex;
+ xoptopt = '-';
+ if (longopts[matchindex].has_arg) {
+ char *eq = strchr(arg2, '=');
+ if (!eq) {
+ /* --option arg のように分かれている場合 */
+ xoptarg = argv[xoptind + 1];
+ if (!xoptarg) {
+ if (longopts[matchindex].has_arg == xrequired_argument)
+ goto argumentmissing;
argshift(argv, xoptind, initind);
xoptind = initind + 1;
- }
- if (longopts[matchindex].flag) {
- *longopts[matchindex].flag = longopts[matchindex].val;
- return 0;
+ } else {
+ argshift(argv, xoptind, initind);
+ argshift(argv, xoptind + 1, initind + 1);
+ xoptind = initind + 2;
+ }
} else {
- return longopts[matchindex].val;
+ /* --option=arg のように '=' で引数を指定している場合 */
+ xoptarg = eq + 1;
+ argshift(argv, xoptind, initind);
+ xoptind = initind + 1;
}
+ } else {
+ /* 引数を取らないオプション */
+ argshift(argv, xoptind, initind);
+ xoptind = initind + 1;
+ }
+ if (longopts[matchindex].flag) {
+ *longopts[matchindex].flag = longopts[matchindex].val;
+ return 0;
+ } else {
+ return longopts[matchindex].val;
+ }
ambiguousmatch:
- if (xopterr) {
- fflush(stdout);
- fprintf(stderr, gt("%s: --%s: ambiguous option\n"), argv[0], arg);
+ if (xopterr) {
+ fflush(stdout);
+ fprintf(stderr, gt("%s: --%s: ambiguous option\n"), argv[0], arg);
#if 0
- for (int i = 0; longopts[i].name; i++)
- if (matchstrprefix(longopts[i].name, arg))
- fprintf(stderr, "\t--%s\n", longopts[i].name);
+ for (int i = 0; longopts[i].name; i++)
+ if (matchstrprefix(longopts[i].name, arg))
+ fprintf(stderr, "\t--%s\n", longopts[i].name);
#endif
- fflush(stderr);
- }
- xoptind++;
- return '?';
+ fflush(stderr);
+ }
+ xoptind++;
+ return '?';
nosuchoption:
- if (xopterr) {
- fflush(stdout);
- fprintf(stderr, gt("%s: %s: invalid option\n"), argv[0], argv[xoptind]);
- fflush(stderr);
- }
- xoptind++;
- return '?';
+ if (xopterr) {
+ fflush(stdout);
+ fprintf(stderr, gt("%s: %s: invalid option\n"), argv[0], argv[xoptind]);
+ fflush(stderr);
+ }
+ xoptind++;
+ return '?';
argumentmissing:
- if (xopterr) {
- fflush(stdout);
- fprintf(stderr, gt("%s: %s: argument missing\n"), argv[0], argv[xoptind]);
- fflush(stderr);
- }
- xoptind++;
- return '?';
+ if (xopterr) {
+ fflush(stdout);
+ fprintf(stderr, gt("%s: %s: argument missing\n"), argv[0], argv[xoptind]);
+ fflush(stderr);
+ }
+ xoptind++;
+ return '?';
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
static inline size_t xstrnlen(const char *s, size_t maxlen)
{
#ifdef HAVE_STRNLEN
- return strnlen(s, maxlen);
+ return strnlen(s, maxlen);
#else
- size_t result = 0;
- while (result < maxlen && s[result]) result++;
- return result;
+ size_t result = 0;
+ while (result < maxlen && s[result]) result++;
+ return result;
#endif
}
* malloc に失敗するとプログラムを強制終了する。 */
static inline char *xstrdup(const char *s)
{
- return xstrndup(s, SIZE_MAX);
+ return xstrndup(s, SIZE_MAX);
}
/* 文字列の長さを返す。ただし文字列の最初の maxlen バイトしか見ない。
static inline size_t xwcsnlen(const wchar_t *s, size_t maxlen)
{
#ifdef HAVE_WCSNLEN
- return wcsnlen(s, maxlen);
+ return wcsnlen(s, maxlen);
#else
- size_t result = 0;
- while (result < maxlen && s[result]) result++;
- return result;
+ size_t result = 0;
+ while (result < maxlen && s[result]) result++;
+ return result;
#endif
}
* malloc に失敗するとプログラムを強制終了する。 */
static inline wchar_t *xwcsdup(const wchar_t *s)
{
- return xwcsndup(s, SIZE_MAX);
+ return xwcsndup(s, SIZE_MAX);
}
/* 整数型 type を文字列に変換した場合の最大長。
* CHAR_BIT の為に limits.h が必要。 */
#define INT_STRLEN_BOUND(type) \
- ((sizeof(type) * CHAR_BIT - IS_TYPE_SIGNED(type)) * 31 / 100 \
- + 1 + IS_TYPE_SIGNED(type))
+ ((sizeof(type) * CHAR_BIT - IS_TYPE_SIGNED(type)) * 31 / 100 \
+ + 1 + IS_TYPE_SIGNED(type))
/********** Error utilities **********/
extern bool xopterr;
struct xoption {
- const char *name;
- enum { xno_argument = 0, xrequired_argument, xoptional_argument, } has_arg;
- int *flag;
- int val;
+ const char *name;
+ enum { xno_argument = 0, xrequired_argument, xoptional_argument, } has_arg;
+ int *flag;
+ int val;
};
__attribute__((nonnull(1,2)))
extern int xgetopt_long(
- char **restrict argv,
- const char *restrict optstring,
- const struct xoption *restrict longopts,
- int *restrict longindex);
+ char **restrict argv,
+ const char *restrict optstring,
+ const struct xoption *restrict longopts,
+ int *restrict longindex);
__attribute__((nonnull(1,2)))
static inline int xgetopt(
- char **restrict argv,
- const char *restrict optstring);
+ char **restrict argv,
+ const char *restrict optstring);
/* 長いオプションがない xgetopt */
static inline int xgetopt(char **restrict argv, const char *restrict optstring)
{
- return xgetopt_long(argv, optstring, NULL, NULL);
+ return xgetopt_long(argv, optstring, NULL, NULL);
}
#endif /* UTIL_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
static const struct xoption long_options[] = {
- { "interactive", xno_argument, NULL, 'i', },
- { "login", xno_argument, NULL, 'l', },
- { "posix", xno_argument, NULL, 'X', },
- { "help", xno_argument, NULL, '?', },
- { "version", xno_argument, NULL, 'V', },
- { NULL, 0, NULL, 0, },
+ { "interactive", xno_argument, NULL, 'i', },
+ { "login", xno_argument, NULL, 'l', },
+ { "posix", xno_argument, NULL, 'X', },
+ { "help", xno_argument, NULL, '?', },
+ { "version", xno_argument, NULL, 'V', },
+ { NULL, 0, NULL, 0, },
};
int main(int argc __attribute__((unused)), char **argv)
{
- bool help = false, version = false;
- bool exec_first_arg = false, read_stdin = false;
- int opt;
- const char *shortest_name;
-
- yash_program_invocation_name = argv[0] ? argv[0] : "";
- yash_program_invocation_short_name
- = strrchr(yash_program_invocation_name, '/');
- if (yash_program_invocation_short_name)
- yash_program_invocation_short_name++;
- else
- yash_program_invocation_short_name = yash_program_invocation_name;
- command_name = yash_program_invocation_name;
- is_login_shell = (yash_program_invocation_name[0] == '-');
- shortest_name = yash_program_invocation_short_name;
- if (shortest_name[0] == '-')
- shortest_name++;
- if (strcmp(shortest_name, "sh") == 0)
- posixly_correct = true;
-
- setlocale(LC_ALL, "");
+ bool help = false, version = false;
+ bool exec_first_arg = false, read_stdin = false;
+ int opt;
+ const char *shortest_name;
+
+ yash_program_invocation_name = argv[0] ? argv[0] : "";
+ yash_program_invocation_short_name
+ = strrchr(yash_program_invocation_name, '/');
+ if (yash_program_invocation_short_name)
+ yash_program_invocation_short_name++;
+ else
+ yash_program_invocation_short_name = yash_program_invocation_name;
+ command_name = yash_program_invocation_name;
+ is_login_shell = (yash_program_invocation_name[0] == '-');
+ shortest_name = yash_program_invocation_short_name;
+ if (shortest_name[0] == '-')
+ shortest_name++;
+ if (strcmp(shortest_name, "sh") == 0)
+ posixly_correct = true;
+
+ setlocale(LC_ALL, "");
#if HAVE_GETTEXT
- bindtextdomain(PACKAGE_NAME, LOCALEDIR);
- textdomain(PACKAGE_NAME);
+ bindtextdomain(PACKAGE_NAME, LOCALEDIR);
+ textdomain(PACKAGE_NAME);
#endif
- /* オプションを解釈する */
- xoptind = 0;
- xopterr = true;
- // TODO yash:main: unimplemented options: -abCefhimnuvx -o
- while ((opt = xgetopt_long(argv, "+cilsV?", long_options, NULL)) >= 0) {
- switch (opt) {
- case 0:
- break;
- case 'c':
- exec_first_arg = (xoptopt == '-');
- break;
- case 'i':
- is_interactive = (xoptopt == '-');
- break;
- case 'l':
- is_login_shell = (xoptopt == '-');
- break;
- case 's':
- read_stdin = (xoptopt == '-');
- break;
- case 'X':
- posixly_correct = true;
- break;
- case 'V':
- version = true;
- break;
- case '?':
- help = true;
- break;
- }
+ /* オプションを解釈する */
+ xoptind = 0;
+ xopterr = true;
+ // TODO yash:main: unimplemented options: -abCefhimnuvx -o
+ while ((opt = xgetopt_long(argv, "+cilsV?", long_options, NULL)) >= 0) {
+ switch (opt) {
+ case 0:
+ break;
+ case 'c':
+ exec_first_arg = (xoptopt == '-');
+ break;
+ case 'i':
+ is_interactive = (xoptopt == '-');
+ break;
+ case 'l':
+ is_login_shell = (xoptopt == '-');
+ break;
+ case 's':
+ read_stdin = (xoptopt == '-');
+ break;
+ case 'X':
+ posixly_correct = true;
+ break;
+ case 'V':
+ version = true;
+ break;
+ case '?':
+ help = true;
+ break;
}
+ }
- /* 最初の引数が "-" なら無視する */
- if (argv[xoptind] && strcmp(argv[xoptind], "-") == 0)
- xoptind++;
+ /* 最初の引数が "-" なら無視する */
+ if (argv[xoptind] && strcmp(argv[xoptind], "-") == 0)
+ xoptind++;
- if (version)
- print_version();
- if (help)
- print_help();
- if (version || help)
- return EXIT_SUCCESS;
+ if (version)
+ print_version();
+ if (help)
+ print_help();
+ if (version || help)
+ return EXIT_SUCCESS;
- shell_pid = getpid();
- init_signal();
- init_job();
+ shell_pid = getpid();
+ init_signal();
+ init_job();
- if (exec_first_arg && read_stdin) {
- xerror(2, 0, Ngt("both -c and -s options cannot be given"));
- }
- if (exec_first_arg) {
- char *command = argv[xoptind++];
- if (!command)
- xerror(2, 0, Ngt("-c option requires an operand"));
- if (argv[xoptind])
- command_name = argv[xoptind++];
- do_job_control = is_interactive_now = is_interactive;
- // TODO yash:main:exec_first_arg シェル環境設定・位置パラメータ
- set_signals();
- exec_mbs(command, posixly_correct ? "sh -c" : "yash -c", true);
+ if (exec_first_arg && read_stdin) {
+ xerror(2, 0, Ngt("both -c and -s options cannot be given"));
+ }
+ if (exec_first_arg) {
+ char *command = argv[xoptind++];
+ if (!command)
+ xerror(2, 0, Ngt("-c option requires an operand"));
+ if (argv[xoptind])
+ command_name = argv[xoptind++];
+ do_job_control = is_interactive_now = is_interactive;
+ // TODO yash:main:exec_first_arg シェル環境設定・位置パラメータ
+ set_signals();
+ exec_mbs(command, posixly_correct ? "sh -c" : "yash -c", true);
+ } else {
+ FILE *input;
+ if (read_stdin || !argv[xoptind]) {
+ input = stdin;
+ if (!argv[xoptind] && isatty(STDIN_FILENO) && isatty(STDERR_FILENO))
+ is_interactive = true;
} else {
- FILE *input;
- if (read_stdin || !argv[xoptind]) {
- input = stdin;
- if (!argv[xoptind] && isatty(STDIN_FILENO) && isatty(STDERR_FILENO))
- is_interactive = true;
- } else {
- command_name = argv[xoptind++];
- input = fopen(command_name, "r");
- // TODO yash:main: fd を shellfd 以上に移す
- if (!input)
- xerror(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC, errno,
- Ngt("cannot open file `%s'"), command_name);
- }
- do_job_control = is_interactive_now = is_interactive;
- set_signals();
- //TODO yash:main: read file and exec commands
- xerror(2, 0, "executing %s: NOT IMPLEMENTED", command_name);
+ command_name = argv[xoptind++];
+ input = fopen(command_name, "r");
+ // TODO yash:main: fd を shellfd 以上に移す
+ if (!input)
+ xerror(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC, errno,
+ Ngt("cannot open file `%s'"), command_name);
}
- assert(false);
+ do_job_control = is_interactive_now = is_interactive;
+ set_signals();
+ //TODO yash:main: read file and exec commands
+ xerror(2, 0, "executing %s: NOT IMPLEMENTED", command_name);
+ }
+ assert(false);
}
static void print_help(void)
{
- if (posixly_correct) {
- printf(gt("Usage: sh [options] [filename [args...]]\n"
- " sh [options] -c command [command_name [args...]]\n"
- " sh [options] -s [args...]\n"));
- printf(gt("Options: -il\n"));
- } else {
- printf(gt("Usage: yash [options] [filename [args...]]\n"
- " yash [options] -c command [args...]\n"
- " yash [options] -s [args...]\n"));
- printf(gt("Short options: -ilV?\n"));
- printf(gt("Long options:\n"));
- for (size_t i = 0; long_options[i].name; i++)
- printf("\t--%s\n", long_options[i].name);
- }
+ if (posixly_correct) {
+ printf(gt("Usage: sh [options] [filename [args...]]\n"
+ " sh [options] -c command [command_name [args...]]\n"
+ " sh [options] -s [args...]\n"));
+ printf(gt("Options: -il\n"));
+ } else {
+ printf(gt("Usage: yash [options] [filename [args...]]\n"
+ " yash [options] -c command [args...]\n"
+ " yash [options] -s [args...]\n"));
+ printf(gt("Short options: -ilV?\n"));
+ printf(gt("Long options:\n"));
+ for (size_t i = 0; long_options[i].name; i++)
+ printf("\t--%s\n", long_options[i].name);
+ }
}
static void print_version(void)
{
- printf(gt("Yet another shell, version %s\n"), PACKAGE_VERSION);
- printf(PACKAGE_COPYRIGHT "\n");
+ printf(gt("Yet another shell, version %s\n"), PACKAGE_VERSION);
+ printf(PACKAGE_COPYRIGHT "\n");
}
* 戻り値: 構文エラー・入力エラーがなければ true */
bool exec_mbs(const char *code, const char *name, bool finally_exit)
{
- bool executed = false;
- struct input_mbs_info iinfo = {
- .src = code,
- .srclen = strlen(code) + 1,
- };
- struct parseinfo_T pinfo = {
- .print_errmsg = true,
- .filename = name,
- .lineno = 1,
- .input = input_mbs,
- .inputinfo = &iinfo,
- };
- memset(&iinfo.state, 0, sizeof iinfo.state); // state を初期状態にする
-
- for (;;) {
- and_or_T *commands;
- switch (read_and_parse(&pinfo, &commands)) {
- case 0: // OK
- if (commands) {
- exec_and_or_lists(commands, finally_exit && !iinfo.src);
- andorsfree(commands);
- executed = true;
- }
- break;
- case EOF:
- if (!executed)
- laststatus = EXIT_SUCCESS;
- if (finally_exit)
- exit(laststatus);
- else
- return true;
- case 1: // 構文エラー
- laststatus = 2;
- if (finally_exit)
- exit(laststatus);
- else
- return false;
+ bool executed = false;
+ struct input_mbs_info iinfo = {
+ .src = code,
+ .srclen = strlen(code) + 1,
+ };
+ struct parseinfo_T pinfo = {
+ .print_errmsg = true,
+ .filename = name,
+ .lineno = 1,
+ .input = input_mbs,
+ .inputinfo = &iinfo,
+ };
+ memset(&iinfo.state, 0, sizeof iinfo.state); // state を初期状態にする
+
+ for (;;) {
+ and_or_T *commands;
+ switch (read_and_parse(&pinfo, &commands)) {
+ case 0: // OK
+ if (commands) {
+ exec_and_or_lists(commands, finally_exit && !iinfo.src);
+ andorsfree(commands);
+ executed = true;
}
+ break;
+ case EOF:
+ if (!executed)
+ laststatus = EXIT_SUCCESS;
+ if (finally_exit)
+ exit(laststatus);
+ else
+ return true;
+ case 1: // 構文エラー
+ laststatus = 2;
+ if (finally_exit)
+ exit(laststatus);
+ else
+ return false;
}
- /* コマンドを一つも実行しなかった場合のみ後から laststatus を 0 にする。
- * 最初に laststatus を 0 にしてしまうと、コマンドを実行する際に $? の値が
- * 変わってしまう。 */
+ }
+ /* コマンドを一つも実行しなかった場合のみ後から laststatus を 0 にする。
+ * 最初に laststatus を 0 にしてしまうと、コマンドを実行する際に $? の値が
+ * 変わってしまう。 */
}
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
#endif /* YASH_H */
+
+
+/* vim: set ts=8 sts=4 sw=4 noet: */