ftp.nice.ch/pub/next/unix/editor/e2.N.bs.tar.gz#/e2.N.bs/read_hist.c

This is read_hist.c in view mode; [Download] [Up]

#include "e.h"

/*
 * read_hist()
 *
 * Do some initialization type things such as finding out if the user has a
 * uid, password entry, home directory etc. Then find out where the history
 * is kept and check to see if it's there. If it's not just indicate this by
 * returning -1 and let other functions deal with this problem as they see
 * fit.
 *
 * If the history exists then read it. The format of the history file is
 *

/absolute/path/name/for/some/directory
\tfilename_1
\tfilename_2
\tfilename_3
\tfilename_4
/absolute/path/of/some/other/directory
\tsome_filename_or_other
\tanother_filename

 *
 * Where \t is of course a single TAB.
 * The files for a directory are kept in least recently used order. So in
 * the above example, 'filename_1' was used before 'filename_2' and so on.
 * There may be a maximum of HIST_LINES file names associated with each 
 * directory.
 *
 * If the history is used and needs to be updated, then we will have to create
 * a new file that looks pretty much like the current one. Unfortunately we
 * will have to read and write the whole of the old file.
 *
 * Seeing as we are going to have to write the new history file, it doesn't
 * make much sense to try and find the relevant directory in a clever manner
 * (e.g. by keeping the history sorted by directory). The point is that
 * we HAVE to read and write the whole file once so it doesn't really matter
 * where we encounter the directory we want (if at all).
 *
 *
 * We return the number of history items found after setting the pointers in
 * hist[] to point to them. hist[0] points to the oldest filename, hist[1]
 * to the next oldest etc etc... hist[hist_count - 1] to the most recently
 * used.
 *
 */

int
read_hist()
{
    static char line[MAXPATHLEN]; /* Static, as saved_line may point at it. */
    int h_index = 0;              /* # of history items found so far.       */
    register int cwd_len;         /* # of chars in the current dir name.    */
    struct stat sbuf;

    cwd_len = strlen(cwd);

    if (stat(ehist, &sbuf) == -1){
        return -1;
    }

    emode = (int)sbuf.st_mode;

    hist_fp = fopen(ehist, "r");
    if (!hist_fp){
        e_error("Could not open history '%s'.", ehist);
    }

    /*
     * Open a new history file that will renamed to the old one once
     * we update. (If we update.)
     *
     */

    get_temp();

	/*
	 * Make sure that the first line of the history starts with a '/'
	 * This way we know we are not dealing with an old-style (pre version 1.3)
	 * history file. The error message here is unsatisfactory - it should make
	 * a better attempt to find out what's wrong and point them to the 
	 * script for converting to the new format etc etc. Fortunately I'm the
	 * only person in the world who uses e and so it's not a problem.
	 *
	 */

    if (!fgets(line, MAXPATHLEN, hist_fp)){
		e_error("Could not read first line of '%s'.\n", ehist);
	}

	if (line[0] != '/'){
		e_error("The history (%s) is munged. It is not in version %s format.",
			ehist, VERSION);
	}

    ok_fprintf(tmp_fp, "%s", line);

    /*
     * Get lines and write them to the new history until you see one that 
     * matches the directory we are in.
     *
     */
    while (fgets(line, MAXPATHLEN, hist_fp)){

        register char *tmp = line;
        int room_left = HIST_LINES * MAXPATHLEN;
        char *room;

        /* 
         * If it's not a path starting with a '/' then continue. 
         * We have a filename. Keep going until the next directory entry.
         *
         */
        if (line[0] != '/'){
            ok_fprintf(tmp_fp, "%s", line);
            continue;
        }

        zap_nl(tmp);

        /*
         * Test to see if this is the directory we want. tmp - line is the
         * length of the name of the found directory. Do a length test first
		 * up to avoid a strcmp if possible.
         *
         */
        if (tmp - line != cwd_len || strcmp(line, cwd)){
            ok_fprintf(tmp_fp, "%s\n", line);
            continue;
        }

        /* 
         * So we have found the directory we were looking for. Allocate a
         * hunk of space to read all the filenames. 
         */
        room = sbrk(room_left);
        if (room == (char *)-1){
            e_error("Could not sbrk().");
        }

        /*
         * Read the filenames. If we reach a line that starts with a '/'
         * then we are onto the next directory in the history and we save
         * a pointer to this line to emit it later.
         *
         */
        while (fgets(room, room_left, hist_fp)){
            char *cp = hist[h_index] = room + 1;
            zap_nl(cp);
            room_left -= (cp - room);

            /*
             * In theory we should never run out of space, but in case we do
             * we might as well try to grab some more rather than just dying.
             *
             */
            if (room_left <= MAXPATHLEN){
                room_left = HIST_LINES * MAXPATHLEN;
                room = sbrk(room_left);
                if (room == (char *)-1){
                    e_error("Could not sbrk().");
                }
            }
            
            if (*room == '/'){
                saved_line = room; /* Read one too many! */
                return h_index;
            }

            room = cp + 1;
            h_index++;

            /*
             * Check to see if we have read HIST_LINES filenames. If we have,
             * make sure that the next line is in fact a directory (by
             * verifying that it starts with a '/'.
             *
             */
            if (h_index == HIST_LINES){
                if (fgets(line, MAXPATHLEN, hist_fp)){
                    if (line[0] != '/'){
                        e_error("History contains too many entries!");
                    }
                    else{
                        tmp = line;
                        zap_nl(tmp);
                        saved_line = line;
                    }
                }
                return HIST_LINES;
            }
        }
        return h_index;
    }
    return h_index;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.