🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.sources.reviewed
Article #3

v02i034: dired - (Ver. 1.8) directory editor in C++, Part02/05

#3
From: Mike Lijewski
Date: Wed, 28 Oct 1992 02:37
1721 lines
56596 bytes
Submitted-by: Mike Lijewski <lijewski@theory.tc.cornell.edu>
Posting-number: Volume 2, Issue 34
Archive-name: dired/part02
Supersedes: dired: Volume 2, Issue 7-12

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 5)."
# Contents:  command1.C classes.h dired.h
# Wrapped by lijewski@xtesoc2 on Mon Oct  5 14:53:34 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'command1.C' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'command1.C'\"
else
echo shar: Extracting \"'command1.C'\" \(35305 characters\)
sed "s/^X//" >'command1.C' <<'END_OF_FILE'
X/*
X** command1.C - some of the commands called from the main command loop.
X**
X**               Command1.C and command2.C
X**               are concatenated during the make into
X**               commands.C, which consists of the main
X**               command loop and all commands called from
X**               within that loop.
X**
X** command1.C 1.103   Delta\'d: 09:49:38 9/28/92   Mike Lijewski, CNSF
X**
X** Copyright \(c\) 1991, 1992 Cornell University
X** All rights reserved.
X**
X** Redistribution and use in source and binary forms are permitted
X** provided that: \(1\) source distributions retain this entire copyright
X** notice and comment, and \(2\) distributions including binaries display
X** the following acknowledgement:  ``This product includes software
X** developed by Cornell University\'\' in the documentation or other
X** materials provided with the distribution and in all advertising
X** materials mentioning features or use of this software. Neither the
X** name of the University nor the names of its contributors may be used
X** to endorse or promote products derived from this software without
X** specific prior written permission.
X**
X** THIS SOFTWARE IS PROVIDED ``AS IS\'\' AND WITHOUT ANY EXPRESS OR
X** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X*/
X
X
X#include <ctype.h>
X
X#ifndef _IBMR2
X#include <libc.h>
X#endif
X
X#include <osfcn.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "dired.h"
X#include "display.h"
X#include "keys.h"
X
X/*
X** scroll_up_one_line - Scroll the listing up one line.
X**                      We only call this routine when we KNOW that
X**                      there is at least one line below the window
X**                      which can be scrolled into it and the cursor
X**                      is on the last line of the screen.
X*/
X
Xstatic void scroll_up_one_line(DirList *dl)
X{
X    dl->setFirst(dl->firstLine()->next());
X    dl->setLast(dl->lastLine()->next());
X    dl->setCurrLine(dl->lastLine());
X
X    if (CS)
X    {
X        scroll_listing_up_one();
X        display_string(dl->currLine()->line(), dl->currLine()->length());
X    }
X    else if (DL || SF)
X    {
X        clear_modeline();
X        scroll_screen_up_one();
X        update_modeline();
X        move_cursor(rows()-3, 0);
X        display_string(dl->currLine()->line(), dl->currLine()->length());
X    }
X    else
X        redisplay();
X
X    dl->saveYXPos(rows()-3, goal_column(dl));
X    move_cursor(rows()-3, dl->savedXPos());
X}
X
X/*
X** scroll_down_one_line - Scroll the listing down one line.
X**                        We only call this routine when we KNOW
X**                        that the head\(\) of the listing is not visible
X**                        and the cursor is on the first line in the window.
X*/
X
Xstatic void scroll_down_one_line(DirList *dl)
X{
X    if (lines_displayed(dl) == rows() - 2)
X        //
X        // Must update lastLine.  We previously had a screenfull of lines.
X        //
X        dl->setLast(dl->lastLine()->prev());
X
X    dl->setFirst(dl->firstLine()->prev());
X    dl->setCurrLine(dl->firstLine());
X
X    if (CS)
X    {
X        scroll_listing_down_one();
X        display_string(dl->currLine()->line(), dl->currLine()->length());
X    }
X    else if (AL || SR)
X    {
X        clear_modeline();
X        scroll_screen_down_one();
X        update_modeline();
X        cursor_home();
X        display_string(dl->currLine()->line(), dl->currLine()->length());
X    }
X    else
X        redisplay();
X
X    dl->saveYXPos(0, goal_column(dl));
X    move_cursor(0, dl->savedXPos());
X}
X
X/*
X** scroll_up_full_window - scroll listing up one full window,
X**                         leaving one line of overlap.  This routine
X**                         is only called when we know that the tail\(\)
X**                         of the listing is not currently displayed.
X*/
X
Xstatic void scroll_up_full_window(DirList *dl)
X{
X    DirLine *ln = dl->lastLine();
X    dl->setFirst(ln);
X    dl->setCurrLine(ln);
X
X    cursor_home();
X    for (int i = 0; i < rows() - 2 && ln; i++, ln = ln->next())
X    {
X        clear_to_end_of_line();
X        display_string(ln->line(), ln->length());
X    }
X    move_cursor(i, 0);
X    for (; i < rows() - 2; i++)
X    {
X        clear_to_end_of_line();
X        cursor_down();
X    }
X    
X    ln ? dl->setLast(ln->prev()) : dl->setLast(dl->tail());
X    dl->saveYXPos(0, goal_column(dl));
X    if (dl->currLine()->length() > columns())
X        leftshift_current_line(dl);
X    else
X        move_cursor(0, dl->savedXPos());
X    
X    synch_display();
X}
X
X/*
X** scroll_down_full_window - try to scroll listing down one full window,
X**                           with one line of overlap.  This routine is
X**                           only called when we KNOW that there is at
X**                           least one line "above" the current listing.
X**                           Only change the current line if it flows off
X**                           the "bottom" of the screen.  This routine is
X**                           only called when we know that the head\(\) of the
X**                           listing isn\'t currently displayed.
X*/
X
Xstatic void scroll_down_full_window(DirList *dl)
X{
X    DirLine *ln = dl->firstLine();
X    for (int y = 0; y < rows() - 3 && ln != dl->head(); y++, ln = ln->prev());
X
X    //
X    // y == # of lines preceding firstLine\(\) to add to screen
X    //
X    
X    dl->setFirst(ln);
X    cursor_home();
X    for (int j = 0; j < rows()-2 && ln; j++, ln = ln->next())
X    {
X        clear_to_end_of_line();
X        display_string(ln->line(), ln->length());
X    }
X    move_cursor(j, 0);
X    for (; j < rows() - 2; j++)
X    {
X        clear_to_end_of_line();
X        cursor_down();
X    }
X    
X    if (ln) dl->setLast(ln->prev());
X    
X    if (dl->savedYPos()+y >= rows()-2)
X    {
X        dl->setCurrLine(dl->lastLine());
X        dl->saveYXPos(rows()-3, goal_column(dl));
X    }
X    else
X        dl->saveYXPos(dl->savedYPos()+y, dl->savedXPos());
X
X    if (dl->currLine()->length() > columns())
X        leftshift_current_line(dl);
X    else
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X    
X    synch_display();
X}
X
X/*
X** scroll_up_half_window - scroll listing up half a window.  This routine
X**                         is only called when the tail\(\) of the listing
X**                         isn\'t being displayed.  We try to leave the
X**                         cursor on the file it was on previously,
X**                         otherwise it is left on the first file in
X**                         the screen.
X*/
X
Xstatic void scroll_up_half_window(DirList *dl, int y)
X{
X    if (dl->currLine()->length() > columns()) rightshift_current_line(dl);
X
X    DirLine *ln = dl->firstLine();
X    for (int i = 0; i < (rows() - 2)/2; i++, ln = ln->next()) ;
X    dl->setFirst(ln);
X    
X    if (CS || DL || SF || DLN)
X    {
X        if (CS)
X            scroll_listing_up_N((rows()-2)/2);
X        else
X        {
X            clear_modeline();
X            scroll_screen_up_N((rows()-2)/2);
X            update_modeline();
X        }
X        move_cursor(rows() - 2 -((rows()-2)/2), 0);
X        ln = dl->lastLine()->next();
X        for (i = 0; i < (rows() - 2)/2 && ln; i++, ln = ln->next())
X            display_string(ln->line(), ln->length());
X        ln ? dl->setLast(ln->prev()) : dl->setLast(dl->tail());
X    }
X    else
X    {
X        
X        cursor_home();
X        for (i = 0; i < rows() - 2 && ln->next(); i++, ln = ln->next())
X        {
X            clear_to_end_of_line();
X            display_string(ln->line(), ln->length());
X        }
X        
X        if (i != rows()-2)
X        {
X            //
X            // We hit last line before outputing all that we could.
X            // Must output lastLine\(\) == tail\(\).
X            //
X            display_string(ln->line(), ln->length());
X            dl->setLast(ln);
X            i++;  // so we know how many lines have been written
X        }
X        else
X            dl->setLast(ln->prev());
X
X        // now clear any remaining rows on the screen
X        move_cursor(i, 0);
X        for (; i < rows() - 2; i++)
X        {
X            clear_to_end_of_line();
X            cursor_down();
X        }
X    }
X
X    int pos = y - (rows()-2)/2;
X    if (pos < 0)
X    {
X        pos = 0;
X        dl->setCurrLine(dl->firstLine());
X    }
X    
X    dl->saveYXPos(pos, goal_column(dl));
X    if (dl->currLine()->length() > columns())
X        leftshift_current_line(dl);
X    else
X        move_cursor(pos, dl->savedXPos());
X    
X    synch_display();
X}
X
X/*
X** scroll_down_half_window - try to scroll listing down half a window.
X**                           If `freshen\' is true, which is the default,
X**                           the screen is refreshed.  It is important
X**                           to note that we may not be able to scroll
X**                           down a complete half window, since we
X**                           always anchor the head of the listing to
X**                           the first line in the screen.  This routine
X**                           is only called when the head\(\) of the
X**                           listing isn\'t being displayed.
X*/
X
Xstatic void scroll_down_half_window(DirList *dl, int y, int freshen = 1)
X{
X    if (dl->firstLine() != dl->head())
X    {
X        //
X        // We can scroll down.  Try to leave the cursor on the file
X        // it started out on.  Otherwise, leave it on the
X        // \(rows\(\)-2\)/2 line, which was the previous firstLine\(\).
X        //
X        DirLine *ln = dl->firstLine();
X        for (int i = 0; i < (rows()-2)/2 && ln->prev(); i++, ln = ln->prev()) ;
X        dl->setFirst(ln);
X
X        if (dl->currLine()->length() > columns()) rightshift_current_line(dl);
X
X        if (CS || AL || ALN || SR)
X        {
X            if (CS)
X                scroll_listing_down_N(i);
X            else
X            {
X                clear_modeline();
X                scroll_screen_down_N(i);
X                update_modeline();
X                clear_message_line();
X            }
X            cursor_home();
X            for (int j = 0; j < i; j++, ln = ln->next())
X                display_string(ln->line(), ln->length());
X            ln = dl->firstLine();
X            for (int i = 0; i < rows()-2 && ln->next(); i++, ln = ln->next()) ;
X            dl->setLast(ln);
X        }
X        else
X        {
X            cursor_home();
X            for (int i = 0; i < rows()-2 && ln->next(); i++, ln = ln->next())
X            {
X                clear_to_end_of_line();
X                display_string(ln->line(), ln->length());
X            }
X            
X            if (i != rows() - 2)
X            {
X                //
X                // We hit last line before outputing all that we could.
X                // Must output lastLine\(\) == tail\(\).
X                //
X                display_string(ln->line(), ln->length());
X                dl->setLast(ln);
X                i++;  // so we know how many lines have been written
X            }
X            else
X                dl->setLast(ln->prev());
X
X            // now clear any remaining rows on the screen
X            int tmp = i;
X            move_cursor(i, 0);
X            for (; i < rows()-2; i++)
X            {
X                clear_to_end_of_line();
X                cursor_down();
X            }
X            i = tmp;  // because we use `i\' below
X        }
X
X        int pos = i + y;
X        if (pos > rows() - 3)
X        {
X            pos = rows() - 3;
X            dl->setCurrLine(dl->lastLine());
X        }
X
X        dl->saveYXPos(pos, goal_column(dl));
X        if (dl->currLine()->length() > columns())
X            leftshift_current_line(dl);
X        else
X            move_cursor(pos, dl->savedXPos());
X
X        if (freshen) synch_display();
X    }
X}
X
X/*
X** goto_first - position cursor on first line in listing.  This routine
X**              is not called if atBegOfList\(\) is true.
X*/
X
Xstatic void goto_first(DirList *dl)
X{
X    if (dl->head() != dl->firstLine())
X        initial_listing(dl);
X    else
X    {
X        if (dl->currLine()->length() > columns()) rightshift_current_line(dl);
X        dl->setCurrLine(dl->head());
X    }
X
X    dl->saveYXPos(0, goal_column(dl));
X    if (dl->currLine()->length() > columns())
X        leftshift_current_line(dl);
X    else
X        move_cursor(0, dl->savedXPos());
X
X    synch_display();
X}
X
X/*
X** goto_last - position cursor on last file in listing.  This routine is
X**             not called if atEndOfList\(\) is true.
X*/
X
Xstatic void goto_last(DirList *dl)
X{
X    if (dl->currLine()->length() > columns()) rightshift_current_line(dl);
X
X    dl->setCurrLine(dl->tail());
X
X    if (dl->tail() == dl->lastLine())
X    {
X        // only need to reposition the cursor
X        dl->saveYXPos(lines_displayed(dl) - 1, goal_column(dl));
X        if (dl->currLine()->length() > columns())
X            leftshift_current_line(dl);
X        else
X            move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X    else
X    {
X        // redisplay end of listing & update our view
X        DirLine *ln = dl->tail();
X        dl->setLast(ln);
X        for (int i = 0; i < rows() - 2; i++, ln = ln->prev())
X        {
X            move_cursor(rows() - 3 - i, 0);
X            clear_to_end_of_line();
X            display_string(ln->line(), ln->length());
X        }
X        dl->setFirst(ln->next());
X        dl->saveYXPos(rows() - 3,goal_column(dl));
X        if (dl->currLine()->length() > columns())
X            leftshift_current_line(dl);
X        else
X            move_cursor(rows() -3 , dl->savedXPos());
X    }
X
X    synch_display();
X}
X
X/*
X** edit_prompted_for_directory - prompt for a directory to edit and edit
X**                               it, provided it is a valid directory.
X**                               If the first character of the directory is
X**                               tilde \(`~\'\), the tilde is expanded to the
X**                               user\'s home directory.
X*/
X
Xstatic void edit_prompted_for_directory(DirList *dl)
X{
X#ifdef COMPLETION
X    const char *dir = prompt("Directory to edit: ", 1); // prompt w/ completion
X#else
X    const char *dir = prompt("Directory to edit: ");
X#endif
X
X    if (dir == 0)
X    {
X        // command was aborted
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X
X    if (*dir == '~') dir = expand_tilde(dir);
X
X    if (!is_directory(dir))
X    {
X        message("`%' is not a valid directory name", dir);
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X
X    if (!read_and_exec_perm(dir))
X    {
X        message("need read & exec permission to edit `%'", dir);
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X
X    dired(dir);
X}
X
X/*
X** reread_listing_line - rereads the listing line for the current line in the
X**                       DirList, which refers to file, and then updates
X**                       the listing line.
X*/
X
Xstatic void reread_listing_line(DirList *dl, const char *file)
X{
X    String cmd = String(ls_cmd[the_sort_order()]) + "'" + file + "'";
X
X    FILE *fp = popen(cmd, "r");
X    if (fp == 0)
X        error("File %s, line %d: popen(%s) failed",
X              __FILE__, __LINE__, (const char *)cmd);
X
X    char *new_line = fgetline(fp);
X    if (fp == 0)
X        error("File %s, line %d: fgetline() failed", __FILE__, __LINE__);
X    (void)pclose(fp);
X
X    dl->currLine()->update(&new_line);
X}
X
X/*
X** edit_current_file - edit the current file in the DirList.
X*/
X
Xstatic void edit_current_file(DirList *dl)
X{
X    const char *file = get_file_name(dl);
X    
X    if (is_directory(file))
X    {
X        if (strcmp(file, ".") == 0 || (strcmp(file, "..") == 0 &&
X                                       strcmp(dl->name(), "/") == 0))
X            return;
X
X        if (!read_and_exec_perm(file))
X        {
X            message("need read & exec permissions to edit `%'", file);
X            move_cursor(dl->savedYPos(), dl->savedXPos());
X            synch_display();
X            return;
X        }
X
X        dired(file);
X    }
X    else if (is_regular_file(file))
X    {
X        char *editor = getenv("EDITOR");
X        if (editor == 0) editor = "vi";
X        String cmd = String(editor) + " '" + file + "'";
X
X        //
X        // Clear screen and position cursor in case the editor doesn\'t
X        // do this itself.  This is primarily for those people who use
X        // non-fullscreen editors, such as `ed\', which don\'t do this.
X        //
X        clear_display();
X        move_to_message_line();
X        synch_display();
X        exec_with_system(cmd, 0);
X
X        //
X        // Re-read the listing line for this file
X        // and insert into the directory listing.
X        // This way, changes in file characteristics are
X        // reflected in the soon-to-be updated listing.
X        //
X        reread_listing_line(dl, file);
X        redisplay();
X    }
X    else
X    {
X        message("can only edit regular files and directories");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X    }
X}
X
X/*
X** type_key_to_continue - ask user to type any key to continue
X*/
X
Xstatic inline void type_any_key_to_continue()
X{
X    eat_a_character("Press Any Key to Continue");
X}
X
X/*
X** page_current_file - attempt to page the current file in the DirList.
X**                     If we have a directory, we edit it.
X*/
X
Xstatic void page_current_file(DirList *dl)
X{
X    const char *file = get_file_name(dl);
X    if (is_directory(file))
X    {
X        if (strcmp(file, ".") == 0 || (strcmp(file, "..") == 0 &&
X                                       strcmp(dl->name(), "/") == 0))
X            return;
X
X        if (!read_and_exec_perm(file))
X        {
X            message("need read & exec permissions to edit `%'", file);
X            move_cursor(dl->savedYPos(), dl->savedXPos());
X            synch_display();
X            return;
X        }
X
X        dired(file);
X    }
X    else if (is_regular_file(file))
X    {
X        char *pager = getenv("PAGER");
X        if (pager == 0) pager = "more";
X        String cmd = String(pager) + " '" + file + "'";
X        clear_display();
X        move_to_message_line();
X        synch_display();
X        exec_with_system(cmd);
X        if (the_sort_order() == ACCESS_TIME ||
X            the_sort_order() == INODE_CHANGE_TIME)
X            //
X            // Re-read the listing line for this file
X            // and insert into the directory listing.
X            // This way, changes in file characteristics are
X            // reflected in the soon-to-be updated listing.
X            // Since we\'ve only paged the file, the listing should only
X            // change, if we\'re interested in the access or inode-
X            // modification times.
X            //
X            reread_listing_line(dl, file); 
X        redisplay();
X    }
X    else
X    {
X        message("can only page through regular files and directories");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X    }
X}
X
X/*
X** insert_line - inserts the current line into the DirList after line y.
X**               Only called if y != rows\(\)-3.  That is, this routine
X**               is for the case when we don\'t need to scroll the screen
X**               to place the line into its logical place on the screen.
X*/
X
Xstatic void insert_line(DirList *dl, int y )
X{
X    if (CS)
X    {
X        insert_listing_line(y + 1);
X        display_string(dl->currLine()->line(), dl->currLine()->length());
X    }
X    else if(AL)
X    {
X        clear_modeline();
X        insert_blank_line(y + 1);
X        display_string(dl->currLine()->line(), dl->currLine()->length());
X        update_modeline();
X    }
X    else
X        redisplay();
X}
X
X/*
X** insert_into_dirlist - inserts the listing line for `dest\' into the
X**                       DirList after line `y\' in the current window.
X*/
X
Xstatic void insert_into_dirlist(DirList *dl, const char *dest, int y)
X{
X    char *pos = strrchr(dest, '/');
X    //
X    // pos is non-zero in those cases where `dest\' contains
X    // `..\' trickery.  Say, ../this-dir/new-file.
X    //
X    String command = String(ls_cmd[the_sort_order()]) + "'" +
X                     (pos ? pos + 1 : dest) + "'";
X
X    FILE *fp = popen(command, "r");
X    if (fp == 0)
X        error("File %s, line %d: popen(%s) failed",
X              __FILE__, __LINE__, (const char *)command);
X
X    char *new_line = fgetline(fp);
X    if (fp == 0)
X        error("File %s, line %d: fgetline() failed", __FILE__, __LINE__);
X    (void)pclose(fp);
X    
X    int nlines = lines_displayed(dl);
X    if (dl->currLine()->length() > columns()) rightshift_current_line(dl);
X    dl->setCurrLine(dl->insert(&new_line));
X    
X    if (nlines == rows() - 2)
X    {
X        if (y == rows() - 3)
X        {
X            //
X            // We must scroll listing up.
X            //
X            dl->setFirst(dl->firstLine()->next());
X            dl->setLast(dl->currLine());
X
X            if (CS)
X            {
X                scroll_listing_up_one();
X                display_string(dl->currLine()->line(), dl->currLine()->length());
X            }
X            else if (DL || SF)
X            {
X                clear_modeline();
X                scroll_screen_up_one();
X                update_modeline();
X                move_cursor(rows()-3, 0);
X                display_string(dl->currLine()->line(), dl->currLine()->length());
X            }
X            else
X                redisplay();
X
X            dl->saveYXPos(y, goal_column(dl));
X            move_cursor(y, dl->savedXPos());
X        }
X        else
X        {
X            //
X            // Just insert line.
X            //
X            dl->setLast(dl->lastLine()->prev());
X            insert_line(dl, y);
X            dl->saveYXPos(y+1, goal_column(dl));
X            move_cursor(y+1, dl->savedXPos());
X        }
X    }
X    else
X    {
X        insert_line(dl, y);
X        dl->saveYXPos(y + 1, goal_column(dl));
X        move_cursor(y + 1, dl->savedXPos());
X        if (nlines == y + 1)
X            //
X            // The new line becomes the new lastLine.
X            //
X            dl->setLast(dl->currLine());
X    }
X
X    if (dl->currLine()->length() > columns()) leftshift_current_line(dl);
X}
X
X/*
X** yes_or_no - returns true if a \'y\' or \'Y\' is typed in response to
X**             the msg.  Deals with SIGWINCH and SIGTSTP. Doesn\'t
X**             synch the display.
X*/
X
Xstatic int yes_or_no(const char *msg)
X{
X    message(msg);
X    char c;
X    while (1)
X        if (read(0, &c, 1) < 0 // assume fails only when errno == EINTR
X#ifdef SIGWINCH
X            || win_size_changed
X#endif
X            )
X        {
X#ifdef SIGWINCH
X            if (win_size_changed)
X            {
X                win_size_changed = 0;
X                adjust_window();
X                redisplay();
X            }
X#endif
X            message(msg);
X        }
X        else
X        {
X            clear_message_line();
X            return c == 'y' || c == 'Y';
X        }
X
X}
X
X/*
X** search - search through the line list, starting with the given DirLine,
X**          for a line whose filename contains a match for `str\'.  The
X**          matching is strictly a string match using `strstr\', not a
X**          regex match.  Returns the first matching line found, or 0
X**          if none found.  `pos\' is a pointer to an int containing
X**          the position in the window of `ln\'.  On exit, it contains the
X**          position of the matching line, relative to the starting position.
X**          If `forward\' is nonzero \(the default\), we search forward,
X**          otherwise we search backwards.  If str is NULL, we redo the
X**          previous search.
X*/
X
Xstatic DirLine *search(DirLine *ln, const char *str, int *pos, char forward=1)
X{
X    static String saved_str;
X    const char *name;
X    
X    if (*str)
X        //
X        // Save copy of `str\' so we can redo searches.
X        //
X        saved_str = str;
X    else if (saved_str != "")
X        //
X        // We have a previous search string.
X        //
X        str = saved_str;
X    else
X        return 0;
X
X    while (ln)
X    {
X#ifndef NO_SYMLINKS
X        if ((name = strstr(ln->line(), " -> ")) != 0)
X            // we have a symbolic link
X            --name;
X        else
X#endif
X            name = ln->line() + ln->length();
X
X        while (!isspace(*name)) --name;
X        if (strstr(name, str)) return ln;
X
X        if (forward)
X        {
X            ln = ln->next();
X            (*pos)++;
X        }
X        else
X        {
X            ln = ln->prev();
X            (*pos)--;
X        }
X    }
X
X    return 0;
X}
X
X/*
X** in_same_directory - returns true if the file `file\', which is
X**                     relative to the DirList `dl\', is actually
X**                     in the DirList\'s directory.
X**                     Returns false on any error.
X*/
X
Xstatic int in_same_directory(DirList *dl, const char *file)
X{
X    const char *last = strrchr(file, '/');
X    if (last == 0) return 1;
X    String dir(file);
X    dir[last - file] = 0;
X    struct stat stbuf1, stbuf2;
X    if (stat(dir, &stbuf1) < 0 || stat(dl->name(), &stbuf2) < 0) return 0;
X    return stbuf1.st_ino == stbuf2.st_ino && stbuf1.st_dev == stbuf2.st_dev;
X}
X
X/*
X** copy_file - copy current file to destination. Update window appropriately.
X*/
X
Xstatic void copy_file(DirList *dl, const char *src, const char *dest)
X{
X    const char *cp = "cp";
X    const char *args[4];
X    args[0] = cp; args[1] = src; args[2] = dest; args[3] = 0;
X
X    if (is_regular_file(dest))
X    {
X        String msg = String("overwrite '") + dest + "'? (y|n) ";
X        if (yes_or_no(msg))
X            if (execute(cp, args))
X            {
X                message("`copy' was successful");
X                if (in_same_directory(dl, dest))
X                {
X                    //
X                    // `dest\' is in our current directory.
X                    // It may contain /\'s due to .. or ~ funny business.
X                    //
X                    int pos = 0;
X                    const char *slash = strrchr(dest, '/');
X                    if (slash) dest   = slash + 1;
X                    DirLine *found    = search(dl->firstLine(), dest, &pos);
X                    if (found && pos < rows() - 2)
X                    {
X                        //
X                        // And it\'s also in our current window.
X                        //
X                        String cmd = String(ls_cmd[the_sort_order()]) +
X                                     "'" + dest + "'";
X
X                        FILE *fp = popen(cmd, "r");
X                        if (fp == 0)
X                            error("File %s, line %d: popen(%s) failed",
X                                  __FILE__, __LINE__, (const char *)cmd);
X
X                        char *new_line = fgetline(fp);
X                        if (fp == 0)
X                            error("File %s, line %d: fgetline() failed",
X                                  __FILE__, __LINE__);
X                        (void)pclose(fp);
X            
X                        update_screen_line(found->line(), new_line, pos);
X                        found->update(&new_line);
X                    }
X                }
X            }
X            else
X                message("`copy' failed");
X
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X    else if (is_directory(dest))
X    {
X        String file(dest);
X        if (dest[strlen(dest) - 1] != '/') file += "/";
X        file += src;
X
X        if (is_regular_file(file))
X        {
X            String msg = String("overwrite `") + file + "'? (y|n) ";
X            if (yes_or_no(msg))
X                if (execute(cp, args))
X                    message("`copy' was successful");
X                else
X                    message("`copy' failed");
X        }
X        else
X        {
X            //
X            // Just do the `cp\'.
X            //
X            if (execute(cp, args))
X                message("`copy' was successful");
X            else
X                message("`copy' failed");
X        }
X
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X    else
X    {
X        // `dest\' doesn\'t already exist
X        if (execute(cp, args))
X        {
X            message("`copy' was successful");
X            //
X            // Is `dest\' in our current directory?
X            //
X            if (in_same_directory(dl, dest))
X                insert_into_dirlist(dl, dest, dl->savedYPos());
X            else
X                move_cursor(dl->savedYPos(), dl->savedXPos());
X        }
X        else
X        {
X            message("`copy' failed");
X            move_cursor(dl->savedYPos(), dl->savedXPos());
X        }
X    }
X}
X
X/*
X** copy_current_file - attempt to copy current file to another
X*/
X
Xstatic void copy_current_file(DirList *dl)
X{
X    const char *src = get_file_name(dl);
X    if (strcmp(src, ".")  == 0 || strcmp(src, "..") == 0)
X    {
X        message("`copying' of `.' and `..' is not allowed");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X    
X#ifdef COMPLETION
X    const char *dest = prompt("Copy to: ", 1);  // prompt with completion
X#else
X    const char *dest = prompt("Copy to: ");
X#endif
X    
X    if (dest == 0)
X    {
X        // command was aborted
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X    else if (*dest == 0)
X    {
X        message("not a valid file name");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X
X    if (*dest == '~') dest = expand_tilde(dest);
X    copy_file(dl, src, dest);
X    synch_display();
X}
X
X/*
X** link_file - attempt to link `file\' to `dest\'.
X*/
X
Xstatic void link_file(DirList *dl, const char *file, const char *dest)
X{
X    if (!link(file, dest))
X    {
X        message("`link' was successful");
X        if (in_same_directory(dl, dest))
X            insert_into_dirlist(dl, dest, dl->savedYPos());
X        else
X            move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X    else
X    {
X        message("`link' failed");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X}
X
X/*
X** link_current_file - attempt to make a link to the current file
X*/
X
Xstatic void link_current_file(DirList *dl)
X{
X    const char *file = get_file_name(dl);
X    const char *link = prompt("Link to: ");
X
X    if (link == 0)
X    {
X        // command was aborted
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X    else if (*link == 0)
X    {
X        message("not a valid file name");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X
X    if (*link == '~') link = expand_tilde(link);
X    link_file(dl, file, link);
X    synch_display();
X}
X
X#ifndef NO_SYMLINKS
X/*
X** symlink_file - symbolically link `file\' to `dest\'
X*/
X
Xstatic void symlink_file(DirList *dl, const char *file, const char *dest)
X{
X    if (!symlink(file, dest))
X    {
X        message("`symlink' was successful");
X        if (in_same_directory(dl, dest))
X            insert_into_dirlist(dl, dest, dl->savedYPos());
X        else
X            move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X    else
X    {
X        message("`symlink' failed");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X    }
X}
X
X/*
X** symlink_current_file - attempt create a symbolic link to the current file
X*/
X
Xstatic void symlink_current_file(DirList *dl)
X{
X    const char *file = get_file_name(dl);
X    const char *link = prompt("Name of symbolic link: ");
X    
X    if (link == 0)
X    {
X        // command was aborted
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X    else if (*link == 0)
X    {
X        message("not a valid file name");
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X        synch_display();
X        return;
X    }
X
X    if (*link == '~') link = expand_tilde(link);
X    symlink_file(dl, file, link);
X    synch_display();
X}
X#endif
X
X
X/*
X** remove_listing_line - delete the current line in the DirList
X**                       and update both the screen and data
X**                       structures appropriately.  `y\' is the position
X**                       in the window of the current line.
X*/
X
Xstatic void remove_listing_line(DirList *dl, int y)
X{
X    if (dl->lastLine() != dl->tail())
X    {
X        //
X        // Last line in listing isn\'t in window, so we\'ll have to set
X        // a new one.  We can just scroll up one line.
X        //
X        dl->setLast(dl->lastLine()->next());
X        dl->deleteLine();
X
X        if (CS || DL)
X        {
X            if (CS)
X                delete_listing_line(y);
X            else
X            {
X                clear_modeline();
X                delete_screen_line(y);
X                update_modeline();
X            }
X            move_cursor(rows()-3, 0);
X            display_string(dl->lastLine()->line(), dl->lastLine()->length());
X        }
X        else
X        {
X            clear_to_end_of_screen(y);
X            move_cursor(y, 0);
X            DirLine *ln = dl->currLine();
X            for (int i = y; i < rows()-2; i++, ln = ln->next())
X                display_string(ln->line(), ln->length());
X            update_modeline();
X        }
X
X        dl->saveYXPos(y, goal_column(dl));
X    }
X    else
X    {
X        //
X        // Last line of listing is visible in window,
X        // so firstLIne\(\) and lastLine\(\) won\'t change.
X        //
X        if (dl->atWindowTop() && dl->atWindowBot())
X        {
X            //
X            // The last line in the window is also the first line.
X            // Since we don\'t allow deletion of `.\' or `..\', there
X            // must be more viewable lines.  Scroll down half
X            // a window to put more into view.
X            //
X            scroll_down_half_window(dl, y, 0);
X            dl->deleteLine();
X            DirLine *ln = dl->firstLine();
X            for (int pos = 0; ln != dl->tail(); pos++, ln = ln->next()) ;
X            dl->saveYXPos(pos, goal_column(dl));
X            move_cursor(pos+1, 0);
X            clear_to_end_of_line();
X            move_cursor(pos, dl->savedXPos());
X        }
X        else if (dl->atWindowBot())
X        {
X            //
X            // We want to delete the last line in the window.
X            //
X            dl->deleteLine();
X            move_cursor(y, 0);
X            clear_to_end_of_line();
X            dl->saveYXPos(y-1, goal_column(dl));
X            move_cursor(y-1, dl->savedXPos());
X        }
X        else
X        {
X            //
X            // We are in the middle of the listing.
X            //
X            dl->deleteLine();
X            if (CS || DL)
X            {
X                if (CS)
X                    delete_listing_line(y);
X                else
X                {
X                    clear_modeline();
X                    delete_screen_line(y);
X                    update_modeline();
X                }
X            }
X            else
X            {
X                clear_to_end_of_screen(y);
X                move_cursor(y, 0);
X                for (DirLine *ln = dl->currLine(); ln; ln = ln->next())
X                    display_string(ln->line(), ln->length());
X                update_modeline();
X            }
X            dl->saveYXPos(y, goal_column(dl));
X         }
X    }
X    if (dl->currLine()->length() > columns())
X        leftshift_current_line(dl);
X    else
X        move_cursor(dl->savedYPos(), dl->savedXPos());
X}
END_OF_FILE
if test 35305 -ne `wc -c <'command1.C'`; then
    echo shar: \"'command1.C'\" unpacked with wrong size!
fi
# end of 'command1.C'
fi
if test -f 'classes.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'classes.h'\"
else
echo shar: Extracting \"'classes.h'\" \(10122 characters\)
sed "s/^X//" >'classes.h' <<'END_OF_FILE'
X/*
X** classes.h - the declarations of the classes used in dired
X**
X** classes.h 1.22   Delta'd: 15:10:40 9/22/92   Mike Lijewski, CNSF
X**
X** Copyright (c) 1991, 1992 Cornell University
X** All rights reserved.
X**
X** Redistribution and use in source and binary forms are permitted
X** provided that: (1) source distributions retain this entire copyright
X** notice and comment, and (2) distributions including binaries display
X** the following acknowledgement:  ``This product includes software
X** developed by Cornell University'' in the documentation or other
X** materials provided with the distribution and in all advertising
X** materials mentioning features or use of this software. Neither the
X** name of the University nor the names of its contributors may be used
X** to endorse or promote products derived from this software without
X** specific prior written permission.
X**
X** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X*/
X
X#ifndef __CLASSES_H
X#define __CLASSES_H
X
X//
X// This should be included by including "dired.".  This is so we get
X// a definition for DELETE.
X//
X
X#include <stddef.h>
X#include <stdlib.h>
X#include <string.h>
X
X/////////////////////////////////////////////////////////////////////////////
X// A Simple reference counted string class.  It is implemented as an
X// Envelope-Letter abstaction with String being the envelope and StringRep
X// being the letter.
X/////////////////////////////////////////////////////////////////////////////
X
Xclass String;
Xclass SBHelper;
X
Xclass StringRep {
X  public:
X    friend class String;
X    friend class SBHelper;
X
X    StringRep() { rep = ::new char[1]; len = 0; *rep = 0; count = 1;    }
X    StringRep(const char *s);
X    StringRep(char** r, size_t slen) { rep = *r; len = slen; count = 1; }
X    ~StringRep()                     { DELETE rep;                      }
X
X    static StringRep *freeList;  // we manage our own storage
X    enum { chunksize = 50 };     // # of StringReps to allocate at a time
X    void *operator new(size_t size);
X    void operator delete(void *object);
X
X    int operator!=(const char *rhs) const;
X    int operator==(const char *rhs) const;
X    int operator!=(const StringRep& rhs) const;
X    int operator==(const StringRep& rhs) const;
X
X    String operator+(const String& s) const;
X
X    size_t length() const { return len; }
X  private:
X    //
X    // Disable these two methods
X    //
X    StringRep(const StringRep&);
X    StringRep& operator=(const StringRep &);
X    union {
X        char *rep;
X        StringRep *next;
X    };
X    size_t len;
X    int count;
X};
X
Xclass String {
X  public:
X    friend class StringRep;
X    friend class SBHelper;
X
X    String()                       { p = new StringRep();                }
X    String(const String& s)        { p = s.p; p->count++;                }
X    String(const char *s)          { p = new StringRep(s);               }
X    String(char **s)               { p = new StringRep(s, ::strlen(*s)); }
X    String(char** s, size_t slen)  { p = new StringRep(s, slen);         }
X    ~String();
X
X    String& operator=(const String& rhs);
X
X    int operator==(const char *rhs)   const;
X    int operator==(const String& rhs) const;
X    int operator!=(const char *rhs)   const;
X    int operator!=(const String& rhs) const;
X
X    String operator+(const String &rhs) const   { return *p + rhs;      }
X    friend String operator+(const char *lhs, const String& rhs)
X                                            { return rhs + String(lhs); }
X
X    void operator+=(const String &rhs);
X    void operator+=(const char *rhs);
X
X    operator const char *() const { return p->rep; }
X    SBHelper operator[](int index);
X    size_t length() const { return p->len; }
X    void range_error(int index);
X  private:
X    StringRep *p;
X};
X
X/////////////////////////////////////////////////////////////////////////////
X// This class is a helper class used by String::operator[] to distinguish
X// between applications of operator[] on the lhs and rhs of "=" signs.
X/////////////////////////////////////////////////////////////////////////////
X
Xclass SBHelper {
X  public:
X    SBHelper(String &s, int i);
X    char operator=(char c);
X    operator char() { return str.p->rep[index]; }
X  private:
X    SBHelper(const SBHelper&);        // disallow this method
X    void operator=(const SBHelper&);  // disallow this method
X    String &str;
X    int index;
X};
X
X///////////////////////////////////////////////////////////////////////////////
X// DirLine - class which contains one line of the long
X//           listing of a directory.
X///////////////////////////////////////////////////////////////////////////////
X
Xclass DirLine {
X    friend class DirList;
X  private:
X    String              _line;
X    DirLine            *_next;
X    DirLine            *_prev;
X
X    //
X    // Disallow these operations by not providing definitions.
X    // Also keep compiler from generating default versions of these.
X    //
X    DirLine();
X    DirLine(const DirLine &);
X    DirLine &operator=(const DirLine &); 
X  public:
X    DirLine(char **line) : _line(line) { _next = _prev = 0; }
X    ~DirLine() { }
X
X    static DirLine *freeList;  // we manage our own storage for DirLines
X    enum { chunksize = 50 };   // size blocks of DirLines we allocate
X    void *operator new(size_t size);
X    void operator delete(void *object);
X
X    const char *line()  const { return _line;          }
X    int length()        const { return _line.length(); }
X    DirLine *next()     const { return _next;          }
X    DirLine *prev()     const { return _prev;          }
X    void update(char **newline) { _line = String(newline); }
X};
X
X///////////////////////////////////////////////////////////////////////////////
X// DirList - class which manages a doubly-linked list of DirLines.
X//           It also maintains our current notion of what is and isn't
X//           visible in the window.
X///////////////////////////////////////////////////////////////////////////////
X
Xclass DirList {
X  private:
X    DirLine    *_head;
X    DirLine    *_tail;
X    char       *_name;        // full pathname of the directory
X    int         _nelems;
X    short       _saved_x;     // saved x cursor position
X    short       _saved_y;     // saved y cursor position
X    DirLine    *_firstLine;   // first viewable dirLine in curses window
X    DirLine    *_lastLine;    // last  viewable dirLine in curses window
X    DirLine    *_currLine;    // line cursor is on in curses window
X    DirList    *_next;
X    DirList    *_prev;
X
X    //
X    // Disallow these operations by not providing definitions.
X    // Also keep compiler from generating default versions of these.
X    //
X    DirList();
X    DirList(const DirList &);
X    DirList &operator=(const DirList &);
X  public:
X    DirList(char *);
X    ~DirList();
X
X    DirLine *head()              const { return _head;                   }
X    DirLine *tail()              const { return _tail;                   }
X    DirLine *firstLine()         const { return _firstLine;              }
X    DirLine *lastLine()          const { return _lastLine;               }
X    DirLine *currLine()          const { return _currLine;               }
X    DirList *next()              const { return _next;                   }
X    DirList *prev()              const { return _prev;                   }
X
X    int savedXPos()              const { return _saved_x;                }
X    int savedYPos()              const { return _saved_y;                }
X
X    void setFirst(DirLine *e)          { _firstLine = e;                 }
X    void setLast (DirLine *e)          { _lastLine  = e;                 }
X    void setCurrLine (DirLine *ln)     { _currLine = ln;                 }
X
X    void setNext (DirList *l)          { _next = l;                      }
X    void setPrev (DirList *l)          { _prev = l;                      }
X
X    const char *name()           const { return _name;                   }
X    int nelems()                 const { return _nelems;                 }
X    void saveYXPos(int y, int x)       { _saved_x = (short)x;
X                                         _saved_y = (short)y;            }
X
X    int atBegOfList()            const { return _currLine == _head;      }
X    int atEndOfList()            const { return _currLine == _tail;      }
X
X    int atWindowTop()            const { return _currLine == _firstLine; }
X    int atWindowBot()            const { return _currLine == _lastLine;  }
X
X    DirLine *insert(char **);
X    void add(DirLine *);
X    void deleteLine();
X};
X
X///////////////////////////////////////////////////////////////////////////////
X// DirStack - class which manages a stack of DirLists.
X///////////////////////////////////////////////////////////////////////////////
X
Xclass DirStack {
X  private:
X    DirList             *_top;
X    int                  _nelems;
X    //
X    // Disallow these operations by not providing definitions.
X    // Also keep compiler from generating default versions of these.
X    //
X    DirStack(const DirStack &);
X    DirStack &operator=(const DirStack &);
X  public:
X    DirStack()                 { _top = 0; _nelems = 0; }
X    DirList *top()       const { return _top;           }
X    int nelems()         const { return _nelems;        }
X    void push(DirList *);
X    DirList *pop();
X};
X
Xinline int StringRep::operator!=(const char *rhs) const {
X    return strcmp(rep, rhs);
X}
X
Xinline int StringRep::operator==(const char *rhs) const {
X    return strcmp(rep, rhs) == 0;
X}
X
Xinline int StringRep::operator!=(const StringRep& rhs) const {
X    return strcmp(rep, rhs.rep);
X}
X
Xinline int StringRep::operator==(const StringRep& rhs) const {
X    return strcmp(rep, rhs.rep) == 0;
X}
X
Xinline int String::operator==(const char *rhs) const {
X    return *p == rhs;
X}
X
Xinline int String::operator==(const String& rhs) const {
X    return *p == *(rhs.p);
X}
X
Xinline int String::operator!=(const char *rhs) const {
X    return *p != rhs;
X}
X
Xinline int String::operator!=(const String& rhs) const {
X    return *p != *(rhs.p);
X}
X
X#endif /* __CLASSES_H */
END_OF_FILE
if test 10122 -ne `wc -c <'classes.h'`; then
    echo shar: \"'classes.h'\" unpacked with wrong size!
fi
# end of 'classes.h'
fi
if test -f 'dired.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dired.h'\"
else
echo shar: Extracting \"'dired.h'\" \(4895 characters\)
sed "s/^X//" >'dired.h' <<'END_OF_FILE'
X/*
X** dired.h - global declarations
X**
X** dired.h 1.50   Delta'd: 17:32:47 10/1/92   Mike Lijewski, CNSF
X**
X** Copyright (c) 1991, 1992 Cornell University
X** All rights reserved.
X**
X** Redistribution and use in source and binary forms are permitted
X** provided that: (1) source distributions retain this entire copyright
X** notice and comment, and (2) distributions including binaries display
X** the following acknowledgement:  ``This product includes software
X** developed by Cornell University'' in the documentation or other
X** materials provided with the distribution and in all advertising
X** materials mentioning features or use of this software. Neither the
X** name of the University nor the names of its contributors may be used
X** to endorse or promote products derived from this software without
X** specific prior written permission.
X**
X** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X*/
X
X#ifndef __DIRED_H
X#define __DIRED_H
X
X#include <stdio.h>
X#include <string.h>
X
X//
X// Take care of compilers which can't deal with 'delete []' form of delete.
X//
X#ifdef  OLDDELETE
X#define DELETE delete
X#else
X#define DELETE delete []
X#endif
X
X#include "classes.h"
X
X// the four ways we sort a directory listing
Xenum sort_order { ALPHABETICALLY, MODIFICATION_TIME,
X                  ACCESS_TIME,    INODE_CHANGE_TIME };
X
X//
X// GLOBALS
X//
Xextern DirStack *dir_stack;                 // our directory stack
Xextern sort_order how_to_sort;              // default sort order
Xextern const char *const ls_cmd[4];         // command to get long listing
Xextern const char *const modeline_prefix;   // modeline prefix
Xextern const char *const version;           // our version number
Xextern const char *const help_file[];       // the help message
Xextern const int HELP_FILE_DIM;             // number of entries in help_file
Xextern int win_size_changed;                // has window size changed
X
X// for POSIX compatibility
X#ifndef EXIT_FAILURE
X#define EXIT_FAILURE 1
X#endif
X#ifndef EXIT_SUCCESS
X#define EXIT_SUCCESS 0
X#endif
X
X//
X// FUNCTION PROTOTYPES
X//
X
X// from `commands.C'
Xextern void read_commands(DirList *);
X
X// from `dired.C'
Xextern void dired(const char *dirname);
X
X// from `utilities.C'
Xextern void        cleanup(int);
Xextern char       *current_directory();
Xextern void        display_string(const char *str, size_t len = 0); 
Xextern void        eat_a_character(const char *msg);
Xextern void        error(const char *str);
Xextern void        error(const char *fmt, int index);
Xextern void        error(const char *fmt, const char *file, int line);
Xextern void        error(const char *fmt, const char *file, int line,
X                         const char *str);
Xextern void        exec_with_system(const char *cmd, int prompt = 1);
Xextern int         execute(const char *file, const char *argv[], int closem=1);
Xextern const char *expand_tilde(const char *str);
Xextern char       *fgetline(FILE *fp);
Xextern DirList    *get_directory_listing(char *dirname);
Xextern const char *get_file_name(DirList *list);
Xextern int         get_key(DirList *dl);
Xextern int         goal_column(DirList *l);
Xextern void        initialize();
Xextern void        initial_listing(DirList *dl);
Xextern int         is_directory(const char *dir);
Xextern int         is_regular_file(const char *file);
Xextern void        leftshift_current_line(DirList *dl);
Xextern int         lines_displayed(DirList *dl);
Xextern void        message(const char *fmt, const char *str = 0);
X#ifdef COMPLETION
Xextern const char *prompt(const char *msg, int do_completion = 0);
X#else
Xextern const char *prompt(const char *msg);
X#endif
Xextern int         read_and_exec_perm(const char *dir);
Xextern int         read_from_keybd();
Xextern void        redisplay();
Xextern void        rightshift_current_line(DirList *dl);
Xextern void        set_signals();
X#ifdef NO_STRCHR
Xextern char       *strchr(const char *s, char charwanted);
Xextern char       *strrchr(const char *s, char charwanted);
X#endif
X#ifdef NO_STRSTR
Xextern char       *strstr(const char *, const char *);
X#endif
Xextern void        update_modeline(const char * = 0, const char * = 0);
Xextern void        unset_signals();
Xextern void        winch(int);
X
X//
X// INLINES
X//
X
X// max - the maximum of two integer arguments.
Xinline int max(int x, int y) { return x >= y ? x : y; }
X
X// set_sort_order - sets the sorting order.
Xinline void set_sort_order(sort_order order) { how_to_sort = order; }
X
X// the_sort_order - returns the sorting order
Xinline sort_order the_sort_order(void) { return how_to_sort; }
X
X//
X// MISCELLANY
X//
X
X// a number of g++ implementations seem not to have this defined
X#if defined(__GNUG__) && !defined(NO_STRSTR)
Xextern "C" {
X	extern char *strstr(const char *, const char *);
X}
X#endif
X
X#endif /* __DIRED_H */
END_OF_FILE
if test 4895 -ne `wc -c <'dired.h'`; then
    echo shar: \"'dired.h'\" unpacked with wrong size!
fi
# end of 'dired.h'
fi
echo shar: End of archive 2 \(of 5\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
exit 0 # Just in case...
-- 
        Andrew Patrick acting as Comp.Sources.Reviewed Moderator
              Department of Communications, Ottawa, CANADA
                         csr@calvin.dgbt.doc.CA
Technical Details
Message-ID: <1992Oct28.023731.28217@rick.dgbt.doc.ca>
Path: arc1-ca.pugleaf.net!sparky!uunet!utcsri!torn!cunews!dgbt!rick.dgbt.doc.ca!calvin.dgbt.doc.ca!csr

Show Full Headers
Complete Article Headers
Newsgroups: comp.sources.reviewed
Path: arc1-ca.pugleaf.net!sparky!uunet!utcsri!torn!cunews!dgbt!rick.dgbt.doc.ca!calvin.dgbt.doc.ca!csr
From: Mike Lijewski <lijewski@theory.tc.cornell.edu>
Subject: v02i034: dired - (Ver. 1.8) directory editor in C++, Part02/05
Message-ID: <1992Oct28.023731.28217@rick.dgbt.doc.ca>
Originator: csr@calvin.dgbt.doc.ca
Sender: news@rick.dgbt.doc.ca
Nntp-Posting-Host: calvin.dgbt.doc.ca
Organization: Communications Research Centre, Ottawa
Date: Wed, 28 Oct 1992 02:37:31 GMT
Approved: csr@calvin.dgbt.doc.ca
Lines: 1721