home *** CD-ROM | disk | FTP | other *** search
- /*
- * SETD
- * Set Directory
- * Version 1.7
- *
- * Sunil William Savkar
- * sunil@hal.com
- * Copyright (c) 1991
- * All Rights Reserved
- *
- * DISCLOSURE
- *
- * This source may be modified or copied freely. The intent
- * is the free distribution of a useful utility used for moving
- * between directories. Any modifications and additions, along
- * with bug reports should be sent to the author, so all might
- * benefit!
- *
- * DESCRIPTION
- *
- * Set directory utility used in conjunction with the
- * mark command to allow ease of directory changes.
- *
- * MODIFICATION HISTORY
- *
- * 8/2/91 Hunter Scales
- * Changed code to allow running on HPs.
- * 8/20/91 Sunil William Savkar
- * Allow fall through of illegal directory
- * change so cd can try to use cdpath variable.
- * 12/6/92 Sunil William Savkar
- * Added changes to allow a mark as a base of a
- * full pathname, thus not needing multiple
- * marks for subdirectories under a common point.
- *
- * Please send all updates along with suggestions
- * to sunil@hal.com
- */
-
- #if (MACH == hp || MACH == m88k || MACH == rs)
- #include <stdlib.h>
- #else
- #include <alloca.h>
- #endif
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include "macros.h"
- #include "enum.h"
- #include "types.h"
-
- /*
- * Global Variable Definitions
- */
-
- COMMAND_NODE command[] = {
-
- K_SETD_DIR, "",
- K_SETD_HOME, "",
- K_POS_QUEUE, "",
- K_BACK_QUEUE, "",
- K_LIST_QUEUE, "-list",
- K_LIST_QUEUE, "-l",
- K_MAX_QUEUE, "-max",
- K_MAX_QUEUE, "-m",
- K_HELP, "-h",
- K_HELP, "-help",
- K_VERSION, "-v",
- K_VERSION, "-ver",
- K_VERSION, "-version",
- K_NULL, NULL
- };
-
- static char version_header[] = "Set Directory\tv1.7\tSunil William Savkar\n";
-
- static char help_header[] =
- "Set Directory\tv1.7\nusage:\tcd <options>\n\n\
- option\t\tdescription\n\n\
- [path]\t\tAttempts change to specified directory pathname\n\
- [mark]\t\tAttempts change to directory specified by the mark alias\n\
- [mark]/[path]\tAttempts change to base mark plus appended pathname\n\
- [env]\t\tAttempts change to directory spec'd by environment variable\n\
- %%[path]\t\tAttempts change to subdirectory pathname of root one above\n\
- -l<ist>\t\tLists previous directories up to maximum set list length\n\
- -m<ax>\t\tSets the maximum depth of the past directory list\n\
- numeric\t\tChanges directory to specified list pos, or offset from top (-)\n\
- \nexamples:\tcd ~savkar, cd %bin, cd -4, cd MARK_NAME, cd MARK_NAME/xxx\n";
-
- /*
- * boolean conv_to_dec( char *string,
- * int *conv_dec)
- *
- * conv_to_dec translates the string to a decimal
- * value, and returns this decimal value in conv_dec.
- * If an error occurs during conversion, the function
- * returns false, else it returns true.
- */
-
- boolean conv_to_dec(string,
- conv_dec)
- char *string; /* The string to convert */
- int *conv_dec; /* The variable to store the converted integer */
- {
-
- int num = 0, /* Used to analyze and store shifted value */
- muln = 1; /* +/- multiplier factor */
-
- /*
- * Check for the sign of the passed string
- */
-
- if (*string == '-') {
-
- if (*(++string) == '\0') return FALSE;
- muln = -1;
- } else if (*string == '+') {
-
- if (*(++string) == '\0') return FALSE;
- }
-
- /*
- * Increment through the string and put together the base ten
- * number which is represented.
- */
-
- for (; *string != '\0'; string++) {
-
- if (!isdigit(*string)) return FALSE;
- num = num*10 + (*string - '0');
- }
-
- *conv_dec = num*muln;
- return TRUE;
- }
-
- /*
- * void push_list( LIST_NODE **list,
- * LIST_NODE *element,
- * int *length)
- *
- * Push new node onto the list.
- */
-
- void push_list(list, element, length)
- LIST_NODE *element;
- LIST_NODE **list;
- int *length;
- {
-
- element->next = *list;
- *list = element;
- (*length)++;
- }
-
- /*
- * LIST_NODE *shift_list( LIST_NODE *list,
- * int *length)
- *
- * Shift off the last element of the list, and pass
- * it to the caller.
- */
-
- LIST_NODE *shift_list(list,
- length)
- LIST_NODE **list;
- int *length;
- {
-
- LIST_NODE *prev, *end;
-
- if (!(*list)) return NULL;
-
- if (!(*list)->next) {
-
- end = *list;
- *list = NULL;
- } else {
-
- for (end = *list; end->next; end = end->next) ;
- for (prev = *list; prev->next != end; prev = prev->next) ;
- prev->next = NULL;
- }
-
- (*length)--;
- return (end);
- }
-
- /*
- * boolean read_into_list( char *setd_fil,
- * LIST_NODE **list_head,
- * int *max_queue,
- * int *list_length)
- *
- * read_into_list attempts to open the setd database and read
- * the list of prior directory changes into the queue. An error
- * is returned if unable to open or read the setd db file.
- *
- * The database of prior locations is read into a list pointed at
- * by *list_head. The length of the list is in the list_length
- * variable, and the max_queue variable is also set at this point.
- */
-
- boolean read_into_list(setd_fil, list_head, max_queue, list_length)
- char *setd_fil;
- LIST_NODE **list_head;
- int *max_queue;
- int *list_length;
- {
-
- FILE *setd_fp;
- LIST_NODE *new_ptr;
- char path[MAX_LINE];
-
- *list_length = 0;
-
- if (!(setd_fp = fopen(setd_fil, "r"))) {
-
- fprintf(stderr, "read_into_list: Unable to open %s\n", setd_fil);
- return FALSE;
- }
-
- /*
- * First argument is the maximum queue length.
- */
-
- *max_queue = 0;
- fscanf(setd_fp, "%d", max_queue);
- if (!(*max_queue)) {
-
- *max_queue = 10;
- }
-
- /*
- * Now continue reading the file and setting up the linked list.
- */
-
- while (fscanf(setd_fp, "%s", path) == 1) {
-
- /*
- * Set up a new node.
- */
-
- new_ptr = (LIST_NODE *)malloc(sizeof(LIST_NODE));
- new_ptr->path = (char *)malloc(strlen(path) + 1);
- new_ptr->next = NULL;
- strcpy(new_ptr->path, path);
-
- push_list( list_head, new_ptr, list_length);
- }
-
- fclose(setd_fp);
- return TRUE;
- }
-
- boolean initialize( home, pwd, setd_fil, list_head, max_queue, list_length)
- LIST_NODE **list_head;
- char *setd_fil;
- char **pwd;
- char **home;
- int *max_queue, *list_length;
- {
-
- FILE *setd_fp;
- char *getenv();
- char *ptr;
-
- /*
- * Get current directory and pointer to the mark directory.
- */
-
- #ifdef HP
-
- if (!(getcwd((*pwd = (char *)malloc(MAX_LINE), MAX_LINE))) {
- #else
-
- if (!(*pwd = getenv("PWD"))) {
- #endif
-
- fprintf(stderr, "initialize: Unable to get environment var $PWD\n");
- return FALSE;
- }
-
- #ifdef HP
-
- /*
- * Notice we would like to strip off the /tmp_mount from the *pwd,
- * if it exists!
- */
-
- if (strncmp(*pwd, "/tmp_mnt", 8) == 0) {
- *pwd += 8;
- }
- #endif
-
- if (!(*home = getenv("HOME"))) {
-
- fprintf(stderr, "initialize: Unable to get environment var $HOME\n");
- return FALSE;
- }
-
- if (!(ptr = getenv("SETD_DIR"))) {
-
- fprintf(stderr, "initialize: Must set environment var $SETD_DIR\n");
- return FALSE;
- } else {
-
- /*
- * Construct setd data base file pointer.
- */
-
- sprintf( setd_fil, "%s/setd_db", ptr);
- }
-
- if (!(setd_fp = fopen(setd_fil, "a"))) {
-
- fprintf(stderr, "initialize: Unable to open %s\n", setd_fil);
- return FALSE;
- }
-
- fclose(setd_fp);
-
- /*
- * Read queue into a linked list, with the path string.
- */
-
- if (!read_into_list(setd_fil, list_head, max_queue, list_length)) {
-
- fprintf(stderr, "initialize: Unable to read setd file %s\n", setd_fil);
- return FALSE;
- }
-
- return TRUE;
- }
-
- T_COMM parse( option)
- char *option;
- {
-
- int j;
- int num;
- char *ptr;
-
- if (*option != '-') {
-
- return K_SETD_DIR;
- }
-
- /*
- * Must be one of the commands, else there is
- * an error.
- */
-
- for (j = 0; (ptr = command[j].text) && !STREQU( ptr, option); j++) ;
-
- if (!ptr) {
-
- if (conv_to_dec(option, &num)) return K_SETD_DIR;
- fprintf(stderr, "parse: unrecognized option from main (%s)\n", option);
- return K_NULL;
- }
-
- return command[j].type;
- }
-
- boolean list_queue( list_ptr, max_queue)
- LIST_NODE *list_ptr;
- int max_queue;
- {
-
- int i;
-
- /*
- * Each line consists of the mark, and then the pathname.
- */
-
- fprintf(stderr, "Current Queue (Max = %d)\n-------------\n\n", max_queue);
- for (i = 0; list_ptr; list_ptr = list_ptr->next, i++) {
-
- fprintf(stderr, "%d. %s\n", i, list_ptr->path);
- }
-
- return TRUE;
- }
-
- boolean update_file( setd_fil, list_head, max_queue)
- char *setd_fil;
- LIST_NODE *list_head;
- int max_queue;
- {
-
- LIST_NODE *element, *last;
- FILE *setd_fp;
-
- /*
- * Write the new list of marks to the update file.
- */
-
- if (!(setd_fp = fopen(setd_fil, "w"))) {
-
- fprintf(stderr, "update_file: Unable to update %s\n", setd_fil);
- return FALSE;
- }
-
- fprintf(setd_fp, "%d\n", max_queue);
-
- /*
- * Use a non-recursive inverted write to the file to speed things up,
- * ever so slightly. There is a need for speed in this filter.
- * The user shouldn't be aware of all the translations.
- */
-
- if (list_head) {
-
- last = NULL;
-
- /*
- * Go to the last element, which hasn't been written yet.
- */
-
- do {
-
- for (element = list_head; element->next != last; element = element->next) ;
- fprintf(setd_fp, "%s\n", element->path);
- last = element;
- } while (element != list_head);
- }
-
- fclose(setd_fp);
- return TRUE;
- }
-
- /*
- * boolean return_dest( char *dest,
- * char *path,
- * LIST_NODE *list,
- * int list_length)
- *
- * return_dest attempts to translate the given path
- * into a proper destination, whether an environment
- * variable, mark, setd list position, or same level
- * subdirectory.
- */
-
- boolean return_dest( dest,
- path,
- list,
- list_length)
- char *path;
- char *dest;
- LIST_NODE *list;
- int list_length;
- {
-
- char temp[MAX_LINE];
- char front[MAX_LINE];
- char *getenv();
- char *mark;
- char *env;
- char *ptr;
- int num = 0;
- sprintf( temp, "mark_%s", path);
-
- /*
- * Two types of mark uses are able to be recognized by
- * setd. The first is just setting directory to the
- * mark by itself. Then the translation is simple.
- * The second method is by using the mark as a base,
- * and adding an extended path after the mark. This
- * method requires a reconstruction of a string to
- * attempt proper mark resolution with the subdir string
- * specified.
- */
-
- mark = getenv(temp);
- env = getenv(path);
-
- strcpy( temp, path);
- if (ptr = strchr( temp, '/')) {
-
- /*
- * Zero out everything past the slash, and
- * attempt to translate the temporary "mark"
- * or environment variable.
- */
-
- *ptr = '\0';
- ptr = strchr( path, '/');
- sprintf( front, "mark_%s", temp);
- if (mark = getenv( front)) {
-
- sprintf( temp, "%s%s", mark, ptr);
- mark = temp;
- } else if (env = getenv( front)) {
-
- sprintf( temp, "%s%s", env, ptr);
- env = temp;
- }
- }
-
- if (chdir(path) == 0) {
-
- strcpy(dest, path);
- } else if (mark) {
-
- strcpy(dest, mark);
- } else if (env) {
-
- strcpy(dest, env);
- } else if (conv_to_dec(path, &num)) {
-
- if ((num = abs(num)) > (list_length - 1)) {
-
- fprintf(stderr, "return_dest: out of bounds (-%d <= num <= %d)\n",
- list_length, list_length);
- return FALSE;
- }
-
- for (; num; num--) list = list->next;
- strcpy(dest, list->path);
-
- } else if (*path == '%') {
-
- sprintf( temp, "../%s", (path + 1));
- return (return_dest(dest, temp, list, list_length));
-
- } else {
-
- /*
- * Let normal cd handle error message.
- */
-
- strcpy(dest, path);
- }
-
- return TRUE;
- }
-
- /*
- * boolean add_pwd( LIST_NODE *list_head,
- * char *pwd,
- * int max_queue,
- * int *list_length,
- * char *setd_fil)
- *
- * add_pwd attempts to push the given pwd onto the queue, unless
- * the pwd is the same as the current pwd at the top of the stack.
- */
-
- boolean add_pwd( list_head,
- pwd,
- max_queue,
- list_length,
- setd_fil)
- LIST_NODE **list_head;
- int *list_length;
- int max_queue;
- char *pwd;
- char *setd_fil;
- {
-
- LIST_NODE *pwd_ptr;
-
- if (*list_head && STREQU((*list_head)->path, pwd)) return TRUE;
-
- pwd_ptr = (LIST_NODE *)malloc(sizeof(LIST_NODE));
- pwd_ptr->next = NULL;
- pwd_ptr->path = (char *)malloc(strlen(pwd) + 1);
- strcpy(pwd_ptr->path, pwd);
-
- push_list(list_head, pwd_ptr, list_length);
-
- if (*list_length > max_queue) free(shift_list(list_head, list_length));
-
- if (!update_file( setd_fil, *list_head, max_queue)) {
-
- fprintf(stderr, "add_pwd: error in update_file\n");
- return FALSE;
- }
-
- return TRUE;
- }
-
- /*
- * main( int argc,
- * char *argv[])
- */
-
- main(argc, argv)
- char *argv[];
- int argc;
- {
-
- LIST_NODE *list_head;
- int old_max;
- int max_queue;
- int i;
- char setd_fil[MAX_LINE];
- char *pwd;
- char *home;
- char dest[MAX_LINE];
- T_COMM option;
- int list_length;
-
- list_head = NULL;
-
- /*
- * First we must initialize, getting pointer to the
- * mark file, and read in the current directory.
- */
-
- if (!initialize(&home, &pwd, setd_fil, &list_head, &max_queue, &list_length)) {
-
- fprintf(stderr, "setd: error code from initialize\n");
- exit(0);
- }
-
- /*
- * Push the current position onto the stack, if not already
- * done. That is, if the current pwd is the same as the top
- * of the stack, then do not add again.
- */
-
- if (!add_pwd( &list_head, pwd, max_queue, &list_length, setd_fil)) {
-
- fprintf( stderr, "setd: error from add_pwd\n");
- exit(-1);
- }
-
- strcpy(dest, pwd);
-
- /*
- * Now we have the file pointer for mark, and the current
- * directory. It is time to start parsing the arguments
- * on the command line.
- */
-
- for (i = 1; i <= argc; i++) {
-
- if (argc == 1) {
-
- option = K_SETD_HOME;
- } else if (i == argc) {
-
- break;
- } else if ((option = parse( argv[i])) == K_NULL) {
-
-
- fprintf(stderr, "setd: error code from parse\n");
- }
-
- /*
- * Switch, based upon the given option, to the
- * proper function.
- */
-
- switch (option) {
-
- case K_VERSION:
- fprintf(stderr, version_header);
- break;
-
- case K_HELP:
- fprintf(stderr, help_header);
- break;
-
- case K_SETD_HOME:
- strcpy(dest, home);
- break;
-
- case K_SETD_DIR:
- if (!return_dest(dest, argv[i], list_head, list_length)) {
-
- fprintf(stderr, "setd: error code from return_dest\n");
- }
- break;
-
- case K_LIST_QUEUE:
- if (!list_queue(list_head, max_queue)) {
-
- fprintf(stderr, "setd: error code from list_queue\n");
- }
- break;
-
- case K_MAX_QUEUE:
-
- old_max = max_queue;
- if ((++i >= argc) || (!conv_to_dec(argv[i], &max_queue))
- || (max_queue <= 0)) {
-
- fprintf(stderr, "setd: invalid maximum specified\n");
- } else {
-
- if (old_max != max_queue) list_head = NULL;
-
- if (!update_file( setd_fil, list_head, max_queue)) {
-
- fprintf(stderr, "setd: error in update_file\n");
- exit(-1);
- }
- }
- break;
-
- default: break;
- }
- }
-
- fprintf(stdout, dest);
-
- exit(0);
- }
-
-