1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/cmd/ksh93/include/argnod.h
Martijn Dekker c734568b02 arithmetic: Fix the octal leading zero mess (#337)
In C/POSIX arithmetic, a leading 0 denotes an octal number, e.g.
010 == 8. But this is not a desirable feature as it can cause
problems with processing things like dates with a leading zero.
In ksh, you should use 8#10 instead ("10" with base 8).

It would be tolerable if ksh at least implemented it consistently.
But AT&T made an incredible mess of it. For anyone who is not
intimately familiar with ksh internals, it is inscrutable where
arithmetic evaluation special-cases a leading 0 and where it
doesn't. Here are just some of the surprises/inconsistencies:

1. The AT&T maintainers tried to honour a leading 0 inside of
   ((...)) and $((...)) and not for arithmetic contexts outside it,
   but even that inconsistency was never quite consistent.

2. Since 2010-12-12, $((x)) and $(($x)) are different:
      $ /bin/ksh -c 'x=010; echo $((x)) $(($x))'
      10 8
   That's a clear violation of both POSIX and the principle of
   least astonishment. $((x)) and $(($x)) should be the same in
   all cases.

3. 'let' with '-o letoctal' acts in this bizarre way:
      $ set -o letoctal; x=010; let "y1=$x" "y2=010"; echo $y1 $y2
      10 8
   That's right, 'let y=$x' is different from 'let y=010' even
   when $x contains the same string value '010'! This violates
   established shell grammar on the most basic level.

This commit introduces consistency. By default, ksh now acts like
mksh and zsh: the octal leading zero is disabled in all arithmetic
contexts equally. In POSIX mode, it is enabled equally.

The one exception is the 'let' built-in, where this can still be
controlled independently with the letoctal option as before (but,
because letoctal is synched with posix when switching that on/off,
it's consistent by default).

We're also removing the hackery that causes variable expansions for
the 'let' builtin to be quietly altered, so that 'x=010; let y=$x'
now does the same as 'let y=010' even with letoctal on.

Various files:
- Get rid of now-redundant sh.inarith (shp->inarith) flag, as we're
  no longer distinguishing between being inside or outside ((...)).

src/cmd/ksh93/sh/arith.c:
- arith(): Let disabling POSIX octal constants by skipping leading
  zeros depend on either the letoctal option being off (if we're
  running the "let" built-in") or the posix option being off.
- sh_strnum(): Preset a base of 10 for strtonll(3) depending on the
  posix or letoctal option being off, not on the sh.inarith flag.

src/cmd/ksh93/include/argnod.h,
src/cmd/ksh93/sh/args.c,
src/cmd/ksh93/sh/macro.c:
- Remove astonishing hackery that violated shell grammar for 'let'.

src/cmd/ksh93/sh/name.c (nv_getnum()),
src/cmd/ksh93/sh/nvdisc.c (nv_getn()):
- Remove loops for skipping leading zeroes that included a broken
  check for justify/zerofill attributes, thereby fixing this bug:
	$ typeset -Z x=0x15; echo $((x))
	-ksh: x15: parameter not set
  Even if this code wasn't redundant before, it is now: sh_arith()
  is called immediately after the removed code and it ignores
  leading zeroes via sh_strnum() and strtonll(3).

Resolves: https://github.com/ksh93/ksh/issues/334
2021-11-17 04:28:08 +01:00

143 lines
4.2 KiB
C

/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2011 AT&T Intellectual Property *
* Copyright (c) 2020-2021 Contributors to ksh 93u+m *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* http://www.eclipse.org/org/documents/epl-v10.html *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
#ifndef ARG_RAW
/*
* struct to hold a word argument
* Written by David Korn
*
*/
#include <stak.h>
struct ionod
{
unsigned iofile;
char *ioname;
struct ionod *ionxt;
struct ionod *iolst;
char *iodelim;
off_t iooffset;
long iosize;
char *iovname;
};
struct comnod
{
int comtyp;
struct ionod *comio;
struct argnod *comarg;
struct argnod *comset;
void *comnamp;
void *comnamq;
void *comstate;
int comline;
};
#define COMBITS 4
#define COMMSK ((1<<COMBITS)-1)
#define COMSCAN (01<<COMBITS)
#define COMFIXED (02<<COMBITS)
struct slnod /* struct for link list of stacks */
{
struct slnod *slnext;
struct slnod *slchild;
Stak_t *slptr;
/* slpad aligns struct functnod = struct slnod + 1 on some architectures */
struct slnod *slpad;
};
/*
* This struct is used to hold $* lists and arrays
*/
struct dolnod
{
int dolrefcnt; /* reference count */
int dolmax; /* size of dolval array */
int dolnum; /* number of elements */
int dolbot; /* current first element */
struct dolnod *dolnxt; /* used when list are chained */
char *dolval[1]; /* array of value pointers */
};
/*
* This struct is used to hold word arguments of variable size during
* parsing and during expansion. The flags indicate what processing
* is required on the argument.
*/
struct argnod
{
union
{
struct argnod *ap;
char *cp;
} argnxt;
union
{
struct argnod *ap;
char *cp;
int len;
} argchn;
unsigned char argflag;
char argval[4];
};
/* The following should evaluate to the offset of argval in argnod */
#define ARGVAL offsetof(struct argnod,argval[0])
#define sh_argstr(ap) ((ap)->argflag&ARG_RAW?sh_fmtq((ap)->argval):(ap)->argval)
#define ARG_SPARE 1
/* legal argument flags */
#define ARG_RAW 0x1 /* string needs no processing */
#define ARG_MAKE 0x2 /* bit set during argument expansion */
#define ARG_COMSUB 0x2 /* command sub */
#define ARG_MAC 0x4 /* string needs macro expansion */
#define ARG_EXP 0x8 /* string needs file expansion */
#define ARG_ASSIGN 0x10 /* argument is an assignment */
#define ARG_QUOTED 0x20 /* word contained quote characters */
#define ARG_MESSAGE 0x40 /* contains international string */
#define ARG_APPEND 0x80 /* for += assignment */
/* The following can be passed as options to sh_macexpand() */
#define ARG_ARITH 0x100 /* arithmetic expansion */
#define ARG_OPTIMIZE 0x200 /* try to optimize */
#define ARG_NOGLOB 0x400 /* no file name expansion */
#define ARG_ARRAYOK 0x1000 /* $x[sub] ==> ${x[sub]} */
extern struct dolnod *sh_argcreate(char*[]);
extern char *sh_argdolminus(void*);
extern int sh_argopts(int,char*[],void*);
extern const char e_heading[];
extern const char e_sptbnl[];
extern const char e_subst[];
extern const char e_option[];
extern const char e_exec[];
extern const char e_devfdNN[];
extern const char e_devfdstd[];
#endif /* ARG_RAW */