Listing 2

/*
 *  CDE.C: Extended "cd" command for MS-DOS.
 *  Written by Leor Zolman, 9/20/89
 *
 *  Features:
 *      1)  Allows changing to another drive and directory in one step
 *      2)  Supports directory aliasing through environment variables
 *      3)  With no arguments, optionally switches to 'home' directory
 *          (if the HOME environment variable is currently defined)
 *      3)  Manages a "previous directory" stack through environment
 *          variables. The number of entries in the stack is dynamically
 *          configurable through a special controlling environment variable.
 *      4)  For special case of stack size = 1, toggling back and forth
 *          between two directories is supported
 *
 *  Usage:
 *     cde [d:] [path]      (changes to given drive/directory)
 *     cde <env-var-name>   (indirect dir change on environment variable)
 *     cde                  (changes to HOME directory, if defined, or
 *                              returns current working directory otherwise)
 *
 *  Compile/Link:
 *      cl /Ox cde.c util.c envlib (where ENVLIB.OBJ is Master Env. Pkg.)
 *
 *  Uses the Master Environment library from CUJ 7/89.
 *
 */

#include    <stdio.h>
#include    <dos.h>
#include    <string.h>
#include    <stdlib.h>
#include    "util.h"

main(int argc, char **argv)
{
    char    *pathp;
    char    cwdbuf[MAX_DIRNAME_SIZE];       /* buffer for current dir name  */

    int     chaincnt;                       /* size of dir stack            */
    char    chaincnt_txt[10], *chaincntp;
    char    chnevar1[MAX_EVARNAME_SIZE],    /* env var names built here     */
           chnevar2[MAX_EVARNAME_SIZE];
    char    chndname_save[MAX_DIRNAME_SIZE], *chndname;
    char    itoabuf[10];                    /* used by itoa() function      */
    int     i;

                            /* Get current dir. name and current drive: */
    getcwd(cwdbuf, MAX_DIRNAME_SIZE);

    if (argc == 1)                       /* if no args given,               */
        if (pathp = m_getenv(HOME_NAME))    /* if HOME directory defined,  */
        {

            change_dir(pathp);            /* then try to change to it.   */
            strcpy(chnevar1, CHAIN_BASE); /* set top-stack env var       */
            strcat(chnevar1, "1");
            if (m_putenv(chnevar1, cwdbuf)) /* to old dir                  */
                error("Error setting environment variable");
             return 0;
        }
        else
        {                                 /* just print current working dir   */
            cputs(cwdbuf);
            putch('\n');
            return 0;

        }

    if (argc != 2)
        error("Usage: cde [d:][newpath] or <environment-var-name>\n");

    pathp = argv[1];                     /* skip whitespace in pathname   */

    if (chndname = m_getenv(pathp))      /* if env-var-name given,        */
        pathp = chndname;               /* use its value as new path     */

    change_dir(pathp);

                  /* Read or initialize master chain length variable: */
    if ((chaincntp = m_getenv(CHAINS_VAR)) == NULL)
        if (m_putenv(CHAINS_VAR,
                  strcpy(chaincntp = chaincnt_txt, DEFAULT_CHAINS)))
           error("Error creating environment variable");

                         /* Update the environment directory chain:   */
    chaincnt = atoi(chaincntp);
    for (i = chaincnt; i > 0; i--)
    {                   /* construct name of previous dirname variable: */
        if (i != 1)
        {
            strcpy(chnevar2, CHAIN_BASE);
            strcat(chnevar2, itoa(i-1, itoabuf, 10));
        }

        if (chndname = ((i != 1) ? m_getenv(chnevar2) : cwdbuf))
        {                           /* copy value of prev. to current   */
            strcpy(chndname_save, chndname);  /* m_putenv() bashes it */
            strcpy(chnevar1, CHAIN_BASE);
            strcat(chnevar1, itoa(i, itoabuf, 10));
            if (m_putenv(chnevar1, chndname_save))
                error("Error setting environment variable");
        }
    }
    return 0;
}