home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / sources / unix / 267 < prev    next >
Encoding:
Text File  |  1992-09-08  |  69.7 KB  |  2,176 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: v26i068: utree - screen oriented filesystem utility (V3.03b-um), Part05/08
  5. Message-ID: <1992Sep7.214926.26985@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:49:26 GMT
  10. Approved: vixie@pa.dec.com
  11. Lines: 2163
  12.  
  13. Submitted-By: klin@iat.uni-paderborn.de (Peter Klingebiel)
  14. Posting-Number: Volume 26, Issue 68
  15. Archive-Name: utree/part05
  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 5 (of 8)."
  24. # Contents:  lib/utree.help src/list.c src/vars.c
  25. # Wrapped by vixie@cognition.pa.dec.com on Mon Sep  7 14:39:56 1992
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'lib/utree.help' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'lib/utree.help'\"
  29. else
  30. echo shar: Extracting \"'lib/utree.help'\" \(22386 characters\)
  31. sed "s/^X//" >'lib/utree.help' <<'END_OF_FILE'
  32. X#
  33. X#       UTREE.HELP
  34. X#       UTREE help pages
  35. X#       3.03-um klin, Sun Feb 23 18:45:19 1992
  36. X#       Directory:      /usr/local/lib (default)
  37. X#
  38. X#       Copyright (c) 1991/92 by Peter Klingebiel & UNIX Magazin Muenchen.
  39. X#       For copying and distribution information see the file COPYRIGHT.
  40. X#
  41. X#       Help about items is enclosed in two lines '#@item' and '#@'.
  42. X#       The string 'item' is used as item for the menuline, the lines
  43. X#       between these opening and closing lines are the help lines
  44. X#       for the topic 'item'. The upper case character in 'item' is used
  45. X#       as hotkey for selecting help about this topic.
  46. X#       Be sure that all items separated by a blank fit in one screen line!
  47. X#       Don't change the hot keys because they are hard coded in utree!
  48. X#
  49. X#       SCCSID=@(#) utree 3.03-um (klin) Feb 23 1992 lib/utree.help
  50. X
  51. X#@Help          h: About help
  52. X
  53. X       The utree help page menu lets you select help pages about the
  54. X       following topics (menu hotkeys are enclosed in brackets):
  55. X
  56. X       (h) Help        This help page.
  57. X       (a) About       About utree and some naming conventions.
  58. X       (u) Usage       Utree usage and command line options.
  59. X       (g) Global      Global commands for tree and file screen.
  60. X       (t) Tree        Commands for the tree screen.
  61. X       (f) File        Commands for the file screen.
  62. X       (e) Edit        Commands for the builtin line editor.
  63. X       (v) Vars        Utree variables and variable definition.
  64. X       (c) Cmds        Filetype dependent command definition.
  65. X       (l) Line        Line format for tree, file and filetype commands.
  66. X       (k) Keys        Function keys used by utree.
  67. X       (p) Patterns    File and time pattern matching.
  68. X#@
  69. X#@About         a: About utree and key naming conventions
  70. X
  71. X       This is utree 3.03-um, a screen oriented filesystem browser.
  72. X
  73. X         Copyright (c) 1991/92 Peter Klingebiel & UNIX Magazin.
  74. X                       All rights reserved.
  75. X
  76. X       First utree version (utree 1.00) created in July 1988.
  77. X
  78. X       The naming conventions for keys in the help pages are:
  79. X       'C-key' means hold the <CONTROL>-key and hit <key>,
  80. X       'key' means a single keystroke on the key <key>.
  81. X
  82. X       For many commands on tree and file screen case is significant.
  83. X       Commands given in lowercase letters work on the current directory
  84. X       or file, commands given in uppercase letters work on the current
  85. X       subtree or on tagged files in current subtree or directory.
  86. X
  87. X       Many function keys are supported by utree, i.e the four cursor
  88. X       keys, the begin and end key and some others. For more information
  89. X       about default key bindings and user definable keybindings see
  90. X       the keys help page.
  91. X#@
  92. X#@Usage         u: About utree usage and command line options
  93. X
  94. X       Usage:  utree [-LSVabcghnrqstuw] [-d var=[val]] [-d typ:[cmd]]
  95. X                     [-f lst] [-i ind] [-l lev] [-p lin] [-v mod] [-x cmd]
  96. X                     [rootdir]
  97. X
  98. X       The meaning of the command line options is:
  99. X
  100. X       -L              Follow symbolic links.
  101. X       -S              Ignore default minimal screen size.
  102. X       -V              Display program version.
  103. X       -a              Read in all (including hidden) directories.
  104. X       -b              Suppress ringing of the bell.
  105. X       -c              Don't display and update a clock in echoline.
  106. X       -d var=[val]    Define/undefine variable var.
  107. X       -d typ:[cmd]    Set/unset type command for filetype typ.
  108. X       -f lst          Build tree from list file lst.
  109. X       -g              Don't use graphic characters.
  110. X       -h              Display usage and meaning of command line options.
  111. X       -i ind          Set maximal tree indention to ind
  112. X       -l lev          Build tree up to level lev.
  113. X       -n              Don't scan tree for changes in tree.
  114. X       -o              Omit saving changes in history/definitions/bindings.
  115. X       -p lin          Set file window to lin lines (1..9)
  116. X       -q              Build tree up to level 2 (like -l 2).
  117. X       -r              Recreate tree list (always scan disk).
  118. X       -s              Don't use hardware scrolling.
  119. X       -t              Sort files by modification times.
  120. X       -u              Update file lists in tree.
  121. X       -v mod          Set video attribute setting (0,1,2)
  122. X       -w              Suppress warnings about unreadable directories.
  123. X       -x cmd          Use string cmd as initial command input.
  124. X
  125. X       The boolean options bcgnosw and the numerical options ipv may also
  126. X       be pre-set in the environment variable UTREE.
  127. X#@
  128. X#@Global        g: About global commands for tree and file screen
  129. X
  130. X       The following commands are common for tree and file screen:
  131. X
  132. X       C-z             Terminate and leave utree.
  133. X       C-c,C-y         Cancel command or input.
  134. X       C-l             Refresh/redisplay screen.
  135. X       Tab,C-t         Move to next tagged directory or file.
  136. X       h,?.C-r         Change to help screen for displaying help pages.
  137. X       @,C-@           Mark current directory or file.
  138. X       #,C-g           Move to previously marked directory/file or position.
  139. X       a               Display utree version.
  140. X       d               Display current date and time.
  141. X       j               Next directory or file (for vi fans).
  142. X       k               Previous directory or file (for vi fans).
  143. X       w               Display full pathname of current directory.
  144. X       =               Change to variables screen for setting variables.
  145. X       :               Change to commands screen for setting filetype commands.
  146. X       |               Change to bindings screen for binding keys.
  147. X       !               Change to shell screen for execution of shell commands.
  148. X       $               Escape to an interactive shell session.
  149. X#@
  150. X#@Tree          t: About utree directory tree screen commands
  151. X
  152. X       All tree commands can be given in lowercase or uppercase letters For
  153. X       some commands a lowercase letter hits the current directory only, an
  154. X       uppercase letter hits a complete subtree or all tagged files in subtree.
  155. X
  156. X       >,CR,NL,SP      Change to file screen of current directory.
  157. X       <               Change to file screen of parent directory.
  158. X       C-n             Move to next directory.
  159. X       C-p             Move to previous directory.
  160. X       C-f             Move to next directory on same level.
  161. X       C-b             Move to previous directory on same level.
  162. X       C-v             Move one page forward.
  163. X       C-w             Move one page backward.
  164. X       C-a             Move to begin of directory tree.
  165. X       C-e             Move to end of directory tree.
  166. X       TAB,C-t         Move to next directory containing tagged files.
  167. X       C-u             Scroll up directory tree.
  168. X       C-d,            Scroll down directory tree.
  169. X       @,C-@           Mark current directory.
  170. X       #,C-g           Goto previously marked directory.
  171. X       b,B             Backup all files/tagged files in subtree.
  172. X       c,C             Change to a directory/Copy tagged files.
  173. X       f,F             Find files in current directory/subtree.
  174. X       g,G             Search for pattern in files in directory/subtree.
  175. X       i               Show some directory information.
  176. X       l,L             List files/tagged files in current subtree.
  177. X       m,M             Make a new directory/Move tagged files.
  178. X       n,N             Change sort criteria, sort files in directory/subtree.
  179. X       o               Write a list of directories, files or tagged files.
  180. X       q               Exit utree.
  181. X       r,R             Remove current directory/Remove tagged files.
  182. X       s               Show/change status of current directory.
  183. X       t,T             Tag files in current directory/subtree.
  184. X       u,U             Untag files in current directory/subtree.
  185. X       z,Z             Zoom files in current directory/subtree.
  186. X       +               Enlarge tree window if possible.
  187. X       -               Shrink tree window if possible.
  188. X       /               Scan tree and rebuild directories if needed.
  189. X       \               Scan directory for subdirectories and insert subtree.
  190. X       0               Switch tree/user commands menuline.
  191. X       1..9            Execute user defined tree command.
  192. X
  193. X       For further information about filename patterns for the commands find,
  194. X       grep, list, tag, untag and zoom see the pattern help page.
  195. X#@
  196. X#@File          f: About utree file screen commands
  197. X
  198. X       All file commands can be given in lower or upper case letters.
  199. X       For most commands a lowercase letter hits the current file only,
  200. X       an uppercase letter hits all selected (tagged) files.
  201. X
  202. X       q,CR,NL,SP      Change back to tree screen.
  203. X       C-f             Move to next file.
  204. X       C-b             Move to previous file.
  205. X       C-n             Move to file on next line.
  206. X       C-p             Move to file on previous line.
  207. X       C-v             Move one page forward.
  208. X       C-w             Move one page backward.
  209. X       C-a             Move to first file.
  210. X       C-e             Move to last file.
  211. X       TAB,C-t         Move to next tagged file.
  212. X       C-u             Scroll up file screen.
  213. X       C-d             Scroll down file screen.
  214. X       @,C-@           Mark current file.
  215. X       #,C-g           Goto previously marked file.
  216. X       c,C             Copy file/tagged files.
  217. X       e,E             Edit file/tagged files.
  218. X       f               Find files matching a pattern.
  219. X       g,G             Search for pattern in file/tagged files.
  220. X       i,I             Show some information about file/tagged files.
  221. X       l,L             List files matching a pattern/tagged files.
  222. X       m,M             Rename/move file/tagged files.
  223. X       n               Change sort criteria and resort file list.
  224. X       p,P             Send file/tagged files to printer spooler.
  225. X       r,R             Remove file/tagged files.
  226. X       s,S             Show/change status of file/tagged files.
  227. X       t,T             Tag/select files for further processing.
  228. X       u,U             Untag file/tagged files.
  229. X       v,V             View file/tagged files.
  230. X       x               Execute current file or call a command for it.
  231. X       z               Zoom files in file list.
  232. X       >               If current file is a directory, change to.
  233. X       <               Change back to parent directory.
  234. X       /               Rebuild file list (i.e. after shell escape).
  235. X       0               Switch file/user commands menuline.
  236. X       1..9            Execute user defined file command.
  237. X
  238. X       For further information about filename patterns for the commands find,
  239. X       grep, list, tag, untag and zoom see the pattern help page.
  240. X#@
  241. X#@Edit          e: About utree line editor commands
  242. X
  243. X       The builtin utree line editor knows the following functions:
  244. X       (Function keys are supported if known by termcap/terminfo)
  245. X
  246. X       CR,NL           Accept and send input line.
  247. X       C-c,C-y         Cancel input line and line editor.
  248. X       C-o             Switch insert/overwrite mode.
  249. X       C-l             Redisplay input line.
  250. X       C-f             Move cursor one character forward.
  251. X       C-b             Move cursor one character backward.
  252. X       C-a             Move cursor to beginning of line.
  253. X       C-b             Move cursor to end of line.
  254. X       C-v             Scroll forward line.
  255. X       C-w,            Scroll backward line.
  256. X       C-d             Delete character under cursor.
  257. X       C-h,DEL         Delete character left from cursor.
  258. X       C-x             Delete line.
  259. X       C-k             Delete from cursor position to end of line.
  260. X       C-t             Transpose characters under and left from cursor.
  261. X       C-r             Display help menu and pages.
  262. X       C-@             Set mark at current position.
  263. X       C-g             Move cursor to previously set mark.
  264. X       C-p             Get previous list entry into line editor.
  265. X       C-n             Get next list entry into line editor.
  266. X#@
  267. X#@Vars          v: About utree variables
  268. X
  269. X       Utree knows about and uses the following variables which may be
  270. X       set/unset at startup in the startupfile '$HOME/.utree', with the
  271. X       commandline option '-d' or the variables command '=':
  272. X
  273. X       BL      BELL            Allow ringing of the bell.
  274. X       CL      CLOCK           Show and update clock every second.
  275. X       GC      GRAPHCHARS      Use graphical character set.
  276. X       TS      TERMSCROLL      Use hardware terminal scrolling.
  277. X       ST      SCANTREE        Allow scanning the filesystem for changes.
  278. X       WD      WARNDIRS        Make warnings about unreadable directories.
  279. X       LS      LEXSORT         Sort filenames in file lists in lexical order.
  280. X       AS      AUTOSAVE        Save changes in history, variables and command
  281. X                               definitions and key bindings.
  282. X       TI      TREEINDENT      Maximal tree indention on tree screen (3..9).
  283. X       VM      VIDEOMODE       Using of video attributes (0=none,1,2=all).
  284. X       FL      FILELINES       Maximal file lines on tree screen (1..9).
  285. X       HS      HISTSIZE        Size of history list (Settable at startup only).
  286. X       SH      SHELL           Interactive shell.
  287. X       ED      EDITOR          Editor.
  288. X       EO      EDITOPTS        Editor options.
  289. X       PG      PAGER           File pager/viewer.
  290. X       PO      PAGEOPTS        Pager options.
  291. X       XD      XDUMPER         File hexdumper.
  292. X       XO      XDUMPOPTS       Dumper options.
  293. X       LP      LPRINTER        Printer spooler command.
  294. X       LO      LPRINTOPTS      Printer options.
  295. X       BK      BACKUP          Backup program.
  296. X       BO      BACKUPOPTS      Backup options.
  297. X       T1..9   TREECMD1..9     User defined commands 1..9 for tree screen.
  298. X       F1..9   FILECMD1..9     User defined commands 1..9 for file screen.
  299. X
  300. X       Variables are set with a line 'shorthand=value' or 'variable=value'
  301. X       (i.e. 't1=ps -ef'), unset with a line 'shorthand=' or 'variable='
  302. X       (i.e. 't1='). When defining user tree or file commands some sprintf
  303. X       like format characters lead in by a percent sign ('%') have a
  304. X       special meaning and are expanded before the command is executed (See
  305. X       also the help page line). A sharp sign (#) in a variable definition
  306. X       is used as leadin for a menu item of the defined user file or tree
  307. X       command or as comment.
  308. X
  309. X       E.g.: the variable definition 'fc1=wc -l %F # Count' for user
  310. X       defined file command 1 is expanded to 'wc -l filename' and in the
  311. X       user command file menu 'Count' is displayed behind menu item 1.
  312. X#@
  313. X#@Cmds          c: About filetype dependent commands
  314. X
  315. X       On file screen you can execute a file or a command on it with
  316. X       the utree command execute ('x'). You are requested for parameters
  317. X       if the current file is executable, for a command to execute on the
  318. X       current file if the current file is not executable. For a type of file
  319. X       you can define so called filetype commands which are called if the
  320. X       current file matches this filetype (or extension).
  321. X
  322. X       Filetype commands can be set/unset at startup in the startupfile
  323. X       '$HOME/.utree', with the commandline option '-d' or the filetype
  324. X       command ':' similar to setting/unsetting variables.
  325. X       Filetype commands are set with a line like 'filetype:command'
  326. X       (e.g. '*.c:cc -c -O'). The command ('cc -c -O') is then executed if
  327. X       the current file matches the filetype pattern (e.g. '*.c' for 'foo.c').
  328. X       Filetype commands are unset with a line 'filetype:' (i.e. '*.c:').
  329. X
  330. X       When defining filetype commands some sprintf like format characters
  331. X       lead in by a percent sign ('%') have a special meaning and are
  332. X       expanded before the command is executed. For further information
  333. X       about filename patterns and the format characters and her meaning
  334. X       see the pattern and line help pages.
  335. X#@
  336. X#@Line          l: About line format for tree, file and filetype commands
  337. X
  338. X       When defining a user defined tree or file command or a filetype
  339. X       command or when entering a shell command some sprintf like format
  340. X       characters are known and expanded before the command is executed.
  341. X       These format characters and their meaning are:
  342. X
  343. X       %B,%b   Basename of current file or directory.
  344. X       %D,%d   Full pathname of current directory.
  345. X       %F,%f   Filename of current file or directory.
  346. X       %H,%h   Full pathname of home directory.
  347. X       %R,%r   Full pathname of root directory.
  348. X       %P,%p   Full pathname of current file or directory.
  349. X       %S,%s   Additional parameter(s) for a command which are requested
  350. X               before the command is executed.
  351. X
  352. X       E.g. the command line 'command %s %f >%b.out' is expanded before
  353. X       execution to 'command parameters filename basename.out' with filename
  354. X       and basename.out ('%f', '%b.out') of the current file or directory and
  355. X       parameters ('%s') which are requested before the command is executed.
  356. X
  357. X       For further information about tree/file and filetype commands see
  358. X       the vars and defs help pages.
  359. X#@
  360. X#@Keys          k: About default and user definable key bindings
  361. X
  362. X       The following list denotes the names of all utree keys, their default
  363. X       key bindings and their meanings on tree and file screen or in the line
  364. X       editor (See also the help pages global, tree, file and edit).
  365. X
  366. X       SELECT   (CR,NL) Select directory/file or accept input line.
  367. X       FORWARD  (C-f)   Move forward directory/file or character.
  368. X       BACKWARD (C-b)   Move back directory/file or character.
  369. X       NEXT     (C-n)   Move to next directory or file or get next list entry
  370. X                        into the line editor.
  371. X       PREVIOUS (C-p)   Move to previous directory or file or get previous list
  372. X                        entry into the line editor.
  373. X       NEXTPAGE (C-v)   Next page/Scroll forward input line.
  374. X       PREVPAGE (C-w)   Previous page/Scroll backward input line.
  375. X       BEGIN    (C-a)   Move to beginning of directories/files or input line.
  376. X       END      (C-e)   Move to end of directories/files or input line.
  377. X       UP       (C-u)   Scroll down up one line directories or files.
  378. X       DOWN     (C-d)   Scroll down one line directories or files (on screens)
  379. X                        or delete character under the cursor (in line editor).
  380. X       INSERT   (C-o)   Toggle insert/overwrite mode flag (in line editor)
  381. X                        or change to current directory (on screens).
  382. X       DELETE   (BS)    Delete character left from cursor (in editor) or
  383. X                        change to parent directory (on screens).
  384. X       KILL     (C-k)   Delete from cursor position to end of input line.
  385. X       SETMARK  (C-@)   Set a mark on current directory/file or at cursor
  386. X                        position.
  387. X       GOTOMARK (C-g)   Move to previously marked directory/file or character.
  388. X       GOTOTAG  (TAB)   Move to tagged directory or file (on screens) or
  389. X                        transpose characters (in line editor).
  390. X       HELP     (C-r)   Get help pages and change to help screen.
  391. X       REFRESH  (C-l)   Refresh and redraw screen or input line.
  392. X       CANCEL   (C-x)   Delete whole input line and leave line editor.
  393. X       BREAK    (C-c)   Break current command or line editor.
  394. X       EXIT     (C-z)   Terminate and leave utree.
  395. X
  396. X       The following function keys are bound at startup if they are defined
  397. X       in your system's termcap or terminfo database:
  398. X
  399. X       CursorRight     FORWARD
  400. X       CursorLeft      BACKWARD
  401. X       CursorUp        PREVIOUS
  402. X       CursorDown      NEXT
  403. X       Home/Begin      BEGIN
  404. X       End             END
  405. X       NextPage        NEXTPAGE
  406. X       PreviousPage    PREVPAGE
  407. X       ScrollUp        UP
  408. X       ScrollDown      DOWN
  409. X       Insert          INSERT
  410. X       Delete          DELETE
  411. X       Clear           REFRESH
  412. X       Help            HELP
  413. X       Select          SELECT
  414. X       Do/Command      SELECT
  415. X       Mark            SETMARK
  416. X       Enter           SELECT
  417. X
  418. X       You may bind any key to the denoted utree key symbols or to string on
  419. X       the binding screen or in terminal startup files with the name
  420. X       '.utree-term' in your home directory ('term' is the terminal type from
  421. X       $TERM). This files contain lines built like 'key_sequence=key_name'
  422. X       or 'keysequence="string"' for string insertion bindings.
  423. X       E.g. the line '\eh=HELP' binds the key <ESC><h> to HELP and and the
  424. X       line '\ei="insert"' binds <ESC><i> to insertion of the string 'insert'
  425. X       into the input buffer for further reading and interpretation.
  426. X#@
  427. X#@Patterns      p: About pattern matching
  428. X
  429. X       Some commands (list, find, grep, tag or untag) require filename
  430. X       patterns for matching files using some special (meta) characters.
  431. X
  432. X       File NAME pattern matching interprets the following meta chars:
  433. X       *       matches all characters in a filename.
  434. X       ?       matches one character in a filename.
  435. X       [class] matches all characters enclosed in brackets '[' and ']'
  436. X               where '!' and '-' have a special meaning, i.e.
  437. X               [abc]   matches the characters 'a', 'b' and 'c'.
  438. X               [a-z_]  matches the characters from 'a' to  'z' and '_'.
  439. X               [!a-z_] matches all characters except 'a' to 'z' and '_'.
  440. X
  441. X       File SIZE pattern matching interprets the following meta chars:
  442. X       =size   matches all files equate size
  443. X       !size   matches all files not equate size
  444. X       >size   matches all files larger than size
  445. X       <size   matches all files smaller than size
  446. X       You may specify the file size in bytes (b, default), kilo bytes (k)
  447. X       or mega bytes (m), i.e. '>2k' matches all files larger than 2 kb or
  448. X       2048 bytes.
  449. X
  450. X       File TIME pattern matching interprets the following meta chars:
  451. X       )time   matches all files modified within time.
  452. X       (time   matches all files not modified within time.
  453. X       You may specify time in minutes (m), hours (h, default), days (d) or
  454. X       weeks (w), i.e. ')2d' matches all files modified within last 2 days.
  455. X
  456. X       To combine file name, size and time patterns use
  457. X       &       for ANDing of name/size/time patterns
  458. X       |       for ORing  of name/size/time patterns.
  459. X       If a character is preceeded by a backslash (\) or enclosed in quotes
  460. X       his interpretation is suppressed and he is used as he is.
  461. X#@
  462. X
  463. END_OF_FILE
  464. if test 22386 -ne `wc -c <'lib/utree.help'`; then
  465.     echo shar: \"'lib/utree.help'\" unpacked with wrong size!
  466. fi
  467. # end of 'lib/utree.help'
  468. fi
  469. if test -f 'src/list.c' -a "${1}" != "-c" ; then 
  470.   echo shar: Will not clobber existing file \"'src/list.c'\"
  471. else
  472. echo shar: Extracting \"'src/list.c'\" \(22046 characters\)
  473. sed "s/^X//" >'src/list.c' <<'END_OF_FILE'
  474. X/*
  475. X *      LIST.C
  476. X *      UTREE directory and file list handling routines.
  477. X *      3.01-um klin, Tue Jun  4 14:17:17 1991
  478. X *              klin, Tue Oct 15 14:02:37 1991, Handling of symlinks changed
  479. X *              klin, Sat Oct 26 15:07:06 1991, Print tree list added
  480. X *                                              writedlist() changed
  481. X *      3.02-um klin, Fri Nov  1 13:41:58 1991, Minor changes
  482. X *              klin, Sun Nov 10 19:37:14 1991, buildlist() changed
  483. X *              klin, Sun Nov 24 11:44:49 1991, Some error fixes reported by
  484. X *                                              Rolf Gebhardt (RG 11/22/91)
  485. X *      3.03-um klin, Sat Feb 15 20:09:09 1992, Minor changes
  486. X *
  487. X *      Copyright (c) 1991/92 by Peter Klingebiel & UNIX Magazin Muenchen.
  488. X *      For copying and distribution information see the file COPYRIGHT.
  489. X */
  490. X#ifndef lint
  491. static char sccsid[] = "@(#) utree 3.03-um (klin) Feb 15 1992 list.c";
  492. X#endif  /* !lint */
  493. X
  494. X#include "defs.h"
  495. X
  496. X/* ---- External variables and functions ------------------------------ */
  497. X
  498. XEXTRN char *readdname();
  499. XEXTRN char *getversion();
  500. X
  501. X/* ---- Local/global functions and procedures --------------------------*/
  502. X
  503. X/*
  504. X *      INTERNAL USED ROUTINES
  505. X */
  506. X
  507. X/* Compare filenames from flist. Called by qsort() */
  508. LOCAL int flistcmp(f1, f2)
  509. X  register flist *f1, *f2;
  510. X{
  511. X  if(sortbytime) {
  512. X    if(FPTIM(f1) < FPTIM(f2))
  513. X      return(99);
  514. X    else if(FPTIM(f1) > FPTIM(f2))
  515. X      return(-99);
  516. X  }
  517. X  return(CMP(FPFIL(f1), FPFIL(f2)));
  518. X
  519. X} /* flistcmp() */
  520. X
  521. X/* Compare filenames from directory name vector. Called by qsort() */
  522. LOCAL int dlistcmp(d1, d2)
  523. X  register char **d1, **d2;
  524. X{
  525. X  return(CMP(*d1, *d2));
  526. X
  527. X} /* dlistcmp() */
  528. X
  529. X/* Count directory level */
  530. LOCAL int countlevl(name)
  531. X  register char *name;
  532. X{
  533. X  register int n;
  534. X
  535. X  if(*name == '/' && *(name+1) == '\0')
  536. X    return(0);
  537. X  n = 0;
  538. X  while(*name)
  539. X    if(*name++ == '/')
  540. X      ++n;
  541. X  return(n);
  542. X
  543. X} /* countlevl() */
  544. X
  545. X/* Align buffer size to avoid too often alloc and free */
  546. LOCAL unsigned alignbsiz(s, n)
  547. X  register unsigned s;
  548. X  register int n;
  549. X{
  550. X  register unsigned ns;
  551. X
  552. X  if(s == 0 || n == 0)
  553. X    ns = 0;
  554. X  else
  555. X    for(ns = NBUFSZ; ns < s; ns += NBUFINC)
  556. X      ;
  557. X  return(ns);
  558. X
  559. X} /* alignbsiz() */
  560. X
  561. X/* Align filevector size to avoid too often alloc and free */
  562. LOCAL int alignnfils(n)
  563. X  register int n;
  564. X{
  565. X  register int nn;
  566. X
  567. X  if(n == 0)
  568. X    nn = 0;
  569. X  else
  570. X    for(nn = NFILES; nn < n; nn += NFILINC)
  571. X      ;
  572. X  return(nn);
  573. X
  574. X} /* alignnfils() */
  575. X
  576. X/*
  577. X *      FILE LIST ROUTINES
  578. X */
  579. X
  580. X/* Update file f in file list */
  581. LOCAL VOID insertflist(dp, f)
  582. X  register dlist *dp;
  583. X  register int f;
  584. X{
  585. X  struct stat st;
  586. X  register char *pn;
  587. X
  588. X  /* Get mode flag for file */
  589. X  pn = pathname(FFNAM(dp, f), DPNAM(dp));
  590. X  if((*statfun)(pn, &st) == 0) {
  591. X    switch(STFMT(&st)) {
  592. X#ifdef  S_IFLNK
  593. X      case S_IFLNK:             /* Symbolic link */
  594. X       FMODE(dp, f) = FF_SLNK;
  595. X       break;
  596. X#endif  /* S_IFLNK */
  597. X#ifdef  S_IFSOCK
  598. X      case S_IFSOCK:            /* Socket */
  599. X       FMODE(dp, f) = FF_SOCK;
  600. X       break;
  601. X#endif
  602. X      case S_IFDIR:             /* Directory */
  603. X       FMODE(dp, f) = FF_DIR;
  604. X       ++DNDIR(dp);
  605. X       break;
  606. X      default:                  /* Executable or other file */
  607. X       FMODE(dp, f) = (st.st_mode & 0111) ? FF_EXEC : FF_NONE;
  608. X       break;
  609. X    }
  610. X    FMTIM(dp, f) = st.st_mtime;
  611. X    FSIZE(dp, f) = st.st_size;
  612. X  }
  613. X  else {
  614. X    FMODE(dp, f) = FF_ERR;
  615. X    FMTIM(dp, f) = (time_t) 0;
  616. X    FSIZE(dp, f) = (off_t) 0;
  617. X  }
  618. X  FITAG(dp, f) = FF_NONE;
  619. X
  620. X} /* insertflist() */
  621. X
  622. X/* Delete an entry from file list */
  623. GLOBL VOID deleteflist(dp, f)
  624. X  register dlist *dp;
  625. X  register int f;
  626. X{
  627. X  register int n;
  628. X
  629. X  /* Do nothing and return if file list is not yet read in (RG 11/22/91) */
  630. X  if(DFVEC(dp) == FNULL)
  631. X    return;
  632. X  /* Move up file name, tag and mode flag in file list */
  633. X  n = f + 1;
  634. X  if(FITAG(dp, f) && DNTAG(dp) > 0)
  635. X    --DNTAG(dp);
  636. X  while(n < DNFIL(dp)) {
  637. X    FFNAM(dp, f) = FFNAM(dp, n);
  638. X    FITAG(dp, f) = FITAG(dp, n);
  639. X    FMODE(dp, f) = FMODE(dp, n);
  640. X    ++f;
  641. X    ++n;
  642. X  }
  643. X  /* Decrement counters */
  644. X  --DNFIL(dp);
  645. X  --filecount;
  646. X
  647. X} /* deleteflist() */
  648. X
  649. X/* Sort or resort file list from directory dp */
  650. GLOBL VOID sortflist(dp)
  651. X  register dlist *dp;
  652. X{
  653. X  register int f;
  654. X
  655. X  f = sortbytime;
  656. X  sortbytime = DSORT(dp) ? 1 : 0;       /* Set flag for comparing */
  657. X  if(DNFIL(dp) > 0)                     /* Sort/resort file list */
  658. X    qsort((char *) DFVEC(dp), (unsigned) DNFIL(dp), sizeof(flist), flistcmp);
  659. X  sortbytime = f;
  660. X
  661. X} /* sortflist() */
  662. X
  663. X/* Zoom file list of directory dp */
  664. GLOBL VOID zoomflist(dp)
  665. X  register dlist *dp;
  666. X{
  667. X  register int f, n;
  668. X
  669. X  if(DZOOM(dp)) {
  670. X    for(f = n = 0; f < DNFIL(dp); f++)
  671. X      if(umatch(dp, f, DZOOM(dp))) {
  672. X       if(n != f)
  673. X         FLIST(dp, n) = FLIST(dp, f);
  674. X       ++n;
  675. X      }
  676. X    DNFIL(dp) = n;
  677. X  }
  678. X
  679. X} /* zoomflist() */
  680. X
  681. X/* Rebuild file list in some cases (i.e. cp, mv ..) */
  682. GLOBL int newflist(dp)
  683. X  register dlist *dp;
  684. X{
  685. X  char cfnam[NAMELEN];
  686. X  struct stat st;
  687. X  register flist *fv;
  688. X  register char *fbp, *name, *fb;
  689. X  register int i, j, k, nfil, ntag;
  690. X  register unsigned size;
  691. X  register DIR *dirfp;
  692. X
  693. X  (void) putecho("Building %s", DPNAM(dp));
  694. X  flushout();
  695. X  /* Set/reset counter */
  696. X  nfil = DNFIL(dp);
  697. X  ntag = DNTAG(dp);
  698. X  filecount -= DNFIL(dp);
  699. X  DNFIL(dp) = DNDIR(dp) = DNTAG(dp) = 0;
  700. X
  701. X  /* Get status of directory and read in */
  702. X  if((*statfun)(DPNAM(dp), &st) == 0 && (dirfp = opendir(DPNAM(dp)))) {
  703. X    /* Save name of current file */
  704. X    if(nfil > 0) {
  705. X      (void) strcpy(cfnam, FFNAM(dp, DFCUR(dp)));
  706. X      /* Save flist array and file buffer */
  707. X      if(ntag > 0) {
  708. X       fb = DFBUF(dp);
  709. X       fv = DFVEC(dp);
  710. X       DFBUF(dp) = NULL;
  711. X       DBSIZ(dp) = 0;
  712. X      }
  713. X    }
  714. X    /* Count files */
  715. X    for(i = 0; readdname(dirfp); i++)
  716. X      ;
  717. X    rewinddir(dirfp);
  718. X    /* Align file count and buffer size */
  719. X    i = alignnfils(i);
  720. X    size = alignbsiz((unsigned) st.st_size, i);
  721. X    /* Release current file list and file name buffer if needed */
  722. X    if(DFBUF(dp) && DBSIZ(dp) < size) {
  723. X      ufree(DFBUF(dp));
  724. X      ufree((char *) DFVEC(dp));
  725. X      DFBUF(dp) = NULL;
  726. X      DBSIZ(dp) = 0;
  727. X    }
  728. X    /* Get memory for file list and file name buffer if not yet done */
  729. X    if(DFBUF(dp) == NULL && i > 0) {
  730. X      DFBUF(dp) = (char *)  ualloc(size, sizeof(char));         /* RG 11/22/91 */
  731. X      DFVEC(dp) = (flist *) ualloc((unsigned) i, sizeof(flist));
  732. X      DBSIZ(dp) = size;
  733. X    }
  734. X    /* Fill up file list and file name buffer */
  735. X    for(i = 0, fbp = DFBUF(dp); name = readdname(dirfp); i++) {
  736. X      FFNAM(dp, i) = strcpy(fbp, name);
  737. X      fbp += strlen(name) + 1;
  738. X      insertflist(dp, i);
  739. X    }
  740. X    closedir(dirfp);
  741. X    DNFIL(dp) = i;
  742. X    sortflist(dp);
  743. X    if(DZOOM(dp))
  744. X      zoomflist(dp);
  745. X    /* Set up other directory data */
  746. X    DFLAG(dp) = FL_FIL;
  747. X    DMTIM(dp) = st.st_mtime;
  748. X    DCTIM(dp) = st.st_ctime;
  749. X    DCANC(dp) = CANCD(DPNAM(dp));
  750. X    /* Try to restore current file */
  751. X    DFTOP(dp) = DFCUR(dp) = 0;
  752. X    if(nfil > 0) {
  753. X      for(i = 0; i < DNFIL(dp); i++)
  754. X       if(cfnam[0] != *FFNAM(dp, i) || CMP(cfnam, FFNAM(dp, i)))
  755. X         (void) gofile(dp, 1);
  756. X       else
  757. X         break;
  758. X      if(i >= DNFIL(dp))
  759. X       while(gofile(dp, -1))
  760. X         ;
  761. X      /* Try to restore tagged files */
  762. X      if(ntag > 0) {
  763. X       i = j = 0;
  764. X       while(i < nfil) {
  765. X         if(FVTAG(fv, i) == FF_TAG)
  766. X           for(k = j; k < DNFIL(dp); k++)
  767. X             if(*FVFIL(fv,i) == *FFNAM(dp,k) && EQU(FVFIL(fv,i), FFNAM(dp,k))) {
  768. X               FITAG(dp, k) = FF_TAG;
  769. X               ++DNTAG(dp);
  770. X               j = k;
  771. X               break;
  772. X             }
  773. X         ++i;
  774. X       }
  775. X      }
  776. X    }
  777. X    filecount += DNFIL(dp);
  778. X  }
  779. X  /* Error in stat: use defaults */
  780. X  else {
  781. X    ufree(DFBUF(dp));
  782. X    ufree((char *) DFVEC(dp));
  783. X    DFBUF(dp) = NULL;
  784. X    DFVEC(dp) = FNULL;
  785. X    DBSIZ(dp) = 0;
  786. X    DFLAG(dp) = FL_FIL;
  787. X    DMTIM(dp) = DCTIM(dp) = (time_t) -1;
  788. X    DCANC(dp) = 0;
  789. X    DFCUR(dp) = DFTOP(dp) = 0;
  790. X    fileflag |= SF_TREE;
  791. X    if(VARSET(V_WD)) {
  792. X      puthelp("BUILD %s (Y:exit  ELSE:continue)", DPNAM(dp));
  793. X      if(errequest(CFNAM, "Cannot read directory. Exit ?") == 'y')
  794. X       return(RV_END);
  795. X    }
  796. X  }
  797. X
  798. X  /* Release saved flist array and file buffer */
  799. X  if(ntag > 0) {
  800. X    ufree(fb);
  801. X    ufree((char *) fv);
  802. X  }
  803. X
  804. X  /* Set screen flags */
  805. X  treeflag |= SF_ECHO;
  806. X  fileflag |= SF_ECHO;
  807. X
  808. X  return(RV_OK);
  809. X
  810. X} /* newflist() */
  811. X
  812. X/*
  813. X *      DIRECTORY LIST ROUTINES
  814. X */
  815. X
  816. X/* Build and set tree info flag */
  817. GLOBL VOID infodlist()
  818. X{
  819. X  register dlist *dp, *np;
  820. X  register int i, j;
  821. X
  822. X  /* For each dir in tree check if there are dirs on the same level */
  823. X  for(dp = droot; dp; dp = (dlist *) DNEXT(dp)) {
  824. X    DINFO(dp) = 0;
  825. X    for(i = 1, j = DLEVL(dp) - 1; i < j; i++) {
  826. X      for(np = (dlist *) DNEXT(dp); np && DLEVL(np) > (i + 1); np = (dlist *) DNEXT(np))
  827. X       ;
  828. X      if(np && DLEVL(np) == (i + 1))
  829. X       DINFO(dp) |= 1 << (i - 1);
  830. X    }
  831. X    for(np = (dlist *) DNEXT(dp); np && DLEVL(np) > DLEVL(dp); np = (dlist *) DNEXT(np))
  832. X      ;
  833. X    if(np && DLEVL(np) == DLEVL(dp))
  834. X      DINFO(dp) |= 1 << (i - 1);
  835. X  }
  836. X
  837. X} /* infodlist() */
  838. X
  839. X/* Insert directory dname into directory tree list */
  840. LOCAL dlist *insertdlist(dname, nfils, fvec)
  841. X  register char *dname;
  842. X  register int nfils;
  843. X  register flist *fvec;
  844. X{
  845. X  register dlist *dp, *rp;
  846. X  register char *np;
  847. X  register int f;
  848. X
  849. X  /* Get memory and save directory name */
  850. X  dp = (dlist *) ualloc(1, sizeof(dlist));
  851. X  np = strsav(pathname(dname, "/"));
  852. X
  853. X  /* Set up pathname/filename and file list */
  854. X  DPNAM(dp) = np;
  855. X  DFNAM(dp) = basename(np);
  856. X  DZOOM(dp) = NULL;
  857. X  DNFIL(dp) = nfils;
  858. X  DFVEC(dp) = fvec;
  859. X  DNEXT(dp) = GNULL;
  860. X  DFCUR(dp) = DFTOP(dp) = 0;
  861. X  DNTAG(dp) = 0;
  862. X  /* For each file in file list create an entry */
  863. X  for(f = 0; f < nfils; f++)
  864. X    insertflist(dp, f);
  865. X
  866. X  /* Insert dlist into tree list */
  867. X  if(droot == DNULL) {
  868. X    DPREV(dp) = GNULL;
  869. X    droot = dp;
  870. X  }
  871. X  else {
  872. X    for(rp = droot; DNEXT(rp); rp = (dlist *) DNEXT(rp))
  873. X      ;
  874. X    DNEXT(rp) = (glist *) dp;
  875. X    DPREV(dp) = (glist *) rp;
  876. X  }
  877. X
  878. X  /* Increment directory and file counters */
  879. X  ++dircount;
  880. X  filecount += nfils;
  881. X
  882. X  return(dp);
  883. X
  884. X} /* insertdlist() */
  885. X
  886. X/* Rebuild directory list after creating a new directory */
  887. GLOBL dlist *newdlist(name, flag)
  888. X  register char *name;
  889. X  register int flag;
  890. X{
  891. X  struct stat st;
  892. X  register dlist *dp, *pdp, *ndp, *p;
  893. X  register char *np;
  894. X  register int levl;
  895. X
  896. X  /* Allocate memory for new dlist entry and for pathname */
  897. X  ndp = (dlist *) ualloc(1, sizeof(dlist));
  898. X  np  = strsav(pathname(name, CPNAM));
  899. X
  900. X  /* Insert dlist into directory tree */
  901. X  levl = CLEVL + 1;
  902. X  for(pdp = cdlist, dp = (dlist *) CNEXT; dp && DLEVL(dp) >= levl; dp = (dlist *) DNEXT(dp)) {
  903. X    if(DLEVL(dp) == levl && CMP(np, DPNAM(dp)) < 0)
  904. X      break;
  905. X    pdp = dp;
  906. X  }
  907. X  if(DNEXT(ndp) = DNEXT(pdp)) {
  908. X    p = (dlist *) DNEXT(ndp);
  909. X    DPREV(p) = (glist *) ndp;
  910. X  }
  911. X  DNEXT(pdp) = (glist *) ndp;
  912. X  DPREV(ndp) = (glist *) pdp;
  913. X
  914. X  /* Fill up dlist record data */
  915. X  DPNAM(ndp) = np;
  916. X  DFNAM(ndp) = basename(np);
  917. X  DZOOM(ndp) = NULL;
  918. X  if((*statfun)(np, &st)) {     /* Bad stat: use defaults */
  919. X    DMTIM(ndp) = DCTIM(ndp) = (time_t) -1;
  920. X    DFLAG(ndp) = FL_FIL;
  921. X    DCANC(ndp) = 0;
  922. X  }
  923. X  else {
  924. X    DMTIM(ndp) = st.st_mtime;
  925. X    DCTIM(ndp) = st.st_ctime;
  926. X    DFLAG(ndp) = flag;
  927. X    DCANC(ndp) = CANCD(np);
  928. X  }
  929. X  DSORT(ndp) = sortbytime ? 1 : 0;
  930. X  DFBUF(ndp) = NULL;
  931. X  DFVEC(ndp) = FNULL;
  932. X  DBSIZ(ndp) = 0;
  933. X  DLEVL(ndp) = levl;
  934. X  if(DLEVL(ndp) > maxlevel)
  935. X    maxlevel = DLEVL(ndp);
  936. X  DNFIL(ndp) = DNDIR(ndp) = 0;
  937. X  DDNUM(ndp) = DDNUM(pdp) + 1;
  938. X  DFCUR(ndp) = DFTOP(ndp) = 0;
  939. X  DNTAG(ndp) = 0;
  940. X
  941. X  /* Increment all following dlist entry numbers */
  942. X  for(dp = (dlist *) DNEXT(ndp); dp; dp = (dlist *) DNEXT(dp))
  943. X    ++DDNUM(dp);
  944. X
  945. X  /* Update counter, flags and return */
  946. X  ++CNDIR;
  947. X  ++dircount;
  948. X  writeflag = 1;
  949. X  checkindent();
  950. X  infodlist();
  951. X  return(ndp);
  952. X
  953. X} /* newdlist() */
  954. X
  955. X/* Delete current entry from directory list */
  956. GLOBL VOID deletedlist(rp)
  957. X  register dlist *rp;
  958. X{
  959. X  register dlist *dp, *p;
  960. X  register int f;
  961. X
  962. X  /* Search for parent directory of directory list entry dp */
  963. X  for(dp = rp; dp && DLEVL(dp) >= DLEVL(rp); dp = (dlist *) DPREV(dp))
  964. X    ;
  965. X
  966. X  /* If found destroy file list entry in parent directory */
  967. X  if(dp) {
  968. X    if(DFVEC(dp)) {             /* RG 11/22/91 */
  969. X      for(f = 0; f < DNFIL(dp); f++)
  970. X       if(EQU(FFNAM(dp, f), DFNAM(rp)))
  971. X         break;
  972. X      deleteflist(dp, f);
  973. X    }
  974. X    --DNDIR(dp);
  975. X  }
  976. X
  977. X  /* Close the directory tree list chain */
  978. X  if(DNEXT(rp)) {
  979. X    for(dp = (dlist *) DNEXT(rp); DNEXT(dp); dp = (dlist *) DNEXT(dp))
  980. X      ;
  981. X    while(dp != rp) {
  982. X      p = (dlist *) DPREV(dp);
  983. X      DDNUM(dp) = DDNUM(p);
  984. X      dp = (dlist *) DPREV(dp);
  985. X    }
  986. X    p = (dlist *) DNEXT(rp);
  987. X    DPREV(p) = DPREV(rp);
  988. X  }
  989. X  if(p = (dlist *) DPREV(rp))
  990. X    DNEXT(p) = DNEXT(rp);
  991. X
  992. X  /* Release memory */
  993. X  ufree(DPNAM(rp));
  994. X  ufree(DFBUF(rp));
  995. X  ufree((char *) DFVEC(rp));
  996. X  if(DZOOM(rp))
  997. X    ufree(DZOOM(rp));
  998. X  ufree((char *) rp);
  999. X
  1000. X  /* Decrement directory counter and update tree info flag */
  1001. X  --dircount;
  1002. X  infodlist();
  1003. X
  1004. X} /* deletedlist() */
  1005. X
  1006. X/* Write out directory list dependent on w to file name */
  1007. GLOBL char *writedlist(name, rp, what, w)
  1008. X  register dlist *rp;
  1009. X  register char *name, *what;
  1010. X  register int w;
  1011. X{
  1012. X  char list[NAMELEN];
  1013. X  register FILE *fp;
  1014. X  register dlist *dp, *p;
  1015. X  register unsigned long info;
  1016. X  register int f, i, levl;
  1017. X  time_t t;
  1018. X
  1019. X  (void) strcpy(list, pathname(name, CPNAM));
  1020. X  if(fp = fopen(list, "w")) {
  1021. X    t  = time((time_t *) 0);
  1022. X    if(w == 'm')
  1023. X      (void) fprintf(fp, "# %s: file list (matching %s)", getversion(), what);
  1024. X    else
  1025. X      (void) fprintf(fp, "# %s: %s list", getversion(), what);
  1026. X    (void) fprintf(fp, ", %s", ctime(&t));
  1027. X    dp = rp;
  1028. X    do {
  1029. X      if(w == 'd')
  1030. X       (void) fprintf(fp, "%s\n", DPNAM(dp));
  1031. X      else if(w == 'l') {
  1032. X       p = (dlist *) DNEXT(dp);
  1033. X       f = p && DLEVL(p) > DLEVL(rp);
  1034. X       if(dp == rp) {
  1035. X         (void) fprintf(fp, "R%s\n", DPNAM(rp));
  1036. X         (void) fprintf(fp, "%cH%s\n", f ? 'U' : 'H', DFNAM(rp));
  1037. X       }
  1038. X       else {
  1039. X         levl = DLEVL(rp) - 1;
  1040. X         info = DINFO(dp) >> levl;
  1041. X         (void) fprintf(fp, "%c", f ? 'V' : 'L');
  1042. X         for(i = 1; i < (DLEVL(dp) - levl - 1); i++)
  1043. X           (void) fprintf(fp, "I%c", info & (1 << (i-1)) ? 'V' : 'S');
  1044. X         (void) fprintf(fp, "I%cH%s\n", info & (1 << (i-1)) ? 'T' : 'L', DFNAM(dp));
  1045. X       }
  1046. X      }
  1047. X      else {
  1048. X       for(f = 0; f < DNFIL(dp); f++)
  1049. X         switch(w) {
  1050. X           case 'm':
  1051. X             if(umatch(dp, f, what))
  1052. X               goto WRITEFILE;
  1053. X             break;
  1054. X           case 't':
  1055. X             if( !ISTAG(dp, f))
  1056. X               break;
  1057. X             /*Fall thru*/
  1058. X           case 'f':
  1059. WRITEFILE:    (void) fprintf(fp, "%s\n", pathname(FFNAM(dp, f), DPNAM(dp)));
  1060. X             break;
  1061. X         }
  1062. X       }
  1063. X      dp = (dlist *) DNEXT(dp);
  1064. X    } while(dp && DLEVL(dp) > DLEVL(rp));
  1065. X    (void) fclose(fp);
  1066. X    return(list);
  1067. X  }
  1068. X  return(NULL);
  1069. X
  1070. X} /* writedlist() */
  1071. X
  1072. X/* Check directory list after file changes in directory name */
  1073. GLOBL VOID checkdlist(name)
  1074. X  register char *name;
  1075. X{
  1076. X  char fname[NAMELEN];
  1077. X  struct stat st;
  1078. X  register dlist *dp;
  1079. X  register char *sp;
  1080. X
  1081. X  if( !ISDIR(name, st)) {
  1082. X    (void) strcpy(fname, name);
  1083. X    name = fname;
  1084. X    if(sp = strrchr(fname, '/'))
  1085. X      *sp = '\0';
  1086. X    if((*statfun)(name, &st))   /* Bad stat: do nothing */
  1087. X      return;
  1088. X  }
  1089. X
  1090. X  for(dp = droot; dp; dp = (dlist *) DNEXT(dp)) {
  1091. X    if(EQU(DPNAM(dp), name) && CHKTIM(dp, st)) {
  1092. X      DFLAG(dp) = FL_CHG;
  1093. X      ++buildflag;
  1094. X      break;
  1095. X    }
  1096. X  }
  1097. X
  1098. X} /* checkdlist() */
  1099. X
  1100. X/* Scan directory tree for changes in filesystem */
  1101. GLOBL int scandlist(rp)
  1102. X  register dlist *rp;
  1103. X{
  1104. X  register dlist *dp;
  1105. X
  1106. X  dp = rp;
  1107. X  do {
  1108. X    if(keypressed() && hitakey(NULL) < RV_NUL)
  1109. X      return(RV_INT);
  1110. X    if(DFLAG(dp) == FL_FIL && changedlist(dp)) {
  1111. X      DFLAG(dp) = FL_CHG;
  1112. X      ++buildflag;
  1113. X    }
  1114. X  } while((dp = (dlist *) DNEXT(dp)) && DLEVL(dp) > DLEVL(rp));
  1115. X  return(RV_OK);
  1116. X
  1117. X} /* scandlist() */
  1118. X
  1119. X/* Check if status of a directory has changed */
  1120. GLOBL int changedlist(dp)
  1121. X  register dlist *dp;
  1122. X{
  1123. X  struct stat st;
  1124. X
  1125. X  return((*statfun)(DPNAM(dp), &st) == 0 && CHKTIM(dp, st));
  1126. X
  1127. X} /* changedlist() */
  1128. X
  1129. X/* Update directory list after changes in filesystem tree */
  1130. GLOBL int updatedlist()
  1131. X{
  1132. X  register dlist *dp;
  1133. X  register int c;
  1134. X
  1135. X  c = RV_OK;
  1136. X  for(dp = droot; dp; dp = (dlist *) DNEXT(dp)) {
  1137. X    if(DFLAG(dp) == FL_CHG) {
  1138. X      if((c = newflist(dp)) != RV_OK)
  1139. X       break;
  1140. X      if(dp == cdlist)
  1141. X       fileflag |= SF_TREE;
  1142. X    }
  1143. X  }
  1144. X  buildflag = 0;
  1145. X  return(c);
  1146. X
  1147. X} /* updatedlist() */
  1148. X
  1149. X/*
  1150. X *      BUILD UP DIRECTORY TREE
  1151. X */
  1152. X
  1153. X/* Build up directory tree and file lists recursively. Work is done hard. */
  1154. X/* For each directory starting with directory pn up to level last a       */
  1155. X/* dlist entry is allocated, the dlist record is filled with all needed   */
  1156. X/* directory data, the directory file list and the file name buffer, and  */
  1157. X/* then inserted into the directory tree list.                            */
  1158. GLOBL int buildread(pn, levl, last, intr)
  1159. X  register char *pn;
  1160. X  register int levl, last, intr;
  1161. X{
  1162. X  char name[NAMELEN];
  1163. X  static int dnum = 0;
  1164. X  struct stat dst, fst;
  1165. X  register DIR *fp;
  1166. X  register dlist *dp;
  1167. X  register flist *fvec;
  1168. X  register char *fbuf, *fbufp, *fn;
  1169. X  register char **dvec;
  1170. X  register int nfils, ndirs, flag, i, rv;
  1171. X  register unsigned bsiz;
  1172. X
  1173. X  /* Is pn a directory? */
  1174. X  if( !ISDIR(pn, dst))
  1175. X    return(RV_ERR);
  1176. X
  1177. X  /* Check for keyboard interrupt if interrupt is allowed */
  1178. X  if(intr && keypressed() && hitakey(NULL) < RV_NUL)
  1179. X    return(RV_INT);
  1180. X
  1181. X  /* Init variables */
  1182. X  ndirs = nfils = 0;
  1183. X  fvec  = FNULL;
  1184. X  fbuf  = NULL;
  1185. X  bsiz  = 0;
  1186. X  flag  = FL_NUL;
  1187. X
  1188. X  /* Read in directory and build dlist entry */
  1189. X  if(levl < last && (fp = opendir(pn))) {
  1190. X    /* Count files */
  1191. X    for(i = 0; readdname(fp); i++)
  1192. X      ;
  1193. X    rewinddir(fp);
  1194. X    (void) putecho("Reading %s (%d files)", pn, i);
  1195. X    flushout();
  1196. X    /* Align nfils and bsiz to avoid too often alloc and free */
  1197. X    i = alignnfils(i);
  1198. X    bsiz = alignbsiz((unsigned) dst.st_size, i);
  1199. X    if(i > 0) {
  1200. X      /* Get memory for file buffer, file list and directory array */
  1201. X      fbuf = (char *)  ualloc(bsiz, sizeof(char));
  1202. X      fvec = (flist *) ualloc((unsigned) i, sizeof(flist));
  1203. X      dvec = (char **) ualloc((unsigned) i, sizeof(char *));
  1204. X    }
  1205. X    else {
  1206. X      fbuf = NULL;
  1207. X      fvec = FNULL;
  1208. X    }
  1209. X    /* Read in directory, fill up file list and directory array */
  1210. X    for(nfils = 0, fbufp = fbuf; fn = readdname(fp); nfils++) {
  1211. X      FVFIL(fvec, nfils) = strcpy(fbufp, fn);
  1212. X      fbufp += strlen(fn) + 1;
  1213. X      (void) strcpy(name, pathname(fn, pn));
  1214. X      if((*statfun)(name, &fst)) {
  1215. X       FVTIM(fvec, nfils) = (time_t) 0;
  1216. X       FVSIZ(fvec, nfils) = (off_t)  0;
  1217. X      }
  1218. X      else {
  1219. X       FVTIM(fvec, nfils) = fst.st_mtime;
  1220. X       FVSIZ(fvec, nfils) = fst.st_size;
  1221. X       if(STFMT(&fst) == S_IFDIR && (hiddendirs || *fn != '.'))
  1222. X         dvec[ndirs++] = FVFIL(fvec, nfils);
  1223. X      }
  1224. X    }
  1225. X    closedir(fp);
  1226. X    /* Sort file list and directory array */
  1227. X    qsort((char *) fvec, (unsigned) nfils, sizeof(flist),  flistcmp);
  1228. X    qsort((char *) dvec, (unsigned) ndirs, sizeof(char *), dlistcmp);
  1229. X    flag = FL_FIL;
  1230. X  }
  1231. X
  1232. X  /* Insert dlist into tree list and set up dlist record */
  1233. X  dp = insertdlist(pn, nfils, fvec);
  1234. X  DFBUF(dp) = fbuf;
  1235. X  DFVEC(dp) = fvec;
  1236. X  DBSIZ(dp) = bsiz;
  1237. X  DCANC(dp) = CANCD(pn);
  1238. X  DMTIM(dp) = dst.st_mtime;
  1239. X  DCTIM(dp) = dst.st_ctime;
  1240. X  DFLAG(dp) = flag;
  1241. X  DSORT(dp) = sortbytime ? 1 : 0;
  1242. X  DLEVL(dp) = levl;
  1243. X  if(DLEVL(dp) > maxlevel)
  1244. X    maxlevel = DLEVL(dp);
  1245. X  DNDIR(dp) = ndirs;
  1246. X  DDNUM(dp) = dnum++;
  1247. X
  1248. X  if(nfils > 0) {
  1249. X    /* Build a dlist entry for each directory found in directory list */
  1250. X    for(i = 0; i < ndirs; i++) {
  1251. X      (void) strcpy(name, pathname(dvec[i], pn));
  1252. X      ++levl;
  1253. X      rv = buildread(name, levl, last, intr);
  1254. X      --levl;
  1255. X      if(intr && rv == RV_INT)
  1256. X       break;
  1257. X    }
  1258. X    /* Release directory array */
  1259. X    ufree((char *) dvec);
  1260. X  }
  1261. X
  1262. X  /* Set up tree info flag and return */
  1263. X  infodlist();
  1264. X  return(intr && rv == RV_INT ? RV_INT : RV_OK);
  1265. X
  1266. X} /* buildread() */
  1267. X
  1268. X/* Build up directory tree from tree list. File lists are built up later.  */
  1269. X/* For each directory starting with directory rn read in from tree list    */
  1270. X/* file lfn a dlist entry is allocated, the dlist record is filled with    */
  1271. X/* all needed directory data and inserted into the directory tree list.    */
  1272. X/* File list and file name buffer are initially unset and filled up later. */
  1273. GLOBL int buildlist(rn, cwd, lfn)
  1274. X  register char *rn, *cwd, *lfn;
  1275. X{
  1276. X  char name[NAMELEN];
  1277. X  struct stat st;
  1278. X  register FILE *fp;
  1279. X  register dlist *dp;
  1280. X  register char *pn;
  1281. X  register int dlen, dlev, dnum, i;
  1282. X
  1283. X  /* Init variables */
  1284. X  dlen = strlen(rn);
  1285. X  dlev = countlevl(rn);
  1286. X  dnum = 0;
  1287. X
  1288. X  /* Read in list file fn */
  1289. X  if(fp = fopen(lfn, "r")) {
  1290. X    (void) putecho("Building tree from list %s ... ", lfn);
  1291. X    flushout();
  1292. X    while(fgets(name, sizeof(name), fp)) {
  1293. X      if(VALID(name[0])) {
  1294. X       if(name[i = strlen(name) - 1] == '\n')
  1295. X         name[i] = '\0';
  1296. X       pn = pathname(name, cwd);
  1297. X       /* Skip bad entries in tree list */
  1298. X       if(strncmp(rn, pn, dlen) || stat(pn, &st) || STFMT(&st) != S_IFDIR) {
  1299. X         writeflag = 1;
  1300. X         continue;
  1301. X       }
  1302. X       /* Skip hidden directories if flag is not set */
  1303. X       if( !hiddendirs && *(basename(pn)) == '.')
  1304. X         continue;
  1305. X       /* Insert into tree list and file up record with directory   */
  1306. X       /* data. File list and file name buffer are initially unset. */
  1307. X       dp = insertdlist(pn, 0, FNULL);
  1308. X       DFBUF(dp) = NULL;
  1309. X       DFVEC(dp) = FNULL;
  1310. X       DBSIZ(dp) = 0;
  1311. X       DCANC(dp) = CANCD(pn);
  1312. X       DMTIM(dp) = st.st_mtime;
  1313. X       DCTIM(dp) = st.st_ctime;
  1314. X       DFLAG(dp) = FL_NUL;
  1315. X       DSORT(dp) = sortbytime ? 1 : 0;
  1316. X       DLEVL(dp) = countlevl(pn) - dlev + 1;
  1317. X       if(DLEVL(dp) > maxlevel)
  1318. X         maxlevel = DLEVL(dp);
  1319. X       DNDIR(dp) = 0;
  1320. X       DDNUM(dp) = dnum++;
  1321. X      }
  1322. X    }
  1323. X    (void) fclose(fp);
  1324. X  }
  1325. X
  1326. X  /* Set up tree info flag and return */
  1327. X  if(dnum) {
  1328. X    infodlist();
  1329. X    return(RV_OK);
  1330. X  }
  1331. X  return(RV_NUL);
  1332. X
  1333. X} /* buildlist() */
  1334. X
  1335. END_OF_FILE
  1336. if test 22046 -ne `wc -c <'src/list.c'`; then
  1337.     echo shar: \"'src/list.c'\" unpacked with wrong size!
  1338. fi
  1339. # end of 'src/list.c'
  1340. fi
  1341. if test -f 'src/vars.c' -a "${1}" != "-c" ; then 
  1342.   echo shar: Will not clobber existing file \"'src/vars.c'\"
  1343. else
  1344. echo shar: Extracting \"'src/vars.c'\" \(22215 characters\)
  1345. sed "s/^X//" >'src/vars.c' <<'END_OF_FILE'
  1346. X/*
  1347. X *      VARS.C
  1348. X *      UTREE variable handling routines.
  1349. X *      3.01-um klin, Sun May  5 11:05:05 1991
  1350. X *      3.02-um klin, Fri Nov  1 10:46:14 1991, Option -u changed to -n
  1351. X *              klin, Sun Nov 24 15:26:19 1991, Video attributes changed
  1352. X *      3.03-um klin, Tue Feb 11 14:18:50 1992, Generic lists for variables
  1353. X *                                              and file type commands
  1354. X *              klin, Sat Feb 15 14:44:52 1992, Video handling and partinioning of
  1355. X *                                              directory and file windows changed
  1356. X *              klin, Sun Feb 23 18:45:19 1992, Keybindings and variable
  1357. X *                                              AUTOSAVE added
  1358. X *              klin, Fri Mar  6 09:34:43 1992, Release undefined commands
  1359. X *            a klin, Sun Mar 15 19:08:25 1992, Accept command without comment
  1360. X *            b klin, Thu Mar 19 10:23:54 1992, Don't free empty strings
  1361. X *
  1362. X *      Copyright (c) 1991/92 by Peter Klingebiel & UNIX Magazin Muenchen.
  1363. X *      For copying and distribution information see the file COPYRIGHT.
  1364. X */
  1365. X#ifndef lint
  1366. static char sccsid[] = "@(#) utree 3.03b-um (klin) Mar 19 1992 vars.c";
  1367. X#endif  /* !lint */
  1368. X
  1369. X#include "defs.h"
  1370. X
  1371. X/* ---- Local variables and definitions ------------------------------- */
  1372. X
  1373. X/* Format for user command menulines on tree and file screen            */
  1374. X#define UMENUFORM \
  1375. X" 1:      2:      3:      4:      5:      6:      7:      8:      9:     "
  1376. X#define FIRST   3
  1377. X#define OFFSET  8
  1378. X#define TITLE   5
  1379. X
  1380. X#define XUNDEF  ((xlist *) -1)  /* Undefined or released xlist          */
  1381. X
  1382. LOCAL int vcchg = 0;            /* Variables/commands changed           */
  1383. LOCAL char *novar = "";         /* Empty string variable                */
  1384. X
  1385. GLOBL VOID checkindent();
  1386. GLOBL VOID checklines();
  1387. LOCAL VOID setsortflag();
  1388. X
  1389. X/* ---- External variables and functions ------------------------------ */
  1390. X
  1391. XEXTRN char *getversion();
  1392. XEXTRN char *strclean();
  1393. X
  1394. X/* ---- Functions and procedures -------------------------------------- */
  1395. X
  1396. X/*
  1397. X *      INTERNAL USED ROUTINES
  1398. X */
  1399. X
  1400. X/* Show all variables */
  1401. LOCAL int showallvars()
  1402. X{
  1403. X  register vlist *vp;
  1404. X  register int l, c;
  1405. X
  1406. X  l = firstline;
  1407. X  c = RV_OK;
  1408. X  clearwindow(firstline, lastline);
  1409. X  for(vp = VARTAB(0), l = firstline; vp; vp = (vlist *) VNEXT(vp)) {
  1410. X    (void) putfxy(0, l, 0, "%s %12s=", VSCUT(vp), VNAME(vp));
  1411. X    if(VTYPE(vp) == VT_B)
  1412. X      c = putfxy(16, l, 0, "%s", VVALE(vp) == VB_ON ? "ON" : "OFF");
  1413. X    else
  1414. X      c = putfxy(16, l, 0, "%s", VVALE(vp) ? VVALE(vp) : "");
  1415. X    if(VCOMM(vp))
  1416. X      (void) putfxy(c > columns/2 ? c : columns/2, l, 0, "#%s", VCOMM(vp));
  1417. X    if(++l > lastline && VNEXT(vp)) {
  1418. X      puthelp("VARIABLES (CR:continue  Q:quit  ELSE:set/unset)");
  1419. X      c = hitakey("More variables ?", echoline, DA_NONE);
  1420. X      if( !(c == ' ' || c == '\n'))
  1421. X       break;
  1422. X      clearwindow(firstline, lastline);
  1423. X      l = firstline;
  1424. X    }
  1425. X  }
  1426. X  treeflag = fileflag = SF_FULL;
  1427. X  return(c);
  1428. X
  1429. X} /* showallvars() */
  1430. X
  1431. X/* Display file type dependent commands */
  1432. LOCAL int showallcmds()
  1433. X{
  1434. X  register xlist *xp;
  1435. X  register int l, c;
  1436. X
  1437. X  l = firstline;
  1438. X  c = RV_OK;
  1439. X  clearwindow(firstline, lastline);
  1440. X  for(xp = xroot, l = firstline; xp; xp = (xlist *) XNEXT(xp)) {
  1441. X    c = putfxy(0, l, 0, "%s:%s", XTYPE(xp), XCOMD(xp));
  1442. X    if(XCOMM(xp))
  1443. X      (void) putfxy(c > (columns/2) ? c+1 : columns/2, l, 0, "#%s", XCOMM(xp));
  1444. X    if(++l > lastline && XNEXT(xp)) {
  1445. X      puthelp("FILETYPE COMMANDS (CR:continue  Q:quit  ELSE:set/unset)");
  1446. X      c = hitakey("More filetype commands ?", echoline, DA_NONE);
  1447. X      if( !(c == ' ' || c == '\n'))
  1448. X       break;
  1449. X      clearwindow(firstline, lastline);
  1450. X      l = firstline;
  1451. X    }
  1452. X  }
  1453. X  treeflag = fileflag = SF_FULL;
  1454. X  return(c);
  1455. X
  1456. X} /* showallcmds() */
  1457. X
  1458. X/* Set sort criteria flag for file lists */
  1459. LOCAL VOID setsortflag(f)
  1460. X  register int f;
  1461. X{
  1462. X  register dlist *dp;
  1463. X
  1464. X  sortbytime = f ? 0 : 1;
  1465. X  for(dp = droot; dp; dp = (dlist *) DNEXT(dp))
  1466. X    (void) sortlist(dp, sortbytime);
  1467. X
  1468. X} /* setsortflag() */
  1469. X
  1470. X/* Set tree indention variable */
  1471. LOCAL int setindent(i)
  1472. X  register int i;
  1473. X{
  1474. X  if(i < MININD || i > MAXIND)          /* Out of range */
  1475. X    return(-1);
  1476. X  maxindent = indent = i;               /* Set indention variables */
  1477. X  checkindent();
  1478. X  return(0);
  1479. X
  1480. X} /* setindent() */
  1481. X
  1482. X/* Set video mode variable */
  1483. GLOBL int setvideomode(i)
  1484. X  register int i;
  1485. X{
  1486. X  if(i  < VMODE0 || i > VMODE2)         /* Out of range */
  1487. X    return(-1);
  1488. X  else if(glitchcap && i > VMODE1)      /* Respect glitches */
  1489. X    i = VMODE1;
  1490. X  videomode = i;                        /* Set video mode variables */
  1491. X  *VARVAL(V_VM) = videomode + '0';
  1492. X  return(0);
  1493. X
  1494. X} /* setvideomode() */
  1495. X
  1496. X/* Set number of file lines on tree screen */
  1497. LOCAL int setfilelines(n)
  1498. X  register int n;
  1499. X{
  1500. X  if(n < MINFIL || n > MAXFIL)          /* Out of range */
  1501. X    return(-1);
  1502. X  maxnflines = n;
  1503. X  checklines(1);
  1504. X  return(0);
  1505. X
  1506. X} /* setfilelines() */
  1507. X
  1508. X/*
  1509. X *      USER COMMAND ROUTINES
  1510. X */
  1511. X
  1512. X/* Build command line s from user command v with value p */
  1513. GLOBL int userformat(s, p, v, w)
  1514. X  register char *s, *p, *w;
  1515. X  register int v;
  1516. X{
  1517. X  char buf[INPLEN];
  1518. X  register char *fp, *pp;
  1519. X  register int c, n;
  1520. X
  1521. X  pp = p;
  1522. X  n  = 0;
  1523. X  while(*p) {                   /* Scan command format */
  1524. X    if(*p == '\\') {
  1525. X      *s++ = *++p;
  1526. X      if(*p)
  1527. X       ++p;
  1528. X    }
  1529. X    else if(*p == '%') {
  1530. X      switch(*++p) {
  1531. X       case 's':               /* Request for parameter */
  1532. X       case 'S':
  1533. X         puthelp("%s: Parameter %d for %s", w, ++n, pp);
  1534. X         c = putecho("Give Parameter %d:", n);
  1535. X         if((c = getline(buf, sizeof(buf), c, 0, NULL, GNULL, 0)) < RV_NUL)
  1536. X           return(c);
  1537. X         fp = buf;
  1538. X         goto DOCOPY;
  1539. X       case 'B':               /* Basename of directory or file */
  1540. X       case 'b':
  1541. X         if(v > V_FC0) {
  1542. X           if(CNFIL == 0)
  1543. X             return(RV_NUL);
  1544. X           (void) strcpy(buf, FFNAM(cdlist, CFCUR));
  1545. X         }
  1546. X         else
  1547. X           (void) strcpy(buf, CFNAM);
  1548. X         if(fp = strrchr(buf, '.'))
  1549. X           *fp = '\0';
  1550. X         fp = buf;
  1551. X         goto DOCOPY;
  1552. X       case 'F':               /* Filename of directory or file */
  1553. X       case 'f':
  1554. X         if(v > V_FC0) {
  1555. X           if(CNFIL == 0)
  1556. X             return(RV_NUL);
  1557. X           fp = FFNAM(cdlist, CFCUR);
  1558. X         }
  1559. X         else
  1560. X           fp = CFNAM;
  1561. X         goto DOCOPY;
  1562. X       case 'R':               /* Root directory */
  1563. X       case 'r':
  1564. X         fp = rootdir;
  1565. X         goto DOCOPY;
  1566. X       case 'H':               /* Home directory */
  1567. X       case 'h':
  1568. X         fp = home;
  1569. X         goto DOCOPY;
  1570. X       case 'P':               /* Full pathname of directory or file */
  1571. X       case 'p':
  1572. X         if(v > V_FC0) {
  1573. X           if(CNFIL == 0)
  1574. X             return(RV_NUL);
  1575. X           fp = CPNAM;
  1576. X           while(*fp)
  1577. X             *s++ = *fp++;
  1578. X           *s++ = '/';
  1579. X           fp = FFNAM(cdlist, CFCUR);
  1580. X           goto DOCOPY;
  1581. X         }
  1582. X         /* Directory: fall thru */
  1583. X       case 'D':               /* Current directory name */
  1584. X       case 'd':
  1585. X         fp = CPNAM;
  1586. DOCOPY:   while(*fp)
  1587. X           *s++ = *fp++;
  1588. X         break;
  1589. X       case '%':               /* As it is */
  1590. X         *s++ = '%';
  1591. X         break;
  1592. X       default:
  1593. X         return(RV_NUL);       /* Bad format */
  1594. X      }
  1595. X      ++p;
  1596. X    }
  1597. X    else
  1598. X      *s++ = *p++;
  1599. X  }
  1600. X
  1601. X  *s = '\0';                    /* Terminate command line */
  1602. X  return(RV_OK);
  1603. X
  1604. X} /* userformat() */
  1605. X
  1606. X/* Execute an user defined command v */
  1607. GLOBL int usercommand(v)
  1608. X  register int v;
  1609. X{
  1610. X  char buf[EXECLEN];
  1611. X  register int c;
  1612. X
  1613. X  /* Check if usercommand is set */
  1614. X  if( !VARSET(v))
  1615. X    return(errequest("User command", "Not defined"));
  1616. X  /* Build command line */
  1617. X  else {
  1618. X    c = userformat(buf, VARVAL(v), v, VARNAM(v));
  1619. X    if(c == RV_NUL)
  1620. X      return(errequest("User command", "Bad format"));
  1621. X    else if(c < 0)
  1622. X      return(c);
  1623. X  }
  1624. X
  1625. X  puthelp("USER COMMAND: %s", buf);
  1626. X  c = callsystem(buf, 1, 0);
  1627. X  checkdlist(CPNAM);
  1628. X
  1629. X  if(c != RV_OK)
  1630. X    return(errequest("User command", "Error in executing"));
  1631. X  return(hitakey("Return from user command (Hit a key)", lines-1, DA_REVERSE));
  1632. X
  1633. X} /* usercommand() */
  1634. X
  1635. X/*
  1636. X *      FILE TYPE COMMAND ROUTINES
  1637. X */
  1638. X
  1639. X/* Set file type command */
  1640. GLOBL xlist *setcommand(type, f)
  1641. X  register char *type;
  1642. X  register int f;
  1643. X{
  1644. X  register xlist *xp, *pp, *p;
  1645. X  register char *comd, *comm;
  1646. X
  1647. X  /* Search for filetype - command separator ':' */
  1648. X  if((comd = strchr(type, ':')) == NULL || comd == type)
  1649. X    return(XNULL);
  1650. X  else
  1651. X    *comd++ = '\0';
  1652. X
  1653. X  /* Get additional comment lead in by '#' */
  1654. X  if(comm = strchr(comd, '#')) {
  1655. X    *comm++ = '\0';
  1656. X    comm = strclean(comm);
  1657. X  }
  1658. X  comd = strclean(comd);
  1659. X
  1660. X  /* Search for file type to set in command list */
  1661. X  for(xp = xroot; xp; xp = (xlist *) XNEXT(xp))
  1662. X    if(EQU(type, XTYPE(xp)))
  1663. X      break;
  1664. X
  1665. X  /* Replace or delete an existing file type command */
  1666. X  if(xp) {
  1667. X    ufree(XCOMD(xp));
  1668. X    ufree(XCOMM(xp));
  1669. X    if(comd == NULL || *comd == '\0') {
  1670. X      if(xroot && xp == xroot) {
  1671. X       if(xroot = (xlist *) XNEXT(xp))
  1672. X         XPREV(xroot) = GNULL;
  1673. X       else
  1674. X         xroot = XNULL;
  1675. X      }
  1676. X      else {
  1677. X       if(p = (xlist *) XPREV(xp))
  1678. X         XNEXT(p) = XNEXT(xp);
  1679. X       if(p = (xlist *) XNEXT(xp))
  1680. X         XPREV(p) = XPREV(xp);
  1681. X      }
  1682. X      ufree(XTYPE(xp));
  1683. X      ufree(xp);
  1684. X      xp = XUNDEF;
  1685. X    }
  1686. X  }
  1687. X  /* Ignore invalid definition */
  1688. X  else if(comd == NULL || *comd == '\0')
  1689. X    return(XUNDEF);
  1690. X  /* Create and insert a new entry in file type command list */
  1691. X  else if(xp = (xlist *) ualloc(1, sizeof(xlist))) {
  1692. X    XTYPE(xp) = strsav(type);
  1693. X    if(xroot && CMP(type, XTYPE(xroot)) < 0) {
  1694. X      for(pp = xroot; XNEXT(pp); pp = (xlist *) XNEXT(pp)) {
  1695. X       p = (xlist *) XNEXT(pp);
  1696. X       if(CMP(type, XTYPE(pp)) > 0)
  1697. X         break;
  1698. X      }
  1699. X      XPREV(xp) = (glist *) pp;
  1700. X      XNEXT(xp) = XNEXT(pp);
  1701. X      if(p = (xlist *) XNEXT(pp))
  1702. X       XPREV(p) = (glist *) xp;
  1703. X      XNEXT(pp) = (glist *) xp;
  1704. X    }
  1705. X    else {
  1706. X      if(xroot)
  1707. X       XPREV(xroot) = (glist *) xp;
  1708. X      XPREV(xp) = GNULL;
  1709. X      XNEXT(xp) = (glist *) xroot;
  1710. X      xroot = xp;
  1711. X    }
  1712. X  }
  1713. X
  1714. X  /* Insert command and comment and return */
  1715. X  if(comd && *comd) {
  1716. X    XCOMD(xp) = strsav(comd);
  1717. X    XCOMM(xp) = comm && *comm ? strsav(comm) : NULL;
  1718. X  }
  1719. X  if(xp) {
  1720. X    if(f == VC_CHG)
  1721. X      vcchg = 1;
  1722. X    return(xp);
  1723. X  }
  1724. X  else
  1725. X    return(XNULL);
  1726. X
  1727. X} /* setcommand() */
  1728. X
  1729. X/* Show and set/unset filetype commands */
  1730. GLOBL int commands()
  1731. X{
  1732. X  char buf[3*INPLEN], typ[INPLEN], cmd[INPLEN], cmt[INPLEN];
  1733. X  register xlist *xp = XUNDEF;
  1734. X  register int c, f;
  1735. X
  1736. X  who = "SET COMMAND";
  1737. X  f = 1;
  1738. X  /* Filetype command loop */
  1739. X  while(1) {
  1740. X    cmd[0] = cmt[0] = '\0';
  1741. X    if(f && ((c = showallcmds()) < RV_NUL || c == 'q'))
  1742. X      break;
  1743. X    f = 0;
  1744. X    if(xp == XUNDEF || xp == XNULL)
  1745. X      xp = xroot;
  1746. X    puthelp("%s: Give filetype or type:command (CR:quit)", who);
  1747. X    c = putecho("Set command:");
  1748. X    if((c = getline(typ, sizeof(typ), c, 'd', NULL, xp ? XLIST(xp) : GNULL, 1)) != RV_OK)
  1749. X      break;
  1750. X    if(strchr(typ, ':'))
  1751. X      (void) strcpy(buf, typ);
  1752. X    else {
  1753. X      puthelp("%s: Give command for %s (CR:unset)", who, typ);
  1754. X      c = putecho("Command for %s:", typ);
  1755. X      for(xp = xroot; xp; xp = (xlist *) XNEXT(xp))
  1756. X       if(EQU(typ, XTYPE(xp)))
  1757. X         break;
  1758. X      if((c = getline(cmd, sizeof(cmd), c, 'd', xp ? XCOMD(xp) : NULL, GNULL, 1)) < RV_NUL)
  1759. X       break;
  1760. X      if(c == RV_NUL)
  1761. X       (void) sprintf(buf, "%s:", typ);
  1762. X      else if(strchr(cmd, '#'))
  1763. X       (void) sprintf(buf, "%s:%s", typ, cmd);
  1764. X      else {
  1765. X       puthelp("%s: Give comment for %s", who, typ);
  1766. X       c = putecho("Comment for %s:", typ);
  1767. X       if((c = getline(cmt, sizeof(cmt), c, 'd', xp ? XCOMM(xp) : NULL, GNULL, 1)) < RV_NUL)
  1768. X         break;
  1769. X       else if(c == RV_OK)
  1770. X         (void) sprintf(buf, "%s:%s#%s", typ, cmd, cmt);
  1771. X     else
  1772. X       (void) sprintf(buf, "%s:%s", typ, cmd);
  1773. X      }
  1774. X    }
  1775. X    if((xp = setcommand(buf, VC_CHG)) == XNULL) {
  1776. X      puthelp("%s %s", who, hitkey);
  1777. X      if((c = errequest(buf, "Error in setting")) < RV_NUL)
  1778. X       break;
  1779. X    }
  1780. X    else
  1781. X      f = 1;
  1782. X  }
  1783. X  return(c);
  1784. X
  1785. X} /* commands() */
  1786. X
  1787. X/*
  1788. X *      VARIABLE ROUTINES
  1789. X */
  1790. X
  1791. X/* Init variables */
  1792. GLOBL VOID initvariables()
  1793. X{
  1794. X  char buf[NAMELEN];
  1795. X  register vlist *vp;
  1796. X  register FILE *fp;
  1797. X  register char *ep;
  1798. X  register int i;
  1799. X
  1800. X  /* Init user commands menu lines for tree and file screen */
  1801. X  (void) strcpy(utreemenu, UMENUFORM);
  1802. X  (void) strcpy(ufilemenu, utreemenu);
  1803. X
  1804. X  /* First: Get and set variables from environment */
  1805. X  if(ep = getenv("SHELL"))
  1806. X    VARDEF(V_SH) = ep;
  1807. X  if(ep = getenv("EDITOR"))
  1808. X    VARDEF(V_ED) = ep;
  1809. X  if(ep = getenv("PAGER"))
  1810. X    VARDEF(V_PG) = ep;
  1811. X
  1812. X  /* Second: Initialize and link variables table */
  1813. X  for(i = 0; VARNAM(i); i++) {
  1814. X    if(VARDEF(i) == NULL)
  1815. X      VARDEF(i) = novar;
  1816. X    VARVAL(i) = VARDEF(i);
  1817. X  }
  1818. X  VARNXT(0) = VARLST(1);
  1819. X  for(i = 1; VARNAM(i+1); i++) {
  1820. X    VARNXT(i) = VARLST(i+1);
  1821. X    VARPRV(i) = VARLST(i-1);
  1822. X  }
  1823. X  VARPRV(i) = VARLST(i-1);
  1824. X
  1825. X#ifdef  UTSTART
  1826. X  /* Third: Get and set variables from startup file */
  1827. X  if(startup(buf, UTSTART) && (fp = fopen(buf, "r"))) {
  1828. X    while(fgets(buf, sizeof(buf), fp))
  1829. X      if(VALID(buf[0])) {
  1830. X       i = strlen(buf) - 1;
  1831. X       if(i > 0 && buf[i] == '\n')
  1832. X         buf[i] = '\0';
  1833. X       if(strchr(buf, '='))
  1834. X         (void) setvariable(buf, VC_SET);
  1835. X       else if(strchr(buf, ':'))
  1836. X         (void) setcommand(buf, VC_SET);
  1837. X      }
  1838. X    (void) fclose(fp);
  1839. X  }
  1840. X#endif  /* UTSTART */
  1841. X
  1842. X  /* Last: Check environment variable UTREE */
  1843. X  if(ep = getenv("UTREE")) {
  1844. X    for(i = 0; ep[i]; i++)
  1845. X      switch(ep[i]) {
  1846. X       default:                /* Do nothing */
  1847. X         break;
  1848. X       case 'b':               /* No bell */
  1849. X         (void) setvariable("BL=", VC_SET);
  1850. X         break;
  1851. X       case 'c':               /* No clock */
  1852. X         (void) setvariable("CL=", VC_SET);
  1853. X         break;
  1854. X       case 'g':               /* No graphic chars */
  1855. X         (void) setvariable("GC=", VC_SET);
  1856. X         break;
  1857. X       case 'i':               /* Tree indention */
  1858. X          if(isdigit(ep[i+1])) {
  1859. X            ++i;
  1860. X            (void) sprintf(buf, "TI=%c", ep[i]);
  1861. X            (void) setvariable(buf, VC_SET);
  1862. X          }
  1863. X          break;
  1864. X       case 'n':               /* No tree scan for changes */
  1865. X         (void) setvariable("ST=", VC_SET);
  1866. X         break;
  1867. X       case 'o':               /* Omit saving definition changes */
  1868. X         (void) setvariable("AS=", VC_SET);
  1869. X         break;
  1870. X       case 'p':               /* File lines on tree screen */
  1871. X          if(isdigit(ep[i+1])) {
  1872. X            ++i;
  1873. X            (void) sprintf(buf, "FL=%c", ep[i]);
  1874. X            (void) setvariable(buf, VC_SET);
  1875. X          }
  1876. X          break;
  1877. X       case 's':               /* No hardware scrolling */
  1878. X         (void) setvariable("TS=", VC_SET);
  1879. X         break;
  1880. X       case 'v':               /* Set video mode */
  1881. X          if(isdigit(ep[i+1])) {
  1882. X            ++i;
  1883. X            (void) sprintf(buf, "VM=%c", ep[i]);
  1884. X            (void) setvariable(buf, VC_SET);
  1885. X          }
  1886. X          break;
  1887. X       case 'w':               /* No warning about unreadable dirs */
  1888. X         (void) setvariable("WD=", VC_SET);
  1889. X         break;
  1890. X      }
  1891. X  }
  1892. X
  1893. X} /* initvariables() */
  1894. X
  1895. X/* Save current settings after changes */
  1896. GLOBL VOID savevariables()
  1897. X{
  1898. X#ifdef UTSTART
  1899. X  char buf[NAMELEN];
  1900. X  register xlist *xp;
  1901. X  register vlist *vp;
  1902. X  register FILE *fp;
  1903. X  time_t t;
  1904. X
  1905. X  if(VARVAL(V_AS) && vcchg) {
  1906. X   (void) sprintf(buf, ".%s", UTSTART);
  1907. X   (void) strcpy(buf, pathname(buf, home));
  1908. X    if(fp = fopen(buf, "w")) {
  1909. X      t = time((time_t *) 0);
  1910. X      (void) fprintf(fp, "# %s: ~/.%s, %s", getversion(), UTSTART, ctime(&t));
  1911. X      /* Save variables */
  1912. X      (void) fprintf(fp, "# Variables\n");
  1913. X      for(vp = VARTAB(0); vp; vp = (vlist *) VNEXT(vp)) {
  1914. X       (void) fprintf(fp, "%s=", VNAME(vp));
  1915. X       if(VVALE(vp))
  1916. X         (void) fprintf(fp, "%s", VTYPE(vp) == VT_B ? "ON" : VVALE(vp));
  1917. X       if(VCOMM(vp))
  1918. X         (void) fprintf(fp, "\t#%s\n", VCOMM(vp));
  1919. X       else
  1920. X         (void) fprintf(fp, "\n");
  1921. X      }
  1922. X      /* Save command settings */
  1923. X      (void) fprintf(fp, "# Commands\n");
  1924. X      for(xp = xroot; xp; xp = (xlist *) XNEXT(xp)) {
  1925. X       (void) fprintf(fp, "%s:%s", XTYPE(xp), XCOMD(xp) ? XCOMD(xp) : "");
  1926. X       if(XCOMM(xp))
  1927. X         (void) fprintf(fp, "\t#%s\n", XCOMM(xp));
  1928. X       else
  1929. X         (void) fprintf(fp, "\n");
  1930. X      }
  1931. X      (void) fclose(fp);
  1932. X    }
  1933. X  }
  1934. X#endif  /* UTSTART */
  1935. X
  1936. X} /* savevariables() */
  1937. X
  1938. X/* Check tree indention */
  1939. GLOBL VOID checkindent()
  1940. X{
  1941. X  register int i;
  1942. X
  1943. X  if(maxlevel > 0)                      /* Calculate max possible indention */
  1944. X    i = (columns - FNAMSZ - 6) / maxlevel;
  1945. X  else
  1946. X    i = indent;
  1947. X  if(i < MININD) i = MININD;
  1948. X  if(i > MAXIND) i = MAXIND;
  1949. X  if(maxindent && i > maxindent)        /* Check and set indention */
  1950. X    i = maxindent;
  1951. X  indent = i;
  1952. X  *VARVAL(V_TI) = indent + '0';         /* Set indention variable value */
  1953. X  treeflag = SF_TREE;
  1954. X
  1955. X} /* checkindent() */
  1956. X
  1957. X/* Calculate max possible number of file lines on tree screen */
  1958. GLOBL int calculatelines()
  1959. X{
  1960. X  register int l;
  1961. X
  1962. X  if((l = (lines-3) / 2) > MAXFIL)
  1963. X    l = MAXFIL;
  1964. X  return(l);
  1965. X
  1966. X} /* calculatelines() */
  1967. X
  1968. X/* Check line partitioning on tree screen */
  1969. GLOBL VOID checklines(f)
  1970. X  register int f;
  1971. X{
  1972. X  register int m, nf;
  1973. X
  1974. X  if(f) {                               /* Calculate new line values */
  1975. X    nf = nflines;
  1976. X    if(maxnflines < MINFIL)
  1977. X      nflines = MINFIL;
  1978. X    else {
  1979. X      m = calculatelines();
  1980. X      nflines = maxnflines > m ? m : maxnflines;
  1981. X    }
  1982. X    firstfline = lastfline - nflines + 1;
  1983. X    lastdline  = firstfline - 2;
  1984. X    ndlines    = lastdline - firstdline;
  1985. X    if(nf != nflines)                   /* Check directory window */
  1986. X      calculatetree(nf-nflines);
  1987. X    treeflag = SF_TREE;
  1988. X  }
  1989. X  else                                  /* Update after resizing */
  1990. X    maxnflines = nflines;
  1991. X  *VARVAL(V_FL) = maxnflines + '0';     /* Set number of file lines */
  1992. X
  1993. X} /* checklines() */
  1994. X
  1995. X/* Set/unset or reset user defined variables */
  1996. GLOBL int setvariable(line, f)
  1997. X  register char *line;
  1998. X  register int f;
  1999. X{
  2000. X  register vlist *vp;
  2001. X  register char *value, *comm, *dp;
  2002. X  register int n, i, j;
  2003. X
  2004. X  /* Search for variable - value separator '=' */
  2005. X  if(f != VC_TST) {
  2006. X    if(value = strchr(line, '='))
  2007. X      *value++ = '\0';
  2008. X    else
  2009. X      return(-1);
  2010. X  }
  2011. X  line = strclean(line);
  2012. X  strupper(line);
  2013. X
  2014. X  /* Search for variable to set in variable list */
  2015. X  for(vp = VARTAB(0); vp; vp = (vlist *) VNEXT(vp))
  2016. X    if(*line == *VNAME(vp) && (EQU(line, VSCUT(vp)) || EQU(line, VNAME(vp))))
  2017. X      break;
  2018. X  if(vp == VNULL)
  2019. X    return(-1);
  2020. X  else if(f == VC_TST)
  2021. X    return(VNUMB(vp));
  2022. X
  2023. X  /* Ignore additional comment */
  2024. X  if(comm = strchr(value, '#')) {
  2025. X    *comm++ = '\0';
  2026. X    comm = strclean(comm);
  2027. X  }
  2028. X  value = strclean(value);
  2029. X
  2030. X  /* Set or unset variable */
  2031. X  n = VNUMB(vp);
  2032. X  switch(VTYPE(vp)) {
  2033. X    case VT_B:                  /* Booleans */
  2034. X      VVALE(vp) = *value ? VB_ON : VB_OFF;
  2035. X      if(n == V_GC)
  2036. X       initgraphics(VVALE(vp));
  2037. X      else if(n == V_LS)
  2038. X       setsortflag(VVALE(vp));
  2039. X      break;
  2040. X    case VT_N:                  /* Numbers */
  2041. X      if(n == V_TI && setindent(atoi(value)))
  2042. X       n = -1;
  2043. X      else if(n == V_VM && setvideomode(atoi(value)))
  2044. X       n = -1;
  2045. X      else if(n == V_FL && setfilelines(atoi(value)))
  2046. X       n = -1;
  2047. X      else if(n == V_HS && (f != VC_SET || sethistorysize(atoi(value))))
  2048. X       n = -1;
  2049. X      break;
  2050. X    case VT_S:                  /* General strings */
  2051. X      if(VVALE(vp) && VVALE(vp) != VDFLT(vp))
  2052. X       ufree(VVALE(vp));
  2053. X      if(*value && *value != '#' && (dp = strsav(value)))
  2054. X       VVALE(vp) = dp;
  2055. X      else if(VDFLT(vp))
  2056. X       VVALE(vp) = VDFLT(vp);
  2057. X      else
  2058. X       VVALE(vp) = NULL;
  2059. X      break;
  2060. X    case VT_U:                  /* Command strings */
  2061. X      if(VVALE(vp) && VVALE(vp) != VDFLT(vp))
  2062. X       ufree(VVALE(vp));
  2063. X      if(VCOMM(vp))
  2064. X       ufree(VCOMM(vp));
  2065. X      VVALE(vp) = VCOMM(vp) = NULL;
  2066. X      dp = NULL;
  2067. X      if(*value) {
  2068. X       if(dp = strsav(value))
  2069. X         VVALE(vp) = dp;
  2070. X       if(comm && *comm)
  2071. X         VCOMM(vp) = strsav(comm);
  2072. X      }
  2073. X      /* Update user command menulines if needed */
  2074. X      if(n > V_FC0)
  2075. X       for(i = (n - V_FC1) * OFFSET + FIRST, j = 0; j < TITLE; i++, j++)
  2076. X         ufilemenu[i] = comm && *comm ? *comm++ : ' ';
  2077. X      else
  2078. X       for(i = (n - V_TC1) * OFFSET + FIRST, j = 0; j < TITLE; i++, j++)
  2079. X         utreemenu[i] = comm && *comm ? *comm++ : ' ';
  2080. X      break;
  2081. X    case VT_O:                  /* User defined strings: not yet! */
  2082. X    default:                    /* ??? */
  2083. X      n = -1;
  2084. X  }
  2085. X
  2086. X  if(n >= 0 && f == VC_CHG)
  2087. X    vcchg = 1;
  2088. X  return(n);
  2089. X
  2090. X} /* setvariable() */
  2091. X
  2092. X/* Show and set/unset common and user defined variables */
  2093. GLOBL int variables()
  2094. X{
  2095. X  char buf[3*INPLEN], var[INPLEN], def[INPLEN], cmt[INPLEN];
  2096. X  register char *dp;
  2097. X  register int f, c, n = -1;
  2098. X
  2099. X  who = "SET VARIABLE";
  2100. X  /* Variable loop */
  2101. X  f = 1;
  2102. X  while(1) {
  2103. X    if(n < 0)
  2104. X      n = 0;
  2105. X    if(f && ((c = showallvars()) < RV_NUL || c == 'q'))
  2106. X      return(c);
  2107. X    f = 0;
  2108. X    puthelp("%s: Give variable or variable=value (CR:quit)", who);
  2109. X    c = putecho("Set variable:");
  2110. X    if((c = getline(var, sizeof(var), c, 'v', NULL, VARLST(n), 1)) != RV_OK)
  2111. X      break;
  2112. X    if(strchr(var, '='))
  2113. X      (void) strcpy(buf, var);
  2114. X    else {
  2115. X      if((n = setvariable(var, VC_TST)) < 0) {
  2116. X       if((c = errequest(var, "Unknown")) < RV_NUL)
  2117. X         break;
  2118. X       else
  2119. X         continue;
  2120. X      }
  2121. X      puthelp("%s: Give definition for %s (CR:unset)", who, var);
  2122. X      c = putecho("Set %s to:", var);
  2123. X      if(VARTYP(n) == VT_B)
  2124. X       dp = VARSET(n) ? "ON" : "";
  2125. X      else
  2126. X       dp = VARVAL(n);
  2127. X      if((c = getline(def, sizeof(def), c, 'v', dp, GNULL, 0)) < RV_NUL)
  2128. X       break;
  2129. X      if(VARTYP(n) != VT_U || strchr(def, '#'))
  2130. X       (void) sprintf(buf, "%s=%s", var, def);
  2131. X      else {
  2132. X       puthelp("%s: Give comment for user command %s", who, VARNAM(n));
  2133. X       c = putecho("Comment for %s:", VARNAM(n));
  2134. X       if((c = getline(cmt, sizeof(cmt), c, 'v', VARCOM(n), GNULL, 0)) < RV_NUL)
  2135. X         break;
  2136. X       (void) sprintf(buf, "%s=%s#%s", var, def, cmt);
  2137. X      }
  2138. X    }
  2139. X    if(setvariable(buf, VC_CHG) < 0) {
  2140. X      puthelp("%s %s", who, hitkey);
  2141. X      if((c = errequest(buf, "Error in setting")) < RV_NUL)
  2142. X       break;
  2143. X    }
  2144. X    else
  2145. X      f = 1;
  2146. X  }
  2147. X
  2148. X  treeflag = fileflag = SF_FULL;
  2149. X  return(c);
  2150. X
  2151. X} /* variables() */
  2152. X
  2153. END_OF_FILE
  2154. if test 22215 -ne `wc -c <'src/vars.c'`; then
  2155.     echo shar: \"'src/vars.c'\" unpacked with wrong size!
  2156. fi
  2157. # end of 'src/vars.c'
  2158. fi
  2159. echo shar: End of archive 5 \(of 8\).
  2160. cp /dev/null ark5isdone
  2161. MISSING=""
  2162. for I in 1 2 3 4 5 6 7 8 ; do
  2163.     if test ! -f ark${I}isdone ; then
  2164.     MISSING="${MISSING} ${I}"
  2165.     fi
  2166. done
  2167. if test "${MISSING}" = "" ; then
  2168.     echo You have unpacked all 8 archives.
  2169.     rm -f ark[1-9]isdone
  2170. else
  2171.     echo You still need to unpack the following archives:
  2172.     echo "        " ${MISSING}
  2173. fi
  2174. ##  End of shell archive.
  2175. exit 0
  2176.