home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / utree / part08 < prev    next >
Encoding:
Text File  |  1992-09-06  |  65.5 KB  |  2,412 lines

  1. Newsgroups: comp.sources.unix
  2. From: klin@iat.uni-paderborn.de (Peter Klingebiel)
  3. Subject: v26i071: utree - screen oriented filesystem utility (V3.03b-um), Part08/08
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: klin@iat.uni-paderborn.de (Peter Klingebiel)
  8. Posting-Number: Volume 26, Issue 71
  9. Archive-Name: utree/part08
  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 8 (of 8)."
  18. # Contents:  src/tree.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Mon Sep  7 14:39:58 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'src/tree.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'src/tree.c'\"
  23. else
  24. echo shar: Extracting \"'src/tree.c'\" \(63122 characters\)
  25. sed "s/^X//" >'src/tree.c' <<'END_OF_FILE'
  26. X/*
  27. X *      TREE.C
  28. X *      UTREE tree menu routines.
  29. X *      3.01-um klin, Tue Jun  4 14:19:16 1991
  30. X *              klin, Tue Oct 15 14:02:37 1991, Handling of symlinks changed
  31. X *              klin, Sat Oct 26 15:07:06 1991, Tagging files changed
  32. X *                                              Sorting and zooming changed
  33. X *                                              Select directories added
  34. X *                                              Print tree list added
  35. X *                                              More local functions
  36. X *      3.02-um klin, Fri Nov  1 10:46:14 1991, Screen layout changed
  37. X *                                              Goto parent added
  38. X *              klin, Sun Nov 24 19:30:43 1991, Cd to current directory before
  39. X *                                              executing some commands
  40. X *                                              Video attributes changed
  41. X *      3.03-um klin, Tue Feb 11 22:58:03 1992, Screen layout changed
  42. X *                                              Shell escape, variables and
  43. X *                                              filetype commands changed
  44. X *              klin, Sat Feb 15 14:44:52 1992, Video handling and partinioning of
  45. X *                                              directory and file windows changed
  46. X *              klin, Sat Feb 22 10:34:03 1992, Many commands changed to work
  47. X *                                              on current directory or subtree
  48. X *                                              or tagged files
  49. X *              klin, Sun Feb 23 17:32:57 1992, Key handling and key bindings
  50. X *                                              changed
  51. X *                                              No removing of subtrees
  52. X *            a klin, Sun Mar 15 19:08:25 1992, Bug fix in gotree()
  53. X *
  54. X *      Copyright (c) 1991/92 by Peter Klingebiel & UNIX Magazin Muenchen.
  55. X *      For copying and distribution information see the file COPYRIGHT.
  56. X */
  57. X#ifndef lint
  58. static char sccsid[] = "@(#) utree 3.03a-um (klin) Mrz 15 1992 tree.c";
  59. X#endif  /* !lint */
  60. X
  61. X#include "defs.h"
  62. X
  63. X/* ---- Local variables and definitions ------------------------------- */
  64. X
  65. LOCAL dlist *tdlist = DNULL;    /* Top dlist on tree screen             */
  66. LOCAL dlist *mdlist = DNULL;    /* Marked dlist entry                   */
  67. LOCAL dlist *tdlast = DNULL;    /* Last tdlist                          */
  68. LOCAL dlist *cdlast = DNULL;    /* Last current dlist entry             */
  69. LOCAL char  *mustup = "Tree must be updated. Continue ?";
  70. LOCAL char  *cancel = "(Hit BREAK to abort)";
  71. X
  72. X/* Tree menu commands in help line                                      */
  73. LOCAL char *tmline =
  74. X" Help Backup Chdir Find Grep Info List Mkdir Out Rmdir Stat Tag Untag Quit";
  75. LOCAL char *menuline = NULL;
  76. X
  77. X#define BCOL    0               /* Column for tree position bar         */
  78. X#define SCOL    1               /* Column for tag or mark sign          */
  79. X#define TCOL    2               /* Startcolumn for directory tree       */
  80. X#define UCOL    -1              /* Column for number of files unknown   */
  81. X#define FCOL    -5              /* Column for number of files           */
  82. X#define SLIN    (lastdline+1)   /* Line for separator line              */
  83. X#define NFFMT   "%5d"           /* Format for number of files           */
  84. X
  85. X#define ONTR(c) ((c) < 'a')     /* Command works on subtree             */
  86. X#define ONTG(c) ((c) < 'a')     /* Command works on tagged files        */
  87. X
  88. X/* ---- External variables and functions ------------------------------ */
  89. X
  90. XEXTRN FILE *popen();
  91. XEXTRN char *writedlist();
  92. XEXTRN char *selectdir();
  93. LOCAL char *dirselect();
  94. X
  95. X/* ---- Functions and procedures -------------------------------------- */
  96. X
  97. X/*
  98. X *      TREE DISPLAY ROUTINES
  99. X */
  100. X
  101. X/* Display files of current directory in file window starting at line l */
  102. LOCAL VOID showflist(l)
  103. X  register int l;
  104. X{
  105. X  register int f, i;
  106. X
  107. X  if((f = (l - firstfline) * fperline) < CNFIL) {
  108. X    while(f < CNFIL && l++ <= lastfline)
  109. X      for(i = 0; f < CNFIL && i < fperline; f++, i++) {
  110. X       putfile(cdlist, f, 0);
  111. X       clearline();
  112. X      }
  113. X    if(l <= lastfline)
  114. X      clearwindow(l, lastfline);
  115. X  }
  116. X  else if(CNFIL == 0 && l == firstfline)
  117. X    clearwindow(l, lastfline);
  118. X
  119. X} /* showflist() */
  120. X
  121. X/* Display directory list entry dp */
  122. LOCAL VOID showdlist(dp, f)
  123. X  register dlist *dp;
  124. X  register int f;
  125. X{
  126. X  /* Is directory on screen? */
  127. X  if(dp && DTROW(dp) >= firstdline && DTROW(dp) <= lastdline) {
  128. X    /* Display directory tag marker */
  129. X    if(DNTAG(dp)) {
  130. X      (void) setgraphic(GC_ON);
  131. X      (void) putcxy(SCOL, DTROW(dp), GC_TG);
  132. X      (void) setgraphic(GC_OFF);
  133. X    }
  134. X    else
  135. X      (void) putcxy(SCOL, DTROW(dp), ' ');
  136. X    /* Display directory filename */
  137. X    if(f && dp == cdlist) {     /* Highlight current directory */
  138. X      if(CCANC) {
  139. X       setvideo(DA_BOLDREV);
  140. X       (void) putfxy(TCOL+DTCOL(dp)-1, DTROW(dp), 0, ">%s ", CFNAM);
  141. X      }
  142. X      else  {
  143. X       setvideo(DA_HALFREV);
  144. X       (void) putfxy(TCOL+DTCOL(dp)-1, DTROW(dp), 0, " %s ", CFNAM);
  145. X      }
  146. X    }
  147. X    else {                      /* Other directory */
  148. X      setvideo(DCANC(dp) ? DA_BOLD : DA_HALF);
  149. X      (void) putfxy(TCOL+DTCOL(dp)-1, DTROW(dp), 0, " %s ", DFNAM(dp));
  150. X    }
  151. X    /* Display number of files if known */
  152. X     setvideo(DA_NORMAL);
  153. X    if(DCANC(dp)) {
  154. X      if(DFLAG(dp) != FL_FIL)
  155. X       putcxy(UCOL, DTROW(dp), '?');
  156. X      else
  157. X       (void) putfxy(FCOL, DTROW(dp), 0, NFFMT, DNFIL(dp));
  158. X    }
  159. X    else
  160. X      putcxy(UCOL, DTROW(dp), '-');
  161. X  }
  162. X
  163. X} /* showdlist() */
  164. X
  165. X/* Display whole directory line for directory dp */
  166. LOCAL VOID showdline(dp)
  167. X  register dlist *dp;
  168. X{
  169. X  register int i, j;
  170. X
  171. X  /* Is directory on screen? */
  172. X  if(dp && DTROW(dp) >= firstdline && DTROW(dp) <= lastdline) {
  173. X    (void) cursorxy(TCOL, DTROW(dp));
  174. X    clearline();
  175. X    (void) setgraphic(GC_ON);
  176. X    if(dp == droot)             /* Root directory */
  177. X      (void) putchar(DNEXT(dp) ? GC_UL : GC_HB);
  178. X    else {                      /* Other directory */
  179. X      (void) putchar(DNEXT(dp) ? GC_VB : GC_LL);
  180. X      for(i = 1, j = DLEVL(dp) - 1; i < j; i++)
  181. X       if(DINFO(dp) & (1 << (i-1)))
  182. X         putcxy(TCOL+i*indent, DTROW(dp), GC_VB);
  183. X      if(DINFO(dp) & (1 << (i-1)))
  184. X       putcxy(TCOL+i*indent, DTROW(dp), GC_LT);
  185. X      else
  186. X       putcxy(TCOL+i*indent, DTROW(dp), GC_LL);
  187. X    }
  188. X    for(i = 2; i < indent; i++)
  189. X      (void) putchar(GC_HB);
  190. X    (void) setgraphic(GC_OFF);
  191. X    showdlist(dp, 0);           /* Display name */
  192. X  }
  193. X
  194. X} /* showdline() */
  195. X
  196. X/* Display the directory list from line f to line t */
  197. LOCAL VOID showdtree(f, t, c)
  198. X  register int f, t, c;
  199. X{
  200. X  register dlist *dp;
  201. X
  202. X  /* Search for first directory to print ... */
  203. X  for(dp = tdlist; dp && DTROW(dp) < f; dp = (dlist *) DNEXT(dp))
  204. X    ;
  205. X  /* ... and print out from f to t */
  206. X  for( ; dp && DTROW(dp) <= t; dp = (dlist *) DNEXT(dp))
  207. X    showdline(dp);
  208. X  /* Clear to end of tree window */
  209. X  if(c && dp && DTROW(dp) < lastdline)
  210. X    clearwindow(DTROW(dp), lastdline);
  211. X
  212. X} /* showdtree() */
  213. X
  214. X/* Display tree position bar */
  215. LOCAL VOID showtbar()
  216. X{
  217. X  static int bar = 0;
  218. X  register dlist *dp;
  219. X  register int f, l, i;
  220. X
  221. X  if(dircount > (ndlines + 1)) {      /* More dirs than lines */
  222. X    dp = tdlist;
  223. X    while(DNEXT(dp) && DTROW(dp) < lastdline)
  224. X      dp = (dlist *) DNEXT(dp);
  225. X    f = ((DDNUM(tdlist) + 1) * ndlines) / dircount + firstdline;
  226. X    l = ((DDNUM(dp)     + 1) * ndlines) / dircount + firstdline;
  227. X    if(f <= firstdline)
  228. X      f = DPREV(tdlist) ? firstdline + 1 : firstdline;
  229. X    if(l >= lastdline)
  230. X      l = DNEXT(dp)     ? lastdline  - 1 : lastdline;
  231. X    i = firstdline;
  232. X    while(i < f)
  233. X      putcxy(BCOL, i++, ' ');
  234. X    if(videomode && (videocap & VA_REVERSE)) {
  235. X      setvideo(DA_HALFREV);
  236. X      putcxy(BCOL, i++, ' ');
  237. X      while(i <= l)
  238. X       putcxy(BCOL, i++, ' ');
  239. X      setvideo(DA_NORMAL);
  240. X    }
  241. X    else {
  242. X      (void) setgraphic(GC_ON);
  243. X      putcxy(BCOL, i++, GC_TT);
  244. X      while(i < l)
  245. X       putcxy(BCOL, i++, GC_VB);
  246. X      putcxy(BCOL, i++, GC_BT);
  247. X      (void) setgraphic(GC_OFF);
  248. X    }
  249. X    while(i <= lastdline)
  250. X      putcxy(BCOL, i++, ' ');
  251. X    bar = 1;
  252. X  }
  253. X  else if(bar) {
  254. X    for(i = firstdline; i <= lastdline; i++)
  255. X      putcxy(BCOL, i, ' ');
  256. X    bar = 0;
  257. X  }
  258. X
  259. X} /* showtbar() */
  260. X
  261. X/* Display separator line between tree and file window */
  262. LOCAL VOID showsline()
  263. X{
  264. X  static int lb = 0;
  265. X  register dlist *dp;
  266. X  register char *cp, *cz;
  267. X  register int i, j;
  268. X
  269. X  cp = CPNAM + strlen(rootdir);
  270. X  cz = CZOOM ? CZOOM : "*";
  271. X  setvideo(DA_REVERSE);
  272. X  if(*cp)
  273. X    i = putfxy(0, SLIN, 0, ".%s/%s: %d file(s) %d dir(s)", cp, cz, CNFIL, CNDIR);
  274. X  else
  275. X    i = putfxy(0, SLIN, 0, "./%s: %d file(s) %d dir(s)", cz, CNFIL, CNDIR);
  276. X  while(i++ < columns)
  277. X    (void) putchar(' ');
  278. X  setvideo(DA_NORMAL);
  279. X
  280. X} /* showsline() */
  281. X
  282. X/*
  283. X *      TREE SCREEN UPDATE AND REFRESH
  284. X */
  285. X
  286. X/* Update tree screen */
  287. LOCAL int updatetree(f)
  288. X  register int f;
  289. X{
  290. X  register int n, rv;
  291. X
  292. X  if(treeflag & SF_LIST) {                      /* Check current directory */
  293. X    if((CFLAG != FL_FIL || changedlist(cdlist)) && newflist(cdlist) != RV_OK)
  294. X      return(RV_ERR);
  295. X  }
  296. X  rv = RV_OK;
  297. X  if(keypressed())                              /* There are chars in input buffer */
  298. X    return(rv);
  299. X  if(treeflag == SF_FULL) {                     /* Full screen update */
  300. X    clearscreen();
  301. X    cdlast = tdlast = DNULL;
  302. X  }
  303. X  if(treeflag & SF_TREE) {                      /* Tree screen */
  304. X    n = tdlast ? DDNUM(tdlast) - DDNUM(tdlist) : 0;
  305. X    if(CANSCROLL && n < 0 && n > -ndlines) {
  306. X      (void) windowup(firstdline, lastdline, -n);
  307. X      showdtree(lastdline + n + 1, lastdline, 0);
  308. X      showdlist(cdlast, 0);
  309. X    }
  310. X    else if(CANSCROLL && n > 0 && n < ndlines) {
  311. X      (void) windowdown(firstdline, lastdline, n);
  312. X      showdtree(firstdline, firstdline + n - 1, 0);
  313. X      showdlist(cdlast, 0);
  314. X    }
  315. X    else
  316. X      showdtree(firstdline, lastdline, treeflag != SF_FULL);
  317. X    treeflag |= SF_PBAR;
  318. X  }
  319. X  else if(treeflag & SF_LAST)                   /* Last directory */
  320. X    showdlist(cdlast, 0);
  321. X  if(treeflag & SF_PBAR)                        /* Tree position bar */
  322. X    showtbar();
  323. X  if(treeflag & SF_LIST) {                      /* Current directory */
  324. X    showdlist(cdlist, 1);
  325. X    showsline();
  326. X  }
  327. X  else if(treeflag & SF_SEPL)
  328. X    showsline();
  329. X  if(treeflag & SF_FILE)                        /* File list */
  330. X    showflist(firstfline);
  331. X  if(treeflag & SF_HELP && !f)                  /* Help line */
  332. X    putmenu("TREE:", menuline);
  333. X  if(treeflag & SF_ECHO && !f)                  /* Echo line */
  334. X    (void) putecho("%s: %d dir(s) %d file(s)", rootdir, dircount, filecount);
  335. X  /* Position to current directory, set variables and return */
  336. X  (void) cursorxy(TCOL+DTCOL(cdlist)-1, DTROW(cdlist));
  337. X  cdlast = cdlist;
  338. X  tdlast = tdlist;
  339. X  treeflag = 0;
  340. X  return(rv);
  341. X
  342. X} /* updatetree() */
  343. X
  344. X/*
  345. X *      SCROLL UP OR DOWN DIRECTORY TREE
  346. X */
  347. X
  348. X/* Scroll directory tree */
  349. LOCAL int scrolltree(dir)
  350. X  register int dir;
  351. X{
  352. X  register dlist *dp;
  353. X  register int i;
  354. X
  355. X  /* Is scrolling possible? */
  356. X  if((dir < 0 && DPREV(tdlist) == GNULL) || (dir > 0 && CNEXT == GNULL))
  357. X    return(0);
  358. X  if(dir < 0) {                 /* Scroll down */
  359. X    tdlist = (dlist *) DPREV(tdlist);
  360. X    if(CANSCROLL) {
  361. X      (void) windowdown(firstdline, lastdline, 1);
  362. X      showdline(tdlist);
  363. X      treeflag |= SF_MOVE|SF_PBAR;
  364. X    }
  365. X    else
  366. X      treeflag |= SF_TREE|SF_LIST|SF_PBAR;
  367. X  }
  368. X  else {                        /* Scroll up */
  369. X    for(dp = tdlist, i = ndlines; i >= 0 ; i--)
  370. X      if(((dp = (dlist *) DNEXT(dp))) == DNULL)
  371. X       return(0);
  372. X    tdlist =  (dlist *) DNEXT(tdlist);
  373. X    if(CANSCROLL) {
  374. X      (void) windowup(firstdline, lastdline, 1);
  375. X      for(dp = tdlist; DTROW(dp) < lastdline; dp = (dlist *) DNEXT(dp))
  376. X       ;
  377. X      showdline(dp);
  378. X      treeflag |= SF_MOVE|SF_PBAR;
  379. X    }
  380. X    else
  381. X      treeflag |= SF_TREE|SF_LIST|SF_PBAR;
  382. X  }
  383. X  if(DTROW(cdlist) < firstdline)        /* Change current directory */
  384. X    (void) gotree(1);                   /* if out of screen         */
  385. X  else if(DTROW(cdlist) > lastdline)
  386. X    (void) gotree(-1);
  387. X  return(1);
  388. X
  389. X} /* scrolltree() */
  390. X
  391. X/*
  392. X *      CHECK TREE
  393. X */
  394. X
  395. X/* Check if all directories in tree are unchanged or read in */
  396. LOCAL int checktree(msg)
  397. X  register char *msg;
  398. X{
  399. X  register dlist *dp;
  400. X  register int c;
  401. X
  402. X  if(VARSET(V_ST) && scandlist(cdlist) != RV_OK)
  403. X    return(RV_NUL);
  404. X  for(dp = (dlist *) CNEXT; dp && DLEVL(dp) > CLEVL; dp = (dlist *) DNEXT(dp)) {
  405. X    if(DFLAG(dp) != FL_FIL) {
  406. X      ++buildflag;
  407. X      bell(VARSET(V_BL));
  408. X      puthelp("%s (Y:continue  ELSE:quit)", who);
  409. X      c = hitakey(msg, echoline, DA_NONE);
  410. X      return(c == 'y' ? RV_OK : c);
  411. X    }
  412. X  }
  413. X  return(RV_OK);
  414. X
  415. X} /* checktree() */
  416. X
  417. X/*
  418. X *      TAG/UNTAG FILES IN TREE
  419. X */
  420. X
  421. X/* Tag files in directory tree */
  422. LOCAL int tagtree(t)
  423. X  register int t;
  424. X{
  425. X  char input[PATLEN];
  426. X  register dlist *dp;
  427. X  register int f, c, ff, nt;
  428. X
  429. X  who = t ? "TAG TREE" : "TAG DIRECTORY";
  430. X  if(t && (c = checktree(mustup)) != RV_OK)
  431. X    return(c);
  432. X
  433. X  puthelp("%s: Give file pattern (CR:%s)", who, tpattern[0] ? tpattern : "quit");
  434. X  if((c = getpattern(input, "Tag which files:")) == RV_OK)
  435. X    (void) strcpy(tpattern, input);
  436. X  else if(c < RV_NUL || (c == RV_NUL && tpattern[0] == '\0'))
  437. X    return(c);
  438. X
  439. X  /* Walk thru subtree */
  440. X  puthelp("%s %s", who, cancel);
  441. X  dp = cdlist;
  442. X  ff = 0;
  443. X  do {
  444. X    nt = DNTAG(dp);
  445. X    if( !DCANC(dp))
  446. X      continue;
  447. X    else if(DFLAG(dp) != FL_FIL && (f = newflist(dp)) != RV_OK) /* Update! */
  448. X      return(f);
  449. X    else if(keypressed() && hitakey(NULL) < RV_NUL)
  450. X      break;
  451. X    /* Walk thru file list */
  452. X    for(f = 0; f < DNFIL(dp); f++)
  453. X      if(umatch(dp, f, tpattern) > 0) {
  454. X       FITAG(dp, f) = FF_TAG;
  455. X       ++DNTAG(dp);
  456. X       ++ff;
  457. X      }
  458. X    if(nt != DNTAG(dp))
  459. X      showdlist(dp, 0);
  460. X  } while(t && (dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > CLEVL);
  461. X
  462. X  if(ff > 0)
  463. X    treeflag |= SF_FILE|SF_LIST;
  464. X  puthelp("%s: %s %s", who, tpattern, hitkey);
  465. X  (void) putecho("Tagged %d file(s) matching %s", ff, tpattern);
  466. X  return(hitakey(NULL));
  467. X
  468. X} /* tagtree() */
  469. X
  470. X/* Untag files in directory tree */
  471. LOCAL int untagtree(t)
  472. X  register int t;
  473. X{
  474. X  char pat[PATLEN];
  475. X  register dlist *dp;
  476. X  register int f, c, ff, nt;
  477. X
  478. X  who = t ? "UNTAG TREE" : "UNTAG DIRECTORY";
  479. X  if(t && (c = checktree(mustup)) != RV_OK)
  480. X    return(c);
  481. X
  482. X  puthelp("%s: Give file pattern (CR:all files)", who);
  483. X  if((c = getpattern(pat, "Untag which files:")) < RV_NUL)
  484. X    return(c);
  485. X  else if(c == RV_NUL)
  486. X    (void) strcpy(pat, "*");
  487. X
  488. X  /* Walk thru subtree */
  489. X  puthelp("%s %s", who, cancel);
  490. X  dp = cdlist;
  491. X  ff = 0;
  492. X  do {
  493. X    nt = DNTAG(dp);
  494. X    if( !DCANC(dp))
  495. X      continue;
  496. X    else if(DFLAG(dp) != FL_FIL && (f = newflist(dp)) != RV_OK)
  497. X      return(f);
  498. X    else if(keypressed() && hitakey(NULL) < RV_NUL)
  499. X      break;
  500. X    /* Walk thru file list */
  501. X    for(f = 0; f < DNFIL(dp); f++)
  502. X      if(ISTAG(dp, f) && umatch(dp, f, pat) > 0) {
  503. X       FITAG(dp, f) = FF_NONE;
  504. X       if(DNTAG(dp) > 0)
  505. X         --DNTAG(dp);
  506. X       ++ff;
  507. X      }
  508. X    if(nt != DNTAG(dp))
  509. X      showdlist(dp, 0);
  510. X  } while(t && (dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > CLEVL);
  511. X
  512. X  if(ff > 0)
  513. X    treeflag |= SF_FILE|SF_LIST;
  514. X  puthelp("%s: %s %s", who, pat, hitkey);
  515. X  (void) putecho("Untagged %d file(s) matching %s", ff, pat);
  516. X  return(hitakey(NULL));
  517. X
  518. X} /* untagtree() */
  519. X
  520. X/* Check if there are tagged files */
  521. LOCAL int checktagged()
  522. X{
  523. X  register dlist *dp;
  524. X  register int f, n;
  525. X
  526. X  /* Walk thru subtree */
  527. X  dp = cdlist;
  528. X  n = 0;
  529. X  do {
  530. X    if( !DCANC(dp))
  531. X      continue;
  532. X    /* Walk thru file list */
  533. X    for(f = 0; f < DNFIL(dp); f++)
  534. X      if(ISTAG(dp, f))
  535. X       ++n;
  536. X  } while((dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > CLEVL);
  537. X  return(n);
  538. X
  539. X} /* checktagged() */
  540. X
  541. X/*
  542. X *      COMMANDS WORKING ON TAGGED FILES
  543. X */
  544. X
  545. X/* Remove tagged files in tree */
  546. GLOBL int removetagged()
  547. X{
  548. X  register dlist *dp;
  549. X  register int c, f, n, rflag;
  550. X
  551. X  who = "REMOVE TAGGED FILES";
  552. X  if(checktagged() == 0) {      /* No tagged files */
  553. X    puthelp("%s %s", who, hitkey);
  554. X    return(errequest(CFNAM, "No tagged files found"));
  555. X  }
  556. X
  557. X  puthelp("%s (Y:request  N:don't request  ELSE:quit)", who);
  558. X  c = hitakey("Request before removing tagged files ?", echoline, DA_NONE);
  559. X  if( !(c == 'y' || c == 'n'))
  560. X    return(c);
  561. X  rflag = c == 'y';
  562. X
  563. X  if(rflag)
  564. X    puthelp("REMOVE FILE (Y:remove  Q:quit  ELSE:don't remove)");
  565. X  else
  566. X    puthelp("%s (In progress ...)", who);
  567. X
  568. X  /* Walk thru subtree */
  569. X  dp = cdlist;
  570. X  n = 0;
  571. X  do {
  572. X    if(CNTAG > 0) {             /* Contains tagged files */
  573. X      treeflag &= ~(SF_ECHO|SF_HELP);
  574. X      (void) updatetree(0);
  575. X      /* Walk thru file list */
  576. X      for(f = CNFIL - 1; f >= 0; f--) {
  577. X       if(ISTAG(cdlist, f)) {
  578. X         c = removefile(cdlist, f, rflag);
  579. X         if(c == 'q' || c < RV_NUL)
  580. X           goto ENDLOOP;
  581. X         else if(c == RV_OK) {
  582. X           ++n;
  583. X           FITAG(cdlist, f) = FF_NONE;
  584. X           if(CNTAG > 0)
  585. X             --CNTAG;
  586. X           if(rflag)
  587. X             showflist(firstfline);
  588. X         }
  589. X       }
  590. X      }
  591. X      if(CFLAG == FL_CHG) {
  592. X       if((c = newflist(cdlist)) != RV_OK)
  593. X         goto ENDLOOP;
  594. X       else
  595. X         showdlist(cdlist, 0);
  596. X      }
  597. X    }
  598. X  } while(gotree(1) && CLEVL > DLEVL(dp));
  599. X
  600. XENDLOOP:
  601. X  if(c == RV_END)
  602. X    return(c);
  603. X  while(cdlist != dp)           /* Position to starting directory */
  604. X    (void) gotree(-1);
  605. X  puthelp("%s %s", who, hitkey);
  606. X  if(n > 0) {
  607. X    treeflag = SF_FULL;
  608. X    (void) putecho("Removed %d tagged file(s)",  n);
  609. X  }
  610. X  else
  611. X    (void) putecho("No files removed");
  612. X  return(hitakey(NULL));
  613. X
  614. X} /* removetagged() */
  615. X
  616. LOCAL char *dirselect(what)
  617. X  register char *what;
  618. X{
  619. X  register char *dn;
  620. X
  621. X  dn = selectdir(what);
  622. X  treeflag = SF_FULL;
  623. X  treeflag &= ~(SF_HELP|SF_ECHO);
  624. X  (void) updatetree(0);
  625. X  return(dn);
  626. X
  627. X} /* dirselect() */
  628. X
  629. X/* Move tagged files in tree */
  630. GLOBL int movetagged()
  631. X{
  632. X  char name[NAMELEN];
  633. X  struct stat st;
  634. X  register dlist *dp;
  635. X  register char *to;
  636. X  register int c, f, n, rflag;
  637. X
  638. X  who = "MOVE TAGGED FILES";
  639. X  if(checktagged() == 0) {      /* No tagged files */
  640. X    puthelp("%s %s", who, hitkey);
  641. X    return(errequest(CFNAM, "No tagged files found"));
  642. X  }
  643. X
  644. X  puthelp("%s: Give destination directory (CR:select one)", who);
  645. X  c = putecho("Move tagged files to:");
  646. X  if((c = getline(name, sizeof(name), c, 0, NULL, CLIST, 0)) < RV_NUL)
  647. X    return(c);
  648. X  if(c == RV_OK) {
  649. X    to = strcpy(name, pathname(name, CPNAM));
  650. X    if((*statfun)(to, &st) < 0) {
  651. X      puthelp("%s %s", who, hitkey);
  652. X      return(errequest(name, "Cannot stat"));
  653. X    }
  654. X    else if(STFMT(&st) != S_IFDIR) {
  655. X      puthelp("%s %s", who, hitkey);
  656. X      return(errequest(name, "Is not a directory"));
  657. X    }
  658. X  }
  659. X  else if((to = dirselect("moving files")) == NULL) {
  660. X    fileflag |= SF_ECHO|SF_HELP;
  661. X    return(RV_NUL);
  662. X  }
  663. X
  664. X  puthelp("%s (Y:request  N:don't request  ELSE:quit)", who);
  665. X  c = hitakey("Request before moving tagged files ?", echoline, DA_NONE);
  666. X  if( !(c == 'y' || c == 'n'))
  667. X    return(c);
  668. X  rflag = c == 'y';
  669. X
  670. X  if(rflag)
  671. X    puthelp("MOVE FILE (Y:copy  Q:quit  ELSE:don't copy)");
  672. X  else
  673. X    puthelp("%s (In progress ...)", who);
  674. X
  675. X  /* Walk thru subtree */
  676. X  dp = cdlist;
  677. X  n = 0;
  678. X  do {
  679. X    if(CNTAG > 0) {             /* Contains tagged files */
  680. X      treeflag &= ~(SF_ECHO|SF_HELP);
  681. X      (void) updatetree(0);
  682. X      /* Walk thru file list */
  683. X      for(f = CNFIL - 1; f >= 0; f--) {
  684. X       if(ISTAG(cdlist, f)) {
  685. X         c = movefile(cdlist, f, to, rflag);
  686. X         if(c == 'q' || c < RV_NUL)
  687. X           goto ENDLOOP;
  688. X         else if(c == RV_OK) {
  689. X           ++n;
  690. X           FITAG(cdlist, f) = FF_NONE;
  691. X           if(CNTAG > 0)
  692. X             --CNTAG;
  693. X         }
  694. X       }
  695. X      }
  696. X      if(CFLAG == FL_CHG) {
  697. X       if((c = newflist(cdlist)) != RV_OK)
  698. X         goto ENDLOOP;
  699. X       else
  700. X         showdlist(cdlist, 0);
  701. X      }
  702. X    }
  703. X  } while(gotree(1) && CLEVL > DLEVL(dp));
  704. X
  705. XENDLOOP:
  706. X  if(c == RV_END)
  707. X    return(c);
  708. X  checkdlist(to);
  709. X  while(cdlist != dp)           /* Position to starting directory */
  710. X    (void) gotree(-1);
  711. X  puthelp("%s %s", who, hitkey);
  712. X  if(n > 0) {
  713. X    treeflag = SF_FULL;
  714. X    (void) putecho("Moved %d file(s) to %s",  n, to);
  715. X  }
  716. X  else
  717. X    (void) putecho("No files moved");
  718. X  return(hitakey(NULL));
  719. X
  720. X} /* movetagged() */
  721. X
  722. X/* Copy tagged files in tree */
  723. GLOBL int copytagged()
  724. X{
  725. X  char name[NAMELEN];
  726. X  struct stat st;
  727. X  register dlist *dp;
  728. X  register char *to;
  729. X  register int c, f, n, rflag;
  730. X
  731. X  who = "COPY TAGGED FILES";
  732. X  if(checktagged() == 0) {      /* No tagged files */
  733. X    puthelp("%s %s", who, hitkey);
  734. X    return(errequest(CFNAM, "No tagged files found"));
  735. X  }
  736. X
  737. X  puthelp("%s: Give destination directory (CR:select one)", who);
  738. X  c = putecho("Copy tagged files to:");
  739. X  if((c = getline(name, sizeof(name), c, 0, NULL, CLIST, 0)) < RV_NUL)
  740. X    return(c);
  741. X  if(c == RV_OK) {
  742. X    to = strcpy(name, pathname(name, CPNAM));
  743. X    if((*statfun)(to, &st) < 0) {
  744. X      puthelp("%s %s", who, hitkey);
  745. X      return(errequest(name, "Cannot stat"));
  746. X    }
  747. X    else if(STFMT(&st) != S_IFDIR) {
  748. X      puthelp("%s %s", who, hitkey);
  749. X      return(errequest(name, "Is not a directory"));
  750. X    }
  751. X  }
  752. X  else if((to = dirselect("copying files")) == NULL) {
  753. X    fileflag |= SF_ECHO|SF_HELP;
  754. X    return(RV_NUL);
  755. X  }
  756. X
  757. X  puthelp("%s (Y:request  N:don't request  ELSE:quit)", who);
  758. X  c = hitakey("Request before copying tagged files ?", echoline, DA_NONE);
  759. X  if( !(c == 'y' || c == 'n'))
  760. X    return(c);
  761. X  rflag = c == 'y';
  762. X
  763. X  if(rflag)
  764. X    puthelp("COPY FILE (Y:copy  Q:quit  ELSE:don't copy)");
  765. X  else
  766. X    puthelp("%s (In progress ...)", who);
  767. X
  768. X  /* Walk thru subtree */
  769. X  dp = cdlist;
  770. X  n = 0;
  771. X  do {
  772. X    if(CNTAG > 0) {             /* Contains tagged files */
  773. X      treeflag &= ~(SF_ECHO|SF_HELP);
  774. X      (void) updatetree(0);
  775. X      /* Walk thru file list */
  776. X      for(f = CNFIL - 1; f >= 0; f--) {
  777. X       if(ISTAG(cdlist, f)) {
  778. X         c = copyfile(cdlist, f, to, rflag);
  779. X         if(c == 'q' || c < RV_NUL)
  780. X           goto ENDLOOP;
  781. X         else if(c == RV_OK) {
  782. X           ++n;
  783. X           FITAG(cdlist, f) = FF_NONE;
  784. X           if(CNTAG > 0)
  785. X             --CNTAG;
  786. X         }
  787. X       }
  788. X      }
  789. X    }
  790. X  } while(gotree(1) && CLEVL > DLEVL(dp));
  791. X
  792. XENDLOOP:
  793. X  if(c == RV_END)
  794. X    return(c);
  795. X  checkdlist(to);
  796. X  while(cdlist != dp)           /* Position to starting directory */
  797. X    (void) gotree(-1);
  798. X  puthelp("%s %s", who, hitkey);
  799. X  if(n > 0) {
  800. X    treeflag = SF_FULL;
  801. X    (void) putecho("Copied %d file(s) to %s",  n, to);
  802. X  }
  803. X  else
  804. X    (void) putecho("No files copied");
  805. X  return(hitakey(NULL));
  806. X
  807. X} /* copytagged() */
  808. X
  809. X/*
  810. X *      RESIZE DIRECTORY TREE WINDOW
  811. X */
  812. X
  813. X/* Recalculate and update dlists on directory window */
  814. GLOBL VOID calculatetree(n)
  815. X  register int n;
  816. X{
  817. X  register dlist *dp;
  818. X
  819. X  if(tdlist && cdlist) {        /* Tree window needs update */
  820. X    if(n < 0 && DTROW(cdlist) > lastdline) {
  821. X      while(DTROW(cdlist) > lastdline)
  822. X       tdlist = (dlist *) DNEXT(tdlist);
  823. X    }
  824. X    else if(n > 0) {
  825. X      for( ; n > 0; n--) {
  826. X       for(dp = cdlist; dp && DTROW(dp) < lastdline; dp = (dlist *) DNEXT(dp))
  827. X         ;
  828. X       if(DPREV(tdlist) && dp == DNULL)
  829. X         tdlist = (dlist *) DPREV(tdlist);
  830. X       else
  831. X         break;
  832. X      }
  833. X    }
  834. X  }
  835. X
  836. X} /* calculatetree() */
  837. X
  838. X/* Enlarge or shrink the tree window  */
  839. LOCAL int resizetree(dir)
  840. X  register int dir;
  841. X{
  842. X  register dlist *dp;
  843. X
  844. X  /* Enlarge tree window if possible */
  845. X  if(dir > 0 && nflines > MINFIL) {
  846. X    ++lastdline;
  847. X    for(dp = cdlist; dp && DTROW(dp) < lastdline; dp = (dlist *) DNEXT(dp))
  848. X      ;
  849. X    if(DPREV(tdlist) && dp == DNULL) {
  850. X      tdlist = (dlist *) DPREV(tdlist);
  851. X      if(CANSCROLL) {
  852. X       (void) windowdown(firstdline, lastfline, 1);
  853. X       showdline(tdlist);
  854. X       treeflag |= SF_MOVE;
  855. X      }
  856. X      else
  857. X       treeflag |= SF_TREE|SF_LIST;
  858. X    }
  859. X    else if(CANSCROLL) {
  860. X      (void) windowdown(lastdline, lastfline, 1);
  861. X      showdline(dp);
  862. X      treeflag |= SF_MOVE;
  863. X    }
  864. X    else
  865. X      treeflag |= SF_TREE|SF_LIST|SF_FILE;
  866. X    ++ndlines;
  867. X    --nflines;
  868. X    ++firstfline;
  869. X    checklines(0);
  870. X  }
  871. X  /* Shrink tree window if possible */
  872. X  else if(dir < 0 && nflines < calculatelines()) {
  873. X    --ndlines;
  874. X    --firstfline;
  875. X    if(DTROW(cdlist) == lastdline) {
  876. X      tdlist = (dlist *) DNEXT(tdlist);
  877. X      if(CANSCROLL) {
  878. X       (void) windowup(firstdline, lastfline, 1);
  879. X       showflist(lastfline);
  880. X       treeflag |= SF_MOVE;
  881. X      }
  882. X      else
  883. X       treeflag |= SF_TREE|SF_LIST|SF_FILE;
  884. X    }
  885. X    else if(CANSCROLL) {
  886. X      (void) windowup(lastdline, lastfline, 1);
  887. X      showflist(lastfline);
  888. X      treeflag |= SF_MOVE;
  889. X    }
  890. X    else
  891. X      treeflag |= SF_TREE|SF_LIST|SF_FILE;
  892. X    --lastdline;
  893. X    ++nflines;
  894. X    checklines(0);
  895. X  }
  896. X  else
  897. X    return(0);
  898. X
  899. X  treeflag |= SF_SEPL|SF_PBAR;
  900. X  return(1);
  901. X
  902. X} /* resizetree() */
  903. X
  904. X/*
  905. X *      INFORMATION AND STATUS OF DIRECTORY
  906. X */
  907. X
  908. X/* Show some directory information */
  909. LOCAL int infodir()
  910. X{
  911. X  char buf[EXECLEN];
  912. X  struct stat st;
  913. X  register FILE *pp;
  914. X  register int i;
  915. X
  916. X  who = "INFO";
  917. X  puthelp("%s: %s %s", who, CPNAM, hitkey);
  918. X  if((*statfun)(CPNAM, &st))
  919. X    return(errequest(CFNAM, "Cannot stat"));
  920. X
  921. X  (void) putecho("Scanning disk for disk usage, wait a moment ... ");
  922. X  flushout();
  923. X  (void) sprintf(buf, "%s %s", DUDIR, CPNAM);
  924. X  if(pp = popen(buf, "r")) {    /* Let du summarize used blocks */
  925. X    (void) fgets(buf, sizeof(buf), pp);
  926. X    (void) pclose(pp);
  927. X    i = 0;
  928. X    while(buf[i] >= '0' && buf[i] <= '9')
  929. X      ++i;
  930. X    buf[i] = '\0';
  931. X  }
  932. X  else                          /* Error in calling du */
  933. X    (void) strcpy(buf, "?");
  934. X  (void) putecho("Access:%s Blocks:%s Files:%d Dirs:%d Date:%s",
  935. X                 fileaccess(&st), buf, CNFIL, CNDIR, ctime(&st.st_mtime));
  936. X  return(hitakey(NULL));
  937. X
  938. X} /* infodir() */
  939. X
  940. X/* Show and change directory status */
  941. LOCAL int statusdir()
  942. X{
  943. X  register int c;
  944. X
  945. X  c = statusfile(CPNAM, 0);
  946. X  if(buildflag) {               /* Rebuilding needed */
  947. X    c = newflist(cdlist);
  948. X    buildflag = 0;
  949. X  }
  950. X  return(c);
  951. X
  952. X} /* statusdir() */
  953. X
  954. X/*
  955. X *      BACKUP DIRECTORY OR TREE
  956. X */
  957. X
  958. X/* Create filelist for backup */
  959. LOCAL int backuplist(name, t)
  960. X  register char *name;
  961. X  register int t;
  962. X{
  963. X  char fname[NAMELEN];
  964. X  register FILE *file;
  965. X  register dlist *dp;
  966. X  register char *dname;
  967. X  register int dlen, i;
  968. X
  969. X  (void) strcpy(fname, pathname(name, CPNAM));
  970. X  if(file = fopen(fname, "w")) {
  971. X    /* Write out tree or subtree list */
  972. X    dlen = strlen(CPNAM);
  973. X    for(i = 0; i < CNFIL ; i++)
  974. X      if( !t || ISTAG(cdlist, i)) {
  975. X       (void) fprintf(file, "%s\n", FFNAM(cdlist, i));
  976. X       FITAG(cdlist, i) = FF_NONE;
  977. X       if(CNTAG > 0)
  978. X         --CNTAG;
  979. X      }
  980. X    for(dp = (dlist *) CNEXT; dp && DLEVL(dp) > CLEVL; dp = (dlist *) DNEXT(dp)) {
  981. X      if( !DCANC(dp))
  982. X       continue;
  983. X      dname = &(DPNAM(dp)[dlen+1]);
  984. X      for(i = 0; i < DNFIL(dp); i++)
  985. X       if( !t || ISTAG(dp, i)) {
  986. X         (void) fprintf(file, "%s\n", pathname(FFNAM(dp, i), dname));
  987. X         FITAG(dp, i) = FF_NONE;
  988. X         if(DNTAG(dp) > 0)
  989. X           --DNTAG(dp);
  990. X       }
  991. X    }
  992. X    (void) fclose(file);
  993. X  }
  994. X  else {
  995. X    puthelp("%s %s", who, hitkey);
  996. X    return(errequest(prgname, "Cannot create backup list file"));
  997. X  }
  998. X
  999. X  checkdlist(fname);            /* Update needed? */
  1000. X  return(buildflag ? updatedlist() : RV_OK);
  1001. X
  1002. X} /* backuplist() */
  1003. X
  1004. X/* Backup directory/subtree or tagged files in subtree */
  1005. LOCAL int backupdir(t)
  1006. X  register int t;
  1007. X{
  1008. X  char name[INPLEN], list[NAMELEN], buf[EXECLEN];
  1009. X  register dlist *dp;
  1010. X  register int c;
  1011. X
  1012. X  who = t ? "BACKUP TAGGED FILES" : "BACKUP TREE";
  1013. X  if( !VARSET(V_BK)) {                  /* No backup program */
  1014. X    puthelp("%s %s", who, hitkey);
  1015. X    return(errequest(prgname, "No backup program defined"));
  1016. X  }
  1017. X  else if(t && checktagged() == 0) {    /* No tagged files */
  1018. X    puthelp("%s %s", who, hitkey);
  1019. X    return(errequest(CFNAM, "No tagged files found"));
  1020. X  }
  1021. X  else if((c = changelist(cdlist, who)) != RV_OK)
  1022. X    return(c);
  1023. X
  1024. X  /* Update subtree if needed */
  1025. X  if( !t) {
  1026. X    if((c = checktree(mustup)) != RV_OK)
  1027. X      return(c);
  1028. X    for(dp = (dlist *) CNEXT; dp && DLEVL(dp) > CLEVL; dp = (dlist *) DNEXT(dp))
  1029. X      if(DFLAG(dp) != FL_FIL) {
  1030. X       if((c = newflist(dp)) != RV_OK)
  1031. X         return(c);
  1032. X       else
  1033. X         treeflag |= SF_TREE|SF_LIST;
  1034. X      }
  1035. X    if(treeflag)
  1036. X      (void) updatetree(0);
  1037. X  }
  1038. X
  1039. X  puthelp("%s: Give filename for backup list (CR:$HOME/%s)", who, UTBACK);
  1040. X  c = putecho("List file name:");
  1041. X  if((c = getline(name, sizeof(name), c, 0, NULL, CLIST, 1)) == RV_OK)
  1042. X    (void) strcpy(list, name);
  1043. X  else if(c == RV_NUL)
  1044. X    (void) strcpy(list, pathname(UTBACK, home));
  1045. X  else
  1046. X    return(c);
  1047. X  if((c = backuplist(list, t)) != RV_OK)
  1048. X    return(c);
  1049. X
  1050. X  /* Build command line and call backup program */
  1051. X  treeflag = SF_FULL;
  1052. X  if( !VARSET(V_BKO))
  1053. X    (void) sprintf(buf, "%s %s", VARVAL(V_BK), list);
  1054. X  else
  1055. X    (void) sprintf(buf, "%s %s %s", VARVAL(V_BK), VARVAL(V_BKO), list);
  1056. X  puthelp("%s %s", who, cancel);
  1057. X  (void) putecho("Executing backup program %s ...", VARVAL(V_BK));
  1058. X  c = callsystem(buf, 1, 0);
  1059. X
  1060. X  puthelp("%s %s", who, hitkey);
  1061. X  if(c != RV_OK)
  1062. X    return(errequest(VARVAL(V_BK), "Error in backup"));
  1063. X  bell(VARSET(V_BL));
  1064. X  return(hitakey("Backup done", echoline, DA_NONE));
  1065. X
  1066. X} /* backupdir() */
  1067. X
  1068. X/*
  1069. X *      CHANGE TO DIRECTORY
  1070. X */
  1071. X
  1072. X/* Goto a directory */
  1073. LOCAL int changedir()
  1074. X{
  1075. X  static char pattern[PATLEN] = { '\0' };
  1076. X  char input[PATLEN];
  1077. X  dlist *dp;
  1078. X  int c, path, found;
  1079. X
  1080. X  who = "CHANGE DIRECTORY";
  1081. X  /* Get directory name to change to */
  1082. X  puthelp("%s: Give directory name (CR:next %s)", who, pattern[0] ? pattern : "quit");
  1083. X  c = putecho("Change to:");
  1084. X  if((c = getline(input, sizeof(input), c, 0, NULL, CLIST, 0)) < RV_NUL)
  1085. X    return(c);
  1086. X  else if(c == RV_NUL) {
  1087. X    if(pattern[0] == '\0')
  1088. X      return(c);
  1089. X  }
  1090. X  else
  1091. X    (void) strcpy(pattern, input);
  1092. X
  1093. X  /* Search for directory in tree */
  1094. X  found = -1;
  1095. X  path  = strchr(pattern, '/') != NULL;
  1096. X  for(dp = (dlist *) CNEXT; dp; dp = (dlist *) DNEXT(dp))
  1097. X    if(match(path ? DPNAM(dp) : DFNAM(dp), pattern) > 0) {
  1098. X      found = DDNUM(dp);
  1099. X      break;
  1100. X    }
  1101. X  if(found < 0)
  1102. X    for(dp = droot; dp && DDNUM(dp) <= CDNUM; dp = (dlist *) DNEXT(dp))
  1103. X      if(match(path ? DPNAM(dp) : DFNAM(dp), pattern) > 0) {
  1104. X       found = DDNUM(dp);
  1105. X       break;
  1106. X      }
  1107. X
  1108. X  if(found < 0) {               /* Not found */
  1109. X    puthelp("%s %s", hitkey, who);
  1110. X    return(errequest(pattern, "Not found"));
  1111. X  }
  1112. X
  1113. X  if(CDNUM == found)            /* Found */
  1114. X    return(RV_OK);
  1115. X  else if(CDNUM > found)        /* Position to directory in tree */
  1116. X    while(CDNUM > found)
  1117. X      (void) gotree(-1);
  1118. X  else
  1119. X    while(CDNUM < found)
  1120. X      (void) gotree(1);
  1121. X
  1122. X  return(RV_OK);
  1123. X
  1124. X} /* changedir() */
  1125. X
  1126. X/*
  1127. X *      LIST FILES IN TREE
  1128. X */
  1129. X
  1130. X/* List matching/tagged files in tree */
  1131. LOCAL int listtree(t)
  1132. X  register int t;
  1133. X{
  1134. X  char pat[PATLEN];
  1135. X  register dlist *dp;
  1136. X  register int c, f, ff, l;
  1137. X
  1138. X  who = t ? "LIST TAGGED FILES" : "LIST FILES";
  1139. X  if(t && checktagged() == 0) {
  1140. X    puthelp("%s %s", who, hitkey);
  1141. X    return(errequest(CFNAM, "No tagged files found"));
  1142. X  }
  1143. X  else if((c = checktree(mustup)) != RV_OK)
  1144. X    return(c);
  1145. X
  1146. X  if( !t) {
  1147. X    puthelp("%s: Give file pattern (CR:all files)", who);
  1148. X    if((c = getpattern(pat, "List which files:")) < RV_NUL)
  1149. X      return(c);
  1150. X    else if(c == RV_NUL)
  1151. X      (void) strcpy(pat, "*");
  1152. X  }
  1153. X
  1154. X  /* Show all matching files */
  1155. X  dp = cdlist;
  1156. X  l = firstline;
  1157. X  ff = 0;
  1158. X  c = RV_OK;
  1159. X  do {
  1160. X    if( !DCANC(dp))
  1161. X      continue;
  1162. X    else if(DFLAG(dp) != FL_FIL && (c = newflist(dp)) != RV_OK)
  1163. X      return(c);
  1164. X    for(f = 0; f < DNFIL(dp); f++)
  1165. X      if((t && ISTAG(dp, f)) || umatch(dp, f, pat) > 0) {
  1166. X       if(l == firstline) {
  1167. X         if(ff > 0) {
  1168. X           if(t)
  1169. X             puthelp("%s (CR:continue  ELSE:quit)", who);
  1170. X           else
  1171. X             puthelp("%s: %s (CR:continue  ELSE:quit)", who, pat);
  1172. X           c = hitakey("Continue listing ?", echoline, DA_NONE);
  1173. X           if( !(c == '\n' || c == ' '))
  1174. X             break;
  1175. X           else
  1176. X             c = RV_OK;
  1177. X         }
  1178. X         treeflag = SF_FULL;
  1179. X         clearwindow(firstline, lastline);
  1180. X       }
  1181. X       ++ff;
  1182. X       (void) putfxy(0, l, 0, "%s", pathname(FFNAM(dp, f), DPNAM(dp)));
  1183. X       if(++l > lastline)
  1184. X         l = firstline;
  1185. X      }
  1186. X  } while(c == RV_OK && (dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > CLEVL);
  1187. X
  1188. X  if(c >= RV_NUL) {
  1189. X    puthelp("%s %s", who, hitkey);
  1190. X    if(t)
  1191. X      (void) putecho("Listed %d tagged file(s)", ff);
  1192. X    else
  1193. X      (void) putecho("Listed %d file(s) matching %s", ff, pat);
  1194. X    c = hitakey(NULL);
  1195. X  }
  1196. X  return(c);
  1197. X
  1198. X} /* listtree() */
  1199. X
  1200. X/*
  1201. X *      CREATE A DIRECTORY
  1202. X */
  1203. X
  1204. X/* Create a directory */
  1205. LOCAL int makedir()
  1206. X{
  1207. X  char newname[NAMELEN], buf[EXECLEN];
  1208. X  register dlist *dp;
  1209. X  register int c, i;
  1210. X
  1211. X  who = "MAKE DIRECTORY";
  1212. X  if( !CCANC) {                 /* Cannot change to directory */
  1213. X    puthelp("%s %s", who, hitkey);
  1214. X    return(errequest(CFNAM, "Cannot make directory"));
  1215. X  }
  1216. X
  1217. X  puthelp("%s: Give directory name (CR:quit)", who);
  1218. X  c = putecho("Make directory:");
  1219. X  if((c = getline(newname, sizeof(newname), c, 0, NULL, GNULL, 0)) != RV_OK)
  1220. X    return(c);
  1221. X
  1222. X  puthelp("%s %s", who, hitkey);
  1223. X  if(strchr(newname, '/') || EQU(newname, ".") || EQU(newname, ".."))
  1224. X    return(errequest(newname, "Cannot make directory"));
  1225. X  for(i = 0; i < CNFIL; i++)
  1226. X    if(EQU(FFNAM(cdlist, i), newname))
  1227. X      return(errequest(newname, "Already exists"));
  1228. X
  1229. X  /* Build command line and call mkdir program */
  1230. X  (void) sprintf(buf, "%s %s", MKDIR, pathname(newname, CPNAM));
  1231. X  if(callsystem(buf, 0, 0) != RV_OK)
  1232. X    return(errequest(newname, "Error in creating"));
  1233. X
  1234. X  /* Insert new directory into tree and file lists */
  1235. X  dp = newdlist(newname, FL_FIL);
  1236. X  c  = newflist(cdlist);
  1237. X
  1238. X  /* Update flag and return */
  1239. X  if(dp) {
  1240. X    treeflag = SF_FULL;
  1241. X    return(c);
  1242. X  }
  1243. X  return(RV_NUL);
  1244. X
  1245. X} /* makedir() */
  1246. X
  1247. X/*
  1248. X *      REMOVE A DIRECTORY OR TREE
  1249. X */
  1250. X
  1251. X/* Remove a directory */
  1252. LOCAL int removedir()
  1253. X{
  1254. X  char buf[EXECLEN];
  1255. X  register dlist *dp;
  1256. X  register int c, i, rflag;
  1257. X
  1258. X  who = "REMOVE DIRECTORY";
  1259. X  /* Check if removing is permitted */
  1260. X  if( !CCANC || cdlist == droot || CNDIR > 0) {
  1261. X    puthelp("%s %s", who, hitkey);
  1262. X    if( !CCANC)                 /* Cannot change to directory */
  1263. X      return(errequest(CFNAM, "Cannot remove"));
  1264. X    else if(cdlist == droot)    /* Root cannot be removed */
  1265. X      return(errequest(CFNAM, "Cannot remove root directory"));
  1266. X    else if(CNDIR > 0)          /* Contains subdirectories */
  1267. X      return(errequest(CFNAM, "Contains subdirectories. Cannot remove subtrees"));
  1268. X  }
  1269. X
  1270. X  puthelp("%s (Y:remove  ELSE:quit)", who);
  1271. X  rflag = 0;
  1272. X  (void) putecho("Remove directory %s ?", CFNAM);
  1273. X  if((c = hitakey(NULL)) != 'y')
  1274. X    return(c);
  1275. X  if(CNFIL > 0) {
  1276. X    puthelp("%s (Y:request  N:don't request  ELSE:quit)", who);
  1277. X    c = hitakey("Directory is not empty, request before removing files ?", echoline, DA_NONE);
  1278. X    if( !(c == 'y' || c == 'n'))
  1279. X      return(c);
  1280. X    rflag = c == 'y';
  1281. X  }
  1282. X
  1283. X  /* First remove files from directory */
  1284. X  if(rflag)
  1285. X    puthelp("REMOVE FILE (Y:remove  Q:quit  ELSE:don't remove)");
  1286. X  else
  1287. X    puthelp("%s (In progress ...)", who);
  1288. X  for(i = CNFIL - 1; i >= 0; i--) {
  1289. X    c = removefile(cdlist, i, rflag);
  1290. X    if(c == 'q' || c < RV_NUL)
  1291. X      return(c);
  1292. X    else if(c == RV_OK && rflag) {
  1293. X      showflist(firstfline);
  1294. X      (void) putfxy(FCOL, DTROW(cdlist), 0, NFFMT, CNFIL);
  1295. X    }
  1296. X  }
  1297. X
  1298. X  /* There are files: cannot remove directory */
  1299. X  if(CNFIL > 0) {
  1300. X    puthelp("%s %s", who, hitkey);
  1301. X    return(errequest(CFNAM, "Is not empty"));
  1302. X  }
  1303. X
  1304. X  if(rflag) {                   /* Request before removing */
  1305. X    puthelp("%s (Y:remove  ELSE:quit)", who);
  1306. X    (void) putecho("Remove directory %s ?", CFNAM);
  1307. X    if((c = hitakey(NULL)) != 'y')
  1308. X      return(c);
  1309. X  }
  1310. X  (void) changelist(droot, NULL);
  1311. X  (void) sprintf(buf, "%s %s", RMDIR, CPNAM);
  1312. X  if(callsystem(buf, 0, 0) != RV_OK) {
  1313. X    puthelp("%s %s", who, hitkey);
  1314. X    return(errequest(CFNAM, "Error in removing"));
  1315. X  }
  1316. X
  1317. X  /* Get new top directory on screen and current directory */
  1318. X  for(dp = cdlist; dp && DTROW(dp) <= lastdline; dp = (dlist *) DNEXT(dp))
  1319. X    ;
  1320. X  if(cdlist == tdlist || (tdlist != droot && dp == DNULL)) {
  1321. X    tdlist = (dlist *) DPREV(tdlist);
  1322. X    c = 1;
  1323. X  }
  1324. X  else {
  1325. X    tdlast = DNULL;
  1326. X    c = 0;
  1327. X  }
  1328. X  cdlist = (dlist *) CPREV;
  1329. X
  1330. X  /* Delete directory list entry */
  1331. X  deletedlist(CNEXT);
  1332. X
  1333. X  /* Update flags */
  1334. X  treeflag = SF_FULL;
  1335. X  writeflag = 1;
  1336. X  return(RV_OK);
  1337. X
  1338. X} /* removedir() */
  1339. X
  1340. X/*
  1341. X *      BUILD SUBDIRECTORY TREE
  1342. X */
  1343. X
  1344. X/* Scan current directory for subdirs and build up and insert subtree */
  1345. LOCAL int buildtree()
  1346. X{
  1347. X  char inp[5], name[NAMELEN];
  1348. X  register dlist *np, *dp, *p;
  1349. X  register int lev, f, n;
  1350. X
  1351. X  who = "BUILD TREE";
  1352. X  /* Check if current directory already contains subdirectories */
  1353. X  if((p = (dlist *) CNEXT) && DLEVL(p) > CLEVL) {
  1354. X    puthelp("%s %s", who, hitkey);
  1355. X    return(errequest(CFNAM, "Contains subdirectories"));
  1356. X  }
  1357. X  /* Check if there is any directory to build */
  1358. X  for(f = 0; f < CNFIL; f++)
  1359. X    if(FMODE(cdlist, f) == FF_DIR)
  1360. X      break;
  1361. X  if(f >= CNFIL) {
  1362. X    puthelp("%s %s", who, hitkey);
  1363. X    return(errequest(CFNAM, "No subdirectories found"));
  1364. X  }
  1365. X
  1366. X  /* Get max level to build up the subtree */
  1367. X  puthelp("%s: Give max tree level (CR:quit)", who, CFNAM);
  1368. X  n = putecho("Give level:");
  1369. X  n = getline(inp, sizeof(inp), n, 0, NULL, GNULL, 0);
  1370. X  if(n != RV_OK || (lev = atoi(inp)) <= 0)
  1371. X    return(n);
  1372. X
  1373. X  /* Preserve next dlist and open dlist chain for buildread() */
  1374. X  np    = (dlist *) CNEXT;
  1375. X  CNEXT = GNULL;
  1376. X  n = dircount;
  1377. X
  1378. X  /* Build up the tree for all files which are directories */
  1379. X  for(f = 0; f < CNFIL; f++)
  1380. X    if(FMODE(cdlist, f) == FF_DIR) {
  1381. X      (void) strcpy(name, pathname(FFNAM(cdlist, f), CPNAM));
  1382. X      puthelp("%s: Building %s %s", FFNAM(cdlist, f), who, cancel);
  1383. X      if(buildread(name, CLEVL+1, CLEVL+lev, 1) == RV_INT)
  1384. X       break;
  1385. X    }
  1386. X  n = dircount - n;
  1387. X
  1388. X  if(n > 0) {
  1389. X    /* Search for last new dlist, update dlist numbers and close dlist chain */
  1390. X    dp = cdlist;
  1391. X    f = CDNUM;
  1392. X    do
  1393. X     DDNUM(dp) = f++;
  1394. X    while(DNEXT(dp) && (dp = (dlist *) DNEXT(dp)));
  1395. X    DNEXT(dp) = (glist *) np;   /* Close the chain */
  1396. X    if(np)
  1397. X      DPREV(np) = (glist *) dp;
  1398. X    for(dp = np; dp; dp = (dlist *) DNEXT(dp), f++)
  1399. X      DDNUM(dp) = f;
  1400. X    infodlist();                /* Rebuild treeinfo */
  1401. X    checkindent();              /* Check indention */
  1402. X    treeflag = SF_FULL;
  1403. X    bell(VARSET(V_BL));
  1404. X    puthelp("%s %s", who, hitkey);
  1405. X    (void) putecho("%d new directories built and inserted", n);
  1406. X  }
  1407. X  else {
  1408. X    /* No new directories found and inserted, close dlist chain */
  1409. X    CNEXT = (glist *) np;
  1410. X    bell(VARSET(V_BL));
  1411. X    puthelp("%s %s", who, hitkey);
  1412. X    (void) putecho("No new directories built or inserted");
  1413. X  }
  1414. X  return(hitakey(NULL));
  1415. X
  1416. X} /* buildtree() */
  1417. X
  1418. X/*
  1419. X *      UPDATE ALL FILE LISTS
  1420. X */
  1421. X
  1422. X/* Scan directory tree and update all file lists not yet read in or changed */
  1423. LOCAL int scantree(f)
  1424. X  register int f;
  1425. X{
  1426. X  register dlist *dp;
  1427. X  register int c;
  1428. X
  1429. X  who = "UPDATE TREE";
  1430. X  if(f && (c = checktree("Update tree ?")) != RV_OK)
  1431. X    return(c);
  1432. X
  1433. X  /* Walk thru directory list and update file lists if needed */
  1434. X  if(buildflag) {
  1435. X    puthelp("%s %s", who, cancel);
  1436. X    dp = cdlist;
  1437. X    do {
  1438. X      if(keypressed() && hitakey(NULL) < RV_NUL)
  1439. X       break;
  1440. X      if( !DCANC(dp)) {                 /* Cannot cd: skip */
  1441. X       DFLAG(dp) = FL_FIL;
  1442. X       continue;
  1443. X      }
  1444. X      else if(DFLAG(dp) != FL_FIL) {    /* Rebuild file list */
  1445. X       if((c = newflist(dp)) != RV_OK)
  1446. X         return(c);
  1447. X       showdline(dp);
  1448. X       flushout();
  1449. X       treeflag |= SF_MOVE|SF_ECHO;
  1450. X      }
  1451. X    } while((dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > CLEVL);
  1452. X  }
  1453. X
  1454. X  return(RV_OK);
  1455. X
  1456. X} /* scantree() */
  1457. X
  1458. X/*
  1459. X *      SORT FILELISTS IN TREE
  1460. X */
  1461. X
  1462. X/* Sort filelists in current directory or subtree */
  1463. LOCAL int sorttree(t)
  1464. X  register int t;
  1465. X{
  1466. X  register dlist *dp;
  1467. X  register int s;
  1468. X
  1469. X  who = t ? "SORT TREE" : "SORT DIRECTORY";
  1470. X  s = CSORT ? 0 : 1;            /* Toggle sort flag */
  1471. X
  1472. X  /* Walk thru subtree */
  1473. X  puthelp("%s %s", who, cancel);
  1474. X  if(t) {
  1475. X    for(dp = (dlist *) CNEXT; dp && DLEVL(dp) > CLEVL; dp = (dlist *) DNEXT(dp)) {
  1476. X      if(keypressed() && hitakey(NULL) < RV_NUL)
  1477. X       return(RV_NUL);
  1478. X      (void) sortlist(dp, s);
  1479. X    }
  1480. X  }
  1481. X  if((s = sortlist(cdlist, s)) == RV_OK)
  1482. X    treeflag |= SF_FILE;
  1483. X
  1484. X  return(s);
  1485. X
  1486. X} /* sorttree() */
  1487. X
  1488. X/*
  1489. X *      ZOOM FILELISTS IN TREE
  1490. X */
  1491. X
  1492. X/* Get zoom pattern and rebuild filelists in directory or subtree */
  1493. LOCAL int zoomtree(t)
  1494. X  register int t;
  1495. X{
  1496. X  char pat[PATLEN];
  1497. X  register dlist *dp;
  1498. X  register int c;
  1499. X
  1500. X  who = t ? "ZOOM TREE" : "ZOOM DIRECTORY";
  1501. X  puthelp("%s: Give file pattern (CR:all files)", who);
  1502. X  if((c = getpattern(pat, "Zoom which files:")) < RV_NUL)
  1503. X    return(c);
  1504. X
  1505. X  /* Walk thru subtree */
  1506. X  puthelp("%s %s", who, cancel);
  1507. X  dp = cdlist;
  1508. X  do {
  1509. X    if(keypressed() && hitakey(NULL) < RV_NUL)
  1510. X      break;
  1511. X    if(zoomlist(dp, pat)) {
  1512. X      showdline(dp);
  1513. X      flushout();
  1514. X    }
  1515. X  } while(t && (dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > CLEVL);
  1516. X
  1517. X  treeflag |= SF_FILE|SF_LIST;
  1518. X  return(RV_OK);
  1519. X
  1520. X} /* zoomtree() */
  1521. X
  1522. X/*
  1523. X *      MARKED AND TAGGED DIRECTORIES
  1524. X */
  1525. X
  1526. X/* Set/unset mark on current directory */
  1527. LOCAL VOID markdir(f)
  1528. X  register int f;
  1529. X{
  1530. X  if(mdlist == cdlist && !f)    /* Reset mark */
  1531. X    mdlist = DNULL;
  1532. X  else                          /* Set mark */
  1533. X    mdlist = cdlist;
  1534. X
  1535. X} /* markdir() */
  1536. X
  1537. X/* Go to marked directory */
  1538. LOCAL int gomarkdir()
  1539. X{
  1540. X  register dlist *mp, *dp;
  1541. X
  1542. X  if(mdlist) {
  1543. X    mp = mdlist;
  1544. X    mdlist = cdlist;
  1545. X    for(dp = cdlist; dp; dp = (dlist *) DNEXT(dp))      /* Search forward */
  1546. X      if(dp == mp) {
  1547. X       while(cdlist != mp && gotree(1))
  1548. X         ;
  1549. X       return(1);
  1550. X      }
  1551. X    for(dp = droot; dp; dp = (dlist *) DNEXT(dp))       /* Search backward */
  1552. X      if(dp == mp) {
  1553. X       while(cdlist != mp && gotree(-1))
  1554. X         ;
  1555. X       return(1);
  1556. X      }
  1557. X  }
  1558. X
  1559. X  return(0);                                    /* No mark set */
  1560. X
  1561. X} /* gomarkdir() */
  1562. X
  1563. X/* Goto directory containing tagged files */
  1564. LOCAL int gotagged()
  1565. X{
  1566. X  register dlist *dp;
  1567. X
  1568. X  for(dp = (dlist *) DNEXT(cdlist); dp; dp = (dlist *) DNEXT(dp))
  1569. X    if(DNTAG(dp)) {
  1570. X      while(gotree(1) && dp != cdlist)
  1571. X       ;
  1572. X      return(1);
  1573. X    }
  1574. X  for(dp = droot; dp; dp = (dlist *) DNEXT(dp)) /* Search backward */
  1575. X    if(DNTAG(dp)) {
  1576. X      if(dp != cdlist)
  1577. X       while(gotree(-1) && dp != cdlist)
  1578. X         ;
  1579. X      return(1);
  1580. X    }
  1581. X
  1582. X  return(0);                                    /* No match */
  1583. X
  1584. X} /* gotagged() */
  1585. X
  1586. X/* Goto parent directory */
  1587. LOCAL int goparent()
  1588. X{
  1589. X  register int lev;
  1590. X
  1591. X  if(cdlist != droot) {
  1592. X    lev = CLEVL - 1;
  1593. X    while(gotree(-1) && CLEVL != lev)
  1594. X      ;
  1595. X    return(1);
  1596. X  }
  1597. X  return(0);
  1598. X
  1599. X} /* goparent() */
  1600. X
  1601. X/*
  1602. X *      SEARCH FOR PATTERN IN TREE
  1603. X */
  1604. X
  1605. X/* Search for pattern in tree */
  1606. LOCAL int greptree(t)
  1607. X  register int t;
  1608. X{
  1609. X  char input[PATLEN];
  1610. X  register dlist *dp;
  1611. X  register int f, c, ff, nt;
  1612. X
  1613. X  who = t ? "GREP TREE" : "GREP DIRECTORY";
  1614. X  if(t && (c = checktree(mustup)) != RV_OK)
  1615. X    return(c);
  1616. X
  1617. X  puthelp("%s: Give search pattern (CR:%s)", who, gpattern[0] ? gpattern : "quit");
  1618. X  c = putecho("Search for pattern:");
  1619. X  if((c = getline(input, sizeof(input), c, 0, NULL, GNULL, 0)) == RV_OK)
  1620. X    (void) strcpy(gpattern, input);
  1621. X  else if(c < RV_NUL || (c == RV_NUL && gpattern[0] == '\0'))
  1622. X    return(c);
  1623. X  puthelp("%s: Give file pattern (CR:all files)", who);
  1624. X  if((c = getpattern(input, "Search in which files:")) == RV_NUL)
  1625. X    (void) strcpy(input, "*");
  1626. X  else if(c != RV_OK)
  1627. X    return(c);
  1628. X
  1629. X  /* Walk thru subtree */
  1630. X  dp = cdlist;
  1631. X  do {
  1632. X    nt = DNTAG(dp);
  1633. X    ff = -1;
  1634. X    if(CFLAG != FL_FIL && (c = newflist(cdlist)) != RV_OK)      /* Update! */
  1635. X      return(c);
  1636. X    /* Walk thru file list */
  1637. X    for(c = RV_NUL, f = 0; f < CNFIL; f++) {
  1638. X      ff = -1;
  1639. X      /* Search in all matching files */
  1640. X      if((c = umatch(cdlist, f, input)) > 0) {
  1641. X       (void) putecho("Search for \'%s\' in %s", gpattern, pathname(FFNAM(cdlist, f), CPNAM));
  1642. X       flushout();
  1643. X       /* Search pattern found: what to do? */
  1644. X       if((c = grepfile(cdlist, f)) == RV_OK) {
  1645. X         ff = f;
  1646. X         treeflag &= ~(SF_ECHO|SF_HELP);
  1647. X         (void) updatetree(0);
  1648. X         puthelp("%s (CR:next  SP:change dir  M:mark dir  T:tag file  ELSE:quit)", who);
  1649. X         (void) putecho("Found \'%s\': %s -> %s", gpattern, FFNAM(cdlist, f), CFNAM);
  1650. X         if((c = hitakey(NULL)) == 't') {
  1651. X           FITAG(cdlist, f) = FF_TAG;
  1652. X           ++CNTAG;
  1653. X           c = '\n';
  1654. X         }
  1655. X         else if(c == 'm') {
  1656. X           markdir(1);
  1657. X           c = '\n';
  1658. X         }
  1659. X         else if(c == ' ') {
  1660. X           if((c = filemenu(ff, RV_NUL)) == RV_END)
  1661. X             return(c);
  1662. X           (void) updatetree(0);
  1663. X           puthelp("%s (CR:continue  SP:select  ELSE:quit)", who);
  1664. X           (void) putecho("Continue searching for \'%s\':", gpattern);
  1665. X           if((c = hitakey(NULL)) == ' ')
  1666. X             return(RV_OK);
  1667. X         }
  1668. X         if(c != '\n')
  1669. X           break;
  1670. X       }
  1671. X       else if(c == RV_INT)
  1672. X         break;
  1673. X      }
  1674. X    }
  1675. X    if(nt != DNTAG(dp))
  1676. X      showdlist(dp, 0);
  1677. X  } while(t && (c == RV_NUL || c == '\n') && gotree(1) && CLEVL > DLEVL(dp));
  1678. X
  1679. X  if(c == RV_END)
  1680. X    return(c);
  1681. X  while(cdlist != dp)           /* Position to starting directory */
  1682. X    (void) gotree(-1);
  1683. X
  1684. X  if(ff < 0) {
  1685. X     puthelp("%s %s", who, hitkey);
  1686. X     return(errequest(gpattern, "Not found"));
  1687. X  }
  1688. X  else
  1689. X    return(RV_OK);
  1690. X
  1691. X} /* greptree() */
  1692. X
  1693. X/*
  1694. X *      FIND A FILE IN TREE
  1695. X */
  1696. X
  1697. X/* Find a file in file tree */
  1698. LOCAL int findtree(t)
  1699. X  register int t;
  1700. X{
  1701. X  char input[PATLEN];
  1702. X  register dlist *dp;
  1703. X  register int f, c, ff, nt;
  1704. X
  1705. X  who = t ? "FIND TREE" : "FIND DIRECTORY";
  1706. X  if(t && (c = checktree(mustup)) != RV_OK)
  1707. X    return(c);
  1708. X
  1709. X  puthelp("%s: Give file pattern (CR:%s)", who, fpattern[0] ? fpattern : "quit");
  1710. X  if((c = getpattern(input, "Search for which file:")) == RV_OK)
  1711. X    (void) strcpy(fpattern, input);
  1712. X  else if(c < RV_NUL || (c == RV_NUL && fpattern[0] == '\0'))
  1713. X    return(c);
  1714. X
  1715. X  /* Walk thru subtree */
  1716. X  dp = cdlist;
  1717. X  do {
  1718. X    nt = DNTAG(dp);
  1719. X    ff = -1;
  1720. X    if(CFLAG != FL_FIL && (c = newflist(cdlist)) != RV_OK)      /* Update! */
  1721. X      return(c);
  1722. X    (void) putecho("Find \'%s\' in %s", fpattern, CPNAM);
  1723. X    flushout();
  1724. X    /* Walk thru file list */
  1725. X    for(c = RV_NUL, f = 0; f < CNFIL; f++) {
  1726. X      ff = -1;
  1727. X      /* File found: what to do now? */
  1728. X      if((c = findfile(cdlist, f)) == RV_OK) {
  1729. X       ff = f;
  1730. X       treeflag &= ~(SF_ECHO|SF_HELP);
  1731. X       (void) updatetree(0);
  1732. X       puthelp("%s (CR:next  SP:change dir  M:mark dir  T:tag file  ELSE:quit)", who);
  1733. X       (void) putecho("Found: %s -> %s", FFNAM(cdlist, f), CFNAM);
  1734. X       if((c = hitakey(NULL)) == 't') {
  1735. X         FITAG(cdlist, f) = FF_TAG;
  1736. X         ++CNTAG;
  1737. X         c = '\n';
  1738. X       }
  1739. X       else if(c == 'm') {
  1740. X         markdir(1);
  1741. X         c = '\n';
  1742. X       }
  1743. X       else if(c == ' ') {
  1744. X         if((c = filemenu(ff, RV_NUL)) == RV_END)
  1745. X           return(c);
  1746. X         (void) updatetree(0);
  1747. X         puthelp("%s (CR:continue  SP:select  ELSE:quit)", who);
  1748. X         (void) putecho("Continue searching file \'%s\':", fpattern);
  1749. X         if((c = hitakey(NULL)) == ' ')
  1750. X           return(RV_OK);
  1751. X       }
  1752. X       if(c != '\n')
  1753. X         break;
  1754. X      }
  1755. X    }
  1756. X    if(nt != DNTAG(dp))
  1757. X      showdlist(dp, 0);
  1758. X  } while(t && (c == RV_NUL || c == '\n') && gotree(1) && CLEVL > DLEVL(dp));
  1759. X
  1760. X  if(c == RV_END)
  1761. X    return(c);
  1762. X  while(cdlist != dp)           /* Position to starting directory */
  1763. X    (void) gotree(-1);
  1764. X
  1765. X  if(ff < 0) {
  1766. X    puthelp("%s %s", who, hitkey);
  1767. X    return(errequest(fpattern, "Not found"));
  1768. X  }
  1769. X  else
  1770. X    return(RV_OK);
  1771. X
  1772. X} /* findtree() */
  1773. X
  1774. X/*
  1775. X *      WRITE TREE LIST
  1776. X */
  1777. X
  1778. X/* Write tree list */
  1779. LOCAL int writetreelist()
  1780. X{
  1781. X  char list[INPLEN], name[NAMELEN], pat[PATLEN];
  1782. X  register char *fn, *w;
  1783. X  register int c, wc;
  1784. X
  1785. X  who = "WRITE TREE";
  1786. X  if((c = changelist(cdlist, who)) < RV_NUL)
  1787. X    return(c);
  1788. X  puthelp("%s: Give list filename (CR:quit)", who);
  1789. X  c = putecho("Write list to:");
  1790. X  if((c = getline(list, sizeof(list), c, 0, NULL, CLIST, 1)) != RV_OK)
  1791. X    return(c);
  1792. X  puthelp("%s: Give choice (D:dirs  F:files  L:list  M:matches  T:tags  ELSE:quit)", who);
  1793. X  (void) putecho("Write out what:");
  1794. X  switch(c = hitakey(NULL)) {
  1795. X    default:  return(c);
  1796. X    case 'D':
  1797. X    case 'd':
  1798. X      wc = 'd';
  1799. X      w = "Directory";
  1800. X      break;
  1801. X    case 'F':
  1802. X    case 'f':
  1803. X      wc = 'f';
  1804. X      w = "File";
  1805. X      break;
  1806. X    case 'L':
  1807. X    case 'l':
  1808. X      wc = 'l';
  1809. X      w = "Tree";
  1810. X      break;
  1811. X    case 'T':
  1812. X    case 't':
  1813. X      wc = 't';
  1814. X      w = "Tagged file";
  1815. X      break;
  1816. X    case 'M':
  1817. X    case 'm':
  1818. X      puthelp("WRITE MATCHING FILES: Give file pattern (CR:quit)");
  1819. X      if((c = getpattern(pat, "Write which files:")) < RV_NUL)
  1820. X       return(c);
  1821. X      wc = 'm';
  1822. X      w = pat;
  1823. X      break;
  1824. X  }
  1825. X
  1826. X  /* Write out list file */
  1827. X  puthelp("%s %s", who, hitkey);
  1828. X  if(fn = writedlist(list, cdlist, w, wc)) {
  1829. X    (void) strcpy(name, fn);
  1830. X    checkdlist(name);
  1831. X    if(buildflag) {
  1832. X      if((c = updatedlist()) != RV_OK)
  1833. X       return(c);
  1834. X      treeflag |= SF_FILE;
  1835. X    }
  1836. X    if(wc == 'm')
  1837. X      (void) putecho("Files matching \'%s\' written to \'%s\'", w, name);
  1838. X    else
  1839. X      (void) putecho("%s list written to \'%s\'", w, name);
  1840. X    return(hitakey(NULL));
  1841. X  }
  1842. X  /* Error in writing */
  1843. X  return(errequest(list, "Cannot write"));
  1844. X
  1845. X} /* writetreelist() */
  1846. X
  1847. X/*
  1848. X *      MOVE UP OR DOWN IN DIRECTORY TREE
  1849. X */
  1850. X
  1851. X/* Go up or down in directory list */
  1852. GLOBL int gotree(dir)
  1853. X  register int dir;
  1854. X{
  1855. X  register int i;
  1856. X
  1857. X  /* At beginning or end of directory tree */
  1858. X  if((dir < 0 && CPREV == GNULL) || (dir > 0 && CNEXT == GNULL))
  1859. X    return(0);
  1860. X  if(dir < 0) {                 /* Previous directory in tree */
  1861. X    cdlist = (dlist *) CPREV;
  1862. X    treeflag |= SF_LIST;
  1863. X    /* Out of screen boundaries */
  1864. X    if(DTROW(cdlist) <= firstdline && cdlist != droot) {
  1865. X      tdlist = cdlist;
  1866. X      for(i = ndlines / 2; i > 0 && DPREV(tdlist); i--)
  1867. X       tdlist = (dlist *) DPREV(tdlist);
  1868. X      treeflag |= SF_TREE;
  1869. X    }
  1870. X    else
  1871. X      treeflag |= SF_LAST;
  1872. X  }
  1873. X  else {                        /* Next directory in tree */
  1874. X    cdlist = (dlist *) CNEXT;
  1875. X    treeflag |= SF_LIST;
  1876. X    /* Out of screen boundaries */
  1877. X    if(DTROW(cdlist) > lastdline || (DTROW(cdlist) == lastdline && CNEXT)) {
  1878. X      tdlist = cdlist;
  1879. X      for(i = ndlines / 2; i > 0 &&  DNEXT(tdlist); i--)
  1880. X       tdlist = (dlist *) DNEXT(tdlist);
  1881. X      for(i = ndlines; DPREV(tdlist) && i > 0; i--)
  1882. X       tdlist = (dlist *) DPREV(tdlist);
  1883. X      treeflag |= SF_TREE;
  1884. X    }
  1885. X    else
  1886. X      treeflag |= SF_LAST;
  1887. X  }
  1888. X
  1889. X  treeflag |= SF_FILE;
  1890. X  return(1);
  1891. X
  1892. X} /* gotree() */
  1893. X
  1894. X/* Go up or down on same level */
  1895. LOCAL int golevel(dir)
  1896. X  register int dir;
  1897. X{
  1898. X  register dlist *dp;
  1899. X  register int l;
  1900. X
  1901. X  l = CLEVL;
  1902. X  if(dir < 0 && cdlist != droot) {      /* Up */
  1903. X    for(dp = (dlist *) CPREV; dp; dp = (dlist *) DPREV(dp))
  1904. X      if(DLEVL(dp) <= l)
  1905. X       break;
  1906. X      do
  1907. X       (void) gotree(dir);
  1908. X      while(dp && cdlist != dp);
  1909. X      if(dp && DLEVL(dp) == l)
  1910. X       return(1);
  1911. X  }
  1912. X  else if(dir > 0 && CNEXT) {           /* Down */
  1913. X    for(dp = (dlist *) CNEXT; dp; dp = (dlist *) DNEXT(dp))
  1914. X      if(DLEVL(dp) <= l)
  1915. X       break;
  1916. X      do
  1917. X       (void) gotree(dir);
  1918. X      while(dp && cdlist != dp);
  1919. X      if(dp && DLEVL(dp) == l)
  1920. X       return(1);
  1921. X  }
  1922. X
  1923. X  return(0);                            /* Not possible */
  1924. X
  1925. X} /* golevel() */
  1926. X
  1927. X/* Go page up or down */
  1928. LOCAL int gopage(dir)
  1929. X  register int dir;
  1930. X{
  1931. X  register int l;
  1932. X
  1933. X  if(dir < 0 && CPREV) {                /* Page up */
  1934. X    for(l = ndlines; l > 0 && gotree(dir); l--)
  1935. X      ;
  1936. X    return(1);
  1937. X  }
  1938. X  else if(dir > 0 && CNEXT) {           /* Page down */
  1939. X    for(l = ndlines; l > 0 && gotree(1) ; l--)
  1940. X      ;
  1941. X    return(1);
  1942. X  }
  1943. X
  1944. X  return(0);                            /* Not possible */
  1945. X
  1946. X} /* gopage() */
  1947. X
  1948. X/* Go to beginning or end of tree */
  1949. LOCAL int gobegend(dir)
  1950. X  register int dir;
  1951. X{
  1952. X  if(dir < 0 && CPREV) {                /* Beginning */
  1953. X    mdlist = cdlist;
  1954. X    while(gotree(dir))
  1955. X      ;
  1956. X    return(1);
  1957. X  }
  1958. X  else if(dir > 0 && CNEXT) {           /* End */
  1959. X    mdlist = cdlist;
  1960. X    while(gotree(dir))
  1961. X      ;
  1962. X    return(1);
  1963. X  }
  1964. X
  1965. X  return(0);                            /* Not possible */
  1966. X
  1967. X} /* gobegend() */
  1968. X
  1969. X/*
  1970. X *      REFRESH ON SCREEN RESIZING
  1971. X */
  1972. X
  1973. X#if     defined(SIGWINCH) && defined(TIOCGWINSZ)
  1974. X/* Refresh tree screen after screen size changes */
  1975. GLOBL int refreshtree(f)
  1976. X  register int f;
  1977. X{
  1978. X  register dlist *dp;
  1979. X
  1980. X  if(f)
  1981. X    (void) refreshfile(0);
  1982. X  checkindent();
  1983. X  ndlines = lastdline - firstdline;
  1984. X  dp = cdlist;
  1985. X  cdlist = tdlist = droot;
  1986. X  while(cdlist != dp && gotree(1))
  1987. X    ;
  1988. X  treeflag = SF_FULL;
  1989. X  return(RV_OK);
  1990. X
  1991. X} /* refreshtree() */
  1992. X#endif  /* SIGWINCH && TIOCGWINSZ */
  1993. X
  1994. X/*
  1995. X *      SELECT DIRECTORY
  1996. X */
  1997. X
  1998. X/* Walk thru tree and select a directory */
  1999. GLOBL char *selectdir(what)
  2000. X  register char *what;
  2001. X{
  2002. X  register dlist *cd, *td;
  2003. X  register char *dn;
  2004. X  register int c, f;
  2005. X
  2006. X  /* Save current and top dirs */
  2007. X  cd = cdlist;
  2008. X  td = tdlist;
  2009. X  dn = what;
  2010. X  treeflag = SF_FULL;
  2011. X
  2012. X  /* Select tree loop */
  2013. X  do {
  2014. X    /* Special update for tree screen if needed */
  2015. X    if(treeflag) {
  2016. X      f = 0;
  2017. X      if(treeflag & SF_HELP)
  2018. X       f |= SF_HELP;
  2019. X      if(treeflag & SF_ECHO)
  2020. X       f |= SF_ECHO;
  2021. X      if((c = updatetree(1)) != RV_OK) {
  2022. X       dn = NULL;
  2023. X       break;
  2024. X      }
  2025. X      if(f & SF_HELP)
  2026. X       puthelp("SELECT DIRECTORY (CR:select  Q:quit)");
  2027. X      if(f & SF_ECHO)
  2028. X       (void) putecho("Move to and select directory for %s", what);
  2029. X      if(f)
  2030. X       (void) cursorxy(TCOL+DTCOL(cdlist)-1, DTROW(cdlist));
  2031. X      f = 0;
  2032. X    }
  2033. X    switch(c = getkey()) {
  2034. X      default:                  /* Ignore */
  2035. X       bell(VARSET(V_BL));
  2036. X       break;
  2037. X      case '>':                 /* Select current directory */
  2038. X      case ' ':
  2039. X      case K_SEL:
  2040. X      case K_INS:
  2041. X       dn = CPNAM;
  2042. X       break;
  2043. X      case '<':                 /* Parent */
  2044. X      case K_DEL:
  2045. X       if( !goparent())
  2046. X         bell(VARSET(V_BL));
  2047. X       break;
  2048. X      case 'q':                 /* Return */
  2049. X      case 'Q':
  2050. X      case K_BRK:
  2051. X      case K_EOF:               /* EOF */
  2052. X       dn = NULL;
  2053. X       break;
  2054. X      case K_PREV:              /* Previous */
  2055. X      case 'k':                 /* For vi fans */
  2056. X       if( !gotree(-1))
  2057. X         bell(VARSET(V_BL));
  2058. X       break;
  2059. X      case K_NEXT:              /* Next */
  2060. X      case 'j':                 /* For vi fans */
  2061. X       if( !gotree(1))
  2062. X         bell(VARSET(V_BL));
  2063. X       break;
  2064. X      case K_BACK:              /* Up on same level */
  2065. X       if( !golevel(-1))
  2066. X         bell(VARSET(V_BL));
  2067. X       break;
  2068. X      case K_FORW:              /* Down on same level */
  2069. X       if( !golevel(1))
  2070. X         bell(VARSET(V_BL));
  2071. X       break;
  2072. X      case K_PPAG:              /* Page up */
  2073. X       if( !gopage(-1))
  2074. X         bell(VARSET(V_BL));
  2075. X       break;
  2076. X      case K_NPAG:              /* Page down */
  2077. X       if( !gopage(1))
  2078. X         bell(VARSET(V_BL));
  2079. X       break;
  2080. X      case K_HOME:              /* Beginning */
  2081. X       if( !gobegend(-1))
  2082. X         bell(VARSET(V_BL));
  2083. X       break;
  2084. X      case K_END:               /* End */
  2085. X       if( !gobegend(1))
  2086. X         bell(VARSET(V_BL));
  2087. X       break;
  2088. X      case 'c':                 /* Change to directory */
  2089. X       c = changedir();
  2090. X       break;
  2091. X      case '@':                 /* Mark current directory */
  2092. X      case K_MARK:
  2093. X       markdir(0);
  2094. X       break;
  2095. X      case '#':                 /* Goto previously marked directory */
  2096. X      case K_GOTO:
  2097. X       if( !gomarkdir())
  2098. X         bell(VARSET(V_BL));
  2099. X       break;
  2100. X      case K_SIZE:              /* Screen size changed */
  2101. X       c = RV_SIZ;
  2102. X       /*FALL THROUGH*/
  2103. X      case K_REFR:              /* Refresh */
  2104. X       treeflag = SF_FULL;
  2105. X       break;
  2106. X    }
  2107. X#if     defined(SIGWINCH) && defined(TIOCGWINSZ)
  2108. X    /* Refresh screen after screen resize */
  2109. X    if(c == RV_SIZ)
  2110. X      (void) refreshtree(1);
  2111. X#endif  /* SIGWINCH && TIOCGWINSZ */
  2112. X  } while(dn == what);
  2113. X
  2114. X  /* Restore current and top dirs */
  2115. X  cdlist = cd;
  2116. X  tdlist = td;
  2117. X
  2118. X  return(dn);
  2119. X
  2120. X} /* selectdir() */
  2121. X
  2122. X/*
  2123. X *      DIRECTORY TREE MENU LOOP
  2124. X */
  2125. X
  2126. X/* Tree menu */
  2127. GLOBL int treemenu(update)
  2128. X  register int update;
  2129. X{
  2130. X  register int c;
  2131. X
  2132. X  /* Init tree variables */
  2133. X  checkindent();
  2134. X  cdlist   = tdlist = droot;
  2135. X  menuline = tmline;
  2136. X  treeflag = SF_FULL;
  2137. X
  2138. X  /* Scan and update file lists in tree if reading from a list file */
  2139. X  if(update && scantree(0) != RV_OK)
  2140. X    return(c);
  2141. X
  2142. X  /* Tree menu loop */
  2143. X  do {
  2144. X    /* Update tree screen if needed and clock */
  2145. X    buildflag = 0;
  2146. X    if(treeflag && (c = updatetree(0)) != RV_OK)
  2147. X      return(c);
  2148. X#ifdef  UTCLOCK
  2149. X    if(VARSET(V_CL))
  2150. X      clockon();
  2151. X#endif  /* UTCLOCK */
  2152. X    c = getkey();
  2153. X#ifdef  UTCLOCK
  2154. X    if(VARSET(V_CL))
  2155. X      clockoff();
  2156. X#endif  /* UTCLOCK */
  2157. X    switch(c) {
  2158. X      case K_BRK:               /* Ignore interrupt */
  2159. X      default:                  /* Unknown: ring the bell */
  2160. X       bell(VARSET(V_BL));
  2161. X       break;
  2162. X      case K_PREV:              /* Previous */
  2163. X      case 'k':                 /* For vi fans */
  2164. X       if( !gotree(-1))
  2165. X         bell(VARSET(V_BL));
  2166. X       break;
  2167. X      case K_NEXT:              /* Next */
  2168. X      case 'j':                 /* For vi fans */
  2169. X       if( !gotree(1))
  2170. X         bell(VARSET(V_BL));
  2171. X       break;
  2172. X      case K_BACK:              /* Up on same level */
  2173. X       if( !golevel(-1))
  2174. X         bell(VARSET(V_BL));
  2175. X       break;
  2176. X      case K_FORW:              /* Down on same level */
  2177. X       if( !golevel(1))
  2178. X         bell(VARSET(V_BL));
  2179. X       break;
  2180. X      case K_TAG:               /* Next directory containing tagged files */
  2181. X       if( !gotagged())
  2182. X         bell(VARSET(V_BL));
  2183. X       break;
  2184. X      case K_UP:                /* Scroll up */
  2185. X       if( !scrolltree(1))
  2186. X         bell(VARSET(V_BL));
  2187. X       break;
  2188. X      case K_DOWN:              /* Scroll down */
  2189. X       if( !scrolltree(-1))
  2190. X         bell(VARSET(V_BL));
  2191. X       break;
  2192. X      case K_PPAG:              /* Page up */
  2193. X       if( !gopage(-1))
  2194. X         bell(VARSET(V_BL));
  2195. X       break;
  2196. X      case K_NPAG:              /* Page down */
  2197. X       if( !gopage(1))
  2198. X         bell(VARSET(V_BL));
  2199. X       break;
  2200. X      case K_HOME:              /* Begin */
  2201. X       if( !gobegend(-1))
  2202. X         bell(VARSET(V_BL));
  2203. X       break;
  2204. X      case K_END:               /* End */
  2205. X       if( !gobegend(1))
  2206. X         bell(VARSET(V_BL));
  2207. X       break;
  2208. X      case '@':                 /* Mark current directory */
  2209. X      case K_MARK:
  2210. X       markdir(0);
  2211. X       break;
  2212. X      case '#':                 /* Goto previously marked directory */
  2213. X      case K_GOTO:
  2214. X       if( !gomarkdir())
  2215. X         bell(VARSET(V_BL));
  2216. X       break;
  2217. X      case K_SIZE:              /* Screen size changed */
  2218. X       c = RV_SIZ;
  2219. X       /*FALL THROUGH*/
  2220. X      case K_REFR:              /* Refresh */
  2221. X       treeflag = SF_FULL;
  2222. X       break;
  2223. X      case '?':                 /* Help */
  2224. X      case 'h':
  2225. X      case 'H':
  2226. X      case K_HELP:
  2227. X       c = showhelp('t');
  2228. X       break;
  2229. X      case '<':                 /* Change to parent */
  2230. X      case K_DEL:
  2231. X       if( !goparent()) {
  2232. X         bell(VARSET(V_BL));
  2233. X         break;
  2234. X       }
  2235. X       /*FALL THROUGH*/
  2236. X      case ' ':                 /* Change to directory */
  2237. X      case '>':
  2238. X      case K_SEL:
  2239. X      case K_INS:
  2240. X       do
  2241. X         c = filemenu(-1, c);
  2242. X       while(c == RV_DIR);
  2243. X       break;
  2244. X      case 'b':                 /* Backup tree */
  2245. X       c = backupdir(ONTG(c));
  2246. X       break;
  2247. X      case 'l':                 /* List file in tree */
  2248. X       c = listtree(ONTG(c));
  2249. X       break;
  2250. X      case 'm':                 /* Create a directory */
  2251. X       c = makedir();
  2252. X       break;
  2253. X      case 'r':                 /* Remove a directory */
  2254. X       c = removedir();
  2255. X       break;
  2256. X      case 'c':                 /* Change to directory */
  2257. X       c = changedir();
  2258. X       break;
  2259. X      case 'L':                 /* List tagged files */
  2260. X       c = listtree(ONTG(c));
  2261. X       break;
  2262. X      case 'B':                 /* Backup tagged files */
  2263. X       c = backupdir(ONTG(c));
  2264. X       break;
  2265. X      case 'C':                 /* Copy tagged files */
  2266. X       c = copytagged();
  2267. X       break;
  2268. X      case 'R':                 /* Remove tagged files */
  2269. X       c = removetagged();
  2270. X       break;
  2271. X      case 'M':                 /* Move tagged files */
  2272. X       c = movetagged();
  2273. X       break;
  2274. X      case 's':                 /* Display directory status info */
  2275. X      case 'S':
  2276. X       c = statusdir();
  2277. X       break;
  2278. X      case 'i':                 /* Display directory information */
  2279. X      case 'I':
  2280. X       c = infodir();
  2281. X       break;
  2282. X      case 'g':                 /* Search for string */
  2283. X      case 'G':
  2284. X       c = greptree(ONTR(c));
  2285. X       break;
  2286. X      case 'f':                 /* Find a file */
  2287. X      case 'F':
  2288. X       c = findtree(ONTR(c));
  2289. X       break;
  2290. X      case 't':                 /* Tag files */
  2291. X      case 'T':
  2292. X       c = tagtree(ONTR(c));
  2293. X       break;
  2294. X      case 'u':                 /* Untag files */
  2295. X      case 'U':
  2296. X       c = untagtree(ONTR(c));
  2297. X       break;
  2298. X      case 'n':                 /* New sort file list */
  2299. X      case 'N':
  2300. X       c = sorttree(ONTR(c));
  2301. X       break;
  2302. X      case 'z':                 /* Zoom file list */
  2303. X      case 'Z':
  2304. X       c = zoomtree(ONTR(c));
  2305. X       break;
  2306. X      case '0':                 /* Switch menu line */
  2307. X       menuline = menuline == utreemenu ? tmline : utreemenu;
  2308. X       treeflag |= SF_HELP;
  2309. X       break;
  2310. X      case '1':                 /* User defined tree command 1..9 */
  2311. X      case '2':
  2312. X      case '3':
  2313. X      case '4':
  2314. X      case '5':
  2315. X      case '6':
  2316. X      case '7':
  2317. X      case '8':
  2318. X      case '9':
  2319. X       if(changelist(cdlist, "USER COMMAND") < RV_NUL)
  2320. X         break;
  2321. X       c = usercommand(c - '0' + V_TC0);
  2322. X       break;
  2323. X      case '!':                 /* Escape to shell */
  2324. X      case '$':
  2325. X       if(changelist(cdlist, "SHELL ESCAPE") < RV_NUL)
  2326. X         break;
  2327. X       c = history(c, V_TC1);
  2328. X       if(VARSET(V_ST))
  2329. X         (void) scandlist(droot);
  2330. X       if(buildflag)
  2331. X         c = updatedlist();
  2332. X       break;
  2333. X      case '=':                 /* Show/set variables */
  2334. X       c = variables();
  2335. X       break;
  2336. X      case ':':                 /* Show/set file type commands */
  2337. X       c = commands();
  2338. X       break;
  2339. X      case '|':                 /* Show key bindings */
  2340. X       c = bindings();
  2341. X       break;
  2342. X      case '+':                 /* Enlarge tree window */
  2343. X       if( !resizetree(1))
  2344. X         bell(VARSET(V_BL));
  2345. X       break;
  2346. X      case '-':                 /* Shrink tree window */
  2347. X       if( !resizetree(-1))
  2348. X         bell(VARSET(V_BL));
  2349. X       break;
  2350. X      case 'o':                 /* Write out tree list */
  2351. X      case 'O':
  2352. X       c = writetreelist();
  2353. X       break;
  2354. X      case '/':                 /* Scan directory tree and update file lists */
  2355. X       c = scantree(1);
  2356. X       break;
  2357. X      case '\\':                /* Build subdirectory tree */
  2358. X       c = buildtree();
  2359. X       break;
  2360. X      case 'a':                 /* Display version string */
  2361. X      case 'A':
  2362. X       c = putversion(echoline, "ABOUT: Utree version");
  2363. X       break;
  2364. X      case 'd':                 /* Date */
  2365. X      case 'D':
  2366. X       c = printdate();
  2367. X       break;
  2368. X      case 'w':                 /* Print current working directory */
  2369. X      case 'W':
  2370. X       c = printcwd();
  2371. X       break;
  2372. X      case 'q':                 /* Exit utree */
  2373. X      case 'Q':
  2374. X      case K_EOF:
  2375. X       c = RV_END;
  2376. X       break;
  2377. X    }
  2378. X#if     defined(SIGWINCH) && defined(TIOCGWINSZ)
  2379. X    /* Refresh screen after screen resize */
  2380. X    if(c == RV_SIZ)
  2381. X      c = refreshtree(1);
  2382. X#endif  /* SIGWINCH && TIOCGWINSZ */
  2383. X  } while( !(c == RV_END || c == RV_ERR));
  2384. X
  2385. X  return(c);
  2386. X
  2387. X} /* treemenu() */
  2388. X
  2389. END_OF_FILE
  2390. if test 63122 -ne `wc -c <'src/tree.c'`; then
  2391.     echo shar: \"'src/tree.c'\" unpacked with wrong size!
  2392. fi
  2393. # end of 'src/tree.c'
  2394. fi
  2395. echo shar: End of archive 8 \(of 8\).
  2396. cp /dev/null ark8isdone
  2397. MISSING=""
  2398. for I in 1 2 3 4 5 6 7 8 ; do
  2399.     if test ! -f ark${I}isdone ; then
  2400.     MISSING="${MISSING} ${I}"
  2401.     fi
  2402. done
  2403. if test "${MISSING}" = "" ; then
  2404.     echo You have unpacked all 8 archives.
  2405.     rm -f ark[1-9]isdone
  2406. else
  2407.     echo You still need to unpack the following archives:
  2408.     echo "        " ${MISSING}
  2409. fi
  2410. ##  End of shell archive.
  2411. exit 0
  2412.