This might help you ....
Extracted from a blog post KSH93 Custom Builtins II I wrote a couple of years ago:
Example 5 Using name-value routines to access ksh93 internals
The purpose of this custom builtin is to set the value of a specified variable (argument 1) to the size of the specified file (argument 2).
$ statsize myfilesize /usr/bin/ksh
$ print ${myfilesize}
1157295
$
This example uses the libast nval(3) name-value routines to access the internals of ksh93 and set up a variable with the specifed name (i.e. myfilesize) and value of 1157295 as returned by stat(2) for the file /usr/bin/ksh. See the nval(3) documentation for more detailed information.
#include <shell.h>
#include <nval.h>
#define SH_DICT "statsize"
static const char usage_statsize[] =
[-?\n@(#)$Id: stat 2008-05-03 $\n]"
[-author?Finnbarr P. Murphy <fpmATiisc.com>]"
[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
[+NAME?statsize - assign size of file to variable]"
[+DESCRIPTION?\bstat\b assigns the size of the specified file"
"(in bytes) to the specified variable.]"
"[+OPTIONS?none.]"
"\n"
"[+EXIT STATUS?] {"
"[+0?Success.]"
"[+>0?An error occurred.]"
"[+SEE ALSO?\bstat\b(2)]"
;
int
b_statsize(int argc, char *argv[], void *extra)
{
Namval_t *nvp = (Namval_t *)NULL;
Shell_t *shp = (Shell_t *)NULL;
struct stat st;
long d;
register int n;
while (n = optget(argv, usage_statsize)) switch(n) {
case ':':
error(2, "%s", opt_info.arg);
break;
case '?':
errormsg(SH_DICT, ERROR_usage(2), "%s",
opt_info.arg);
break;
}
argc -= opt_info.index;
argv += opt_info.index;
if (argc != 2)
errormsg(SH_DICT, ERROR_usage(2), "%s",
optusage((char*)0));
/* get current shell context */
shp = sh_getinterp();
/* retrieve information about file */
stat(argv[1], &st);
/* assign size of file to long */
d = (long) st.st_size;
/* access the variables tree and add specified variable */
nvp = nv_open(argv[0], shp->var_tree,
NV_NOARRAY|NV_VARNAME|NV_NOASSIGN);
if (!nv_isnull(nvp))
nv_unset(nvp);
nv_putval(nvp, (char *)&d, NV_INTEGER|NV_RDONLY);
nv_close(nvp);
return(0);
}
This custom builtin can easily be extended to provide much more information about a file using command line options. I will leave it as an exercise for you the reader.
Example 6 Print out detailed information about a specified shell variable.
$ showvar HOME
Value: /home/fpm, Flags: 12288 NV_EXPORT NV_IMPORT
$ integer i=123
$ showvar i
Value: 123, Flags: 10 NV_UINT64 NV_UTOL
See the libast header <nval.h> for detailed information about the different flags which can be associated with each variable. Note that some flags are overloaded so that they mean different things according to how they are OR�ed with other flags.
#include <shell.h>
#include <nval.h>
#define SH_DICT "showvar"
static const char usage_showvar[] =
"[-?\n@(#)$Id: showvar 2008-05-04 $\n]"
"[-author?Finnbarr P. Murphy <fpmATiisc.com>]"
"[-licence?http://www.opensource.org/licenses/cpl1.0.txt]"
"[+NAME?showvar - display variable details]"
"[+DESCRIPTION?\bshowvar\b displays details about the
specified variable.]"
"[+OPTIONS?none.]"
"\n"
"\nvariable_name\n"
"\n"
"[+EXIT STATUS?] {"
"[+0?Success.]"
"[+>0?An error occurred.]"
"}"
"[+SEE ALSO?\bstat\b(2)]"
;
struct Flag {
int flag;
char *name;
};
/* Note: not a complete list of all possible flags */
struct Flag Flags[] = {
NV_ARRAY, "NV_ARRAY",
NV_BINARY, "NV_BINARY",
NV_EXPORT, "NV_EXPORT",
NV_HOST, "NV_HOST",
NV_IMPORT, "NV_IMPORT",
NV_LJUST, "NV_LJUST",
NV_LTOU, "NV_LTOU",
NV_RAW, "NV_RAW",
NV_RDONLY, "NV_RDONLY",
NV_REF, "NV_REF",
NV_RJUST, "NV_RJUST",
NV_TABLE, "NV_TABLE",
NV_TAGGED, "NV_TAGGED",
NV_UTOL, "NV_UTOL",
NV_ZFILL, "NV_ZFILL",
0,(char *)NULL
};
struct Flag IntFlags[] = {
NV_LTOU|NV_UTOL|NV_INTEGER, "NV_UINT64",
NV_LTOU|NV_RJUST|NV_INTEGER, "NV_UINT16",
NV_RJUST|NV_ZFILL|NV_INTEGER, "NV_FLOAT",
NV_UTOL|NV_ZFILL|NV_INTEGER, "NV_LDOUBLE",
NV_RJUST|NV_INTEGER, "NV_INT16",
NV_LTOU|NV_INTEGER, "NV_UINT32",
NV_UTOL|NV_INTEGER, "NV_INT64",
NV_RJUST, "NV_SHORT",
NV_UTOL, "NV_LONG",
NV_LTOU, "NV_UNSIGN",
NV_ZFILL, "NV_DOUBLE",
NV_LJUST, "NV_EXPNOTE",
NV_INTEGER, "NV_INT32(NV_INTEGER)",
0,(char *)NULL
};
int
b_showvar(int argc, char *argv[], void *extra)
{
Shell_t *shp = (Shell_t *)NULL;
Namval_t *nvp = (Namval_t *)NULL;
char *ptr = (char *)NULL;
int i;
while (i = optget(argv, usage_showvar)) switch(i) {
case ':':
error(2, "%s", opt_info.arg);
break;
case '?':
errormsg(SH_DICT, ERROR_usage(2), "%s", opt_info.arg);
break;
}
argc -= opt_info.index;
argv += opt_info.index;
if (argc != 1)
errormsg(SH_DICT, ERROR_usage(2), "%s", optusage((char*)0));
/* get current shell context */
shp = sh_getinterp();
if ((nvp = nv_search(*argv, shp->var_tree, 0)) == NULL) {
errormsg(SH_DICT, ERROR_exit(1),
"%s: variable not found", *argv);
return(1);
}
if ((ptr = nv_getval(nvp)) == NULL) {
errormsg(SH_DICT, ERROR_exit(3),
"%s: variable is NULL", *argv);
return(1);
}
sfprintf(sfstdout,
"Value: %s, Flags: %d", ptr, (int)nvp->nvflag);
if ((int)nvp->nvflag & NV_INTEGER) {
for (i=0; IntFlags.name != NULL; i++) {
if ((int)nvp->nvflag & IntFlags.flag) {
sfprintf(sfstdout, " %s", IntFlags.name);
break;
}
}
}
for (i=0; Flags.name != NULL; i++) {
if ((int)nvp->nvflag & Flags.flag)
sfprintf(sfstdout, " %s", Flags.name);
}
sfprintf(sfstdout,"\n");
nv_close(nvp);
return(0);
}