home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / sources / unix / 270 < prev    next >
Encoding:
Text File  |  1992-09-07  |  65.7 KB  |  2,418 lines

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