summary refs log tree commit diff
Commit message (Collapse)AuthorAge
...
* [VAR] Fix poplocalvar leakHerbert Xu2010-05-26
| | | | | | | | | | When a variable is marked as local, we set VSTRFIXED on its vp recored. However, poplocalvar never clears this flag for variables that were unset to begin with. Thus if you ever made an unset variable local, it would get the VSTRFIXED bit and stick around forever. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [VAR] Add localvars nestingHerbert Xu2010-05-26
| | | | | | | This patch adds localvars nesting infrastructure so we can reuse the localvars mechanism for command evaluation. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [EVAL] Fix command -- crashGerrit Pape2010-05-03
| | | | | | | | | | | | | | | parse_command_args() returning a **argv pointer with *argv == 0 makes dash segfault in find_command(). To reproduce run dash -c 'command --' With this commit, parse_command_args() returns 0 if *argv is null after parsing --, and so fixes the subsequent segfault. Reported by Jonny through http://bugs.debian.org/579543 Signed-off-by: Gerrit Pape <pape@smarden.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [JOBS] Fix for job control off warningH. Peter Anvin2010-04-15
| | | | | | | | | | | There seems to be a problem with the new version of dash with job control off. I can't tell if it is just a warning or is a manifest bug. usr/dash/trap.c: In function `exitshell': usr/dash/trap.c:376: warning: suggest braces around empty body in an `if' statement Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Use faccessat if availableHerbert Xu2010-04-02
| | | | | | | | | | | | Eric Blake suggested that we should use faccessat so that ACLs and other corner cases are handled correctly. This patch does exactly that. Note that faccessat doesn't handle ACLs when euid != uid, as this case is currently implemented by glibc instead of the kernel, using code similar to the existing dash test. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* Release 0.5.6.Herbert Xu2010-04-02
|
* [BUILTIN] Make trap signal name/number errors non-fatal.Herbert Xu2010-04-02
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | On Wed, Feb 24, 2010 at 10:23:34AM +0000, Peter Kjellerstedt wrote: > > there seems to be a problem with the trap implementation in dash > (tested with 0.5.4 and 0.5.5.1). If I specify a signal which is not > supported, the shell unconditionally aborts. E.g., I had expected > the following to print foo (like bash and zsh do): > > # dash -c 'trap "echo trap executed" UNKNOWNSIGNAL || echo "foo"' > trap: 1: UNKNOWNSIGNAL: bad trap > > This means I cannot write a construct like the following to take > advantage of the ERR signal which is present in some shells: > > trap "echo ERR trap executed" ERR 2>/dev/null || : > > I also checked the POSIX documentation, and quoting from > http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html > (exit status): "For both interactive and non-interactive shells, > invalid signal names [XSI] [Option Start] or numbers [Option End] > shall not be considered a syntax error and do not cause the shell > to abort." This patch replaces sh_error with a outfmt + return 1 in trapcmd so that these errors are no longer fatal. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Use TMPDIR in mkbuiltinsmaximilian attems2010-04-02
| | | | | | | | while merging upstream dash in klibc, noticed that klibc dash had grown that useful feature. Signed-off-by: maximilian attems <max@stro.at> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [ARITH] Fix logical or result valueJilles Tjoelker2010-03-10
| | | | | | | | | | | Another change I'm making to the arith code is making || return 0 or 1 only, matching C, POSIX and other shells. Apart from the compliance issue, it is also bad to expose implementation details like the exact meaning of 'noeval' to scripts such that they may come to depend on them. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [REDIR] Do not truncate file for FROMTO redirectionHerbert Xu2010-03-09
| | | | | | | | | | | | | | | | On Tue, Jun 23, 2009 at 10:06:30AM +0000, Nikola Vladov wrote: > May be this is a bug: > > echo XX > uu > cat <> uu > > dash truncates file uu. The open flag O_TRUNC must be removed. > I'm not 100% shure what POSIX say about: program <> file Indeed, this is a bug we inherited from NetBSD. This patch removes the O_TRUNC flag for FROMTO. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [ARITH] Fix binary operator parsingHerbert Xu2010-03-09
| | | | | | | | | | | | | Jilles Tjoelker reported that binary operator parsing doesn't respect operator precedence correctly in the case where a lower- precedence operator is followed by a higher-precedence operator, and then by a lower-precedence operator. This patch fixes this by stopping when we encounter a binary oeprator with a precedence lower than one that we have already encountered. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILD] Fix changelog entryHerbert Xu2010-03-09
| | | | Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Fix off-by-one recordregion in readcmdHerbert Xu2009-11-26
| | | | | | | | | | | | | | | | | | | | | | | Alexey Gladkov <gladkov.alexey@gmail.com> wrote: > > I found another example: > > $ tr -d '[:print:]' < /etc/passwd |tr -d '\t\n' |wc -c > 0 > > $ dash -c 'while read o p; do printf "[%s] [%s]\n" "$o" "$p"; done < > /etc/passwd' |tr -d '[:print:]' |tr -d '[:space:]' |wc -c > 61 > > bug is not fixed yet :( This bug is caused by an off-by-one error in the recordregion call in readcmd. It included the terminating NUL in the region which causes ifsbreakup to include the string after it for scanning. Setting the correct length fixes the problem. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [PARSER] Fix syntax array sizeJim Meyering2009-11-04
| | | | | | | | | | | | | | | On Mon, Sep 28, 2009 at 11:00:05AM +0200, Jim Meyering wrote: > A DEL (0177, dec 127) byte in a here-document would cause dash to > access uninitialized memory at the end of one of the syntax.c tables, > since those tables are sized to accommodate a maximum index of > BASESYNTAX + 126. Make the generated tables one byte larger. > printf ':<<\\E\n\200y\nE'|./dash > * src/mksyntax.c (filltable): Use 258, not 257 as the size, > so that BASESYNTAX(=130) + 127 is a valid index. > (print): Likewise. > Don't emit explicit array dimension in declaration. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [CD] Lookup PWD after going through CDPATHHerbert Xu2009-08-31
| | | | | | | | | | | | | | | | | | | | | | | On Tue, Jul 14, 2009 at 09:39:03PM +0000, Eric Blake wrote: > For the cd command, POSIX 2008 requires that after all pathnames in CDPATH > have been tested and failed in step 5, then step 6 interprets the directory > argument relative to PWD. In other words, this demonstrates a bug: > > $ dash -c 'cd /tmp; mkdir -p foo; CDPATH=oops; cd foo; echo $?; pwd' > cd: 1: can't cd to foo > 2 > /tmp > > while bash gets it correct: > > $ bash -c 'cd /tmp; mkdir -p foo; CDPATH=oops; cd foo; echo $?; pwd' > 0 > /tmp/foo This patch fixes the problem. Reported-by: Eric Blake <ebb9@byu.net> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Avoid compiler warnings on isdigitEric Blake2009-08-31
| | | | | | | Pass correct type to ctype macro. Signed-off-by: Eric Blake <ebb9@byu.net> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Add another missing LC_COLLATE to mkbuiltinsMatthew Burgess2009-08-31
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | On Sat, Aug 15, 2009 at 06:07:16PM +0000, Matthew Burgess wrote: > > My system has Coreutils-7.4 compiled with the i18n patch from > http://cvs.fedoraproject.org/viewvc/devel/coreutils/coreutils-i18n.patch. > > Using this to compile dash, when in an en_GB.UTF-8 locale, I get the following error: > > if gcc -DHAVE_CONFIG_H -I. -I. -I.. -include ../config.h -DBSD=1 -DSHELL -DIFS_BROKEN -Wall -g -O2 -MT eval.o -MD -MP -MF ".deps/eval.Tpo" -c -o eval.o eval.c; \ > then mv -f ".deps/eval.Tpo" ".deps/eval.Po"; else rm -f ".deps/eval.Tpo"; exit 1; fi > eval.c: In function ‘evalcommand’: > eval.c:810: error: ‘EXECCMD’ undeclared (first use in this function) > eval.c:810: error: (Each undeclared identifier is reported only once > eval.c:810: error: for each function it appears in.) > eval.c:812: error: ‘COMMANDCMD’ undeclared (first use in this function) > make[3]: *** [eval.o] Error 1 > > This is because the src/mkbuiltins script ends up generating an incomplete > src/builtins.h file. This, in turn, is caused by 'sort -u -k 3,3' not > working correctly. > > The attached patch fixes/works around things by setting LC_CTYPE=C, thus > overriding the build environment (in a similar manner to the earlier call to > 'sort' in that same script). I've changed it to use LC_COLLATE. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Fix NUL termination in readcmdHerbert Xu2009-08-31
| | | | | | | | | | | | Commit 55c46b7286f5d9f2d8291158203e2b61d2494420 ([BUILTIN] Honor tab as IFS whitespace when splitting fields in readcmd) introduced a bug where sometimes garbage would follow the last field preceding the end-of-line. This was caused by an off-by-one error in the string length calculation. This patch fixes the bug. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [EVAL] Revert SKIPEVAL into EXEXITHerbert Xu2009-08-11
| | | | | | | Now that eval handles EV_TESTED correctly, we can remove the SKIPEVAL hack and simply use EXEXIT for set -e. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [EVAL] Pass EV_TESTED into evalcmdHerbert Xu2009-08-11
| | | | | | | | | | | | | | | | | | This patch fixes the case where the eval command is used with set -e and as part of a construct that should not cause the shell to abort, e.g., as part of the condition of an if statement. This is achieved by propagating the EV_TESTED flag into the evalstring function through evalcmd. As this alters the prototype of evalcmd it is now invoked explicitly by evalbltin. The built-in infrastructure has been changed to accomodate this special case. In order to ensure that the EXIT trap is properly executed this patch clears evalskip in exitshell. This wasn't needed before because of the broken way evalstring worked where it always clears evalskip when called by minusc. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [SHELL] Add preliminary LINENO supportRocky Bernstein2009-08-11
| | | | | | | | | | | | | | | | | | | | | | | Looks like in contrast to what the dash.1 manual page says, expansion of PS{1,2,4} does work. Here is a little patch to set LINENO. The ways in that it is less than ideal mirror the ways that the line number error reporting is also less than ideal. For example if you run this: ( x=$((1/0)) # Just to add another line # And another ) # error reports this line The error reported will be the closing parenthesis even though I think most people would prefer the error to be the one where x was set. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Honor tab as IFS whitespace when splitting fields in readcmdStefan Potyra2009-08-11
| | | | | | | | | | | | | | | | | | | When I try to split fields by tabs, dash doesn't honour multiple tabs between fields as whitespace (at least that's how I interpret [1], please correct me if I'm wrong). #!/bin/sh # "1\t2\t\t3" TESTSTRING="1 2 3" # only "\t" IFS=" " echo "$TESTSTRING" | while read p1 p2 p3; do echo "p1=${p1}, p2=${p2}, p3=${p3}" done Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [EXPAND] Fix quoted pattern patch breakageHerbert Xu2009-06-27
| | | | | | | | | | | | | | The change [EXPAND] Do not quote back slashes in parameter expansions outside quotes broke quote removal after parameter expansion. This is because its effecte extended beyond that of quoted patterns. This patch fixes this by limiting the change to just quoted patterns. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [REDIR] Fix incorrect savefd conversionsHerbert Xu2009-06-27
| | | | | | | | | When I added savefd we may end up closing stderr if that is how we get to the tty. This patch fixes by adding a second argument to indicate what fd should be closed which lets jobs.c get around the problem. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [MAN] Update manual page to differentiate dash from ashGerrit Pape2009-05-23
| | | | | | | | | | | | Rename sh to dash in the header and synopsis; remove reference to the 4.4 BSD release in the description, and replace the history information with a reference to NetBSD's ash. Suggested by jaalto through http://bugs.debian.org/499838 Signed-off-by: Gerrit Pape <pape@smarden.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [PARSER] Use CHKNL to parse case statementsHerbert Xu2009-02-22
| | | | | | | | Instead of open-coding the newline loop, use the CHKNL flag to get readtoken to eat the newlines before the in keyword for the case statement. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [PARSER] Allow newlines after var name in for statementsHerbert Xu2009-02-22
| | | | | | | | | POSIX allows newlines before the "in" keyword in for statements so we should too. Thanks to Maximilian Bernöcker for reporting this. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [JOBS] Do not close stderr when /dev/tty fails to openHerbert Xu2009-02-22
| | | | | | | | | As it stands if we fail to open /dev/tty we end up closing stderr after saving it at a higher fd. Thanks to David van Gorkom for reporting this. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [SIGNAL] Remove EXSIGHerbert Xu2009-02-22
| | | | | | Now that waitcmd no longer uses EXSIG we can remove it. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [JOBS] Fix dowait signal raceHerbert Xu2009-02-22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This test program by Alexey Gladkov can cause dash to enter an infinite loop in waitcmd. #!/bin/dash trap "echo TRAP" USR1 stub() { echo ">>> STUB $1" >&2 sleep $1 echo "<<< STUB $1" >&2 kill -USR1 $$ } stub 3 & stub 2 & until { echo "###"; wait; } do echo "*** $?" done The problem is that if we get a signal after the wait3 system call has returned but before we get to INTON in dowait, then we can jump back up to the top and lose the exit status. So if we then wait for the job that has just exited, then it'll stay there forever. I made the original change that caused this bug to fix pretty much the same bug but in the opposite direction. That is, if we get a signal after we enter wait3 but before we hit the kernel then it too can cause the wait to go on forever (assuming the child doesn't exit). In fact this is pretty much exactly the scenario that you'll find in glibc's documentation on pause(). The solution is given there too, in the form of sigsuspend, which is the only way to do the check and wait atomically. So this patch fixes Alexey's race without reintroducing the old bug by converting the blocking wait3 to a sigsuspend. In order to do this we need to set a signal handler for SIGCHLD, so the code has been modified to always do that. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* Release 0.5.5.1.Herbert Xu2009-01-14
|
* [BUILD] Add arith_yacc.h to dash_SOURCESHerbert Xu2009-01-14
| | | | | | | The file arith_yacc.h was missing from dash_SOURCES causing it to be excluded from the generated tar file. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* Release 0.5.5.Herbert Xu2009-01-13
|
* [BUILD] Fixed build on OS XMark Mentovai2009-01-13
| | | | | | | | | | | | | | | | | | | | Hi, Herbert and friends. I've created a small patch that allows dash to be built on Mac OS X. I'm contributing it here with the hope that it's suitable for inclusion in dash. The changes in this patch are: - __attribute__((__alias__())) is not supported, add an autoconf check - open64 is not present although the stat64 family is, separate the autoconf checks - A syntax error had slipped into a non-glibc codepath - mkbuiltins had a nonportable mktemp invocation for the case where tempfile is not availalble Nothing in this patch is actually Mac OS X-specific, so it might aid portability to other platforms as well. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILD] Fixed build on NetBSDAleksey Cheusov2009-01-13
| | | | | | | | | | Hi, I propose to apply the following patch for dash. The problem is alloca.h is absent on many platforms including NetBSD I'm running. Also, NetBSD's version of mktemp doesn't work without temporary filename pattern. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [MAN] Removed obsolete for loop syntaxHerbert Xu2008-10-17
| | | | | | | | Sven Mascheck reported that we no longer accept the non-standard for {} syntax but the manual page still refers to it. This patch removes that reference. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [CD] Fixed getcwd build error for the non-glibc caseHerbert Xu2008-08-05
| | | | | | | | | | | | | | | | | | | | On Sat, Aug 02, 2008 at 01:24:16AM +0200, Peter Hartlich wrote: > > dash's debian/diff/0048--CD-Restored-warning-when-getcwd-fails.diff > contains the following lines: > > - return getcwd(buf, sizeof(buf)) ? savestr(buf) : nullstr; > + > + if (getcwd(buf, sizeof(buf)) > + return savestr(buf); > > The if condition is missing a closing parenthesis, which probably went > unnoticed because it occurs in a section only compiled if __GLIBC__ is > not defined. This patch adds the extra parenthesis. Thanks Peter. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [MAN] Added missing right parenthesisGerrit Pape2008-07-13
| | | | | | | | | | | | | | In section Redirection the following text misses a left brace: where redir-op is one of the redirection operators mentioned previously. Following is a list of the possible redirections. The [n] is an optional number, as in \u20183\u2019 (not \u2018[3]\u2019, that refers to a file descriptor. Reported by Jörg Sommer through http://bugs.debian.org/481365 Signed-off-by: Gerrit Pape <pape@smarden.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [OPTIONS] Added support for -lHerbert Xu2008-07-13
| | | | | | | This patch adds support for the -l option (login shell) as required by the LSB. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [SHELL] Expand ENV before using itHerbert Xu2008-07-13
| | | | | | Per POSIX ENV needs to undergo parameter expansion. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [INPUT] Made setinputfd staticHerbert Xu2008-07-13
| | | | | | This function is no longer used anywhere else. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Made t_lex reentrantHerbert Xu2008-07-13
| | | | | | | The previous two changes were broken because t_lex uses global state. This patch removes that by making t_wp local to t_lex. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Made aexpr/oexpr non-recursiveHerbert Xu2008-07-13
| | | | | | | Making these functions non-recursive is straightforward since they carry no state. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [BUILTIN] Fixed 3,4-argument cases for test per POSIXHerbert Xu2008-07-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ----- Forwarded message from Gerrit Pape <pape@smarden.org> ----- Subject: Bug#455828: dash: 4-argument test "test \( ! -e \)" yields an error Date: Fri, 28 Dec 2007 08:53:29 +0000 From: Gerrit Pape <pape@smarden.org> To: Vincent Lefevre <vincent@vinc17.org>, 455828@bugs.debian.org On Thu, Dec 27, 2007 at 06:23:20PM +0100, Vincent Lefevre wrote: > On 2007-12-27 16:00:06 +0000, Gerrit Pape wrote: > > On Wed, Dec 12, 2007 at 02:18:47AM +0100, Vincent Lefevre wrote: > > > According to POSIX[*], "test \( ! -e \)" is a 4-argument test and is > > > here equivalent to "test ! -e". But dash (like ksh93 and bash) yields > > > an error: > > > > > > $ test \( ! -e \) || echo $? > > > test: 1: closing paren expected > > > 2 > > > $ test ! -e || echo $? > > > 1 > > > > Hi Vincent, > > > > the -e switch to test takes an argument, a pathname. > > According to POSIX, in both above examples, "-e" is *not* a switch, > just a string. > > test \( ! -e \) > > means: return true if the string "-e" is empty, otherwhise return false. > The error in dash is that it incorrectly thinks that "-e" is a switch in > this context. I see, you're right. Thanks, Gerrit. ----- End forwarded message ----- This patch hard-codes the 3,4-argument cases in the way required by POSIX. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [EXPAND] Fixed non-leading slash treatment in expmetaHerbert Xu2008-05-19
| | | | | | | | | | | | | | | | | | | | | | | | | | Back in January an attempt was made to fix the interpretation of quoted slashes in expmeta. However, this only fixed those cases where the quoted slash is at the front of the word. The case of non-leading slashes caused the previous directory part to gain a back slash suffix which causes subsequent pattern matches to fail. This patch fixes this by removing the back slash in that case. Thanks to Romain Tartière fox reporting this bug. Test case: echo /*"/null" Old result: /*/null New result: /dev/null Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [ARITH] Fixed lexical error on & and |Gerrit Pape2008-05-07
| | | | | | | | | | | The parser used to skip a byte when parsing the & and | operators, testcase: $ dash -c 'echo $((7&1))' $ dash -c 'echo $((7& 1))' $ dash -c 'echo $((7&11))' Signed-off-by: Gerrit Pape <pape@smarden.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [SHELL] Added gitignoreDan McGee2008-05-03
| | | | | | | This gitignore covers most of the generated files in the src/ directory. Signed-off-by: Dan McGee <dpmcgee@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [SHELL] Use uninitialized_var to silence bogus warningsHerbert Xu2008-05-03
| | | | | | | | gcc generates bogus warnings about uninitialised variables in parser.c. This patch borrows the uninitialized_var macro from Linux to silence them. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [SHELL] Fixed klibc/klcc build problemsDan McGee2008-05-03
| | | | | | | | | | | | klibc does not have mempcpy, so system.h must be included where this is used to provide the replacement. glob.h doesn't exist, so we need to guard this include with the HAVE_GLOB definition. Finally, klcc didn't like the syntax of the main definition in mksignames, and the resulting program segfaulted when trying to dereference any part of the argv array. Updating the main function definition solved the problem. Signed-off-by: Dan McGee <dpmcgee@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
* [ERROR] Set default exvwarning2 arg0 for errors during early initialisationHerbert Xu2008-05-03
| | | | | | | | As it stands if we get an error before procargs gets called by main() we'll try to print out a null pointer. This patch avoids this by printing out "sh" instead. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>