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

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