home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / maint / part07 < prev    next >
Encoding:
Text File  |  1992-05-13  |  80.4 KB  |  2,636 lines

  1. Newsgroups: comp.sources.unix
  2. From: peirce@gw.wmich.edu (Leonard J. Peirce)
  3. Subject: v26i055: maint - full-screen file and directory maintenance tool, Part07/07
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: peirce@gw.wmich.edu (Leonard J. Peirce)
  8. Posting-Number: Volume 26, Issue 55
  9. Archive-Name: maint/part07
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 7 (of 7)."
  18. # Contents:  main.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Thu May 14 23:05:44 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'main.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'main.c'\"
  23. else
  24. echo shar: Extracting \"'main.c'\" \(78195 characters\)
  25. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  26. X/******************************************************************************
  27. X*******************************************************************************
  28. X
  29. X   Site:    Western Michigan University Academic Computer Center
  30. X
  31. X   System:    Directory/File System Maintenance
  32. X  
  33. X   Program:    maint
  34. X
  35. X   Version=01    Level=00    01/24/92    Leonard J. Peirce
  36. X
  37. X   Purpose:    This program provides the user with a full-screen method for
  38. X        maintaining directories and file systems.  The directory
  39. X        will be presented to the user in a series of screens, each
  40. X        of which will contain information about individual files.
  41. X        The user may move through a directory structure, marking files
  42. X        for deletion, changing protection modes, renaming files,
  43. X        creating text descriptors, copying files, editing files, and
  44. X        viewing files.  Other options are available to allow the user
  45. X        to fork a subprocess to return to shell and search for a
  46. X        file.
  47. X
  48. X        See the manual page maint.1 for more details.
  49. X
  50. X   Arguments:
  51. X
  52. X        -a            auto-advance the cursor on
  53. X                    Delete or Unmark
  54. X        -c            ask for confirmation before executing
  55. X        -d            include date field for files
  56. X        -f            full info; implies -ogds
  57. X        -g            include group name for files
  58. X        -o            include owner field for files
  59. X        -p            include protection field for files
  60. X        -s            include size (in bytes) for files
  61. X        -t            start up in text mode
  62. X        -S <sort-opt>        sort files by <sort-opt>; legal
  63. X                    values are:  size, date, protection,
  64. X                    filename; default is filename
  65. X
  66. X   External variables:    See individual routine(s)
  67. X
  68. X   Maint external functions:
  69. X
  70. X    Defined:    None
  71. X
  72. X    Called:        cat, check_marks, clean_up, clear_mess, config_options,
  73. X            create_text, edit, erase_tag, file_locate,
  74. X            file_ptr_locate, file_select, follow_link, free_comm,
  75. X            free_pool, get_args, get_bnum, get_dir, get_dir_mem,
  76. X            get_filemarks, get_num_file, get_scr_num, give_help,
  77. X            highlite, info, init_pool, initialize, make_screen,
  78. X            make_slot, mark_cancel, mark_copy_ren, mark_delete,
  79. X            mark_group, mark_owner, mark_protect, mark_rename,
  80. X            mark_repeat, mark_text, prompt_getstr, put_pagnum,
  81. X            put_slot, put_spec, put_stat, put_text, read_text_des,
  82. X            screen_reset, set_args, set_nodes, set_screen,
  83. X            sort_files, strindex, strmcpy, strdel, tag_file, xecute
  84. X
  85. X   Files accessed:    only those in the directory and possibly .maint.tdf
  86. X            in other directories
  87. X
  88. X   Return codes:    0    Successful completion
  89. X
  90. X   Compiling instructions:    See Makefile.
  91. X
  92. X   Linking instructions:    See Makefile.
  93. X
  94. X   Other information:    (C) Copyright 1992, Leonard J. Peirce
  95. X
  96. X   Data structures:
  97. X
  98. X   Several different data structures are used internally to Maint to store
  99. X   all kinds of information, ranging from the filenames and related information
  100. X   to text descriptors and new filenames.
  101. X
  102. X   Directory information for the files in a directory is allocated dynamically
  103. X   upon entry to the proc_dir() function.  An automatic pointer, dirptr, is
  104. X   used to point to the memory that holds the information about the files.
  105. X   This pointer MUST remain automatic because each directory needs it own
  106. X   copy.  After the number of files in the directory is determined, the
  107. X   amount of memory needed to hold the information about each file in the
  108. X   directory can be calculated.  It is calculated by taking the number of
  109. X   files in the directory, adding one, and multiplying it by the length of
  110. X   the structure definition ENT_DEF.  This is the number of bytes needed.
  111. X   The memory is allocated by calling malloc() and the pointer to the
  112. X   memory is stored in dirptr.
  113. X
  114. X   When a Finish command is issued or the commands in a directory are executed,
  115. X   the memory is deallocated, the number of files is computed, the size of
  116. X   the memory necessary is calculated, and the memory is allocated once again.
  117. X
  118. X   A) Memory Pools
  119. X
  120. X   MAINT uses its own memory pool allocation scheme.  These memory pools are
  121. X   used to store only CHARACTER data and thus there is no need to worry about
  122. X   byte alignment for integer values and such.  Items that are stored in the
  123. X   memory pools include:  1) the full filename of a file, and 2) the text
  124. X   descriptor of the file in case the user selects Text mode.
  125. X
  126. X   The pools are allocated on a demand basis and are linked together into a
  127. X   linked list.  The size of each memory pool in the list can vary, depending
  128. X   on the state of the information that will be included for each directory.
  129. X   The global variable ent_factor is initially set to FUDGE_FACTOR, which is
  130. X   a guess at the number of bytes that each file entry is going to need to
  131. X   store its information.  Then the run-time arguments are taken into account,
  132. X   with ent_factor being updated for each that argument that will require
  133. X   something stored in the memory pools.  See the routine set_factors() for
  134. X   the values that ent_factor is increased by.
  135. X
  136. X   When it is time to redo the information for a directory, the memory in the
  137. X   memory pools is reclaimed rather than released and reallocated.  The pointer 
  138. X   to the next available byte in the structure is set to point to the beginning
  139. X   of the memory pool and the remaining length is reset to the original length
  140. X   of the pool.  This may waste a little memory but it saves a few calls that
  141. X   would be needed to free and reallocate the memory.
  142. X
  143. X   B) Command structures
  144. X
  145. X   Command structures are used to hold the information necessary to carry out
  146. X   commands for a specific file.  When the first command for a file is speci-
  147. X   fied by the user, a new command structure is allocated and linked to the
  148. X   file entry for the file, the pointer to the command structure being stored
  149. X   in the command field of the ENT_DEF structure.
  150. X
  151. X   All of the information in the command structure that requires string values
  152. X   (such as ren_name, copy_name, and text) are stored in memory allocated by
  153. X   malloc() and NOT in a memory pool.  This is to cut down on wasting of
  154. X   memory for file commands that are cancelled.
  155. X
  156. X   When commands for a file are cancelled, all the memory for any of the char-
  157. X   acter strings are freed (via free()) and the command structure itself
  158. X   is freed.
  159. X
  160. X********************************************************************************
  161. X*******************************************************************************/
  162. X
  163. X/******************************************************************************/
  164. X/*                                                                            */
  165. X/*                        # I N C L U D E   F I L E S                         */
  166. X/*                                                                            */
  167. X/******************************************************************************/
  168. X
  169. X#ifdef ultrix
  170. X#include <cursesX.h>
  171. X#include <unistd.h>
  172. X#else
  173. X#include <curses.h>
  174. X#include <sys/file.h>
  175. X#endif
  176. X#include <sys/param.h>
  177. X#include <sys/stat.h>
  178. X#include <stdio.h>            /* who knows?    (NULL maybe?)          */
  179. X#include <time.h>            /* for getting current year value     */
  180. X#include <string.h>            /* string functions              */
  181. X#include <malloc.h>            /* so free is declared right          */
  182. X#include "maint.h"            /* our very own header file          */
  183. X
  184. X/******************************************************************************/
  185. X/*                                                                            */
  186. X/*                             # D E F I N E S                                */
  187. X/*                                                                            */
  188. X/******************************************************************************/
  189. X
  190. X#define MAX_DIR 15            /* max. # of subdirectories to save   */
  191. X
  192. X/******************************************************************************/
  193. X/*                                                                            */
  194. X/*          S T R U C T U R E S ,   U N I O N S ,   T Y P E D E F S           */
  195. X/*                                                                            */
  196. X/******************************************************************************/
  197. X
  198. X/******************************************************************************/
  199. X/*                                                                            */
  200. X/*   E X T E R N A L   D E F I N I T I O N S   &   D E C L A R A T I O N S    */
  201. X/*                                                                            */
  202. X/******************************************************************************/
  203. X
  204. extern     char      *getenv();
  205. X
  206. extern     u_int      sleep();
  207. X
  208. extern     int      strindex(),
  209. X          access();
  210. X
  211. extern     long      get_bnum();
  212. X
  213. extern     int      mark_text(),
  214. X          mark_delete(),
  215. X          mark_copy_ren(),
  216. X          mark_protect(),
  217. X          mark_rename(),
  218. X          mark_repeat(),
  219. X          mark_owner(),
  220. X          mark_group(),
  221. X          check_marks(),
  222. X          put_slot(),
  223. X          file_select(),
  224. X          edit(),
  225. X          make_slot(),
  226. X          read_text_des(),
  227. X          file_locate(),
  228. X          file_ptr_locate(),
  229. X          follow_link(),
  230. X          config_options(),
  231. X          create_text();
  232. X
  233. extern     short      info(),
  234. X          get_num_file(),
  235. X          get_scr_num();
  236. X
  237. extern     void      mark_cancel(),
  238. X          free_comm(),
  239. X          set_screen(),
  240. X          set_args(),
  241. X          set_nodes(),
  242. X          get_args(),
  243. X          get_dir_mem(),
  244. X          get_dir(),
  245. X          make_screen(),
  246. X          init_pool(),
  247. X          free_pool(),
  248. X          initialize(),
  249. X          put_stat(),
  250. X          put_spec(),
  251. X          put_pagnum(),
  252. X          prompt_getstr(),
  253. X          screen_reset(),
  254. X          clear_mess(),
  255. X          highlite(),
  256. X          tag_file(),
  257. X          erase_tag(),
  258. X          clean_up(),
  259. X          put_text(),
  260. X          xecute(),
  261. X          get_text(),
  262. X          get_filemarks(),
  263. X          give_help();
  264. X
  265. X#if defined(SYSV) && !defined(sun)
  266. X
  267. extern     char      *getcwd();
  268. extern     u_short  geteuid();
  269. X
  270. X#else
  271. X
  272. extern     char      *getwd();
  273. X
  274. X#endif
  275. X
  276. X     ENT_DEF  *baseptr;        /* pointer to directory entries          */
  277. X
  278. X     WINDOW      *spec_win,        /* directory spec/page # window          */
  279. X          *main_win,        /* main display window              */
  280. X          *stat_win;        /* stats/options window              */
  281. X
  282. X     int      *global_row,        /* so others functions can use it     */
  283. X          *global_col,        /* ditto....                  */
  284. X           curr_year,        /* current year value              */
  285. X          main_rows;        /* rows in main window              */
  286. X
  287. X     u_short  node_row_max,        /* max. # of rows in nodes array      */
  288. X          node_col_max,        /* max. # of columns in nodes array   */
  289. X          cont_flag;        /* set if continuing after suspend    */
  290. X
  291. X     ARG_DEF  args;            /* run-time argument flags          */
  292. X
  293. X     NODE_DEF nodes[MAX_NODE_ROW+1][MAX_NODE_COL+1];
  294. X
  295. X     ARG_STR  arg_strings[] = {
  296. X{"Include file size? (-s)                 ",&args.size},
  297. X{"Include file protection? (-p)           ",&args.prot},
  298. X{"Include date? (-d)                      ",&args.date},
  299. X{"Include group? (-g)                     ",&args.group},
  300. X{"Include owner? (-o)                     ",&args.owner},
  301. X{"Confirm before Xecuting marks? (-c)     ",&args.confirm},
  302. X{"Auto-feed on Delete/Unmark? (-A)        ",&args.auto_feed},
  303. X{"Include text descriptors? (-t)          ",&args.text},
  304. X{"Include dot-files? (-a)                 ",&args.dot_files},
  305. X{"Include file marks? (-F)                ",&args.filemarks},
  306. X{"Sort field? (-S)                        ",&args.sort}
  307. X};
  308. X
  309. X/******************************************************************************/
  310. X/*                                                                            */
  311. X/*     S T A T I C   D E F I N I T I O N S   &   D E C L A R A T I O N S      */
  312. X/*                                                                            */
  313. X/******************************************************************************/
  314. X
  315. static     DIR_PTR  dir_ent_head,        /* head of directory node info list   */
  316. X          dir_ent_tail,        /* tail.......                  */
  317. X          *link_dir_ent(),    /* link active directory node          */
  318. X          *find_dir();        /* for searching the list          */
  319. X
  320. static     size_t      ent_factor;        /* ent. size memory allocation factor */
  321. X
  322. static     int      home_len,        /* length of home_dir              */
  323. X          get_year(),        /* get current year value          */
  324. X          proc_dir();        /* process current directory          */
  325. X
  326. static     short      def_slot_wid;        /* default slot width              */
  327. X
  328. static     char      home_dir[MAXPATHLEN+3];
  329. X
  330. static     void      unlink_dir_ent();    /* unlink active directory node          */
  331. X          
  332. X/******************************************************************************/
  333. X/*                                                                            */
  334. X/*                        M A I N   P R O C E S S I N G                       */
  335. X/*                                                                            */
  336. X/******************************************************************************/
  337. X
  338. main(argc,argv)
  339. X                    /*******   FORMAL  PARAMETERS   *******/
  340. X     int      argc;            /* number of run-time arguments          */
  341. X     char      **argv;        /* run-time argument strings          */
  342. X
  343. X{    /*** main ***/
  344. X                    /********   LOCAL  VARIABLES   ********/
  345. X     short      retval;        /* return value from proc_dir()          */
  346. X
  347. X
  348. X   /* check the command-line arguments and set up 1) the screen width and 2)
  349. X    * the slot width
  350. X    */
  351. X
  352. X   get_args(argc,argv,&args);
  353. X
  354. X   curr_year = get_year();        /* get the current year              */
  355. X
  356. X   strcpy(home_dir,getenv("HOME"));
  357. X   home_len = strlen(home_dir);
  358. X
  359. X   /* initialize/allocate all of the windows that will be needed and get
  360. X    * the necessary control strings from the termcap database
  361. X    */
  362. X
  363. X   initialize(&spec_win,&main_win,&stat_win,&node_row_max,&node_col_max);
  364. X
  365. X   /* initialize some global factors, such as the ent_factor and default
  366. X    * slot width
  367. X    */
  368. X
  369. X   set_args(&args,&def_slot_wid,&ent_factor);
  370. X
  371. X   /* set up the active directory linked list */
  372. X
  373. X   dir_ent_head.next = &dir_ent_tail;
  374. X   dir_ent_head.prev = &dir_ent_tail;
  375. X   dir_ent_tail.next = &dir_ent_head;
  376. X   dir_ent_tail.prev = &dir_ent_head;
  377. X   /* go for it -- process the directories and any thing else that the
  378. X    * user might desire
  379. X    */
  380. X
  381. X   do
  382. X   {
  383. X      retval = proc_dir();
  384. X   }
  385. X   while(retval == RECALL_PROC);
  386. X
  387. X   clean_up();                /* reset things                  */
  388. X
  389. X}    /*** main ***/
  390. X
  391. X/*******************************************************************************
  392. X********************************************************************************
  393. X
  394. X  Function:    proc_dir
  395. X
  396. X  Purpose:    Process the current directory.  This includes allocating memory
  397. X        for storing the information about the files and handling all
  398. X        of the user responses.  This routine is recursive and is called
  399. X        each time the user "selects" a new directory; the current dir-
  400. X        ectory is switched and this routine is called again.  When the
  401. X        user exits a directory, this routine frees up the memory that
  402. X        was allocated for the directory and returns.  The cursor is
  403. X        left pointing to the directory that was just exited.
  404. X
  405. X        This is a *RECURSIVE* function.
  406. X
  407. X  Global variables:
  408. X
  409. X    Name            Examine/Modify/Use/Read/Write
  410. X    ----            -----------------------------
  411. X    args               X        X
  412. X    user_dir                X
  413. X    ent_factor                X
  414. X    def_slot_wid              X    X
  415. X    main_rows                X
  416. X    main_win                X
  417. X    home_dir                X
  418. X    home_len                X
  419. X    node_row_max                X
  420. X    dir_ent_head                X
  421. X    dir_ent_tail                X
  422. X
  423. X  Return Codes:
  424. X
  425. X    Code            Reason
  426. X    ----            ------
  427. X         0            return normally
  428. X    RECALL_PROC        return and force this procedure to be recalled
  429. X                immediately
  430. X    EMPTY_DIR        the directory entry selected to get us here is
  431. X                empty
  432. X
  433. X********************************************************************************
  434. X*******************************************************************************/
  435. X
  436. static int proc_dir()
  437. X
  438. X{      /*** proc_dir ***/
  439. X                    /*********   LOCAL VARIABLES   ********/
  440. register int      term_code;        /* code for keystroke              */
  441. X     DIR_PTR  *dir_ent_ptr;        /* pointer to directory info node     */
  442. X     ENT_DEF  *dirptr,        /* pointer to directory information   */
  443. X          *entptr,        /* pointer to directory entry          */
  444. X          *prev_ptr;        /* ptr to file from previous command  */
  445. X     POOL_DEF *first_pool,        /* pointer to first memory pool          */
  446. X          *curr_pool;        /* pointer to current memory pool     */
  447. X     char      *dir_text= NULL,     /* pointer to directory text descrip  */
  448. X          *dir_name;        /* current directory name          */
  449. X     long      num_block = 0L;    /* number of blocks in directory      */
  450. X     u_int      dirsize;        /* size of directory info memory      */
  451. X     size_t      pool_length;        /* length for allocating new pools    */
  452. X     time_t      stat_time;        /* last mod time for directory          */
  453. X     int      scr_col,        /* current screen column          */
  454. X               scr_row;        /* current screen row              */
  455. X     u_short  prev_command;        /* last command -- used for repeating */
  456. X     short      num_col,        /* number of columns for full screen  */
  457. X          node_col,        /* current node array column          */
  458. X           node_row,        /* current node array row          */
  459. X          slot_width,        /* slot width for current directory   */
  460. X          num_row,        /* number of rows for full screen     */
  461. X               num_file = 0,        /* number of files in directory          */
  462. X               curr_screen = 1,    /* current screen of directory          */
  463. X               num_screen = 0,    /* number of screens in directory     */
  464. X                 scr_file,        /* number of files for current screen */
  465. X               num_slot,        /* number of slots per screen          */
  466. X          branched = FALSE,    /* TRUE if we Branched to a directory */
  467. X          filemarks_flag = 0,    /* TRUE if marks processed in dir     */
  468. X          sort_flag = 0,    /* TRUE if entries have been sorted   */
  469. X           text_flag = 0;    /* text descrip file processed flag   */
  470. X                    /** above vars MUST remain automatic **/
  471. static     COM_DEF  *comm_ptr;        /* for saving pointer to commands     */
  472. static     char      *tptr;        /* temporary character pointer          */
  473. static     int      curr_type,        /* type of current file              */
  474. X           status;        /* return code status              */
  475. static     short      temp,            /* temporary value              */
  476. X          temp2,        /* temporary value #2              */
  477. X          save_width,        /* temporary slot width holder          */
  478. X          change_dir,        /* set if we're changing directories  */
  479. X          new_screen,        /* new screen when locating files     */
  480. X          level;        /* what recursion level we are at     */
  481. static     DIR_SUMM dirmem[MAX_DIR];    /* summary info for all directories   */
  482. static     struct      stat   statbuf;    /* for getting access time for dir    */
  483. static     u_char      mess_flag,        /* set if information mess on screen  */
  484. X               cursor_flag,        /* set if cursor needs to be set      */
  485. X          exec_flag,        /* set if we just executed commands   */
  486. X          pass;            /* for one-time execution of stuff    */
  487. static     char      slot_buf[BUFSIZ];    /* for formatting screen slots          */
  488. X
  489. X
  490. X   cursor_flag = 0;
  491. X   prev_ptr = NULL;            /* no previous command yet          */
  492. X   slot_width = def_slot_wid;        /* initialize the slot width          */
  493. X   num_row = node_row_max;        /* set number of rows for now          */
  494. X
  495. X   /* this is kind of weird; we need to get the directory name soon after
  496. X    * entering proc_dir() and BEFORE calling get_num_file() in case we hit
  497. X    * hit an empty directory; the reason is that we might be coming backing
  498. X    * in to a directory that was previously non-empty and thus would need to
  499. X    * find the node in the active directory list for this directory and delete
  500. X    * it; and since we search the list by directory, we need the directory
  501. X    * name; grrr......
  502. X    */
  503. X
  504. X   dir_name = (char *) malloc(MAXPATHLEN+3);
  505. X
  506. X#if defined(SYSV) && !defined(sun)
  507. X   getcwd(dir_name,MAXPATHLEN+2);
  508. X#else
  509. X   getwd(dir_name);
  510. X#endif
  511. X
  512. X   /* find the active node for this directory, if it exists */
  513. X
  514. X   dir_ent_ptr = find_dir(&dir_ent_head,&dir_ent_tail,dir_name);
  515. X
  516. X   num_file = get_num_file(&args);    /* get number of files in directory   */
  517. X
  518. X   if(num_file == 0 || stat(".",&statbuf) != 0)
  519. X   {
  520. X      /* have we been here before?  if so, we need to free up the memory
  521. X       * pools
  522. X       */
  523. X
  524. X      if(dir_ent_ptr != NULL)
  525. X      {
  526. X     free_pool(dir_ent_ptr->first_pool);
  527. X     dir_ent_ptr->num_file = 0;    /* gone but not forgotten          */
  528. X     unlink_dir_ent(dir_ent_ptr);
  529. X      }
  530. X
  531. X      return(EMPTY_DIR);
  532. X   }
  533. X
  534. X   stat_time = statbuf.st_ctime;    /* save time directory last changed   */
  535. X   sort_flag = args.sort;
  536. X
  537. X   if(dir_ent_ptr != NULL)
  538. X   {
  539. X      /* this directory is currently active */
  540. X
  541. X      free(dir_name);            /* don't need this anymore          */
  542. X      dirptr = dir_ent_ptr->dirptr;
  543. X      dir_name = dir_ent_ptr->dir_name;
  544. X      first_pool = dir_ent_ptr->first_pool;
  545. X      curr_pool = dir_ent_ptr->curr_pool;
  546. X      pool_length = dir_ent_ptr->pool_length;
  547. X      num_file = dir_ent_ptr->num_file;
  548. X      dir_ent_ptr->count += 1;        /* update the active count          */
  549. X   }
  550. X   else
  551. X   {
  552. X      /* this directory currently has no activity; this *doesn't* mean that
  553. X       * it hasn't seen before; it just means that the user hasn't visited
  554. X       * it, Branched out, and returned to it
  555. X       */
  556. X
  557. X      /* get some memory to hold info about individual files */
  558. X
  559. X      get_dir_mem(&dirptr,&dirsize,num_file);
  560. X
  561. X      /* initialize the memory pools for holding the full filenames of the
  562. X       * files in the directory
  563. X       */
  564. X
  565. X      pool_length = (num_file + 1) * ent_factor;
  566. X      init_pool(&first_pool,pool_length);
  567. X      curr_pool = first_pool;        /* set current pool pointer          */
  568. X                                         
  569. X      /* get all of the information about the files in the directory */
  570. X             
  571. X      get_dir(dirptr,&args,&num_block,&curr_pool,&num_file,pool_length);
  572. X
  573. X      /* were there any files to get?  there might not be, depending on the
  574. X       * volatility of the directory and file protections
  575. X       */
  576. X
  577. X      if(!num_file)
  578. X      {
  579. X     free_pool(first_pool);        /* free up the memory pools first     */
  580. X
  581. X     /* now free up the memory for the directory information */
  582. X
  583. X     free((char *) dirptr);
  584. X     return(EMPTY_DIR);
  585. X      }
  586. X
  587. X      get_text(&args,dirptr,&curr_pool,&dir_text,&mess_flag,&slot_width,
  588. X           &text_flag,pool_length,num_file);
  589. X
  590. X      /* make a directory node entry and add it to the list */
  591. X
  592. X      dir_ent_ptr = link_dir_ent(&dir_ent_head,&dir_ent_tail,dirptr,dir_name,
  593. X                 first_pool,curr_pool,pool_length,stat_time,
  594. X                 num_file);
  595. X   }
  596. X
  597. X   global_row = &scr_row;        /* mostly for handling signals          */
  598. X   global_col = &scr_col;
  599. X
  600. X   dirmem[level].ptr = dirptr;        /* save a pointer to this memory      */
  601. X   dirmem[level].num_file = num_file;
  602. X
  603. X   /* count this recursion level; when it equals one, it means that we are in
  604. X    * the top-level directory for this session
  605. X    */
  606. X
  607. X   level++;
  608. X
  609. X   /* all of the information about the files in the directory has been
  610. X    * obtained; now initialize the screen parameters, including the screen
  611. X    * nodes and the number of screens for the directory
  612. X    */
  613. X
  614. X   set_screen(&num_screen,&scr_file,num_file,slot_width,node_row_max,&num_col);
  615. X
  616. X   num_slot = scr_file;            /* save number of slots per screen    */
  617. X
  618. X   /* initialize the screen slot node pointers for the screen */
  619. X
  620. X   set_nodes(nodes,node_row_max,&scr_file,num_screen,curr_screen,num_file,
  621. X         slot_width,num_col);
  622. X
  623. X   /* write the directory statistics line at the bottom of the display
  624. X    * and the directory spec/page number line at the top of the display
  625. X    */
  626. X
  627. X   put_spec(spec_win,dir_name,home_dir,home_len,num_screen);
  628. X   put_stat(stat_win,num_block,num_file);
  629. X
  630. X   if(args.text)            /* write text descrip for directory?  */
  631. X      put_text(spec_win,dir_text);
  632. X
  633. X   /* clear the main virtual display; we do this every time we enter a
  634. X    * directory to make things simple; some directories might have text
  635. X    * descriptors and some might not; this way, we make sure that we have
  636. X    * a clean display to work with, no matter what
  637. X    */
  638. X
  639. X   werase(main_win);
  640. X
  641. X   /* put the information about the files for the first screen on the screen */
  642. X             
  643. X   make_screen(main_win,nodes,dirptr,&args,curr_screen,node_row_max,
  644. X           node_col_max,scr_file,num_slot,slot_width,text_flag);
  645. X
  646. X   /* position the cursor to the first file in the directory */
  647. X
  648. X   node_row = 0;            /* start in top left of nodes array   */
  649. X   node_col = 0;
  650. X   scr_row = (int) nodes[0][0].row;    /* start in top left of screen, too   */
  651. X   scr_col = (int) nodes[0][0].column;
  652. X
  653. X   /* write the options line only once */
  654. X
  655. X   if(!pass)
  656. X   {
  657. X      put_options(stat_win);
  658. X      pass++;
  659. X   }
  660. X
  661. X   /* set the cursor position to the first file */
  662. X
  663. X   wmove(main_win,scr_row,scr_col);
  664. X   wrefresh(main_win);
  665. X
  666. X   /* this is the main processing loop for the whole program; each keystroke
  667. X    * is read and appropriate action is taken for each; this is an infinite
  668. X    * loop and the only way out is to break out from the middle and return
  669. X    * to a previous invocation of this function
  670. X    */
  671. X
  672. X   for(;;)                   /* loop forever.........          */
  673. X   {
  674. X      /* get a keystroke from the keyboard (store in term_code) */
  675. X
  676. X      term_code = wgetch(main_win);
  677. X
  678. X      if(mess_flag)            /* was a message on the screen?          */
  679. X      {
  680. X     clear_mess(main_win);        /* clear the message              */
  681. X     mess_flag = 0;            /* clear the message flag          */
  682. X
  683. X     /* reset the cursor to where it should be */
  684. X
  685. X     wmove(main_win,scr_row,scr_col);
  686. X      }
  687. X
  688. X      /* now look at the key that was pressed and take appropriate action */
  689. X
  690. X      switch(term_code)
  691. X      {
  692. X     case(CONTROL_I):        /**************************************/
  693. X     case(' '):            /*             right-arrow          */
  694. X     case('>'):            /**************************************/
  695. X     case('L'):
  696. X     case('l'):
  697. X     case(KEY_RIGHT):
  698. X
  699. X        /* update the pointer to the screen and then update the position
  700. X         * of the physical cursor; we must use temp to get the up_row
  701. X         * position and then assign it to node_row because we can't have
  702. X         * node_row changing before we use it to get node_col
  703. X         */
  704. X
  705. X        temp = (short) nodes[node_row][node_col].right_row;
  706. X        node_col = (short) nodes[node_row][node_col].right_col;
  707. X        node_row = temp;
  708. X        scr_row = (int) nodes[node_row][node_col].row;
  709. X        scr_col = (int) nodes[node_row][node_col].column;
  710. X
  711. X        cursor_flag++;        /* reset the cursor down below          */
  712. X        break;
  713. X
  714. X     case(BACKSPACE):        /**************************************/
  715. X     case('<'):            /*             left-arrow          */
  716. X     case('H'):            /**************************************/
  717. X     case(KEY_BACKSPACE):
  718. X     case('h'):
  719. X     case(KEY_LEFT):
  720. X
  721. X        /* update the pointer to the screen and then update the position
  722. X         * of the physical cursor; we must use temp to get the up_row
  723. X         * position and then assign it to node_row because we can't have
  724. X         * node_row changing before we use it to get node_col
  725. X         */
  726. X
  727. X        temp =  (short) nodes[node_row][node_col].left_row;
  728. X        node_col = (short) nodes[node_row][node_col].left_col;
  729. X        node_row = temp;
  730. X        scr_row = (int) nodes[node_row][node_col].row;
  731. X        scr_col = (int) nodes[node_row][node_col].column;
  732. X
  733. X        cursor_flag++;        /* reset the cursor down below          */
  734. X        break;
  735. X
  736. X     case(LINEFEED):        /**************************************/
  737. X     case('J'):            /*             down-arrow          */
  738. X     case('j'):            /**************************************/
  739. X     case(KEY_DOWN):
  740. X
  741. X        /* update the pointer to the screen and then update the position
  742. X         * of the physical cursor; we must use temp to get the up_row
  743. X         * position and then assign it to node_row because we can't have
  744. X         * node_row changing before we use it to get node_col
  745. X         */
  746. X
  747. X        temp = (short) nodes[node_row][node_col].down_row;
  748. X        node_col = (short) nodes[node_row][node_col].down_col;
  749. X        node_row = temp;
  750. X        scr_row = (int) nodes[node_row][node_col].row;
  751. X        scr_col = (int) nodes[node_row][node_col].column;
  752. X
  753. X        cursor_flag++;        /* reset the cursor down below          */
  754. X        break;
  755. X
  756. X     case('^'):            /**************************************/
  757. X     case('K'):            /*              up-arrow          */
  758. X     case('k'):            /**************************************/
  759. X     case(KEY_UP):
  760. X
  761. X        /* update the pointer to the screen and then update the position
  762. X         * of the physical cursor; we must use temp to get the up_row
  763. X         * position and then assign it to node_row because we can't have
  764. X         * node_row changing before we use it to get node_col
  765. X         */
  766. X
  767. X        temp = (short) nodes[node_row][node_col].up_row;
  768. X        node_col = (short) nodes[node_row][node_col].up_col;
  769. X        node_row = temp;
  770. X        scr_row = (int) nodes[node_row][node_col].row;
  771. X        scr_col = (int) nodes[node_row][node_col].column;
  772. X
  773. X        cursor_flag++;        /* reset the cursor down below          */
  774. X        break;
  775. X
  776. X     case(CARRIAGE_RETURN):        /**************************************/
  777. X                    /*          carriage return          */
  778. X                    /**************************************/
  779. X
  780. X        /* go to left of screen and down one row on the screen */
  781. X
  782. X        node_row = nodes[node_row][0].down_row;
  783. X        node_col = 0;
  784. X        scr_row = (int) nodes[node_row][node_col].row;
  785. X        scr_col = (int) nodes[node_row][node_col].column;
  786. X
  787. X        cursor_flag++;        /* reset the cursor down below          */
  788. X        break;
  789. X
  790. X     case('='):            /**************************************/
  791. X     case('+'):            /*            plus-screen          */
  792. X     case(CONTROL_F):        /**************************************/
  793. X     case(KEY_NPAGE):
  794. X
  795. X        if(num_screen > 1)        /* more than one screen?          */
  796. X        {
  797. X           curr_screen++;        /* go to next screen              */
  798. X           if(curr_screen > num_screen)
  799. X          curr_screen = 1;    /* oops, I meant the first screen     */
  800. X
  801. X           if((curr_screen == 1) || (curr_screen == num_screen))
  802. X           {
  803. X          set_nodes(nodes,node_row_max,&scr_file,num_screen,
  804. X                curr_screen,num_file,slot_width,num_col); 
  805. X           }
  806. X
  807. X           /* update the page number in the corner */
  808. X
  809. X           put_pagnum(spec_win,curr_screen,num_screen);
  810. X
  811. X           /* write the files to the screen */
  812. X
  813. X           make_screen(main_win,nodes,dirptr,&args,curr_screen,
  814. X               node_row_max,node_col_max,scr_file,num_slot,
  815. X               slot_width,text_flag);
  816. X
  817. X           /* reset screen and node pointers */
  818. X
  819. X           node_row = 0;
  820. X           node_col = 0;
  821. X           scr_row = (int) nodes[0][0].row;
  822. X           scr_col = (int) nodes[0][0].column;
  823. X
  824. X           /* home the cursor */
  825. X
  826. X           cursor_flag++;        /* reset the cursor down below          */
  827. X        }
  828. X
  829. X        break;
  830. X
  831. X     case('-'):            /**************************************/
  832. X     case('_'):            /*            minus-screen          */
  833. X     case(CONTROL_B):        /**************************************/
  834. X     case(KEY_PPAGE):
  835. X                           
  836. X        /* reset the screen nodes if we have to */
  837. X
  838. X        if(num_screen > 1)
  839. X        {
  840. X           curr_screen--;        /* go to previous screen           */
  841. X           if(curr_screen == 0)    /* were we on the first screen?          */
  842. X          curr_screen = num_screen; /* oops, go to last screen          */
  843. X
  844. X           if(curr_screen >= (num_screen-1))
  845. X           {
  846. X               set_nodes(nodes,node_row_max,&scr_file,num_screen,
  847. X                curr_screen,num_file,slot_width,num_col); 
  848. X           }
  849. X
  850. X           /* update the page number in the corner */
  851. X
  852. X           put_pagnum(spec_win,curr_screen,num_screen);
  853. X
  854. X           /* write the files to the screen */
  855. X
  856. X           make_screen(main_win,nodes,dirptr,&args,curr_screen,
  857. X               node_row_max,node_col_max,scr_file,num_slot,
  858. X               slot_width,text_flag);
  859. X
  860. X           /* reset screen and node pointers */
  861. X
  862. X           node_row = 0;
  863. X           node_col = 0;                         
  864. X           scr_row = (int) nodes[0][0].row;
  865. X           scr_col = (int) nodes[0][0].column;
  866. X
  867. X           /* home the cursor */
  868. X
  869. X           cursor_flag++;        /* reset the cursor down below          */
  870. X        }
  871. X
  872. X        break;
  873. X
  874. X     case('/'):            /**************************************/
  875. X                    /*            Locate-file          */
  876. X                    /**************************************/
  877. X
  878. X        /* user wants to search for a filename; go for it */
  879. X
  880. X        temp = (short) file_locate(main_win,dirptr,num_file);
  881. X
  882. X        if(temp >= 0)
  883. X        {
  884. X           /* file was found; recompute the node indexes so that we
  885. X        * can change the cursor on the screen
  886. X        */
  887. X
  888. X           new_screen = (temp / num_slot) + 1;
  889. X
  890. X           /* get us to the current screen */
  891. X
  892. X           temp2 = temp - ((new_screen - 1) * num_slot);
  893. X           node_col = temp2 / num_row;
  894. X           node_row = temp % num_row;
  895. X
  896. X           /* do we need to go to a new screen?  if so, make the new
  897. X        * one now
  898. X        */
  899. X
  900. X           if(new_screen != curr_screen)
  901. X           {
  902. X          /* create the new screen by first putting the new page
  903. X           * number in the upper-right and then rebuilding the
  904. X           * main display
  905. X           */
  906. X
  907. X                 /* do we need to update the screen node pointers? */
  908. X
  909. X          if((new_screen == num_screen) ||
  910. X             (curr_screen == num_screen))
  911. X          {
  912. X             /* set the nodes */
  913. X                                                      
  914. X             set_nodes(nodes,node_row_max,&scr_file,num_screen,
  915. X                   new_screen,num_file,slot_width,num_col);
  916. X          }
  917. X
  918. X          curr_screen = new_screen;
  919. X
  920. X            /* put the new page number on the screen */
  921. X
  922. X          put_pagnum(spec_win,curr_screen,num_screen);
  923. X
  924. X          /* build the display for the new screen */
  925. X
  926. X          make_screen(main_win,nodes,dirptr,&args,curr_screen,
  927. X                  node_row_max,node_col_max,scr_file,num_slot,
  928. X                  slot_width,text_flag);
  929. X           }
  930. X
  931. X           /* make the cursor point to the file that was found */
  932. X
  933. X           scr_row = (int) nodes[node_row][node_col].row;
  934. X           scr_col = (int) nodes[node_row][node_col].column;
  935. X        }
  936. X        else if(temp == -1)
  937. X        {
  938. X           /* no file found; just put up a message and that's it */
  939. X
  940. X           beep();
  941. X           info_mess("File not found");
  942. X           mess_flag++;
  943. X        }
  944. X
  945. X        /* set the cursor where it is supposed to be, whether on the
  946. X         * file that was found or the file that it was on when the
  947. X         * failed search request was initiated
  948. X         */
  949. X
  950. X        cursor_flag++;        /* reset the cursor down below          */
  951. X        break;
  952. X
  953. X     case('U'):            /**************************************/
  954. X     case('u'):            /*              Unmark              */
  955. X                      /**************************************/
  956. X
  957. X        /* first get the entry pointer for the file selected */
  958. X                      
  959. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  960. X             (node_col * num_row) + node_row;
  961. X
  962. X        /* now cancel all commands for the file entry and free up the
  963. X         * command structure that was allocated for it
  964. X         */
  965. X
  966. X        mark_cancel(entptr);
  967. X
  968. X        /* remake the slot so it can be written */
  969. X
  970. X        temp = make_slot(slot_buf,entptr,&args,slot_width,text_flag);
  971. X
  972. X        /* now write the file information to the screen in the
  973. X         * right spot
  974. X         */
  975. X
  976. X        put_slot(main_win,scr_row,scr_col+1,slot_buf,A_NORMAL);
  977. X
  978. X        if(args.auto_feed == TRUE)
  979. X        {
  980. X           /* move to the next logical file on the screen; basically, we are
  981. X        * just performing the same stuff we do for a down-arrow
  982. X        */
  983. X
  984. X           temp = (short) nodes[node_row][node_col].down_row;
  985. X           node_col = (short) nodes[node_row][node_col].down_col;
  986. X           node_row = temp;
  987. X           scr_row = (int) nodes[node_row][node_col].row;
  988. X           scr_col = (int) nodes[node_row][node_col].column;
  989. X        }
  990. X
  991. X        cursor_flag++;
  992. X        break;
  993. X
  994. X     case('S'):            /**************************************/
  995. X     case('s'):            /*               Select              */
  996. X                    /**************************************/
  997. X     case('B'):            /*               Branch              */
  998. X     case('b'):            /**************************************/
  999. X
  1000. X        change_dir = FALSE;        /* just to be safe              */
  1001. X
  1002. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1003. X             (node_col * num_row) + node_row;
  1004. X
  1005. X        /* if the current file is a symbolic link, try to find out what
  1006. X         * it is pointing to in case we need it later
  1007. X         */
  1008. X
  1009. X        if(entptr->type == LINK)
  1010. X           curr_type = follow_link(entptr->filename);
  1011. X        else
  1012. X           curr_type = entptr->type; /* just use what we already have     */
  1013. X
  1014. X        if(term_code == 'S' || term_code == 's')
  1015. X        {
  1016. X           /* now see what was Selected */
  1017. X
  1018. X           if(entptr->type == REGULAR || curr_type == REGULAR)
  1019. X           {
  1020. X          /* Selecting a file; just call the PAGER */
  1021. X
  1022. X          if(access(entptr->filename,R_OK) != 0)
  1023. X              status = CANT_OPEN;
  1024. X          else if(entptr->size != 0)
  1025. X          {
  1026. X             /* the file is not empty; go ahead and try to look at it */
  1027. X
  1028. X             status = file_select(entptr->filename);
  1029. X             touchwin(main_win);
  1030. X             touchwin(spec_win);
  1031. X             touchwin(stat_win);
  1032. X             wrefresh(main_win);
  1033. X             wrefresh(spec_win);
  1034. X             wrefresh(stat_win);
  1035. X          }
  1036. X          else
  1037. X             status = EMPTY_FILE; /* file is empty              */
  1038. X
  1039. X          switch(status)    /* what happened with the file?          */
  1040. X          {
  1041. X             case(FAILURE):
  1042. X
  1043. X            beep();
  1044. X            info_mess("Cannot display selected file");
  1045. X            mess_flag++;
  1046. X            break;
  1047. X
  1048. X             case(EMPTY_FILE):
  1049. X
  1050. X            beep();
  1051. X            info_mess("Selected file is empty");
  1052. X            mess_flag++;
  1053. X            break;
  1054. X
  1055. X             case(CANT_OPEN):
  1056. X
  1057. X            beep();
  1058. X            info_mess("Cannot open file");
  1059. X            mess_flag++;
  1060. X            break;
  1061. X
  1062. X             default:                      
  1063. X            break;
  1064. X          }
  1065. X           }
  1066. X           else if(entptr->type == DIRECTORY || curr_type == DIRECTORY)
  1067. X           {
  1068. X          /* Selected a directory; first see if we can even change
  1069. X           * to it
  1070. X           */
  1071. X
  1072. X          if(chdir(entptr->filename) != 0)
  1073. X          {
  1074. X             beep();
  1075. X             info_mess("Cannot change to selected directory");
  1076. X             mess_flag++;
  1077. X             cursor_flag++;
  1078. X          }
  1079. X          else
  1080. X          {
  1081. X             if(term_code == 'b') /* ask for confirmation first          */
  1082. X             {
  1083. X            info_mess("There are commands in this directory.  Execute them before branching? [y] ");
  1084. X
  1085. X            term_code = wgetch(main_win);
  1086. X
  1087. X            if(term_code == 'N' || term_code == 'n')
  1088. X               break;
  1089. X             }
  1090. X
  1091. X             change_dir = TRUE;
  1092. X          }
  1093. X           }
  1094. X        }
  1095. X        else
  1096. X        {
  1097. X           /* must be a Branch command */
  1098. X
  1099. X           prompt_getstr(main_win,"Directory: ",slot_buf,main_rows,
  1100. X                 sizeof(slot_buf));
  1101. X
  1102. X           if(slot_buf[0] == '\0')
  1103. X           {
  1104. X          /* user just hit a return */
  1105. X
  1106. X          cursor_flag++;
  1107. X           }
  1108. X           else if(chdir(slot_buf) != 0)
  1109. X           {
  1110. X          beep();
  1111. X          info_mess("Cannot change to specified directory");
  1112. X          mess_flag++;
  1113. X          cursor_flag++;
  1114. X           }
  1115. X           else
  1116. X           {
  1117. X          /* it worked; save the directory name and set the
  1118. X           * flag that says we are Jumping
  1119. X           */
  1120. X
  1121. X          branched = TRUE;
  1122. X          change_dir = TRUE;
  1123. X           }
  1124. X        }
  1125. X
  1126. X        if(change_dir == TRUE)
  1127. X        {
  1128. X           /* now call ourselves and start over with the new directory */
  1129. X
  1130. X           /***********************************
  1131. X            *   R E C U R S I V E   C A L L   *
  1132. X            ***********************************/
  1133. X
  1134. X           do
  1135. X           {
  1136. X          temp = proc_dir();
  1137. X           }
  1138. X           while(temp == RECALL_PROC);
  1139. X
  1140. X           baseptr = dirptr;    /* point to current directory          */
  1141. X
  1142. X           /* change back to the directory that we should be in */
  1143. X
  1144. X           if(chdir(dir_name) != 0)
  1145. X           {
  1146. X          /* problems changing to directory; scream at the user
  1147. X           * and get out of here
  1148. X           */
  1149. X
  1150. X           beep();
  1151. X           info_mess("Cannot reset directory....exiting...");
  1152. X           sleep(2);
  1153. X           exit(0);
  1154. X           }
  1155. X
  1156. X           /* see if the current directory has changed; if it has, we
  1157. X        * need to rebuild it
  1158. X        */
  1159. X
  1160. X           if(stat(".",&statbuf) != 0)
  1161. X          exit();
  1162. X
  1163. X           if(stat_time < statbuf.st_ctime)
  1164. X           {
  1165. X          /* see if there are any commands to execute */
  1166. X
  1167. X          if(check_marks(dirptr,num_file) == TRUE)
  1168. X          {
  1169. X             info_mess("Directory has been updated.  Execute marks before rebuilding? [Y] ");
  1170. X             term_code = wgetch(main_win);
  1171. X             clear_mess(main_win);
  1172. X
  1173. X             if(term_code != 'N' && term_code != 'n')
  1174. X            xecute(dirptr,dir_text,num_file);
  1175. X             else
  1176. X             {
  1177. X            /* free up the memory for any command structures that
  1178. X             * might have been allocated
  1179. X             */
  1180. X
  1181. X            free_comm(dirptr,num_file);
  1182. X             }
  1183. X          }
  1184. X
  1185. X          info_mess("Rebuilding directory.....");
  1186. X          level--;        /* decrement recursion level counter  */
  1187. X
  1188. X          /* free up the memory pools first */
  1189. X
  1190. X          free_pool(first_pool);
  1191. X          unlink_dir_ent(dir_ent_ptr);
  1192. X
  1193. X          /* now free up the memory for the directory information */
  1194. X
  1195. X          free((char *) dirptr);
  1196. X
  1197. X          werase(main_win);    /* erase display to be sure...          */
  1198. X          return(RECALL_PROC);    /* go back to where we were called    */
  1199. X           }
  1200. X
  1201. X            if(temp == EMPTY_DIR)    /* did the user make a good choice?   */
  1202. X           {
  1203. X          /* the directory that was selected was empty */
  1204. X
  1205. X          beep();
  1206. X          info_mess("Directory is empty...........");
  1207. X
  1208. X          if(exec_flag)
  1209. X          {
  1210. X             sleep(2);        /* only pause if we just executed     */
  1211. X             clear_mess(main_win);
  1212. X          }
  1213. X          else
  1214. X             mess_flag++;    /* clear it on next keystroke          */
  1215. X           }
  1216. X
  1217. X           /* reset some things on the screen since we are actually
  1218. X        * returning from a directory
  1219. X        */
  1220. X                        
  1221. X           if((args.text) && (!text_flag) && temp != EMPTY_DIR)
  1222. X           {
  1223. X          /* when we left this directory to go down, the
  1224. X           * text descriptors were not included (at least not
  1225. X           * not on the screen, anyway); when we were in
  1226. X           * one of the descendant directories, the text
  1227. X           * descriptors were selected; we must read them
  1228. X           * in here; first, update the slot width on the
  1229. X           * assumption that we can get the text descriptors
  1230. X           * for the current directory without any trouble and
  1231. X           * set the flag that signifies that we have text
  1232. X           * descriptors read in for the current directory
  1233. X           */
  1234. X
  1235. X          if(args.text == DISPLAY_TEXT)    /* room to display descrips?  */
  1236. X             slot_width += TEXT_MAX + 1; /* yes, assume we get them   */
  1237. X
  1238. X          text_flag = args.text;
  1239. X
  1240. X          /* erase the display to make sure we don't have any
  1241. X           * garbage left over if we need to reformat the screen
  1242. X           */
  1243. X
  1244. X          werase(main_win);
  1245. X
  1246. X          temp = read_text_des(dirptr,&curr_pool,&dir_text,
  1247. X                      pool_length,num_file);
  1248. X
  1249. X          if(temp == BAD_FILE)
  1250. X          {
  1251. X             beep();
  1252. X             info_mess("Invalid format for text descriptor file");
  1253. X             mess_flag++;
  1254. X             text_flag = 0;
  1255. X
  1256. X             if(args.text == DISPLAY_TEXT)
  1257. X                slot_width = slot_width - (TEXT_MAX + 1);
  1258. X
  1259. X             sleep(1);
  1260. X          }
  1261. X          else if(temp == CANT_OPEN)
  1262. X          {
  1263. X             beep();
  1264. X             info_mess("Cannot open text descriptor file");
  1265. X             mess_flag++;
  1266. X             text_flag = 0;
  1267. X
  1268. X             if(args.text == DISPLAY_TEXT)
  1269. X                slot_width = slot_width - (TEXT_MAX + 1);
  1270. X
  1271. X             sleep(1);
  1272. X          }
  1273. X          else if(temp == NO_FILE)
  1274. X          {
  1275. X             text_flag = 0;
  1276. X
  1277. X             if(args.text == DISPLAY_TEXT)
  1278. X                slot_width = slot_width - (TEXT_MAX + 1);
  1279. X          }
  1280. X          else if(temp == 0)
  1281. X          {
  1282. X             /* reset the screen parameters, just in case they need
  1283. X              * to be changed to reflect text descriptors
  1284. X              */
  1285. X
  1286. X             set_screen(&num_screen,&scr_file,num_file,slot_width,
  1287. X                node_row_max,&num_col);
  1288. X             num_slot = scr_file;
  1289. X          }
  1290. X               }
  1291. X
  1292. X           if(args.filemarks && !filemarks_flag)
  1293. X           {
  1294. X          /* the user has filemarks selected from a descendent
  1295. X           * directory but we don't have them included in the
  1296. X           * current directory; add them here
  1297. X           */
  1298. X
  1299. X          get_filemarks(dirptr,num_file);
  1300. X          filemarks_flag = 1;
  1301. X           }
  1302. X
  1303. X           if(args.sort && !sort_flag)
  1304. X           {
  1305. X          /* the user turned on sorting in a descendent directory
  1306. X           * but the directory isn't sorted; go ahead and sort now
  1307. X           */
  1308. X
  1309. X          sort_files(num_file - 1,args.sort);
  1310. X          sort_flag = 1;
  1311. X           }
  1312. X/*
  1313. X           if((temp == EMPTY_DIR && exec_flag) || temp != EMPTY_DIR)
  1314. X           {
  1315. X*/
  1316. X          /* we just executed commands in a directory so we must
  1317. X           * rebuild stuff
  1318. X           */
  1319. X
  1320. X          set_nodes(nodes,node_row_max,&scr_file,num_screen,
  1321. X                curr_screen,num_file,slot_width,num_col);
  1322. X
  1323. X          /* rewrite all of the stuff local to this directory */
  1324. X
  1325. X          put_spec(spec_win,dir_name,home_dir,home_len,num_screen);
  1326. X          put_stat(stat_win,num_block,num_file);
  1327. X
  1328. X          if(args.text)     /* text descriptor to write?          */
  1329. X             put_text(spec_win,dir_text);
  1330. X
  1331. X          /* this is important; we have to look for the directory
  1332. X           * that we were on when the last Select was done and de-
  1333. X           * termine what page it is on; we might have to change the
  1334. X           * current page and everything just to put the cursor back
  1335. X           * in the right spot
  1336. X           */
  1337. X
  1338. X          screen_reset(nodes,dirptr,entptr->filename,&node_row,
  1339. X                   &node_col,&scr_file,&curr_screen,node_row_max,
  1340. X                   num_file,num_slot,num_screen,slot_width,
  1341. X                   num_row,num_col);
  1342. X
  1343. X          /* put the new page number on the screen */
  1344. X
  1345. X          put_pagnum(spec_win,curr_screen,num_screen);
  1346. X
  1347. X          /* create and write the screen again for the current
  1348. X           * directory
  1349. X           */
  1350. X
  1351. X          make_screen(main_win,nodes,dirptr,&args,curr_screen,
  1352. X                  node_row_max,node_col_max,scr_file,
  1353. X                  num_slot,slot_width,text_flag);
  1354. X
  1355. X          exec_flag = 0;    /* make sure to reset this          */
  1356. X
  1357. X          /* reset the screen row and column */
  1358. X
  1359. X          scr_row = (int) nodes[node_row][node_col].row;
  1360. X          scr_col = (int) nodes[node_row][node_col].column;
  1361. X/*
  1362. X           }
  1363. X*/
  1364. X        }
  1365. X
  1366. X        exec_flag = 0;
  1367. X        cursor_flag++;        /* reset the cursor down below          */
  1368. X        break;
  1369. X                        
  1370. X     case('X'):            /**************************************/
  1371. X     case('x'):            /*             eXecute              */
  1372. X                    /**************************************/
  1373. X
  1374. X        if(args.confirm)        /* should we ask to make sure?          */
  1375. X        {
  1376. X           /* the user wants to be asked if they REALLY want to execute
  1377. X        * the commands for the directory
  1378. X        */
  1379. X
  1380. X           info_mess("REALLY eXecute commands? [N] ");
  1381. X           term_code = wgetch(main_win);
  1382. X
  1383. X           /* now look at what the keystroke is; if it is not Y or y,
  1384. X        * then we DO NOT execute the commands for the directory
  1385. X            */
  1386. X
  1387. X           if((term_code != 'Y') && (term_code != 'y'))
  1388. X           {
  1389. X          /* clear out the prompt message first and then set the
  1390. X           * flag to reset the cursor
  1391. X           */
  1392. X
  1393. X          clear_mess(main_win);
  1394. X          cursor_flag++;    /* reset the cursor              */
  1395. X          break;        /* nope, don't do anything yet.....   */
  1396. X           }
  1397. X        }
  1398. X
  1399. X        /* execute the file commands for all of the files in the current
  1400. X         * directory; informational messages will appear for each action
  1401. X         * for each file
  1402. X         */
  1403. X
  1404. X        xecute(dirptr,dir_text,num_file);
  1405. X        exec_flag++;        /* set flag saying we just executed   */
  1406. X
  1407. X        /* just fall through here and do what we would normally do for
  1408. X         * a REBUILD command; no sense in putting the code in two places,
  1409. X         * now is there?
  1410. X         */
  1411. X
  1412. X     case(CONTROL_R):        /**************************************/
  1413. X                    /*     rebuild the directory          */
  1414. X                    /**************************************/
  1415. X
  1416. X        /* if we are really just rebuilding, free up any command
  1417. X         * structures for the directory
  1418. X         */
  1419. X
  1420. X        if(!exec_flag)
  1421. X           free_comm(dirptr,num_file);
  1422. X
  1423. X        /* tell the user we are doing something so they don't worry */
  1424. X
  1425. X        xmess("Rebuilding directory information......",0);
  1426. X
  1427. X        /* decrement the recursion level before returning */
  1428. X
  1429. X        --level;
  1430. X
  1431. X        /* free the memory pools first */
  1432. X
  1433. X        free_pool(first_pool);
  1434. X        unlink_dir_ent(dir_ent_ptr);
  1435. X
  1436. X        /* now free up the memory for the directory information */
  1437. X
  1438. X        free((char *) dirptr);
  1439. X
  1440. X        return(RECALL_PROC);    /* force proc_dir() to be recalled    */
  1441. X
  1442. X     case('?'):            /**************************************/
  1443. X                    /*               Help              */
  1444. X                    /**************************************/
  1445. X
  1446. X        give_help(main_win);
  1447. X        mess_flag++;
  1448. X        cursor_flag++;
  1449. X        break;
  1450. X
  1451. X     case('D'):            /**************************************/
  1452. X     case('d'):            /*              Delete              */
  1453. X                    /**************************************/
  1454. X
  1455. X        /* first get the entry pointer for the file indicated */
  1456. X
  1457. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1458. X             (node_col * num_row) + node_row;
  1459. X
  1460. X        mark_delete(entptr);    /* mark file for deletion          */
  1461. X
  1462. X        temp = make_slot(slot_buf,entptr,&args,slot_width,text_flag);
  1463. X
  1464. X        /* now write the file information to the screen in the right spot */
  1465. X
  1466. X        put_slot(main_win,scr_row,scr_col+1,slot_buf,A_BOLD);
  1467. X
  1468. X        if(args.auto_feed == TRUE)
  1469. X        {
  1470. X           /* move to the next logical file on the screen; basically, we are
  1471. X        * just performing the same stuff we do for a down-arrow
  1472. X        */
  1473. X
  1474. X           temp = (short) nodes[node_row][node_col].down_row;
  1475. X           node_col = (short) nodes[node_row][node_col].down_col;
  1476. X           node_row = temp;
  1477. X           scr_row = (int) nodes[node_row][node_col].row;
  1478. X           scr_col = (int) nodes[node_row][node_col].column;
  1479. X        }
  1480. X
  1481. X        cursor_flag++;
  1482. X        prev_ptr = entptr;        /* save in case user wants to repeat  */
  1483. X        prev_command = DELETE;
  1484. X        break;
  1485. X
  1486. X     case('P'):            /**************************************/
  1487. X     case('p'):            /*              Protect              */
  1488. X                    /**************************************/
  1489. X
  1490. X        /* first get the entry pointer for the file indicated */
  1491. X
  1492. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1493. X             (node_col * num_row) + node_row;
  1494. X
  1495. X        tag_file(main_win,scr_row,scr_col);
  1496. X
  1497. X        /* get the new filename and mark the file to be renamed */
  1498. X
  1499. X        temp = mark_protect(main_win,entptr,0,FALSE);
  1500. X
  1501. X        if(temp != SUCCESS)        /* wot happen?                  */
  1502. X        {
  1503. X           beep();
  1504. X           info_mess("Invalid protection string");
  1505. X           mess_flag++;
  1506. X        }
  1507. X        else
  1508. X        {
  1509. X           /* highlite the file slot */
  1510. X
  1511. X           highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  1512. X            slot_width,text_flag);
  1513. X           prev_ptr = entptr;    /* save in case user wants to repeat  */
  1514. X           prev_command = PROTECT;
  1515. X        }
  1516. X
  1517. X        erase_tag(main_win,scr_row,scr_col);
  1518. X        cursor_flag++;        /* reset the cursor down below          */
  1519. X        break;
  1520. X
  1521. X     case('F'):            /**************************************/
  1522. X     case('f'):            /*              Finish              */
  1523. X                    /**************************************/
  1524. X
  1525. X
  1526. X        if(level == 1)        /* are we at the top?              */
  1527. X        {
  1528. X           /* beep and continue, ignoring the Finish command */
  1529. X
  1530. X           beep();
  1531. X           break;            /* yes, we can't go up any more       */
  1532. X        }
  1533. X
  1534. X        /* check for marked files first; if some are marked, ask the user
  1535. X         * if Finishing is the right thing to do
  1536. X         */
  1537. X
  1538. X        if(check_marks(dirptr,num_file) == TRUE && term_code == 'f')
  1539. X        {
  1540. X           info_mess("There are commands in this directory.  Execute them before finishing? [y] ");
  1541. X
  1542. X           term_code = wgetch(main_win);
  1543. X           clear_mess(main_win);
  1544. X           cursor_flag++;
  1545. X
  1546. X           if(term_code != 'N' && term_code != 'n')
  1547. X          xecute(dirptr,dir_text,num_file);
  1548. X           else
  1549. X          free_comm(dirptr,num_file);
  1550. X        }
  1551. X
  1552. X        /* the user is finished with the current directory; free up the
  1553. X         * memory that was allocated for the directory and just return;
  1554. X         * whether we return to the mainline or to a previous call to
  1555. X           * proc_dir() is no matter to us at this point
  1556. X         */
  1557. X
  1558. X        level--;            /* decrement recursion level counter  */
  1559. X
  1560. X        /* free up the memory pools first */
  1561. X
  1562. X        free_pool(first_pool);
  1563. X
  1564. X        /* now free up the memory for the directory information */
  1565. X
  1566. X        free((char *) dirptr);
  1567. X
  1568. X        /* unlink the active directory node from the list */
  1569. X
  1570. X        unlink_dir_ent(dir_ent_ptr);
  1571. X
  1572. X        return(0);            /* go back to where we were called    */
  1573. X
  1574. X     case('E'):            /**************************************/
  1575. X     case('e'):            /*               Edit              */
  1576. X                    /**************************************/
  1577. X
  1578. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1579. X             (node_col * num_row) + node_row;
  1580. X
  1581. X        if(entptr->type != DIRECTORY)
  1582. X        {
  1583. X           /* Editing a file; fine... */
  1584. X
  1585. X           if(access(entptr->filename,R_OK) != 0)
  1586. X           {
  1587. X          beep();
  1588. X          info_mess("Cannot open file");
  1589. X          mess_flag++;
  1590. X           }
  1591. X           else
  1592. X           {
  1593. X          /* the file is not empty; go ahead and try to edit it */
  1594. X
  1595. X          /* subtract the number of blocks for the file from the total
  1596. X           * for the directory because the size of the file might be
  1597. X           * different
  1598. X           */
  1599. X
  1600. X          num_block -= get_bnum(entptr->filename);
  1601. X
  1602. X          status = edit(entptr->filename);
  1603. X          touchwin(main_win);
  1604. X          touchwin(spec_win);
  1605. X          touchwin(stat_win);
  1606. X          wrefresh(main_win);
  1607. X          wrefresh(spec_win);
  1608. X          wrefresh(stat_win);
  1609. X           }
  1610. X
  1611. X           if(status == FAILURE)
  1612. X           {
  1613. X          beep();
  1614. X          info_mess("Cannot edit selected file");
  1615. X          mess_flag++;
  1616. X           }
  1617. X
  1618. X           /* rebuild the file entry for the file to reflect the new info;
  1619. X        * save the command pointer and re-attach it to the entry because
  1620. X        * make_ent() will wipe it out
  1621. X        */
  1622. X
  1623. X           comm_ptr = entptr->command;
  1624. X           make_ent(entptr,entptr->filename,&num_block);
  1625. X           entptr->command = comm_ptr;
  1626. X           status = make_slot(slot_buf,entptr,&args,slot_width,text_flag);
  1627. X           put_slot(main_win,scr_row,scr_col+1,slot_buf,status);
  1628. X
  1629. X           /* update the stat line */
  1630. X
  1631. X           put_stat(stat_win,num_block,num_file);
  1632. X           cursor_flag++;
  1633. X        }
  1634. X        else
  1635. X        {
  1636. X           beep();
  1637. X           info_mess("Cannot edit a directory");
  1638. X           mess_flag++;
  1639. X           cursor_flag++;
  1640. X        }
  1641. X
  1642. X        break;
  1643. X
  1644. X     case('I'):            /**************************************/
  1645. X     case('i'):            /*               Info              */
  1646. X                    /**************************************/
  1647. X
  1648. X        /* first get the entry pointer for the file indicated */
  1649. X
  1650. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1651. X             (node_col * num_row) + node_row;
  1652. X
  1653. X        /* display all of the information about the file on the screen */
  1654. X
  1655. X        if(info(entptr,&args) != SUCCESS)
  1656. X        {
  1657. X           beep();
  1658. X           info_mess("Cannot obtain information for file");
  1659. X           mess_flag++;
  1660. X        }
  1661. X
  1662. X        touchwin(main_win);        /* to force it to be refreshed          */
  1663. X        wnoutrefresh(main_win);
  1664. X        touchwin(stat_win);
  1665. X        wnoutrefresh(stat_win);
  1666. X        doupdate();
  1667. X        cursor_flag++;        /* reset the cursor              */
  1668. X
  1669. X        break;
  1670. X
  1671. X     case('R'):            /**************************************/
  1672. X     case('r'):            /*              Rename              */
  1673. X                    /**************************************/
  1674. X
  1675. X        /* first get the entry pointer for the file indicated */
  1676. X
  1677. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1678. X             (node_col * num_row) + node_row;
  1679. X
  1680. X        tag_file(main_win,scr_row,scr_col);
  1681. X
  1682. X        /* get the new filename and mark the file to be renamed */
  1683. X
  1684. X        temp = mark_copy_ren(main_win,entptr,RENAME,NULL,FALSE);
  1685. X
  1686. X        if(temp != SUCCESS)        /* wot happen?                  */
  1687. X        {
  1688. X           beep();
  1689. X           info_mess("Error in trying to rename file");
  1690. X           mess_flag++;
  1691. X        }
  1692. X        else
  1693. X        {
  1694. X           /* highlite the file slot */
  1695. X
  1696. X           highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  1697. X            slot_width,text_flag);
  1698. X           prev_ptr = entptr;    /* save in case user wants to repeat  */
  1699. X           prev_command = RENAME;
  1700. X        }
  1701. X
  1702. X        erase_tag(main_win,scr_row,scr_col);
  1703. X        cursor_flag++;        /* reset the cursor down below          */
  1704. X
  1705. X        break;
  1706. X
  1707. X     case('C'):            /**************************************/
  1708. X     case('c'):            /*               Copy               */
  1709. X                    /**************************************/
  1710. X
  1711. X         /* first get the entry pointer for the file indicated */
  1712. X
  1713. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1714. X             (node_col * num_row) + node_row;
  1715. X        if(entptr->type != DIRECTORY)
  1716. X        {
  1717. X           tag_file(main_win,scr_row,scr_col);
  1718. X
  1719. X           /* get the new filename and mark the file to be copied */
  1720. X
  1721. X           temp = mark_copy_ren(main_win,entptr,COPY,NULL,FALSE);
  1722. X
  1723. X           if(temp != SUCCESS)    /* wot happen?                  */
  1724. X           {
  1725. X           beep();
  1726. X           info_mess("Error in trying to copy file");
  1727. X           mess_flag++;
  1728. X           }
  1729. X           else
  1730. X           {
  1731. X          /* highlite the file slot */
  1732. X
  1733. X          highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  1734. X               slot_width,text_flag);
  1735. X              prev_ptr = entptr;    /* save in case user wants to repeat  */
  1736. X          prev_command = COPY;
  1737. X           }
  1738. X
  1739. X           erase_tag(main_win,scr_row,scr_col);
  1740. X        }
  1741. X        else
  1742. X        {
  1743. X           beep();
  1744. X           info_mess("Copy is invalid for that file");
  1745. X           mess_flag++;
  1746. X        }
  1747. X
  1748. X        cursor_flag++;
  1749. X        wrefresh(main_win);        /* make sure screen is up to date     */
  1750. X        break;
  1751. X
  1752. X     case('T'):            /**************************************/
  1753. X     case('t'):            /*               Text              */
  1754. X                    /**************************************/
  1755. X
  1756. X         /* first save what file the cursor was pointing to */
  1757. X
  1758. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1759. X             (node_col * num_row) + node_row;
  1760. X        if(!text_flag)
  1761. X        {
  1762. X           /* were text descriptors already turned on? */
  1763. X
  1764. X           if(!args.text)
  1765. X           {
  1766. X          /* now see what we need to set the text global run-time
  1767. X           * flag to (whether we should display text descriptors
  1768. X           * or not
  1769. X           */
  1770. X
  1771. X          save_width = slot_width;
  1772. X
  1773. X          if((slot_width + TEXT_MAX + 1) <= COLS)
  1774. X          {
  1775. X             /* Good news!  The text descriptors will fit on the
  1776. X              * screen; update the current slot width but leave the
  1777. X              * global slot width alone
  1778. X              */                                 
  1779. X
  1780. X             slot_width = slot_width + TEXT_MAX + 1;
  1781. X             args.text = DISPLAY_TEXT;
  1782. X          }
  1783. X          else
  1784. X          {
  1785. X             /* no, the text descriptors will not fit on the screen;
  1786. X              * but we want them read in from now on anyway
  1787. X              */
  1788. X
  1789. X             args.text = SLOT_OVF;
  1790. X          }
  1791. X           }
  1792. X
  1793. X           /* text descriptors have NOT been read in for the current dir-
  1794. X        * ectory; first we must see if the text descriptor file exists;
  1795. X        * if it is there, we will use it; if not, we will ask if they
  1796. X        * want to create one
  1797. X        */
  1798. X
  1799. X           text_flag = args.text;
  1800. X
  1801. X           temp = read_text_des(dirptr,&curr_pool,&dir_text,pool_length,
  1802. X                    num_file);
  1803. X
  1804. X           if(temp == NO_FILE)
  1805. X           {
  1806. X          /* the text descriptor file does not exist; ask the user if
  1807. X           * it should be created
  1808. X           */
  1809. X
  1810. X          temp = create_text(main_win);
  1811. X           }
  1812. X
  1813. X           switch(temp)        /* what happened with the file?          */
  1814. X           {
  1815. X          case(NEW_FILE):    /* new text descriptor file?          */
  1816. X
  1817. X             /* ask the user if the commands should be executed
  1818. X              * before rebuilding things
  1819. X              */
  1820. X
  1821. X             if(check_marks(dirptr,num_file) == TRUE)
  1822. X             {
  1823. X            info_mess("Commands will be wiped out.  eXecute them?\
  1824. X [y] ");
  1825. X
  1826. X            term_code = wgetch(main_win);
  1827. X            clear_mess(main_win);
  1828. X
  1829. X            if(term_code != 'N' && term_code != 'n')
  1830. X            {
  1831. X               /* execute the stuff first */
  1832. X
  1833. X               /* make sure we don't try to create a text descriptor
  1834. X                * file before eXecuting the commands
  1835. X                */                                 
  1836. X
  1837. X               xecute(dirptr,dir_text,num_file);
  1838. X            }
  1839. X            else
  1840. X               free_comm(dirptr,num_file);
  1841. X             }
  1842. X
  1843. X             /* free up the memory pools first */
  1844. X
  1845. X             free_pool(first_pool);
  1846. X             unlink_dir_ent(dir_ent_ptr);
  1847. X             /* now free up the memory for the directory info */
  1848. X
  1849. X             free((char *) dirptr);
  1850. X
  1851. X             --level;        /* don't count this level anymore     */
  1852. X
  1853. X             /* return here and force the routine to be called
  1854. X              * again; this makes the function epilogue (don't
  1855. X              * you just love those programming language terms?)
  1856. X              * do all of the work by allocating and initializing
  1857. X              * all of the automatic variables; this is a neat
  1858. X              * way to take advantage of the recursive structure
  1859. X              * we have set up for ourselves because all of the
  1860. X              * code to reinitialize a directory does not have
  1861. X              * to be duplicated
  1862. X              */
  1863. X
  1864. X             return(RECALL_PROC);
  1865. X
  1866. X          case(SUCCESS):    /* text descriptors read in ok?          */
  1867. X
  1868. X             /* the text descriptors were read in ok; now rebuild the
  1869. X              * nodes for the directory and remake the screen
  1870. X              */
  1871. X
  1872. X             text_flag = args.text;
  1873. X             set_screen(&num_screen,&scr_file,num_file,slot_width,
  1874. X                node_row_max,&num_col);
  1875. X             num_slot = scr_file;
  1876. X             set_nodes(nodes,node_row_max,&scr_file,num_screen,
  1877. X                   curr_screen,num_file,slot_width,num_col);
  1878. X             put_spec(spec_win,dir_name,home_dir,home_len,num_screen);
  1879. X             put_text(spec_win,dir_text);
  1880. X
  1881. X             /* we have to look for the file that was being point to
  1882. X              * when the Text command was done and determine what page
  1883. X              * it is on; we might have to change the current page and
  1884. X              * everything just to put the cursor back in the right spot
  1885. X              */
  1886. X
  1887. X             screen_reset(nodes,dirptr,entptr->filename,&node_row,
  1888. X                  &node_col,&scr_file,&curr_screen,
  1889. X                  node_row_max,num_file,num_slot,num_screen,
  1890. X                  slot_width,num_row,num_col);
  1891. X
  1892. X             /* put the page number on the screen again, just in case
  1893. X              * it might have changed
  1894. X              */
  1895. X
  1896. X             put_pagnum(spec_win,curr_screen,num_screen);
  1897. X
  1898. X             /* clear the screen to make sure we don't have any
  1899. X              * any garbage left over when we put the text des-
  1900. X              * criptors on the screen
  1901. X              */
  1902. X
  1903. X             werase(main_win);
  1904. X
  1905. X             /* remake the virtual display now that it is clear */
  1906. X
  1907. X             make_screen(main_win,nodes,dirptr,&args,curr_screen,
  1908. X                 node_row_max,node_col_max,scr_file,
  1909. X                 num_slot,slot_width,text_flag);
  1910. X
  1911. X             /* reset the screen cursor values */
  1912. X
  1913. X             scr_row = (int) nodes[node_row][node_col].row;
  1914. X             scr_col = (int) nodes[node_row][node_col].column;
  1915. X
  1916. X             /* make the sure pool length is set properly */
  1917. X
  1918. X             pool_length = (num_file + 1) * ent_factor;
  1919. X             cursor_flag++;    /* reset the cursor              */
  1920. X             break;
  1921. X
  1922. X          case(BAD_FILE):
  1923. X
  1924. X             /* bad format for text descriptor file */
  1925. X
  1926. X             info_mess("Invalid format for text descriptor file");
  1927. X             beep();
  1928. X
  1929. X             /* reset the slot width */
  1930. X
  1931. X             slot_width = save_width;
  1932. X             text_flag = 0;
  1933. X             mess_flag++;
  1934. X             break;
  1935. X
  1936. X          case(CANT_OPEN):
  1937. X
  1938. X             beep();
  1939. X             info_mess("Cannot open text descriptor file");
  1940. X
  1941. X             /* reset the slot width */
  1942. X
  1943. X             slot_width = save_width;
  1944. X             text_flag = 0;
  1945. X             mess_flag++;
  1946. X             break;
  1947. X
  1948. X          case(DONT_CREATE):
  1949. X          default:
  1950. X
  1951. X             /* reset the slot width */
  1952. X
  1953. X             slot_width = save_width;
  1954. X             text_flag = 0;
  1955. X             break;
  1956. X           }
  1957. X        }
  1958. X        else
  1959. X        {
  1960. X           /* the text descriptors have already been read in; get the
  1961. X        * text descriptor for the selected file and store it in a
  1962. X        * memory pool
  1963. X        */
  1964. X
  1965. X           /* first get the entry pointer for the file indicated */
  1966. X
  1967. X           entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  1968. X            (node_col * num_row) + node_row;
  1969. X
  1970. X           tag_file(main_win,scr_row,scr_col);
  1971. X
  1972. X           /* get the text descriptor and mark the file */
  1973. X
  1974. X           temp = mark_text(main_win,entptr,NULL,FALSE);
  1975. X
  1976. X           if(temp != SUCCESS)    /* did everything go ok?          */
  1977. X           {
  1978. X          beep();
  1979. X          info_mess("Invalid text descriptor");
  1980. X          mess_flag++;
  1981. X           }
  1982. X           else
  1983. X           {
  1984. X          /* highlite the file slot */
  1985. X
  1986. X          highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  1987. X               slot_width,text_flag);
  1988. X              prev_ptr = entptr;    /* save in case user wants to repeat  */
  1989. X          prev_command = TEXT;
  1990. X           }
  1991. X
  1992. X           erase_tag(main_win,scr_row,scr_col);
  1993. X        }
  1994. X
  1995. X        cursor_flag++;        /* reset the cursor down below          */
  1996. X        break;
  1997. X
  1998. X     case('.'):            /**************************************/
  1999. X                    /*            Repeat              */
  2000. X                     /**************************************/
  2001. X
  2002. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  2003. X             (node_col * num_row) + node_row;
  2004. X
  2005. X        if(prev_ptr != NULL)
  2006. X        {
  2007. X           mark_repeat(main_win,entptr,prev_ptr,prev_command);
  2008. X           highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  2009. X            slot_width,text_flag);
  2010. X        }
  2011. X        else
  2012. X        {
  2013. X           beep();
  2014. X           info_mess("No previous command");
  2015. X           mess_flag++;
  2016. X        }
  2017. X
  2018. X        cursor_flag++;
  2019. X        break;
  2020. X
  2021. X     case('Q'):            /**************************************/
  2022. X     case('q'):            /*               Quit              */
  2023. X                     /**************************************/
  2024. X
  2025. X        /* check for marked files first; if some are marked, ask the user
  2026. X         * if Quitting is the right thing to do
  2027. X         */
  2028. X
  2029. X        for(temp = 0,status = FALSE; temp < level && status == FALSE;
  2030. X        temp++)
  2031. X           status = check_marks(dirmem[temp].ptr,dirmem[temp].num_file);
  2032. X
  2033. X        if(status == TRUE && term_code == 'q')
  2034. X        {
  2035. X           info_mess("There are commands in this directory.  Execute them before quitting? [y] ");
  2036. X
  2037. X           term_code = wgetch(main_win);
  2038. X           clear_mess(main_win);
  2039. X           cursor_flag++;
  2040. X
  2041. X           if(term_code != 'N' && term_code != 'n')
  2042. X          xecute(dirptr,dir_text,num_file);
  2043. X        }
  2044. X
  2045. X        clean_up();
  2046. X        exit(0);            /* now we can exit              */
  2047. X
  2048. X        break;
  2049. X                                    
  2050. X       case('!'):            /**************************************/
  2051. X                    /*           Shell escape          */
  2052. X                     /**************************************/
  2053. X
  2054. X        /* clear out the options line so we can jump to the shell
  2055. X         * a little cleaner
  2056. X         */
  2057. X
  2058. X        wmove(stat_win,STAT_WINDOW_ROWS - 1,0);
  2059. X        wclrtoeol(stat_win);
  2060. X        wrefresh(stat_win);
  2061. X
  2062. X        if(spawn() == FAILURE)    /* fork the shell              */
  2063. X           info_mess("Cannot fork");
  2064. X
  2065. X        /* refresh the screen */
  2066. X
  2067. X        put_options(stat_win);
  2068. X        touchwin(main_win);
  2069. X        touchwin(spec_win);
  2070. X        wrefresh(main_win);
  2071. X        wrefresh(spec_win);
  2072. X        wrefresh(stat_win);
  2073. X        cursor_flag++;
  2074. X        break;
  2075. X
  2076. X     case(CONTROL_W):        /**************************************/
  2077. X     case(CONTROL_L):        /*           repaint screen          */
  2078. X                    /**************************************/
  2079. X
  2080. X        touchwin(spec_win);
  2081. X        touchwin(main_win);
  2082. X        touchwin(stat_win);
  2083. X        wnoutrefresh(spec_win);
  2084. X        wnoutrefresh(main_win);
  2085. X        wnoutrefresh(stat_win);
  2086. X        doupdate();
  2087. X        cursor_flag++;
  2088. X        break;
  2089. X
  2090. X     case(CONTROL_G):        /**************************************/
  2091. X                    /*                Goto              */
  2092. X                    /**************************************/
  2093. X
  2094. X        /* ask for a new screen number */
  2095. X
  2096. X        temp = get_scr_num(main_win,curr_screen,num_screen);
  2097. X
  2098. X        if(temp == BAD_SCREEN_NO)    /* was it a bad screen number?          */
  2099. X        {
  2100. X           beep();
  2101. X           info_mess("Invalid page number");
  2102. X           mess_flag++;
  2103. X        }
  2104. X        else
  2105. X        {
  2106. X           /* was the page number specified different from the
  2107. X        * current one?  If not, don't do anything
  2108. X        */
  2109. X
  2110. X           if(curr_screen != temp)
  2111. X           {
  2112. X          /* the page number specified was valid; set up the new page */
  2113. X
  2114. X          curr_screen = temp;    /* store the new current screen          */
  2115. X
  2116. X          /* update the screen nodes array */
  2117. X
  2118. X          set_nodes(nodes,node_row_max,&scr_file,num_screen,
  2119. X                curr_screen,num_file,slot_width,num_col);
  2120. X
  2121. X          /* update the page number in the corner */
  2122. X
  2123. X          put_pagnum(spec_win,curr_screen,num_screen);
  2124. X
  2125. X          /* remake the screen to reflect the new screen specified */
  2126. X
  2127. X          make_screen(main_win,nodes,dirptr,&args,curr_screen,
  2128. X                  node_row_max,node_col_max,scr_file,num_slot,
  2129. X                  slot_width,text_flag);
  2130. X
  2131. X          /* reset the screen and node pointers */
  2132. X
  2133. X          node_row = 0;
  2134. X          node_col = 0;
  2135. X          scr_row = (int) nodes[0][0].row;
  2136. X          scr_col = (int) nodes[0][0].column;
  2137. X           }
  2138. X        }
  2139. X
  2140. X        cursor_flag++;        /* set the cursor              */
  2141. X        break;
  2142. X
  2143. X     case('o'):            /**************************************/
  2144. X                    /*             Owner              */
  2145. X                    /**************************************/
  2146. X
  2147. X#if !defined(SYSV) || defined(sun)
  2148. X        if(geteuid() != 0)
  2149. X        {
  2150. X           beep();
  2151. X           info_mess("Only the superuser can use the Owner command");
  2152. X           mess_flag++;
  2153. X           cursor_flag++;
  2154. X           break;
  2155. X        }
  2156. X#endif
  2157. X
  2158. X        /* change the owner of a file */
  2159. X
  2160. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  2161. X             (node_col * num_row) + node_row;
  2162. X
  2163. X        tag_file(main_win,scr_row,scr_col);
  2164. X
  2165. X        temp = mark_owner(main_win,entptr,0,FALSE);
  2166. X
  2167. X        if(temp == SUCCESS)
  2168. X        {
  2169. X           /* highlite the file slot */
  2170. X
  2171. X           highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  2172. X                slot_width,text_flag);
  2173. X           prev_ptr = entptr;    /* save in case user wants to repeat  */
  2174. X           prev_command = OWNER;
  2175. X        }
  2176. X        else if(temp == BAD_OWNER)
  2177. X        {
  2178. X               info_mess("Invalid owner specified");
  2179. X           beep();
  2180. X           mess_flag++;
  2181. X        }
  2182. X
  2183. X        erase_tag(main_win,scr_row,scr_col);
  2184. X        cursor_flag++;        /* reset the cursor down below          */
  2185. X        break;
  2186. X
  2187. X
  2188. X     case('G'):            /**************************************/
  2189. X     case('g'):            /*             Group              */
  2190. X                    /**************************************/
  2191. X
  2192. X        /* change the group of a file */
  2193. X
  2194. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  2195. X             (node_col * num_row) + node_row;
  2196. X
  2197. X        tag_file(main_win,scr_row,scr_col);
  2198. X
  2199. X        temp = mark_group(main_win,entptr,0,FALSE);
  2200. X
  2201. X        if(temp == SUCCESS)
  2202. X        {
  2203. X           /* highlite the file slot */
  2204. X
  2205. X           highlite(main_win,slot_buf,entptr,&args,scr_row,scr_col+1,
  2206. X                slot_width,text_flag);
  2207. X           prev_ptr = entptr;    /* save in case user wants to repeat  */
  2208. X           prev_command = GROUP;
  2209. X        }
  2210. X        else if(temp == BAD_GROUP)
  2211. X        {
  2212. X               info_mess("Invalid group specified");
  2213. X           beep();
  2214. X           mess_flag++;
  2215. X        }
  2216. X
  2217. X        erase_tag(main_win,scr_row,scr_col);
  2218. X        cursor_flag++;        /* reset the cursor down below          */
  2219. X        break;
  2220. X
  2221. X     case('O'):            /**************************************/
  2222. X                    /*           Options              */
  2223. X                    /**************************************/
  2224. X
  2225. X        /* first get the entry pointer for the current file */
  2226. X                      
  2227. X        entptr = dirptr + ((curr_screen - 1) * (num_row * num_col)) +
  2228. X             (node_col * num_row) + node_row;
  2229. X
  2230. X        temp = config_options(&args);
  2231. X
  2232. X        /* reinitialize the global factors */
  2233. X
  2234. X        set_args(&args,&def_slot_wid,&ent_factor);
  2235. X
  2236. X        /* slot width has probably changed */
  2237. X
  2238. X        slot_width = def_slot_wid;
  2239. X
  2240. X        if(temp & REBUILD_DIRECTORY)
  2241. X        {
  2242. X           /* ask the user if the commands should be executed
  2243. X        * before rebuilding things
  2244. X        */
  2245. X
  2246. X           if(check_marks(dirptr,num_file) == TRUE)
  2247. X           {
  2248. X          touchwin(main_win);
  2249. X          wnoutrefresh(main_win);
  2250. X          doupdate();
  2251. X          info_mess("Commands will be wiped out.  eXecute them? [y] ");
  2252. X          term_code = wgetch(main_win);
  2253. X          clear_mess(main_win);
  2254. X
  2255. X          if(term_code != 'N' && term_code != 'n')
  2256. X          {
  2257. X             /* execute the stuff first */
  2258. X
  2259. X             xecute(dirptr,dir_text,num_file);
  2260. X          }
  2261. X          else
  2262. X             free_comm(dirptr,num_file);
  2263. X           }
  2264. X
  2265. X           /* refresh the stat window because we overwrote it */
  2266. X
  2267. X           touchwin(stat_win);
  2268. X           wrefresh(stat_win);
  2269. X
  2270. X           /* free up the memory pools first */
  2271. X
  2272. X           free_pool(first_pool);
  2273. X           unlink_dir_ent(dir_ent_ptr);
  2274. X
  2275. X           /* now free up the memory for the directory info */
  2276. X
  2277. X           free((char *) dirptr);
  2278. X
  2279. X           --level;            /* don't count this level anymore     */
  2280. X
  2281. X           return(RECALL_PROC);    /* recall proc_dir() to rebuild       */
  2282. X        }
  2283. X
  2284. X        if(temp & REBUILD_SCREEN)
  2285. X        {
  2286. X           if(temp & REBUILD_WITH_FILEMARKS)
  2287. X           {
  2288. X          get_filemarks(dirptr,num_file);
  2289. X          filemarks_flag = args.filemarks;
  2290. X           }
  2291. X
  2292. X           if(temp & REBUILD_WITH_SORT)
  2293. X           {
  2294. X          tptr = entptr->filename;
  2295. X          sort_files(num_file - 1,args.sort);
  2296. X          sort_flag = args.sort;
  2297. X           }
  2298. X
  2299. X           if(text_flag && !args.text)
  2300. X           {
  2301. X          /* text descriptors were turned off; make sure that we
  2302. X           * wipe out any directory text descriptor
  2303. X           */
  2304. X
  2305. X          put_text(spec_win,NULL);
  2306. X          text_flag = 0;
  2307. X           }
  2308. X
  2309. X           get_text(&args,dirptr,&curr_pool,&dir_text,&mess_flag,
  2310. X            &slot_width,&text_flag,pool_length,num_file);
  2311. X
  2312. X           /* reinitialize the screen parameters */
  2313. X
  2314. X           set_screen(&num_screen,&scr_file,num_file,slot_width,
  2315. X              node_row_max,&num_col);
  2316. X
  2317. X           num_slot = scr_file;    /* save number of slots per screen    */
  2318. X
  2319. X           /* search for the filename of the file we were on so we can
  2320. X        * go back to it; we might as well do this every time, es-
  2321. X        * pecially since the search for it is fast (we're only
  2322. X        * comparing pointer values instead of strings
  2323. X        */
  2324. X
  2325. X           temp = (short) file_ptr_search(dirptr,tptr,num_file);
  2326. X
  2327. X           if(temp >= 0)
  2328. X           {
  2329. X          /* file was found; recompute the node indexes so that we
  2330. X           * can change the cursor on the screen
  2331. X           */
  2332. X
  2333. X          new_screen = (temp / num_slot) + 1;
  2334. X
  2335. X          /* get us to the current screen */
  2336. X
  2337. X          temp2 = temp - ((new_screen - 1) * num_slot);
  2338. X          node_col = temp2 / num_row;
  2339. X          node_row = temp % num_row;
  2340. X          curr_screen = new_screen;
  2341. X           }
  2342. X
  2343. X           /* create the new screen by first putting the new page
  2344. X        * number in the upper-right and then rebuilding the
  2345. X        * main display
  2346. X        */
  2347. X
  2348. X           put_pagnum(spec_win,curr_screen,num_screen);
  2349. X
  2350. X           set_nodes(nodes,node_row_max,&scr_file,num_screen,new_screen,
  2351. X             num_file,slot_width,num_col);
  2352. X
  2353. X           if(args.text)        /* write text descrip for directory?  */
  2354. X          put_text(spec_win,dir_text);
  2355. X
  2356. X           werase(main_win);    /* make sure we start clean          */
  2357. X
  2358. X           /* display the current screen */
  2359. X             
  2360. X           make_screen(main_win,nodes,dirptr,&args,curr_screen,
  2361. X               node_row_max,node_col_max,scr_file,num_slot,
  2362. X               slot_width,text_flag);
  2363. X
  2364. X           /* get the cursor coordinates so we can reset it */
  2365. X
  2366. X           scr_row = (int) nodes[node_row][node_col].row;
  2367. X           scr_col = (int) nodes[node_row][node_col].column;
  2368. X        }
  2369. X
  2370. X        put_stat(stat_win,num_block,num_file);
  2371. X        put_options(stat_win);
  2372. X        touchwin(stat_win);
  2373. X        touchwin(main_win);
  2374. X        wnoutrefresh(main_win);
  2375. X        wnoutrefresh(stat_win);
  2376. X        doupdate();
  2377. X        cursor_flag++;
  2378. X        break;
  2379. X
  2380. X     case(0):            /**************************************/
  2381. X                          /*        something weird  :-C          */
  2382. X                    /**************************************/
  2383. X        break;
  2384. X
  2385. X     default:            /**************************************/
  2386. X                    /*            all others          */
  2387. X                         /**************************************/
  2388. X
  2389. X        /* scream at the user (ring the bell) */
  2390. X
  2391. X        beep();
  2392. X        break;
  2393. X
  2394. X      } /* switch(term_code) */
  2395. X
  2396. X      /* do we need reposition the cursor? */
  2397. X
  2398. X      if(cursor_flag)
  2399. X      {
  2400. X     /* set the cursor where it should be */
  2401. X
  2402. X     wmove(main_win,scr_row,scr_col);
  2403. X     wrefresh(main_win);        /* make sure screen is up to date     */
  2404. X     cursor_flag = 0;        /* clear the cursor set flag          */
  2405. X      }
  2406. X
  2407. X   } /* for(;;) */            /* end of main processing loop          */
  2408. X
  2409. X}    /*** proc_dir ***/
  2410. X
  2411. X/*******************************************************************************
  2412. X********************************************************************************
  2413. X
  2414. X  Function:    find_dir
  2415. X
  2416. X  Purpose:    Search for a directory info node in the link list.  If one
  2417. X        is found, it means that the directory is currently active.
  2418. X
  2419. X  Global variables:
  2420. X
  2421. X    Name            Examine/Modify/Use/Read/Write
  2422. X    ----            -----------------------------
  2423. X    none
  2424. X
  2425. X  Return Codes:
  2426. X
  2427. X    Code            Reason
  2428. X    ----            ------
  2429. X    none
  2430. X
  2431. X********************************************************************************
  2432. X*******************************************************************************/
  2433. X
  2434. static DIR_PTR *find_dir(head,tail,dir_name)
  2435. X                    /*******   FORMAL  PARAMETERS   *******/
  2436. X     DIR_PTR  *head,        /* pointer to head of dir info nodes  */
  2437. X          *tail;        /* pointer to end of dir info nodes   */
  2438. X     char      *dir_name;        /* directory name to search for          */
  2439. X
  2440. X{    /*** find_dir ***/
  2441. X
  2442. X   head = head->next;
  2443. X
  2444. X   while(head != tail && strcmp(head->dir_name,dir_name) != 0)
  2445. X      head = head->next;
  2446. X
  2447. X   if(head == tail)
  2448. X      return(NULL);
  2449. X
  2450. X   return(head);
  2451. X
  2452. X}    /*** find_dir ***/
  2453. X
  2454. X/*******************************************************************************
  2455. X********************************************************************************
  2456. X
  2457. X  Function:    link_dir_ent
  2458. X
  2459. X  Purpose:    Link the info for the current directory into the active
  2460. X        directory linked list.
  2461. X
  2462. X  Global variables:
  2463. X
  2464. X    Name            Examine/Modify/Use/Read/Write
  2465. X    ----            -----------------------------
  2466. X    none
  2467. X
  2468. X  Return Codes:
  2469. X
  2470. X    Code            Reason
  2471. X    ----            ------
  2472. X    temp_ptr        pointer to new node
  2473. X    NULL            couldn't get memory for node
  2474. X
  2475. X********************************************************************************
  2476. X*******************************************************************************/
  2477. X
  2478. static DIR_PTR *link_dir_ent(dir_ent_head,dir_ent_tail,dirptr,dir_name,
  2479. X                 first_pool,curr_pool,pool_length,stat_time,
  2480. X                 num_file)
  2481. X                    /*******   FORMAL  PARAMETERS   *******/
  2482. X     DIR_PTR  *dir_ent_head,    /* head of directory chain list          */
  2483. X          *dir_ent_tail;    /* tail of directory chain list          */
  2484. X     ENT_DEF  *dirptr;        /* pointer to directory information   */
  2485. X     char      *dir_name;        /* name of current directory          */
  2486. X     POOL_DEF *first_pool,        /* first memory pool for directory    */
  2487. X          *curr_pool;        /* current memory pool              */
  2488. X     size_t      pool_length;        /* length to allocate for new pool    */
  2489. X     time_t      stat_time;        /* time directory was last modified   */
  2490. X     short      num_file;        /* number of files in directory          */
  2491. X
  2492. X{    /*** link_dir_ent ***/
  2493. X                    /********   LOCAL  VARIABLES   ********/
  2494. X     DIR_PTR  *new_ptr,        /* new node pointer              */          *temp_ptr;        /* previous node in list          */
  2495. X
  2496. X
  2497. X   /* allocate the node first */
  2498. X
  2499. X   new_ptr = (DIR_PTR *) malloc(sizeof(DIR_PTR));
  2500. X
  2501. X   if(new_ptr == NULL)
  2502. X      return(NULL);            /* couldn't get the memory          */
  2503. X
  2504. X   /* got the memory for the node; link it in */
  2505. X
  2506. X   temp_ptr = dir_ent_tail->prev;    /* save where we were              */
  2507. X   dir_ent_tail->prev = new_ptr;
  2508. X   new_ptr->next = dir_ent_tail;
  2509. X   temp_ptr->next = new_ptr;
  2510. X   new_ptr->prev = temp_ptr;
  2511. X
  2512. X   new_ptr->dirptr = dirptr;
  2513. X   new_ptr->dir_name = dir_name;
  2514. X   new_ptr->first_pool = first_pool;
  2515. X   new_ptr->curr_pool = curr_pool;
  2516. X   new_ptr->pool_length = pool_length;
  2517. X   new_ptr->num_file = num_file;
  2518. X   new_ptr->stat_time = stat_time;
  2519. X   new_ptr->count = 1;            /* first time here              */
  2520. X
  2521. X   return(new_ptr);            /* return pointer to new node          */
  2522. X
  2523. X}    /*** link_dir_ent ***/
  2524. X
  2525. X/*******************************************************************************
  2526. X********************************************************************************
  2527. X
  2528. X  Function:    unlink_dir_ent
  2529. X
  2530. X  Purpose:    Unlink the info for the current directory from the active
  2531. X        directory linked list.
  2532. X
  2533. X  Global variables:
  2534. X
  2535. X    Name            Examine/Modify/Use/Read/Write
  2536. X    ----            -----------------------------
  2537. X    none
  2538. X
  2539. X  Return Codes:
  2540. X
  2541. X    Code            Reason
  2542. X    ----            ------
  2543. X    none
  2544. X
  2545. X********************************************************************************
  2546. X*******************************************************************************/
  2547. X
  2548. static void unlink_dir_ent(current)
  2549. X                    /*******   FORMAL  PARAMETERS   *******/
  2550. X     DIR_PTR  *current;        /* active directory list node          */
  2551. X
  2552. X{    /*** unlink_dir_ent ***/
  2553. X                    /********   LOCAL  VARIABLES   ********/
  2554. X     DIR_PTR  *temp;        /* temporary node pointer          */
  2555. X
  2556. X
  2557. X   if(current->count > 1)        /* can we unlink it?              */
  2558. X   {
  2559. X      current->count -= 1;
  2560. X      return;                /* nope, still active              */
  2561. X   }
  2562. X
  2563. X   temp = current->prev;
  2564. X   temp->next = current->next;
  2565. X   temp = current->next;
  2566. X   temp->prev = current->prev;
  2567. X   free(current->dir_name);        /* free up directory name string      */
  2568. X   free(current);            /* free up the node itself          */
  2569. X
  2570. X   return;
  2571. X
  2572. X}    /*** unlink_dir_ent ***/
  2573. X
  2574. X/*******************************************************************************
  2575. X********************************************************************************
  2576. X
  2577. X  Function:    get_year
  2578. X
  2579. X  Purpose:    Obtain and return the value for the current year.
  2580. X
  2581. X  Global variables:
  2582. X
  2583. X    Name            Examine/Modify/Use/Read/Write
  2584. X    ----            -----------------------------
  2585. X    none
  2586. X
  2587. X  Return Codes:
  2588. X
  2589. X    Code            Reason
  2590. X    ----            ------
  2591. X    tstr->tm_year        current year value
  2592. X
  2593. X********************************************************************************
  2594. X*******************************************************************************/
  2595. X
  2596. static int get_year()
  2597. X
  2598. X{    /*** get_year ***/
  2599. X                    /********   LOCAL  VARIABLES   ********/
  2600. X     long      clock;        /* binary time value              */
  2601. struct     tm      *tstr;        /* time structure pointer          */
  2602. X
  2603. X
  2604. X   clock = (long) time((long *) 0);    /* get current time              */
  2605. X   tstr = localtime(&clock);        /* fill in the time structure          */
  2606. X   return(tstr->tm_year);        /* return the current year value      */
  2607. X
  2608. X}    /*** get_year ***/
  2609. END_OF_FILE
  2610. if test 78195 -ne `wc -c <'main.c'`; then
  2611.     echo shar: \"'main.c'\" unpacked with wrong size!
  2612. fi
  2613. # end of 'main.c'
  2614. fi
  2615. echo shar: End of archive 7 \(of 7\).
  2616. cp /dev/null ark7isdone
  2617. MISSING=""
  2618. for I in 1 2 3 4 5 6 7 ; do
  2619.     if test ! -f ark${I}isdone ; then
  2620.     MISSING="${MISSING} ${I}"
  2621.     fi
  2622. done
  2623. if test "${MISSING}" = "" ; then
  2624.     echo You have unpacked all 7 archives.
  2625.     rm -f ark[1-9]isdone
  2626. else
  2627.     echo You still need to unpack the following archives:
  2628.     echo "        " ${MISSING}
  2629. fi
  2630. ##  End of shell archive.
  2631. exit 0
  2632.