1 /***********************************************************************
2  *                                                                      *
3  *               This software is part of the ast package               *
4  *          Copyright (c) 1982-2014 AT&T Intellectual Property          *
5  *                      and is licensed under the                       *
6  *                 Eclipse Public License, Version 1.0                  *
7  *                    by AT&T Intellectual Property                     *
8  *                                                                      *
9  *                A copy of the License is available at                 *
10  *          http://www.eclipse.org/org/documents/epl-v10.html           *
11  *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12  *                                                                      *
13  *              Information and Software Systems Research               *
14  *                            AT&T Research                             *
15  *                           Florham Park NJ                            *
16  *                                                                      *
17  *                    David Korn <dgkorn@gmail.com>                     *
18  *                                                                      *
19  ***********************************************************************/
20 //
21 // David Korn
22 // AT&T Labs
23 //
24 // Interface definitions of structures for name-value pairs.
25 // These structures are used for named variables, functions and aliases.
26 //
27 #ifndef _NAME_H
28 #define _NAME_H 1
29 
30 #include <stdbool.h>
31 #include <stdio.h>
32 
33 #include "ast.h"
34 #include "ast_assert.h"
35 #include "cdt.h"
36 #include "option.h"
37 
38 struct pathcomp;
39 
40 // Nodes can have all kinds of values. We track the type last stored and check the type is what we
41 // expect on retrieval.
42 //
43 // This list must be kept in sync with the `value_type_names` array in module "name.c". These values
44 // do not have to be in the same order as the elements of the union in `struct Value` but keeping
45 // them in the same order is a good idea. You also have to update the `dprint_vtp_dispatch` array in
46 // module "debug.c" if this list is changed.
47 enum value_type {
48     VT_do_not_use = 0,
49     VT_vp,
50     VT_cp,
51     VT_const_cp,
52     VT_pp,
53     VT_uc,
54     VT_h,
55     VT_i,
56     VT_l,
57     VT_d,
58     VT_f,
59     VT_i16,
60     VT_ip,
61     VT_i16p,
62     VT_i32p,
63     VT_i64p,
64     VT_dp,
65     VT_fp,
66     VT_sfdoublep,
67     VT_np,
68     VT_up,
69     VT_rp,
70     VT_funp,
71     VT_nrp,
72     VT_shbltinp,
73     VT_pathcomp,
74     VT_pidp,
75     VT_uidp,
76     VT_sentinal  // this has to be the last member of this enum
77 };
78 
79 // The following array in name.c must be kept in sync with enum value_type.
80 extern const char *value_type_names[];
81 
82 struct Value {
83     const char *funcname;
84     const char *filename;
85     int line_num;
86     enum value_type type;
87     union {
88         void *vp;
89         char *cp;
90         const char *const_cp;
91         char **pp;
92 
93         unsigned char uc;
94         short h;
95         int i;
96         long l;
97         double d;
98         float f;
99         int16_t i16;
100 
101         int *ip;
102         int16_t *i16p;
103         int32_t *i32p;
104         int64_t *i64p;
105         double *dp;
106         float *fp;
107 
108         Sfdouble_t *sfdoublep;
109         struct Namval *np;
110         struct Value *up;
111         struct Ufunction *rp;
112         struct Namfun *funp;
113         struct Namref *nrp;
114         Shbltin_f shbltinp;
115         struct pathcomp *pathcomp;
116 
117         pid_t *pidp;
118         uid_t *uidp;
119     } _val;
120 };
121 
122 // I dislike macros like these but since C doesn't support polymorphism directly this is the most
123 // straightforward way to access any of the fields of the value union.
124 //
125 // TODO: Remove the `1 ||` once the obvious bugs introduced by converting `union Value` to the
126 //       `struct Value` above have been eliminated.
127 #if 1 || !DEBUG_BUILD
128 
129 // Non-debugging versions of the struct Value getter functions.
130 #define fetch_vt(line, value_obj, which) (value_obj)._val.which
131 #define fetch_vtp(line, value_objp, which) (value_objp)->_val.which
132 
133 #else
134 
135 // Debugging versions of the struct Value getter functions.
136 #define fetch_abort() 0      // abort()
137 #define fetch_backtrace() 0  // dump_backtrace(0)
138 
139 #define fetch_vt(line, value_obj, which)                                                         \
140     (((value_obj).type == VT_##which || (VT_##which == VT_vp) ||                                 \
141       (VT_##which == VT_const_cp && (value_obj).type == VT_cp))                                  \
142          ? (value_obj)._val.which                                                                \
143          : (DPRINTF("fetched value type != stored type:"),                                       \
144             DPRINTF("fetching \"%s\"", value_type_names[VT_##which]),                            \
145             DPRINTF("stored   \"%s\" @ %s:%d in %s()", value_type_names[(value_obj).type],       \
146                     (value_obj).filename ? (value_obj).filename : "undef", (value_obj).line_num, \
147                     (value_obj).funcname ? (value_obj).funcname : "undef"),                      \
148             fetch_backtrace(), fetch_abort(), (value_obj)._val.which))
149 
150 #define fetch_vtp(line, value_objp, which)                                                   \
151     (((value_objp)->type == VT_##which || (VT_##which == VT_vp) ||                           \
152       (VT_##which == VT_const_cp && (value_objp)->type == VT_cp))                            \
153          ? (value_objp)->_val.which                                                          \
154          : (DPRINTF("fetched value type != stored type:"),                                   \
155             DPRINTF("fetching \"%s\"", value_type_names[VT_##which]),                        \
156             DPRINTF("stored   \"%s\" @ %s:%d in %s()", value_type_names[(value_objp)->type], \
157                     (value_objp)->filename ? (value_objp)->filename : "undef",               \
158                     (value_objp)->line_num,                                                  \
159                     (value_objp)->funcname ? (value_objp)->funcname : "undef"),              \
160             fetch_backtrace(), fetch_abort(), (value_objp)->_val.which))
161 
162 #endif
163 
164 #define dprint_vtp(value_objp)                                                                 \
165     DPRINTF("stored value type \"%s\" @ %s:%d in %s()", value_type_names[(value_objp)->type],  \
166             (value_objp)->filename ? (value_objp)->filename : "undef", (value_objp)->line_num, \
167             (value_objp)->funcname ? (value_objp)->funcname : "undef")
168 
169 #define is_vt(value_obj, which) ((value_obj).type == VT_##which)
170 
171 #define is_vtp(value_objp, which) ((value_objp)->type == VT_##which)
172 
173 // Always store all the meta data. Even if building without the getter checks enabled. That's
174 // because a) the info may be useful when debugging core dumps, and b) the value type is needed for
175 // the IS_VT macro.
176 #define store_vt(line, value_obj, which, val)              \
177     do {                                                   \
178         (value_obj).funcname = __FUNCTION__;               \
179         (value_obj).filename = strrchr(__FILE__, '/') + 1; \
180         (value_obj).line_num = line;                       \
181         (value_obj).type = VT_##which;                     \
182         (value_obj)._val.which = val;                      \
183     } while (0)
184 
185 #define store_vtp(line, value_objp, which, val)              \
186     do {                                                     \
187         (value_objp)->funcname = __FUNCTION__;               \
188         (value_objp)->filename = strrchr(__FILE__, '/') + 1; \
189         (value_objp)->line_num = line;                       \
190         (value_objp)->type = VT_##which;                     \
191         (value_objp)->_val.which = val;                      \
192     } while (0)
193 
194 // These four macros must be used when retrieving or storing a value in a `struct Value` object.
195 #define FETCH_VT(value_obj, which) fetch_vt(__LINE__, value_obj, which)
196 #define FETCH_VTP(value_objp, which) fetch_vtp(__LINE__, value_objp, which)
197 #define STORE_VT(value_obj, which, val) store_vt(__LINE__, value_obj, which, val)
198 #define STORE_VTP(value_objp, which, val) store_vtp(__LINE__, value_objp, which, val)
199 
200 // These two macros can be used to test the type of the value stored in the `struct Value` object.
201 #define IS_VT(value_obj, which) is_vt(value_obj, which)
202 #define IS_VTP(value_objp, which) is_vtp(value_objp, which)
203 
204 typedef struct Namdisc Namdisc_t;
205 typedef struct Nambfun Nambfun_t;
206 typedef struct Namarray Namarr_t;
207 typedef struct Namdecl Namdecl_t;
208 
209 // Any place that assigns or compares the NV_* symbols below to a var should use `nvflag_t` for the
210 // type of the var rather than `unsigned short`, `int`, etc.
211 typedef uint32_t nvflag_t;
212 // Number of low numbered bits valid in a (struct Namval).nvflag.
213 #define NV_nbits 16
214 
215 //
216 // This defines the template for nodes that have their own assignment and or lookup functions.
217 //
218 struct Namdisc {
219     size_t dsize;
220     void (*putval)(Namval_t *, const void *, nvflag_t, Namfun_t *);
221     char *(*getval)(Namval_t *, Namfun_t *);
222     Sfdouble_t (*getnum)(Namval_t *, Namfun_t *);
223     char *(*setdisc)(Namval_t *, const void *, Namval_t *, Namfun_t *);
224     Namval_t *(*createf)(Namval_t *, const void *, nvflag_t, Namfun_t *);
225     Namfun_t *(*clonef)(Namval_t *, Namval_t *, nvflag_t, Namfun_t *);
226     char *(*namef)(const Namval_t *, Namfun_t *);
227     Namval_t *(*nextf)(Namval_t *, Dt_t *, Namfun_t *);
228     Namval_t *(*typef)(Namval_t *, Namfun_t *);
229     int (*readf)(Namval_t *, Sfio_t *, int, Namfun_t *);
230     int (*writef)(Namval_t *, Sfio_t *, int, Namfun_t *);
231 };
232 
233 struct Namfun {
234     const Namdisc_t *disc;
235     char nofree;
236     unsigned char subshell;
237     uint32_t dsize;
238     Namfun_t *next;
239     char *last;
240     Namval_t *type;
241 };
242 
243 struct Nambfun {
244     Namfun_t fun;
245     int num;
246     const char **bnames;
247     Namval_t *bltins[1];
248 };
249 
250 // The following constants define operations on associative arrays performed by `nv_associative()`.
251 enum {
252     ASSOC_OP_INIT_val = 1,  // initialize
253     ASSOC_OP_FREE_val,      // free array
254     ASSOC_OP_NEXT_val,      // advance to next subscript
255     ASSOC_OP_NAME_val,      // return subscript name
256     ASSOC_OP_DELETE_val,    // delete current subscript
257     ASSOC_OP_ADD_val,       // add subscript if not found
258     ASSOC_OP_ADD2_val,      // ??? (this used to be the constant zero passed to nv_associative())
259     ASSOC_OP_CURRENT_val,   // return current subscript Namval_t*
260     ASSOC_OP_SETSUB_val,    // set current subscript
261 };
262 
263 typedef struct {
264     int val;
265 } Nvassoc_op_t;
266 extern const Nvassoc_op_t ASSOC_OP_INIT;
267 extern const Nvassoc_op_t ASSOC_OP_FREE;
268 extern const Nvassoc_op_t ASSOC_OP_NEXT;
269 extern const Nvassoc_op_t ASSOC_OP_NAME;
270 extern const Nvassoc_op_t ASSOC_OP_DELETE;
271 extern const Nvassoc_op_t ASSOC_OP_ADD;
272 extern const Nvassoc_op_t ASSOC_OP_ADD2;
273 extern const Nvassoc_op_t ASSOC_OP_CURRENT;
274 extern const Nvassoc_op_t ASSOC_OP_SETSUB;
275 
276 // This is an array template header.
277 struct Namarray {
278     Namfun_t namfun;
279     long nelem;                                            // number of elements
280     void *(*fun)(Namval_t *, const char *, Nvassoc_op_t);  // associative array ops
281     Dt_t *table;                                           // for subscripts
282     Dt_t *scope;                                           // non-NULL when scoped
283     int flags;
284 };
285 
286 // The context pointer for declaration command.
287 struct Namdecl {
288     Namval_t *tp;  // point to type
289     const char *optstring;
290     Optdisc_t *optinfof;
291 };
292 
293 // This defines the attributes for a name-value node.
294 struct Namval {
295     Dtlink_t nvlink;      // space for cdt links
296     char *nvname;         // pointer to name of the node
297     nvflag_t nvflag;      // attributes
298     uint32_t nvsize;      // size or base
299     Namfun_t *nvfun;      // pointer to trap functions
300     struct Value nvalue;  // value field
301     Shell_t *nvshell;     // shell pointer
302     Namval_t *nvenv;      // pointer to environment name
303     bool nvenv_is_cp;
304 };
305 
306 #define NV_CLASS ".sh.type"
307 #define NV_DATA "_"  // special class or instance variable
308 #define NV_MINSZ (sizeof(struct Namval) - sizeof(Dtlink_t) - sizeof(char *))
309 #define nv_namptr(p, n) ((Namval_t *)((char *)(p) + (n)*NV_MINSZ - sizeof(Dtlink_t)))
310 
311 // Namval attribute bits for use with nv_isattr(), nv_onattr(), nv_offattr(), etc. These affect how
312 // a namval behaves although not all of them affect the value. Some, such as NV_NOFREE, don't affect
313 // the interpretation of the value but do affect how the namval node behaves.
314 //
315 // For the moment we are limited to 16 bits since the namval->nvflag is an unsigned short.
316 //
317 // Note: If these definitions are changed remember to update `nvflags` in src/cmd/ksh93/sh/debug.c.
318 #define NV_RDONLY ((nvflag_t)1 << 0)   // readonly bit -- does not affect the value
319 #define NV_INTEGER ((nvflag_t)1 << 1)  // integer attribute
320 #define NV_LTOU ((nvflag_t)1 << 2)     // convert to uppercase
321 #define NV_UTOL ((nvflag_t)1 << 3)     // convert to lowercase
322 #define NV_ZFILL ((nvflag_t)1 << 4)    // right justify and fill with leading zeros
323 #define NV_RJUST ((nvflag_t)1 << 5)    // right justify and blank fill
324 #define NV_LJUST ((nvflag_t)1 << 6)    // left justify and blank fill
325 #define NV_MISC ((nvflag_t)1 << 7)     // this is overloaded to mean many things
326 #define NV_BINARY ((nvflag_t)1 << 8)   // fixed size data buffer
327 #define NV_NOFREE ((nvflag_t)1 << 9)   // don't free the space when releasing value
328 #define NV_ARRAY ((nvflag_t)1 << 10)   // node is an array
329 #define NV_TABLE ((nvflag_t)1 << 11)   // node is a dictionary table
330 #define NV_IMPORT ((nvflag_t)1 << 12)  // value imported from environment
331 #define NV_EXPORT ((nvflag_t)1 << 13)  // export bit -- does not affect the value
332 #define NV_REF ((nvflag_t)1 << 14)     // reference bit
333 #define NV_TAGGED ((nvflag_t)1 << 15)  // user tagged (typeset -t ...) -- does not affect the value
334 
335 // Aliases or compound types.
336 #define NV_RAW NV_LJUST                // used only with NV_BINARY
337 #define NV_HOST (NV_RJUST | NV_LJUST)  // map to host filename
338 #define NV_MINIMAL NV_IMPORT           // node does not contain all fields
339 #define NV_BLTINOPT NV_ZFILL           // mark builtins in `shtab_builtins[]` that are optional
340 #define NV_NODISC NV_MISC              // ignore disciplines
341 #define NV_CLONED NV_MISC  // the value is cloned from an outer scope and thus can't be freed
342 
343 #define NV_NOPRINT (NV_LTOU | NV_UTOL)  // do not print
344 #define NV_NOALIAS (NV_NOPRINT | NV_IMPORT)
345 #define NV_NOEXPAND NV_RJUST  // do not expand alias
346 #define NV_BLTIN (NV_NOPRINT | NV_EXPORT)
347 #define NV_NOTSET (NV_INTEGER | NV_BINARY)
348 
349 // The following are used with NV_INTEGER.
350 #define NV_SHORT NV_RJUST                  // when integers are not long
351 #define NV_LONG NV_UTOL                    // for long long and long double
352 #define NV_UNSIGN NV_LTOU                  // for unsigned quantities
353 #define NV_DOUBLE (NV_INTEGER | NV_ZFILL)  // for floating point
354 #define NV_EXPNOTE NV_LJUST                // for scientific notation
355 #define NV_HEXFLOAT NV_LTOU                // for C99 base16 float notation
356 
357 // Numeric types.
358 #define NV_INT16P (NV_LJUST | NV_SHORT | NV_INTEGER)
359 // #define NV_UINT16P (NV_LJUST | NV_UNSIGN | NV_SHORT | NV_INTEGER)
360 #define NV_INT16 (NV_SHORT | NV_INTEGER)
361 #define NV_INT32 NV_INTEGER
362 #define NV_INT64 (NV_LONG | NV_INTEGER)
363 #define NV_UINT16 (NV_UNSIGN | NV_SHORT | NV_INTEGER)
364 #define NV_UINT32 (NV_UNSIGN | NV_INTEGER)
365 // #define NV_UINT64 (NV_UNSIGN | NV_LONG | NV_INTEGER)
366 #define NV_FLOAT (NV_SHORT | NV_DOUBLE)
367 #define NV_LDOUBLE (NV_LONG | NV_DOUBLE)
368 
369 // JSON handling.
370 #if SUPPORT_JSON
371 #define NV_JSON NV_TAGGED      // for json formatting
372 #define NV_JSON_LAST NV_TABLE  // last for json formatting
373 #else
374 #define NV_JSON 0
375 #define NV_JSON_LAST 0
376 #endif  // SUPPORT_JSON
377 
378 // These are for use with nodes which are not name-values.
379 #define NV_FUNCTION (NV_RJUST | NV_FUNCT)  // value is shell function
380 #define NV_FPOSIX NV_LJUST                 // posix function semantics
381 #define NV_FTMP NV_ZFILL                   // function source in tmpfile
382 #define NV_STATICF NV_INTEGER              // static class function
383 #define NV_OPTGET NV_BINARY                // function calls getopts
384 #define NV_SHVALUE NV_TABLE                // function assigns .sh.value
385 
386 // Options for nv_open(), nv_search(), sh_setlist(), etc. They are not valid bits in a nvflag_t;
387 // i.e., (struct Namval*)->nvflag.
388 #define NV_APPEND ((nvflag_t)1 << 16)   // append value
389 #define NV_VARNAME ((nvflag_t)1 << 17)  // name must be ?(.)id*(.id)
390 #define NV_NOADD ((nvflag_t)1 << 18)    // do not add node
391 #define NV_NOSCOPE ((nvflag_t)1 << 19)  // look only in current scope
392 #define NV_NOFAIL ((nvflag_t)1 << 20)   // return 0 on failure, no msg
393 #define NV_NOARRAY ((nvflag_t)1 << 21)  // array name not possible
394 #define NV_IARRAY ((nvflag_t)1 << 22)   // for indexed array
395 #define NV_ADD ((nvflag_t)1 << 23)      // add node if not found
396 #define NV_UNJUST ((nvflag_t)1 << 23)   // clear justify attributes
397 #define NV_TYPE ((nvflag_t)1 << 24)
398 #define NV_STATIC ((nvflag_t)1 << 25)
399 #define NV_COMVAR ((nvflag_t)1 << 26)
400 #define NV_MOVE ((nvflag_t)1 << 27)    // for use with nv_clone()
401 #define NV_ASSIGN ((nvflag_t)1 << 28)  // assignment is allowed
402 #define NV_DECL ((nvflag_t)1 << 29)
403 
404 // This serves two purposes. First, it may help detect an nvflag_t value that has the high bit set
405 // when that should not occur. Second, it provides a way to silence Coverity Scan warnings about
406 // "logically dead code" due to constructs like `nvflag & NV_JSON` always being false when JSON
407 // support is disabled and `NV_JSON` would otherwise be defined as zero.
408 //
409 // This definition causes only the high bit to be set in a portable manner regardless of the size
410 // of nvflag_t.
411 #define NV_INVALID (~(~(nvflag_t)0 >> 1))
412 
413 // See the uses of these symbols in name.c.
414 #define NV_NOREF NV_REF    // don't follow reference
415 #define NV_FUNCT NV_IDENT  // option for nv_create
416 #define NV_IDENT NV_MISC   // name must be identifier
417 
418 // Name-value attribute test or modification routines. These used to be macros. They are now static
419 // inline functions rather than macros to facilitate instrumentation while still being fast. In
420 // particular validating the nvflag value; both current and new. Variants such as nv_isnull() are
421 // not static inline functions because they do more work and were historically extern functions.
422 
423 // Check that nvflag is valid. At the moment this is just a sanity check that the high bit is
424 // not set since that should never happen.
425 #ifdef NDEBUG
426 #define nv_isvalid(nvflag) ((vpoi)0)
427 #else   // NDEBUG
nv_isvalid(const nvflag_t nvflag)428 static inline void nv_isvalid(const nvflag_t nvflag) {
429     if (nvflag & NV_INVALID) {
430         DPRINTF("nvflag_t %" PRIX32 " is not valid", nvflag);
431         dump_backtrace(0);
432         abort();
433     }
434 }
435 #endif  // NDEBUG
436 
437 // Return true if the mask is set in nvflags.
nv_isflag(const nvflag_t nvflags,const nvflag_t mask)438 static inline bool nv_isflag(const nvflag_t nvflags, const nvflag_t mask) {
439     nv_isvalid(nvflags);
440     nv_isvalid(mask);
441     if (!mask) return false;
442     return (nvflags & mask) == mask;
443 }
444 
445 // Return any bits in mask that are set in the Namval_t.
446 // TODO: Convert this to returning a truth value (all bits in mask set or not) to mimic nv_isflag().
nv_isattr(const Namval_t * np,const nvflag_t mask)447 static inline int nv_isattr(const Namval_t *np, const nvflag_t mask) { return np->nvflag & mask; }
448 
nv_isarray(const Namval_t * np)449 static inline bool nv_isarray(const Namval_t *np) { return nv_isattr(np, NV_ARRAY) == NV_ARRAY; }
450 
nv_onattr(Namval_t * np,nvflag_t nvflag)451 static inline void nv_onattr(Namval_t *np, nvflag_t nvflag) {
452     nv_isvalid(nvflag);
453     nv_isvalid(np->nvflag);
454     nvflag &= ~(~(nvflag_t)0U << NV_nbits);  // strip bits valid for nv_open() but not nvflag
455     np->nvflag |= nvflag;
456 }
457 
nv_offattr(Namval_t * np,nvflag_t nvflag)458 static inline void nv_offattr(Namval_t *np, nvflag_t nvflag) {
459     nv_isvalid(nvflag);
460     nv_isvalid(np->nvflag);
461     nvflag &= ~(~(nvflag_t)0U << NV_nbits);  // strip bits valid for nv_open() but not nvflag
462     np->nvflag &= ~nvflag;
463 }
464 
nv_setattr(Namval_t * np,nvflag_t nvflag)465 static inline void nv_setattr(Namval_t *np, nvflag_t nvflag) {
466     nv_isvalid(nvflag);
467     nv_isvalid(np->nvflag);
468     nvflag &= ~(~(nvflag_t)0U << NV_nbits);  // strip bits valid for nv_open() but not nvflag
469     np->nvflag = nvflag;
470 }
471 
472 // The following symbols are for use with nv_disc().
473 enum {
474     DISC_OP_NOOP_val = 1,  // ??? (this used to be the magic `0` constant used by four callers)
475     DISC_OP_FIRST_val,     // Move or push <fp> to top of the stack or delete top
476     DISC_OP_LAST_val,      // Move or push <fp> to bottom of stack or delete last
477     DISC_OP_POP_val,       // Delete <fp> from top of the stack
478     DISC_OP_CLONE_val      // Replace <fp> with a copy created my malloc() and return it
479 };
480 
481 typedef struct {
482     int val;
483 } Nvdisc_op_t;
484 
485 extern const Nvdisc_op_t DISC_OP_NOOP;
486 extern const Nvdisc_op_t DISC_OP_FIRST;
487 extern const Nvdisc_op_t DISC_OP_LAST;
488 extern const Nvdisc_op_t DISC_OP_POP;
489 extern const Nvdisc_op_t DISC_OP_CLONE;
490 
491 // The following are operations for nv_putsub().
492 #define ARRAY_BITS 22
493 #define ARRAY_ADD ((nvflag_t)1 << (0 + ARRAY_BITS))    // add subscript if not found
494 #define ARRAY_SCAN ((nvflag_t)1 << (1 + ARRAY_BITS))   // For ${array[@]}
495 #define ARRAY_UNDEF ((nvflag_t)1 << (2 + ARRAY_BITS))  // For ${array}
496 
497 // These symbols are passed to `nv_discfun()` to cause it to return a set of disciplines that
498 // implement a specific policy. We start with the arbitrary value 19 to help ensure that calling
499 // `nv_discfun()` with an unexpected op value will fail.
500 typedef enum {
501     DISCFUN_ADD = 19,  // for vars that have named shell level disciplines (e.g., var.get() {...})
502     DISCFUN_RESTRICT   // for vars that cannot be modified in a restricted shell
503 } Nvdiscfun_op_t;
504 
505 // Prototype for array interface.
506 extern Namarr_t *nv_arrayptr(Namval_t *);
507 extern Namarr_t *nv_setarray(Namval_t *, void *(*)(Namval_t *, const char *, Nvassoc_op_t));
508 extern int nv_arraynsub(Namarr_t *);
509 extern void *nv_associative(Namval_t *, const char *, Nvassoc_op_t);
510 extern int nv_aindex(Namval_t *);
511 extern bool nv_nextsub(Namval_t *);
512 extern char *nv_getsub(Namval_t *);
513 extern Namval_t *nv_putsub(Namval_t *, char *, long, nvflag_t);
514 extern Namval_t *nv_opensub(Namval_t *);
515 
516 // Name-value pair function prototypes.
517 extern bool nv_adddisc(Namval_t *, const char **, Namval_t **);
518 extern int nv_clone(Namval_t *, Namval_t *, nvflag_t);
519 extern void nv_close(Namval_t *);
520 extern Namval_t *nv_create(const char *, Dt_t *, nvflag_t, Namfun_t *);
521 extern void nv_delete(Namval_t *, Dt_t *, nvflag_t);
522 extern Dt_t *nv_dict(Namval_t *);
523 extern Sfdouble_t nv_getn(Namval_t *, Namfun_t *);
524 extern Sfdouble_t nv_getnum(Namval_t *);
525 extern char *nv_getv(Namval_t *, Namfun_t *);
526 extern char *nv_getval(Namval_t *);
527 extern Namfun_t *nv_hasdisc(const Namval_t *, const Namdisc_t *);
528 extern bool nv_isnull(Namval_t *);
529 extern Namfun_t *nv_isvtree(Namval_t *);
530 extern Namval_t *nv_lastdict(void *);
531 extern Namval_t *nv_mkinttype(char *, size_t, int, const char *, Namdisc_t *);
532 extern void nv_newattr(Namval_t *, nvflag_t, int);
533 extern void nv_newtype(Namval_t *);
534 extern Namval_t *nv_open(const char *, Dt_t *, nvflag_t);
535 extern void nv_putval(Namval_t *, const void *, nvflag_t);
536 extern void nv_putv(Namval_t *, const void *, nvflag_t, Namfun_t *);
537 extern bool nv_rename(Namval_t *, nvflag_t);
538 extern int nv_scan(Dt_t *, void (*)(Namval_t *, void *), void *, nvflag_t, nvflag_t);
539 extern char *nv_setdisc(Namval_t *, const void *, Namval_t *, Namfun_t *);
540 extern void nv_setref(Namval_t *, Dt_t *, nvflag_t);
541 extern int nv_settype(Namval_t *, Namval_t *, nvflag_t);
542 extern void nv_setvec(Namval_t *, int, int, char *[]);
543 extern void nv_setvtree(Namval_t *);
544 extern int nv_setsize(Namval_t *, int);
545 extern Namfun_t *nv_disc(Namval_t *, Namfun_t *, Nvdisc_op_t);
546 extern int nv_unall(char **, bool, nvflag_t, Dt_t *, Shell_t *);
547 extern void nv_unset(Namval_t *); /*obsolete */
548 extern void _nv_unset(Namval_t *, nvflag_t);
549 extern Namval_t *nv_search(const char *, Dt_t *, nvflag_t);
550 extern Namval_t *nv_search_namval(const Namval_t *, Dt_t *, nvflag_t);
551 extern char *nv_name(const Namval_t *);
552 extern Namval_t *nv_type(Namval_t *);
553 // Note that the third parameter should be a pointer to a Optdisc_t or a structure where that type
554 // is the first member.
555 extern void nv_addtype(Namval_t *, const char *, void *, size_t);
556 extern const Namdisc_t *nv_discfun(Nvdiscfun_op_t);
557 
558 #define nv_unset(np) _nv_unset(np, 0)
559 #define nv_size(np) nv_setsize((np), -1)
560 #define nv_stack(np, nf) nv_disc(np, nf, DISC_OP_NOOP)
561 
562 // Used for arrays.
563 #if _ast_sizeof_pointer >= 8
564 #define ARRAY_MAX (1UL << 31)  // maximum number of elements in an array
565 #else
566 #define ARRAY_MAX (1UL << ARRAY_BITS)  // maximum number of elements in an array
567 #endif
568 
569 // Number of elements to grow when array bound exceeded.  Must be a power of 2.
570 #define ARRAY_INCR 32
571 #define ARRAY_FILL ((nvflag_t)1 << (3 + ARRAY_BITS))     // used with nv_putsub()
572 #define ARRAY_NOCLONE ((nvflag_t)1 << (4 + ARRAY_BITS))  // do not clone array disc
573 #define ARRAY_NOCHILD ((nvflag_t)1 << (5 + ARRAY_BITS))  // skip compound arrays
574 #define ARRAY_SETSUB ((nvflag_t)1 << (6 + ARRAY_BITS))   // set subscript
575 #define ARRAY_NOSCOPE ((nvflag_t)1 << (7 + ARRAY_BITS))  // top level scope only
576 #define ARRAY_TREE ((nvflag_t)1 << (8 + ARRAY_BITS))     // arrays of compound vars
577 
578 // These flags are used as options to array_get().
579 #define ARRAY_ASSIGN 0
580 #define ARRAY_LOOKUP 1
581 #define ARRAY_DELETE 2
582 
583 struct Namref {
584     Namval_t *np;
585     Namval_t *table;
586     Namval_t *oldnp;
587     Dt_t *root;
588     char *sub;
589 };
590 
591 // This describes a user shell function node.
592 struct Ufunction {
593     int64_t lineno;    // line number of function start
594     int *ptree;        // address of parse tree
595     short argc;        // number of references
596     short running;     // function is running
597     char **argv;       // reference argument list
598     off_t hoffset;     // offset into source or history file
599     Namval_t *nspace;  // pointer to name space
600     char *fname;       // file name where function defined
601     char *help;        // help string
602     Dt_t *sdict;       // dictionary for statics
603     Dt_t *fdict;       // dictionary node belongs to
604     Namval_t *np;      // function node pointer
605 };
606 
607 #ifndef ARG_RAW
608 struct argnod;
609 #endif  // !ARG_RAW
610 
611 // Attributes of Namval_t items.
612 
613 // The following attributes are for internal use.
614 #define NV_NOCHANGE (NV_EXPORT | NV_IMPORT | NV_RDONLY | NV_TAGGED | NV_NOFREE | NV_ARRAY)
615 #define NV_PARAM NV_NODISC  // expansion use positional params
616 
617 #define BLT_ENV (NV_RDONLY)      // non-stoppable, can modify environment
618 #define BLT_DISABLE (NV_BINARY)  // bltin disabled
619 #define BLT_SPC (NV_TAGGED)      // special built-ins
620 #define BLT_EXIT (NV_RJUST)      // exit value can be > 255
621 #define BLT_DCL (NV_LJUST)       // declaration command
622 #define BLT_NOSFIO (NV_IMPORT)   // doesn't use sfio
623 
624 #define nv_isref(n) (nv_isattr((n), NV_REF | NV_TAGGED | NV_FUNCT) == NV_REF)
625 #define is_abuiltin(n) (nv_isattr(n, NV_BLTIN | NV_INTEGER) == NV_BLTIN)
626 #define is_afunction(n) (nv_isattr(n, NV_FUNCTION | NV_REF) == NV_FUNCTION)
627 #define nv_funtree(n) FETCH_VT((n)->nvalue, rp)->ptree
628 #define funptr(n) FETCH_VT((n)->nvalue, shbltinp)
629 
630 #define NV_SUBQUOTE (NV_ADD << 1)  // used with nv_endsubscript
631 
632 // NAMNOD macros.
633 //
634 // ... for attributes.
635 #define nv_context(_np) ((void *)(_np)->nvfun)
636 // The following are for name references.
637 #define nv_refnode(_np) FETCH_VT((_np)->nvalue, nrp)->np
638 #define nv_reftree(_np) FETCH_VT((_np)->nvalue, nrp)->root
639 #define nv_reftable(_np) FETCH_VT((_np)->nvalue, nrp)->table
640 #define nv_refsub(_np) FETCH_VT((_np)->nvalue, nrp)->sub
641 #define nv_refoldnp(_np) FETCH_VT((_np)->nvalue, nrp)->oldnp
642 // ... for etc.
643 #define nv_setsize(_np, s) ((_np)->nvsize = ((s)*4) | 2)
644 #undef nv_size
645 #define nv_size(_np) ((_np)->nvsize >> 2)
646 #define nv_attr(_np) ((_np)->nvflag & ~NV_MINIMAL)
647 // ... for arrays.
648 #define array_elem(ap) ((ap)->nelem)
649 // An array is associative if it has a function pointer else it is a simple indexed array.
650 #define is_associative(ap) ((ap)->fun)
651 
652 struct nvdir;
653 
654 extern int array_maxindex(Namval_t *);
655 extern int array_isempty(Namval_t *);
656 extern char *nv_endsubscript(Namval_t *, char *, nvflag_t, void *);
657 extern Namfun_t *nv_cover(Namval_t *);
658 extern Namarr_t *nv_arrayptr(Namval_t *);
659 extern bool nv_arrayisset(Namval_t *, Namarr_t *);
660 extern bool nv_arraysettype(Namval_t *, Namval_t *, const char *, nvflag_t);
661 extern int nv_aimax(Namval_t *);
662 extern struct Value *nv_aivec(Namval_t *, unsigned char **);
663 extern int nv_aipack(Namarr_t *);
664 extern bool nv_atypeindex(Namval_t *, const char *);
665 extern bool nv_setnotify(Namval_t *, char **);
666 extern bool nv_unsetnotify(Namval_t *, char **);
667 extern struct argnod *nv_onlist(struct argnod *, const char *);
668 extern void nv_optimize(Namval_t *);
669 extern void nv_unref(Namval_t *);
670 extern bool nv_hasget(Namval_t *);
671 void clone_all_disc(Namval_t *, Namval_t *, nvflag_t);
672 extern Namfun_t *nv_clone_disc(Namfun_t *, nvflag_t);
673 extern struct nvdir *nv_diropen(Namval_t *, const char *, void *);
674 extern char *nv_dirnext(void *);
675 extern void nv_dirclose(struct nvdir *);
676 extern char *nv_getvtree(Namval_t *, Namfun_t *);
677 extern void nv_attribute(Namval_t *, Sfio_t *, char *, int);
678 extern Namval_t *nv_bfsearch(const char *, Dt_t *, Namval_t **, char **);
679 extern Namval_t *nv_mkclone(Namval_t *);
680 extern Namval_t *nv_mktype(Namval_t **, int);
681 extern Namval_t *nv_addnode(Namval_t *, int);
682 extern Namval_t *nv_parent(const Namval_t *);
683 extern Namval_t *nv_mount(Namval_t *, const char *name, Dt_t *);
684 extern Namval_t *nv_arraychild(Namval_t *, Namval_t *, int);
685 extern int nv_compare(Dt_t *, void *, void *, Dtdisc_t *);
686 extern void nv_outnode(Namval_t *, Sfio_t *, int, int);
687 extern bool nv_subsaved(Namval_t *, bool);
688 extern void nv_typename(Namval_t *, Sfio_t *);
689 extern void nv_newtype(Namval_t *);
690 extern Namval_t *nv_typeparent(Namval_t *);
691 extern bool nv_istable(const Namval_t *);
692 extern size_t nv_datasize(Namval_t *, size_t *);
693 extern Namfun_t *nv_mapchar(Namval_t *, const char *);
694 extern void nv_checkrequired(Namval_t *);
695 
696 extern const Namdisc_t RESTRICTED_disc;
697 extern const Namdisc_t ENUM_disc;
698 extern const Namdisc_t OPTIMIZE_disc;
699 extern bool nv_local;
700 extern Dtdisc_t _Nvdisc;
701 extern const char *nv_discnames[];
702 extern const char e_subscript[];
703 extern const char e_nullset[];
704 extern const char e_notset[];
705 extern const char e_notset2[];
706 extern const char e_noparent[];
707 extern const char e_notelem[];
708 extern const char e_readonly[];
709 extern const char e_badfield[];
710 extern const char e_restricted[];
711 extern const char e_ident[];
712 extern const char e_varname[];
713 extern const char e_noalias[];
714 extern const char e_noarray[];
715 extern const char e_notenum[];
716 extern const char e_nounattr[];
717 extern const char e_aliname[];
718 extern const char e_badexport[];
719 extern const char e_badref[];
720 extern const char e_badsubscript[];
721 extern const char e_noref[];
722 extern const char e_selfref[];
723 extern const char e_staticfun[];
724 extern const char e_envmarker[];
725 extern const char e_badlocale[];
726 extern const char e_loop[];
727 extern const char e_redef[];
728 extern const char e_required[];
729 extern const char e_badappend[];
730 extern const char e_unknowntype[];
731 extern const char e_unknownmap[];
732 extern const char e_mapchararg[];
733 extern const char e_subcomvar[];
734 extern const char e_badtypedef[];
735 extern const char e_typecompat[];
736 extern const char e_globalref[];
737 extern const char e_tolower[];
738 extern const char e_toupper[];
739 extern const char e_wordbreaks[];
740 
741 #endif  // _NAME_H
742