Sponsored Content
Top Forums UNIX for Advanced & Expert Users Writing Custom Builtins for KSH93 Post 302471146 by hergp on Friday 12th of November 2010 05:18:04 AM
Old 11-12-2010
Some years ago I wrote a few ksh93 builtins. One of them can manipulate the PATH variable and similar ones (like MANPATH, etc). I haven't used it for some time now, so I am not sure, if it still works with a current ksh93 binary. But maybe you get an idea, how variables can be manipulated.

Code:
/*****************************************************************************
 *
 * $Id$
 *
 * Kornshell 93 builtin function 'setpath'.
 *
 *****************************************************************************/

#include <shell.h>

/*-------------*/
/* definitions */
/*-------------*/

#define DELIMITER     ':'
#define DEFAULTVAR    "PATH"

/*-----------------------------------------*/
/* embedded manpage and options definition */
/*-----------------------------------------*/

static char optget_opts[] =
"[+NAME?setpath - manipulate PATH type variables]"
"[-AUTHOR?Paul Herger <ph@herger.at>]"
"[+DESCRIPTION?\bsetpath\b manipulates $PATH or other PATH type shell "
    "variables.]"
"[+?The names of directories or files can be "
    "appended to the end (option \b-a\b), "
    "prepended to the beginning (option \b-p\b) or "
    "excluded (option  \b-x\b) from the variable. "
    "These options are mutually exclusive.]"
"[+?After these manipulations, duplicate entries can be removed from the "
    "variable if the \b-u\b option is specified. Each first occurence of "
    "duplicate entries is kept while all others are deleted.]"
"[+?If the \b-e\b option is specified, all directories or files that do not "
    "exists are deleted.]"

"[a?Append to the end of the variable]"
"[p?Prepend to the beginning of the variable]"
"[x?Exclude from the variable]"
"[e?Delete from or do not include into the path variable non existing"
    "directories or files]"
"[u?Make elements unique by deleting all but the first occurence of"
    "every directory or file]"
"[v?Use \avname\a instead of $PATH]:[vname]"
"\n"
"\n[path ...]\n"
"\n"
"[+EXIT STATUS?]{"
    "[+0?Completed successfully.]"
    "[+>0?An error occurred.]}"
"[+EXAMPLE?\b$ setpath -aeu /opt/bin /usr/local/bin\b]"
"[+?Both /opt/bin and /usr/local/bin are appended at the end of the shell "
    "variable $PATH, if they are not yet elements of it. If they do not "
    "exist they are not appended to or are deleted from $PATH.]"
"[+?\b$ setpath -xv MANPATH /opt/man\b]"
"[+?/opt/man is deleted from $MANPATH.]"
"[+?\b$ setpath -ue\b]"
"[+?Duplicate entries and entries that do not refer to an existing "
    "filesystem object are deleted from $PATH.]";

/*----------------------*/
/* other error messages */
/*----------------------*/

static char usage[]        = "[{-a|-p|-x}] [-eu] [-v vname] [path ...]";
static char err_internal[] = "internal error";
static char err_mutual[]   = "options -%c and -%c are mutually exclusive";

/*===========================================================================*/
/* Add a copy of a string to a container (set or queue). If the string       */
/* contains delimiters, split the string at the delimiters and add each part */
/* of the string as independent string to the container, thus splitting PATH */
/* type strings in their components.                                         */
/*===========================================================================*/

static void add_to_container(Dt_t *container, char *string)
{
    char *copy, *ptr;

    if (!(copy = stkcopy(stkstd, string))) return;

    dtinsert(container, copy);

    for (ptr = copy; *ptr; ptr++)
        if (*ptr == DELIMITER)
        {
            *ptr = '\0';
            dtinsert(container, ptr+1);
        }
}

/*===========================================================================*/
/* This is the main routine of the 'setpath' builtin. It processes the       */
/* arguments, sets up containers and builts the result on the stack.         */
/*===========================================================================*/

int b_setpath(int argc, char *argv[], void *context)
{
    Shell_t  *shp = (Shell_t*)context;
    Namval_t *np;
    Dtdisc_t disc = {0, 0, -1};
    Dt_t     *dt_old, *dt_del;
    char     ch, action = '\0', *obj, *vname = NULL;
    int      flag_e = 0, flag_u = 0, output = 0, stktop;

    /*-----------------------*/
    /* process the arguments */
    /*-----------------------*/

    while (ch = optget(argv, optget_opts))
        switch (ch)
        {
            /*-------------------*/
            /* action to perform */
            /*-------------------*/

            case 'a':
            case 'p':
            case 'x':
                if (action)
                    error(ERROR_ERROR, err_mutual, action, ch);
                else
                    action = ch;
                break;

            /*--------------------------*/
            /* what variable to process */
            /*--------------------------*/

            case 'v':
                if (vname)
                    error(ERROR_WARNING, "option -v can only be used "
                          "once, ignoring -v %s", opt_info.arg);
                else
                    vname = opt_info.arg;
                break;

            /*-------------*/
            /* other flags */
            /*-------------*/

            case 'e':
                flag_e = 1;
                break;

            case 'u':
                flag_u = 1;
                break;

            /*----------------------*/
            /* error and usage info */
            /*----------------------*/

            case ':':
                error(2, "%s", opt_info.arg);
                break;

            case '?':
                error(ERROR_usage(2), "%s", opt_info.arg);
                break;
        }

    /*-----------------------------*/
    /* finish processing arguments */
    /*-----------------------------*/

    argv += opt_info.index;
    argc -= opt_info.index;

    if (error_info.errors) error(ERROR_usage(2), "%s", usage);
    if (argc == 0 && flag_e == 0 && flag_u == 0) return 0;
    if (!vname) vname = DEFAULTVAR;

    /*---------------------------------------------------------------------*/
    /* create containers and get current content of the processed variable */
    /*---------------------------------------------------------------------*/

    dt_old = dtopen (&disc, Dtqueue);
    dt_del = dtopen (&disc, Dtset);

    np = nv_open(vname, shp->var_tree, NV_VARNAME);

    if (!dt_old || !dt_del || !np) error(ERROR_exit(1), err_internal);

    /*-------------------------------------------------------------*/
    /* fill containers with arguments and current variable content */
    /*-------------------------------------------------------------*/

    if (action == 'p')
        while (argc-- > 0) add_to_container(dt_old, *argv++);

    add_to_container (dt_old, (char *) nv_getval(np));

    if (action == 'a')
        while (argc-- > 0) add_to_container(dt_old, *argv++);

    if (action == 'x')
        while (argc-- > 0) add_to_container(dt_del, *argv++);

    /*---------------------------------------------------------------*/
    /* now copy entries from 'dt_old' to the stack for output        */
    /* - skip elements in 'dt_del' (options '-x' and '-u')           */
    /* - check for existence if option '-e' is set                   */
    /* - insert into 'dt_del' if option '-u' is set                  */
    /* - if all tests passed copy to the stack to build the new path */
    /*---------------------------------------------------------------*/

    stktop = stktell(stkstd);

    for (obj = dtfirst(dt_old); obj; obj = dtnext(dt_old, obj))
    {
        if (dtmatch(dt_del, obj)) continue;
        if (flag_e && *obj && *obj != '.' && access(obj, F_OK) < 0) continue;
        if (flag_u) dtinsert(dt_del, obj);
        if (output) sfputc(stkstd, DELIMITER);
        sfprintf(stkstd, "%s", obj);
        output = 1;
    }

    /*--------------------------------------------------*/
    /* copy the result string to the processed variable */
    /*--------------------------------------------------*/

    sfputc(stkstd, '\0');
    nv_putval(np, stkptr(stkstd, stktop), 0);
    nv_close(np);
    dtclose(dt_old);
    dtclose(dt_del);
    return 0;
}

This User Gave Thanks to hergp For This Post:
 

10 More Discussions You Might Find Interesting

1. Shell Programming and Scripting

ksh93 deprecation...

Any means of running ksh93 in a ksh88-mode? Might sound odd, but I want/need to restrict U/Win-developed scripts to correspond to the ksh88 version on my Solaris environment(s). Thanks. (2 Replies)
Discussion started by: curleb
2 Replies

2. Shell Programming and Scripting

ksh88 or ksh93

Hi all! Does anybody know how can I check if any UNIX installation has implemented ksh88 or ksh93? Thanks in advance. Néstor. (3 Replies)
Discussion started by: Nestor
3 Replies

3. Shell Programming and Scripting

program name and function name builtins

Hi Is there a way to get the program/script name or function name usng built ins. Like in many languages arg holds the program name regards (2 Replies)
Discussion started by: xiamin
2 Replies

4. Programming

pthread_mutex_lock in ANSI C vs using Atomic builtins of GCC

I have a program which has 7-8 threads, and lots of shared variables; these variables (and also they may not the primitive type, they may be enum or struct ), then they may read/write by different threads at the same time. Now, my design is like this, typedef unsigned short int UINT16;... (14 Replies)
Discussion started by: sehang
14 Replies

5. Shell Programming and Scripting

Ksh93 vs. Pdksh88: Custom PS1 prompt not working

Greetings! I have to work with a NFS user id between two hosts: A running Ksh 93 and B running pdksh 88. My problem has to do with the custom prompt I created on A: it works like a charm and display colors: PS1="$'\E But I switch over to B, it all goes to hell (private info... (4 Replies)
Discussion started by: alan
4 Replies

6. UNIX for Dummies Questions & Answers

Why does /bin contain binaries for builtins?

Why do shell builtins like echo and pwd have binaries in /bin? When I do which pwd, I get the one in /bin. that means that I am not using the builtin version? What determines which one gets used? Is the which command a definitive way to determine what is being run when I enter pwd? (16 Replies)
Discussion started by: glev2005
16 Replies

7. UNIX for Dummies Questions & Answers

Shell and bash builtins...

Not sure if this is the right forum but I have collated a listing of shell and bash builtins. Builtins is a loose word and may include the '/bin' drawer/folder/directory but NOT any others in the path list. In the case of my Macbook Pro, OSX 10.7.5 the enabled internals is also listed... ... (1 Reply)
Discussion started by: wisecracker
1 Replies

8. UNIX for Advanced & Expert Users

Ksh93 on Linux compatible with ksh93 on AIX

Hi Experts, I have several shell scripts that have been developed on a Linux box for korn ksh93. If we want to run this software on an AIX 6.1 box that runs ksh88 by default can we just change the she-bang line to reference /bin/ksh93 which ships with AIX as its "enhanced shell" to ensure... (6 Replies)
Discussion started by: Keith Turley
6 Replies

9. Programming

Help w/ writing a custom Linux shell using x86 assembly (NASM)

Hello world, I thought this might be a great start to help me with an assignment I have that requires me to write an assembly program that mimics a 32 bit Linux command shell: When launched, your program will perform the following steps in a loop: 1. Print a prompt, specifically “$ “... (1 Reply)
Discussion started by: turtle13
1 Replies

10. AIX

Ksh93/AIX compatibility

Hi everyone ! Im trying to know from wich version of AIX KSH93 is available ? Internet tell me 6.x and 7.x AIX are available, bue what about 5.x ? Is KSH93 available on AIX 5.x ? Is it the same way to manipulate variables as KSH93 on 7.x ? Thanks for your support and have a nice day ! (2 Replies)
Discussion started by: majinfrede
2 Replies
All times are GMT -4. The time now is 10:30 PM.
Unix & Linux Forums Content Copyright 1993-2022. All Rights Reserved.
Privacy Policy