more clueful (automatic) getopt string generation

This commit is contained in:
tg 2013-11-17 22:21:18 +00:00
parent 44a58fb3e9
commit d1245ee13a
5 changed files with 335 additions and 176 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.648 2013/10/31 20:05:38 tg Exp $'
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.649 2013/11/17 22:21:16 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -325,9 +325,12 @@ addsrcs() {
}
curdir=`pwd` srcdir=`dirname "$0" 2>/dev/null` check_categories=
test -n "$srcdir" || srcdir=. # in case dirname does not exist
dstversion=`sed -n '/define MKSH_VERSION/s/^.*"\([^"]*\)".*$/\1/p' $srcdir/sh.h`
curdir=`pwd` srcdir=`dirname "$0" 2>/dev/null`
case x$srcdir in
x) srcdir=. ;;
*"'"*) echo Source directory must not contain single quotes.; exit 1 ;;
esac
dstversion=`sed -n '/define MKSH_VERSION/s/^.*"\([^"]*\)".*$/\1/p' "$srcdir/sh.h"`
add_cppflags -DMKSH_BUILDSH
e=echo
@ -336,6 +339,7 @@ eq=0
pm=0
cm=normal
optflags=-std-compile-opts
check_categories=
last=
tfn=
legacy=0
@ -1598,7 +1602,7 @@ else
#define EXTERN
#define MKSH_INCLUDES_ONLY
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.648 2013/10/31 20:05:38 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.649 2013/11/17 22:21:16 tg Exp $");
int main(void) { printf("Hello, World!\n"); return (0); }
EOF
case $cm in
@ -2253,7 +2257,7 @@ echo tcfn=$mkshexe >>Rebuild.sh
echo "$CC $CFLAGS $LDFLAGS -o \$tcfn $lobjs $LIBS $ccpr" >>Rebuild.sh
echo "test -f \$tcfn || exit 1; $SIZE \$tcfn" >>Rebuild.sh
if test $cm = makefile; then
extras='emacsfn.h sh.h sh_flags.h var_spec.h'
extras='emacsfn.h genopt.sh rlimits.opt sh.h sh_flags.h var_spec.h'
test 0 = $HAVE_SYS_SIGNAME && extras="$extras signames.inc"
cat >Makefrag.inc <<EOF
# Makefile fragment for building mksh $dstversion

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/Makefile,v 1.126 2013/09/10 17:32:57 tg Exp $
# $MirOS: src/bin/mksh/Makefile,v 1.127 2013/11/17 22:21:17 tg Exp $
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -56,6 +56,7 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 -DMKSH_DISABLE_DEPRECATED \
-DHAVE_SYS_ERRLIST_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \
-DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=489
CPPFLAGS+= -D${${PROG:L}_tf:C/(Mir${MAN:E}{0,1}){2}/4/:S/x/mksh_BUILD/:U}
CPPFLAGS+= -I.
COPTS+= -std=c99 -Wall
.endif
@ -80,6 +81,16 @@ LINKS+= ${BINDIR}/${PROG} ${BINDIR}/${_i}
MLINKS+= ${PROG}.1 ${_i}.1
.endfor
OPTGENS!= cd ${.CURDIR:Q} && echo *.opt
.for _i in ${OPTGENS}
GENERATED+= ${_i:R}.gen
${_i:R}.gen: ${_i} ${.CURDIR}/genopt.sh
${MKSH} ${.CURDIR:Q}/genopt.sh ${.CURDIR:Q}/${_i}
.endfor
CLEANFILES+= ${GENERATED}
${PROG} beforedepend: ${GENERATED}
regress: ${PROG} check.pl check.t
-rm -rf regress-dir
mkdir -p regress-dir

208
funcs.c
View File

@ -38,7 +38,7 @@
#endif
#endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.249 2013/11/17 22:20:20 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.250 2013/11/17 22:21:17 tg Exp $");
#if HAVE_KILLPG
/*
@ -3341,16 +3341,6 @@ ptest_error(Test_env *te, int ofs, const char *msg)
#define SOFT 0x1
#define HARD 0x2
struct limits {
const char *name;
int resource; /* resource to get/set */
unsigned int factor; /* multiply by to get rlim_{cur,max} values */
char option;
};
static void print_ulimit(const struct limits *, int);
static int set_ulimit(const struct limits *, const char *, int);
/* Magic to divine the 'm' and 'v' limits */
#ifdef RLIMIT_AS
@ -3393,159 +3383,38 @@ static int set_ulimit(const struct limits *, const char *, int);
#undef ULIMIT_M_IS_VMEM
#endif
#if defined(ULIMIT_M_IS_RSS) && defined(ULIMIT_M_IS_VMEM)
# error nonsensical m ulimit
#endif
#if defined(ULIMIT_V_IS_VMEM) && defined(ULIMIT_V_IS_AS)
# error nonsensical v ulimit
#endif
#define RLIMITS_DEFNS
#include "rlimits.gen"
static void print_ulimit(const struct limits *, int);
static int set_ulimit(const struct limits *, const char *, int);
static const struct limits * const rlimits[] = {
#define RLIMITS_ITEMS
#include "rlimits.gen"
};
static const char rlimits_opts[] =
#define RLIMITS_OPTCS
#include "rlimits.gen"
;
int
c_ulimit(const char **wp)
{
static const struct limits limits[] = {
/* do not use options -H, -S or -a or change the order */
#ifdef RLIMIT_CPU
{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
#endif
#ifdef RLIMIT_FSIZE
{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
#endif
#ifdef RLIMIT_CORE
{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
#endif
#ifdef RLIMIT_DATA
{ "data(KiB)", RLIMIT_DATA, 1024, 'd' },
#endif
#ifdef RLIMIT_STACK
{ "stack(KiB)", RLIMIT_STACK, 1024, 's' },
#endif
#ifdef RLIMIT_MEMLOCK
{ "lockedmem(KiB)", RLIMIT_MEMLOCK, 1024, 'l' },
#endif
#ifdef RLIMIT_NOFILE
{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
#endif
#ifdef RLIMIT_NPROC
{ "processes", RLIMIT_NPROC, 1, 'p' },
#endif
#ifdef RLIMIT_SWAP
{ "swap(KiB)", RLIMIT_SWAP, 1024, 'w' },
#endif
#ifdef RLIMIT_TIME
{ "humantime(seconds)", RLIMIT_TIME, 1, 'T' },
#endif
#ifdef RLIMIT_NOVMON
{ "vnodemonitors", RLIMIT_NOVMON, 1, 'V' },
#endif
#ifdef RLIMIT_SIGPENDING
{ "sigpending", RLIMIT_SIGPENDING, 1, 'i' },
#endif
#ifdef RLIMIT_MSGQUEUE
{ "msgqueue(bytes)", RLIMIT_MSGQUEUE, 1, 'q' },
#endif
#ifdef RLIMIT_AIO_MEM
{ "AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024, 'M' },
#endif
#ifdef RLIMIT_AIO_OPS
{ "AIOoperations", RLIMIT_AIO_OPS, 1, 'O' },
#endif
#ifdef RLIMIT_TCACHE
{ "cachedthreads", RLIMIT_TCACHE, 1, 'C' },
#endif
#ifdef RLIMIT_SBSIZE
{ "sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024, 'B' },
#endif
#ifdef RLIMIT_PTHREAD
{ "threadsperprocess", RLIMIT_PTHREAD, 1, 'P' },
#endif
#ifdef RLIMIT_NICE
{ "maxnice", RLIMIT_NICE, 1, 'e' },
#endif
#ifdef RLIMIT_RTPRIO
{ "maxrtprio", RLIMIT_RTPRIO, 1, 'r' },
#endif
#if defined(ULIMIT_M_IS_RSS)
{ "resident-set(KiB)", RLIMIT_RSS, 1024, 'm' },
#elif defined(ULIMIT_M_IS_VMEM)
{ "memory(KiB)", RLIMIT_VMEM, 1024, 'm' },
#endif
#if defined(ULIMIT_V_IS_VMEM)
{ "virtual-memory(KiB)", RLIMIT_VMEM, 1024, 'v' },
#elif defined(ULIMIT_V_IS_AS)
{ "address-space(KiB)", RLIMIT_AS, 1024, 'v' },
#endif
{ NULL, 0, 0, 0 }
};
static const char opts[] = "a"
#ifdef RLIMIT_SBSIZE
"B"
#endif
#ifdef RLIMIT_TCACHE
"C"
#endif
#ifdef RLIMIT_CORE
"c"
#endif
#ifdef RLIMIT_DATA
"d"
#endif
#ifdef RLIMIT_NICE
"e"
#endif
#ifdef RLIMIT_FSIZE
"f"
#endif
"H"
#ifdef RLIMIT_SIGPENDING
"i"
#endif
#ifdef RLIMIT_MEMLOCK
"l"
#endif
#ifdef RLIMIT_AIO_MEM
"M"
#endif
#if defined(ULIMIT_M_IS_RSS) || defined(ULIMIT_M_IS_VMEM)
"m"
#endif
#ifdef RLIMIT_NOFILE
"n"
#endif
#ifdef RLIMIT_AIO_OPS
"O"
#endif
#ifdef RLIMIT_PTHREAD
"P"
#endif
#ifdef RLIMIT_NPROC
"p"
#endif
#ifdef RLIMIT_MSGQUEUE
"q"
#endif
#ifdef RLIMIT_RTPRIO
"r"
#endif
"S"
#ifdef RLIMIT_STACK
"s"
#endif
#ifdef RLIMIT_TIME
"T"
#endif
#ifdef RLIMIT_CPU
"t"
#endif
#ifdef RLIMIT_NOVMON
"V"
#endif
#if defined(ULIMIT_V_IS_VMEM) || defined(ULIMIT_V_IS_AS)
"v"
#endif
#ifdef RLIMIT_SWAP
"w"
#endif
;
size_t i = 0;
int how = SOFT | HARD, optc, what = 'f';
bool all = false;
const struct limits *l;
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
while ((optc = ksh_getopt(wp, &builtin_opt, rlimits_opts)) != -1)
switch (optc) {
case 'H':
how = HARD;
@ -3557,31 +3426,32 @@ c_ulimit(const char **wp)
all = true;
break;
case '?':
bi_errorf("usage: ulimit [-%s] [value]", opts);
bi_errorf("usage: ulimit [-%s] [value]", rlimits_opts);
return (1);
default:
what = optc;
}
for (l = limits; l->name && l->option != what; l++)
;
if (!l->name) {
internal_warningf("ulimit: %c", what);
return (1);
while (i < NELEM(rlimits)) {
if (rlimits[i]->optchar == what)
goto found;
++i;
}
internal_warningf("ulimit: %c", what);
return (1);
found:
if (wp[builtin_opt.optind]) {
if (all || wp[builtin_opt.optind + 1]) {
bi_errorf("too many arguments");
return (1);
}
return (set_ulimit(l, wp[builtin_opt.optind], how));
return (set_ulimit(rlimits[i], wp[builtin_opt.optind], how));
}
if (!all)
print_ulimit(l, how);
else for (l = limits; l->name; l++) {
shprintf("%-20s ", l->name);
print_ulimit(l, how);
print_ulimit(rlimits[i], how);
else for (i = 0; i < NELEM(rlimits); ++i) {
shprintf("%-20s ", rlimits[i]->name);
print_ulimit(rlimits[i], how);
}
return (0);
}

169
genopt.sh Normal file
View File

@ -0,0 +1,169 @@
#!/bin/sh
# $MirOS: src/bin/mksh/genopt.sh,v 1.1 2013/11/17 22:21:18 tg Exp $
#-
# Copyright (c) 2013
# Thorsten Glaser <tg@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un-
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said person's immediate fault when using the work as intended.
#-
# Compile *.opt files to *.gen (F0, FN, getopt string) files.
LC_ALL=C
export LC_ALL
case $ZSH_VERSION:$VERSION in
:zsh*) ZSH_VERSION=2 ;;
esac
if test -n "${ZSH_VERSION+x}" && (emulate sh) >/dev/null 2>&1; then
emulate sh
NULLCMD=:
fi
if test -d /usr/xpg4/bin/. >/dev/null 2>&1; then
# Solaris: some of the tools have weird behaviour, use portable ones
PATH=/usr/xpg4/bin:$PATH
export PATH
fi
allu=QWERTYUIOPASDFGHJKLZXCVBNM
alll=qwertyuiopasdfghjklzxcvbnm
nl='
'
me=`basename "$0"`
curdir=`pwd` srcdir=`dirname "$0" 2>/dev/null`
case x$srcdir in
x) srcdir=. ;;
*"'"*) echo Source directory must not contain single quotes.; exit 1 ;;
esac
die() {
if test -n "$1"; then
echo >&2 "E: $*"
echo >&2 "E: in '$srcfile': '$line'"
else
echo >&2 "E: invalid input in '$srcfile': '$line'"
fi
rm -f "$bn.gen"
exit 1
}
soptc() {
optc=`echo "$line" | sed 's/^[<>]\(.\).*$/\1/'`
test x"$optc" = x'|' && return
optclo=`echo "$optc" | tr $allu $alll`
if test x"$optc" = x"$optclo"; then
islo=1
else
islo=0
fi
sym=`echo "$line" | sed 's/^[<>]/|/'`
o_str=$o_str$nl"<$optclo$islo$sym"
}
for srcfile
do
bn=`basename "$srcfile" | sed 's/.opt$//'`
o_gen=
o_str=
o_sym=
ddefs=
state=0
while IFS= read -r line; do
case $state:$line in
2:'|'*)
# end of input
o_sym=`echo "$line" | sed 's/^.//'`
o_gen=$o_gen$nl"#undef F0"
o_gen=$o_gen$nl"#undef FN"
for sym in $ddefs; do
o_gen=$o_gen$nl"#undef $sym"
done
state=3
;;
1:@@)
# begin of data block
o_gen=$o_gen$nl"#endif"
o_gen=$o_gen$nl"#ifndef F0"
o_gen=$o_gen$nl"#define F0 FN"
o_gen=$o_gen$nl"#endif"
state=2
;;
*:@@*)
die ;;
0:@*|1:@*)
# begin of a definition block
sym=`echo "$line" | sed 's/^@//'`
if test $state = 0; then
o_gen=$o_gen$nl"#if defined($sym)"
else
o_gen=$o_gen$nl"#elif defined($sym)"
fi
ddefs="$ddefs $sym"
state=1
;;
0:*|3:*)
die ;;
1:*)
# definition line
o_gen=$o_gen$nl$line
;;
2:'<'*'|'*)
soptc
;;
2:'>'*'|'*)
soptc
cond=`echo "$line" | sed 's/^[^|]*|//'`
case x$cond in
x) cond= ;;
x*' '*) cond="#if $cond" ;;
x*) cond="#ifdef $cond" ;;
esac
case $optc in
'|') optc=0 ;;
*) optc=\'$optc\' ;;
esac
IFS= read -r line || die Unexpected EOF
test -n "$cond" && o_gen=$o_gen$nl"$cond"
o_gen=$o_gen$nl"$line, $optc)"
test -n "$cond" && o_gen=$o_gen$nl"#endif"
;;
esac
done <"$srcfile"
case $state:$o_sym in
3:) die Expected optc sym at EOF ;;
3:*) ;;
*) die Missing EOF marker ;;
esac
echo "$o_str" | sort | while IFS='|' read -r x opts cond; do
test -n "$x" || continue
case x$cond in
x) cond= ;;
x*' '*) cond="#if $cond" ;;
x*) cond="#ifdef $cond" ;;
esac
test -n "$cond" && echo "$cond"
echo "\"$opts\""
test -n "$cond" && echo "#endif"
done | {
echo "#ifndef $o_sym$o_gen"
echo "#else"
cat
echo "#undef $o_sym"
echo "#endif"
} >"$bn.gen"
done
exit 0

105
rlimits.opt Normal file
View File

@ -0,0 +1,105 @@
@RLIMITS_DEFNS
__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.1 2013/11/17 22:21:18 tg Exp $");
struct limits {
/* limit resource */
int resource;
/* multiply by to get rlim_{cur,max} values */
unsigned int factor;
/* getopts char */
char optchar;
/* limit name */
char name[1];
};
#define FN(lname,lid,lfac,lopt) \
static const struct { \
int resource; \
unsigned int factor; \
char optchar; \
char name[sizeof(lname)]; \
} rlimits_ ## lid = { \
lid, lfac, lopt, lname \
};
@RLIMITS_ITEMS
#define FN(lname,lid,lfac,lopt) \
(const struct limits *)(&rlimits_ ## lid),
@@
/* generic options for the ulimit builtin */
<a|
<H|
<S|
/* do not use options -H, -S or -a or change the order */
>t|RLIMIT_CPU
FN("time(cpu-seconds)", RLIMIT_CPU, 1
>f|RLIMIT_FSIZE
FN("file(blocks)", RLIMIT_FSIZE, 512
>c|RLIMIT_CORE
FN("coredump(blocks)", RLIMIT_CORE, 512
>d|RLIMIT_DATA
FN("data(KiB)", RLIMIT_DATA, 1024
>s|RLIMIT_STACK
FN("stack(KiB)", RLIMIT_STACK, 1024
>l|RLIMIT_MEMLOCK
FN("lockedmem(KiB)", RLIMIT_MEMLOCK, 1024
>n|RLIMIT_NOFILE
FN("nofiles(descriptors)", RLIMIT_NOFILE, 1
>p|RLIMIT_NPROC
FN("processes", RLIMIT_NPROC, 1
>w|RLIMIT_SWAP
FN("swap(KiB)", RLIMIT_SWAP, 1024
>T|RLIMIT_TIME
FN("humantime(seconds)", RLIMIT_TIME, 1
>V|RLIMIT_NOVMON
FN("vnodemonitors", RLIMIT_NOVMON, 1
>i|RLIMIT_SIGPENDING
FN("sigpending", RLIMIT_SIGPENDING, 1
>q|RLIMIT_MSGQUEUE
FN("msgqueue(bytes)", RLIMIT_MSGQUEUE, 1
>M|RLIMIT_AIO_MEM
FN("AIOlockedmem(KiB)", RLIMIT_AIO_MEM, 1024
>O|RLIMIT_AIO_OPS
FN("AIOoperations", RLIMIT_AIO_OPS, 1
>C|RLIMIT_TCACHE
FN("cachedthreads", RLIMIT_TCACHE, 1
>B|RLIMIT_SBSIZE
FN("sockbufsiz(KiB)", RLIMIT_SBSIZE, 1024
>P|RLIMIT_PTHREAD
FN("threadsperprocess", RLIMIT_PTHREAD, 1
>e|RLIMIT_NICE
FN("maxnice", RLIMIT_NICE, 1
>r|RLIMIT_RTPRIO
FN("maxrtprio", RLIMIT_RTPRIO, 1
>m|ULIMIT_M_IS_RSS
FN("resident-set(KiB)", RLIMIT_RSS, 1024
>m|ULIMIT_M_IS_VMEM
FN("memory(KiB)", RLIMIT_VMEM, 1024
>v|ULIMIT_V_IS_VMEM
FN("virtual-memory(KiB)", RLIMIT_VMEM, 1024
>v|ULIMIT_V_IS_AS
FN("address-space(KiB)", RLIMIT_AS, 1024
|RLIMITS_OPTCS