home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume35 / describe / part01 next >
Text File  |  1993-02-04  |  56KB  |  1,981 lines

  1. Newsgroups: comp.sources.misc
  2. From: tim@deakin.edu.au (Tim Cook)
  3. Subject: v35i012:  describe - File Descriptions, Part01/03
  4. Message-ID: <csm-v35i012=describe.001203@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: da7f0b40525d7523a8d71a222e28446a
  6. Date: Tue, 2 Feb 1993 06:14:03 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: tim@deakin.edu.au (Tim Cook)
  10. Posting-number: Volume 35, Issue 12
  11. Archive-name: describe/part01
  12. Environment: UNIX, DBM
  13.  
  14. Have you ever wondered what on earth "xfrg2.2.tar.Z" was?  Are you
  15. wondering whether "foo" is really a scratch file?  Does it ashame you
  16. especially, seeing that these files were created by you?
  17.  
  18. I have the solution for you...  File Descriptions.
  19.  
  20. I'm sure some operating system or another once had the ability to set
  21. a descriptive comment on a file, but Unix wasn't one of them.  It is
  22. possible, however, to retro-fit onto Unix an implementation that works
  23. quite well.
  24.  
  25. In this package, I have provided a utility to set/delete/list file
  26. descriptions (describe), and a directory listing utility that shows
  27. any file descriptions that are set next to the respective files (dl).
  28.  
  29.  Implementation
  30.  --------------
  31. The storage/retrieval of file-descriptions is implemented in the
  32. following way:
  33.  
  34.     All file descriptions are stored in a DBM file called .desc,
  35.     in  the same directory as the files described.  This in fact
  36.     means that you have two files, .desc.pag and .desc.dir.
  37.  
  38.     Each description is indexed by the name of the file (excluding
  39.     any path information).  To provide a better chance of finding
  40.     the description after the file has been renamed (within the
  41.     same directory), the name is also indexed by the inode-number.
  42.     This means that the file's description will still be found
  43.     after it has been renamed (within the same directory) or
  44.     re-written by an editor.  To prevent the two indexes from
  45.     becoming mixed up, whenever a name/description pair are stored
  46.     with a name that is the same size as an inode-number, the name
  47.     is stored with a trailing null byte.
  48.  
  49.  Purpose
  50.  -------
  51. My reason for coming up with this idea is simple.  I got tired of
  52. logging on to some distant site's anonymous FTP area, and coming
  53. across something like:
  54.  
  55. -rw-r--r--  1 root       214807 May 22  1989 3c503.tar.Z
  56. -rw-r--r--  1 bin         27751 Aug 22 16:35 bonnie
  57. -rw-rw-r--  1 uucp        65383 Aug 23 02:54 dynafeed.tar.Z
  58. -rw-r--r--  1 bin         10444 Nov  3 21:58 fpipe
  59. -rw-r--r--  1 bin         47138 Aug 22 16:41 opaque    (good name!)
  60. -rw-r--r--  1 don        683759 May 29 23:21 psiber.tar.Z
  61.  
  62. You know?  You sit there and think ... "some of those sound
  63. interesting, but it wouldn't be nice for me to download them just to
  64. find out what they are...".
  65.  
  66. If there is no other demand for describe/dl, there should be as a
  67. replacement for ls in anonymous FTP areas.  And that's how simple it
  68. is, once you have dl installed, simply copy it to ~ftp/bin/ls, and
  69. the FTP daemon will use it instead of standard ls for anonymous
  70. logins.  The output of dl was actually designed with anonymous FTP
  71. use in mind (who cares who owns the file or which group it belongs
  72. to?).
  73.  
  74. Of course, the site administrator has to provide meaningful
  75. descriptions for what has been put in the anonymous FTP area.  I don't
  76. think it would be too hard to generate descriptions files from an
  77. index of something like comp.sources.misc, though.  A dozen lines of
  78. perl should do it.
  79.  
  80.  An Example
  81.  ----------
  82. As an example of what an anonymous FTP site that uses dl looks like,
  83. try my back yard, archive.viccol.edu.au.
  84.  
  85. E-mail: tim@deakin.edu.au
  86.  
  87. Tim Cook
  88. ----------------
  89. #! /bin/sh
  90. # This is a shell archive.  Remove anything before this line, then feed it
  91. # into a shell via "sh file" or similar.  To overwrite existing files,
  92. # type "sh file -c".
  93. # Contents:  README config.h describe.c dl.c list.c other other/descopt
  94. #   patches patches/GNU-compress.patch patches/GNU-mv.patch
  95. # Wrapped by kent@sparky on Mon Feb  1 10:15:03 1993
  96. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
  97. echo If this archive is complete, you will see the following message:
  98. echo '          "shar: End of archive 1 (of 3)."'
  99. if test -f 'README' -a "${1}" != "-c" ; then 
  100.   echo shar: Will not clobber existing file \"'README'\"
  101. else
  102.   echo shar: Extracting \"'README'\" \(5222 characters\)
  103.   sed "s/^X//" >'README' <<'END_OF_FILE'
  104. XDescription
  105. X-----------
  106. XHave you ever wondered what on earth "xfrg2.2.tar.Z" was?  Are you
  107. Xwondering whether "foo" is really a scratch file?  Does it ashame you
  108. Xespecially, seeing that these files were created by you?
  109. X
  110. XI have the solution for you...  File Descriptions.
  111. X
  112. XI'm sure some operating system or another once had the ability to set
  113. Xa descriptive comment on a file, but Unix wasn't one of them.  It is
  114. Xpossible, however, to retro-fit onto Unix an implementation that works
  115. Xquite well.
  116. X
  117. XIn this package, I have provided a utility to set/delete/list file
  118. Xdescriptions (describe), and a directory listing utility that shows
  119. Xany file descriptions that are set next to the respective files (dl).
  120. X
  121. XImplementation
  122. X--------------
  123. XThe storage/retrieval of file-descriptions is implemented in the
  124. Xfollowing way:
  125. X
  126. X    All file descriptions are stored in a DBM file called .desc,
  127. X    in  the same directory as the files described.  This in fact
  128. X    means that you have two files, .desc.pag and .desc.dir.
  129. X
  130. X    Each description is indexed by the name of the file (excluding
  131. X    any path information).  To provide a better chance of finding
  132. X    the description after the file has been renamed (within the
  133. X    same directory), the name is also indexed by the inode-number.
  134. X    This means that the file's description will still be found
  135. X    after it has been renamed (within the same directory) or
  136. X    re-written by an editor.  To prevent the two indexes from
  137. X    becoming mixed up, whenever a name/description pair are stored
  138. X    with a name that is the same size as an inode-number, the name
  139. X    is stored with a trailing null byte.
  140. X    
  141. X
  142. XPurpose
  143. X-------
  144. XMy reason for coming up with this idea is simple.  I got tired of
  145. Xlogging on to some distant site's anonymous FTP area, and coming
  146. Xacross something like:
  147. X
  148. X-rw-r--r--  1 root       214807 May 22  1989 3c503.tar.Z
  149. X-rw-r--r--  1 bin         27751 Aug 22 16:35 bonnie
  150. X-rw-rw-r--  1 uucp        65383 Aug 23 02:54 dynafeed.tar.Z
  151. X-rw-r--r--  1 bin         10444 Nov  3 21:58 fpipe
  152. X-rw-r--r--  1 bin         47138 Aug 22 16:41 opaque    (good name!)
  153. X-rw-r--r--  1 don        683759 May 29 23:21 psiber.tar.Z
  154. X
  155. XYou know?  You sit there and think ... "some of those sound
  156. Xinteresting, but it wouldn't be nice for me to download them just to
  157. Xfind out what they are...".
  158. X
  159. XIf there is no other demand for describe/dl, there should be as a
  160. Xreplacement for ls in anonymous FTP areas.  And that's how simple it
  161. Xis, once you have dl installed, simply copy it to ~ftp/bin/ls, and
  162. Xthe FTP daemon will use it instead of standard ls for anonymous
  163. Xlogins.  The output of dl was actually designed with anonymous FTP
  164. Xuse in mind (who cares who owns the file or which group it belongs
  165. Xto?).
  166. X
  167. XOf course, the site administrator has to provide meaningful
  168. Xdescriptions for what has been put in the anonymous FTP area.  I don't
  169. Xthink it would be too hard to generate descriptions files from an
  170. Xindex of something like comp.sources.unix, though.  A dozen lines of
  171. Xperl should do it.
  172. X
  173. XAn Example
  174. X----------
  175. XAs an example of what an anonymous FTP site that uses dl looks like,
  176. Xtry my back yard, archive.viccol.edu.au.
  177. X
  178. XCopyright
  179. X---------
  180. XThe whole system is Copyright (c) Tim Cook 1991, 1992, apart from
  181. Xstrpbrk.c which is Copyright (c) 1985 Regents of the University of
  182. XCalifornia.  All together, the package can be distributed provided no
  183. Xprofit is made from any distribution, and all copyright notices remain
  184. Xintact.
  185. X
  186. XThe Author
  187. X----------
  188. XTim Cook, Systems Programmer, Computing & Communications Services,
  189. XDeakin University.
  190. X
  191. XE-mail: tim@deakin.edu.au
  192. X
  193. X(Note that Victoria College (viccol) has merged with Deakin
  194. XUniversity.)
  195. X
  196. XMiscellaneous
  197. X-------------
  198. XThe "dl" command used to be known as "dls", but Ultrix already had a
  199. X"dls" command, which is for "DECnet ls", so I changed it.
  200. X
  201. XThe dl/describe package was developed under DYNIX version 3.0.12 and
  202. X3.1.2, which is a BSD 4.2 based version of Unix.  This means that
  203. Xdl/describe should compile on "most" BSD 4.2 derived systems.  I have
  204. Xpersonally had success compiling it on SunOS 4.1 and Solaris 2.0
  205. Xsystems.  It has also compiled on several SYSV-based systems.  See
  206. XINSTALL, config.h and Makefile for porting details.
  207. X
  208. XCould I ask all those who install dl in their Anonymous FTP areas to
  209. Xdrop me a line?  Any criticisms or suggestions gladly accepted.  I am
  210. Xquite interested in what people think of this idea.
  211. X
  212. XI am also interested in seeing the results of any porting efforts, so
  213. Xthat I can incorporate them in later releases.  Depending on the level
  214. Xof my spare time, I would even be prepared to assist you in porting
  215. Xthis to your particular brand of Unix.  I have a desire to see this
  216. Xpropagate as far as possible around the world of Unix anonymous FTP
  217. Xsites.
  218. X
  219. XThe Future for dl/describe
  220. X---------------------------
  221. XSo far, dl has been installed in only a few Anonymous FTP
  222. Xinstallations.  I would like to lobby, or have others lobby some of
  223. Xthe larger or more popular sites to have them think about dl.
  224. X
  225. XTo make dl seem better though, I will be adding the following (I
  226. Xcan't say when though):
  227. X
  228. X   1.  Better co-operation with ftpd and the archie system.
  229. X
  230. X   2.  Add to the set of patches to make commonly used file utilities
  231. X       aware of file descriptions.
  232. X
  233. X   3.  Better portability.
  234. END_OF_FILE
  235.   if test 5222 -ne `wc -c <'README'`; then
  236.     echo shar: \"'README'\" unpacked with wrong size!
  237.   fi
  238.   # end of 'README'
  239. fi
  240. if test -f 'config.h' -a "${1}" != "-c" ; then 
  241.   echo shar: Will not clobber existing file \"'config.h'\"
  242. else
  243.   echo shar: Extracting \"'config.h'\" \(7107 characters\)
  244.   sed "s/^X//" >'config.h' <<'END_OF_FILE'
  245. X/* config.h -    Configuration and portability definitions
  246. X *
  247. X * Copyright (c) 1991,1992 Tim Cook.
  248. X * Non-profit distribution allowed.  See README for details.
  249. X *
  250. X * $Id: config.h,v 1.7 1993/01/29 04:32:37 tim Exp tim $
  251. X */
  252. X
  253. X#ifndef _CONFIG_H_
  254. X#define _CONFIG_H_
  255. X
  256. X/*****************************************************************************
  257. X * SVR4.
  258. X *
  259. X * If you are running System V, Release 4, define SVR4, which will
  260. X * activate the following assumptions:
  261. X *    - readdir, etc requires <dirent.h>
  262. X *    - readdir return struct dirent
  263. X *    - No "d_namlen" field in DIRENT structure
  264. X *    - Include <fcntl.h> to get O_CREAT, etc.
  265. X */
  266. X/* #define SVR4            /* */
  267. X
  268. X/*****************************************************************************
  269. X * SYSV
  270. X *
  271. X * If you have a System V or System V based system, define SYSV.  This
  272. X * will activate the following assumptions: 
  273. X *    - Include <time.h> instead of <sys/time.h>.
  274. X *    - No "d_namlen" field in DIRENT structure.
  275. X *    - Include <fcntl.h> to get O_CREAT, etc.
  276. X */
  277. X/* #define SYSV            /* */
  278. X
  279. X/*****************************************************************************
  280. X * Date orientation.
  281. X *
  282. X * For those who prefer seeing the month before the day of the month
  283. X * in dates, define US_DATE_FORMAT. 
  284. X */
  285. X/* #define US_DATE_FORMAT    /* */
  286. X
  287. X/*****************************************************************************
  288. X * Display of symbolic links.
  289. X *
  290. X * If you want "dl" to display the contents of a symbolic link,
  291. X * preceded by "-> " if there is no description for the link. Define
  292. X * SHOW_SYMLINK.  If your system does not have symbolic links, do not
  293. X * define SHOW_SYMLINK. 
  294. X */
  295. X#define SHOW_SYMLINK        /* */
  296. X
  297. X/*****************************************************************************
  298. X * DBM library
  299. X *
  300. X * If you have an NDBM-compatible library, define NDBM, otherwise, you
  301. X * will need DBM.  If you have a version of DBM that does not include
  302. X * the dbmclose(3) routine, define NO_DBMCLOSE. 
  303. X */
  304. X#define NDBM            /* */
  305. X/* #define NO_DBMCLOSE        /* */
  306. X
  307. X/*****************************************************************************
  308. X * Directory reading routines.
  309. X *
  310. X * Check your man page for directory(3) and define one of DIRENT,
  311. X * SYS_DIR or SYS_NDIR to denote where the necessary include file is.
  312. X * If your readdir(3) returns a "struct direct" pointer, define
  313. X * DIRECT, otherwise it will be assumed that readdir(3) returns a
  314. X * "struct dirent" pointer.
  315. X */
  316. X#ifdef SVR4
  317. X
  318. X#define DIRENT
  319. X#define NO_D_NAMLEN        /* No d_namlen field in dirent structure */
  320. X
  321. X#else    /* SVR4 */
  322. X
  323. X#ifdef SYSV
  324. X#define NO_D_NAMLEN
  325. X#endif
  326. X
  327. X/* #define DIRENT        /* to include <dirent.h> */
  328. X#define SYS_DIR             /* to include <sys/dir.h> */
  329. X/* #define SYS_NDIR        /* to include <sys/ndir.h> */
  330. X
  331. X#define DIRECT            /* readdir(3) returns "struct direct *" */
  332. X
  333. X#endif    /* SVR4 */
  334. X
  335. X/*****************************************************************************
  336. X * Uid/gid types
  337. X *
  338. X * Define these to what is returned by getuid(2) and getgid(2) (check
  339. X * the man pages).  If not defined, "uid_t" and "gid_t" will be used
  340. X * (from <sys/types.h>).
  341. X */
  342. X#ifndef SVR4
  343. X/* #define UID_T    int        /* */
  344. X/* #define GID_T    int        /* */
  345. X#endif
  346. X
  347. X/*****************************************************************************
  348. X * Data alignment
  349. X *
  350. X * If your architecture requires particular data items to be aligned,
  351. X * you may need to define this (you will if you get a "bus error" when
  352. X * you attempt a "dl -t").  Define it to 2 for word alignment or 4 for
  353. X * longword alignment.
  354. X */
  355. X
  356. X#ifdef sparc
  357. X#define ALIGN    4        /* Longword alignment */
  358. X#endif
  359. X
  360. X/* #define ALIGN    2    /* Word alignment */
  361. X
  362. X/*****************************************************************************
  363. X * strings.h/string.h
  364. X *
  365. X * If you have no <string.h> on your system, define STRINGS and
  366. X * <strings.h> will be included instead.  Check the manual page for
  367. X * strcat(3).
  368. X */
  369. X#ifndef SVR4
  370. X/* #define STRINGS        /* */
  371. X#endif
  372. X
  373. X/*****************************************************************************
  374. X * str(r)chr/(r)index
  375. X *
  376. X * If you have no str(r)chr(3) on your system, define INDEX and
  377. X * (r)index(3) will be used instead.
  378. X */
  379. X#ifndef SVR4
  380. X/* #define INDEX        /* */
  381. X#endif
  382. X
  383. X/*****************************************************************************
  384. X * memcpy/bcopy
  385. X *
  386. X * If you have no memcpy(3), memset(3) etc., but you do have bcopy(3),
  387. X * bzero(3), etc., define BCOPY.
  388. X */
  389. X#ifndef SVR4
  390. X/* #define BCOPY        /* */
  391. X#endif
  392. X
  393. X/*****************************************************************************
  394. X * Void types
  395. X *
  396. X * If your compiler does not handle any of these types, define them to
  397. X * something it will handle.  The recognised types will be used if
  398. X * these macros are not defined.
  399. X */
  400. X
  401. X/* #define VOID        int    /* replacement for "void" */
  402. X/* #define VOID_PTR    char *    /* replacement for "void *" */
  403. X/* #define VOID_PTR_PTR    char ** /* replacement for "void **" */
  404. X
  405. X
  406. X/*****************************************************************************
  407. X *              NOTHING PAST HERE SHOULD NEED TO BE MODIFIED                 *
  408. X *****************************************************************************/
  409. X
  410. X#ifdef NDBM
  411. X
  412. X# include <ndbm.h>
  413. X# define DBM_fetch(db, key)    dbm_fetch (db, key)
  414. X# define DBM_store(db, key, val) \
  415. X                 dbm_store(db, key, val, DBM_REPLACE)
  416. X# define DBM_delete(db, key)    dbm_delete (db, key)
  417. X# define DBM_firstkey(db)    dbm_firstkey (db)
  418. X# define DBM_nextkey(db, key)    dbm_nextkey (db)
  419. X
  420. X# define DBM_close(db)        if (! (db)) ; else dbm_close (db)
  421. X
  422. X#else
  423. X
  424. X# include <dbm.h>
  425. X# define DBM_fetch(db, key)    fetch (key)
  426. X# define DBM_store(db, key, val) \
  427. X                store(key, val)
  428. X# define DBM_delete(db, key)    delete (key)
  429. X# define DBM_firstkey(db)    firstkey ()
  430. X# define DBM_nextkey(db, key)    nextkey (key)
  431. X
  432. X# ifdef NO_DBMCLOSE
  433. X#  define DBM_close(db)
  434. X# else
  435. X#  define DBM_close(db)        dbmclose ()
  436. X# endif
  437. X
  438. X# ifdef NULL
  439. X#  undef NULL        /* Aaaaaaarrrrgghhh! */
  440. X# endif
  441. X#endif
  442. X
  443. X/* This will probably be needed by one of the next three */
  444. X#include <sys/types.h>
  445. X
  446. X#ifdef DIRENT
  447. X# include <dirent.h>
  448. X# undef DIRENT
  449. X#else
  450. X# ifdef SYS_DIR
  451. X#  include <sys/dir.h>
  452. X#  undef SYS_DIR
  453. X# else
  454. X#  ifdef SYS_NDIR
  455. X#   include <sys/ndir.h>
  456. X#   undef SYS_NDIR
  457. X#  endif
  458. X# endif
  459. X#endif
  460. X
  461. X#ifdef DIRECT
  462. X# define DIRENT    struct direct
  463. X# undef DIRECT
  464. X#else
  465. X# define DIRENT    struct dirent
  466. X#endif
  467. X
  468. X#ifndef UID_T
  469. X#define UID_T    uid_t
  470. X#endif
  471. X#ifndef GID_T
  472. X#define GID_T    gid_t
  473. X#endif
  474. X
  475. X#ifdef ALIGN
  476. X# if ALIGN == 1
  477. X#  undef ALIGN
  478. X# endif
  479. X#endif
  480. X
  481. X#ifdef STRINGS
  482. X# include <strings.h>
  483. X# undef STRINGS
  484. X#else
  485. X# include <string.h>
  486. X#endif
  487. X
  488. X#ifdef INDEX
  489. X# define strchr        index
  490. X# define strrchr    rindex
  491. X# undef INDEX
  492. X#endif
  493. X
  494. X#ifdef BCOPY
  495. X# define memcpy(d,s,n)    bcopy(s,d,n)
  496. X# define memzero(s,n)    bzero(s,n)
  497. X# undef BCOPY
  498. X#else
  499. X# define memzero(s,n)    memset(s,'\0',n)
  500. X#endif
  501. X
  502. X#ifndef    VOID
  503. X# define VOID        void
  504. X#endif
  505. X#ifndef VOID_PTR
  506. X# define VOID_PTR    void *
  507. X#endif
  508. X#ifndef VOID_PTR_PTR
  509. X# define VOID_PTR_PTR    void **
  510. X#endif
  511. X
  512. X/* Miscellaneous */
  513. X#ifndef TRUE
  514. X#define TRUE        1
  515. X#define FALSE        0
  516. X#endif
  517. X
  518. X#ifndef EOS
  519. X#define EOS        '\0'
  520. X#endif
  521. X
  522. X#ifndef NULL_CP
  523. X#define    NULL_CP        ((char *) 0)
  524. X#endif
  525. X
  526. X#ifndef print
  527. X#define print(s)    fputs (s, stdout)
  528. X#define printc(c)    putc (c, stdout)
  529. X#endif
  530. X
  531. X#endif    /* _CONFIG_H_ */
  532. END_OF_FILE
  533.   if test 7107 -ne `wc -c <'config.h'`; then
  534.     echo shar: \"'config.h'\" unpacked with wrong size!
  535.   fi
  536.   # end of 'config.h'
  537. fi
  538. if test -f 'describe.c' -a "${1}" != "-c" ; then 
  539.   echo shar: Will not clobber existing file \"'describe.c'\"
  540. else
  541.   echo shar: Extracting \"'describe.c'\" \(6025 characters\)
  542.   sed "s/^X//" >'describe.c' <<'END_OF_FILE'
  543. X/* describe.c -    Set or list a descriptive comment for a file
  544. X *
  545. X * Copyright (c) 1991, 1992 Tim Cook.
  546. X * Non-profit distribution allowed.  See README for details.
  547. X */
  548. X
  549. Xstatic char rcsid[] = "$Id: describe.c,v 1.15 1993/01/29 03:53:22 tim Exp tim $";
  550. X
  551. X#include "config.h"
  552. X#include <stdio.h>
  553. X#include <sys/param.h>
  554. X#include <sys/file.h>
  555. X#include <sys/stat.h>
  556. X
  557. X#if defined(SYSV) || defined(SVR4)
  558. X#include <fcntl.h>        /* for O_CREAT, etc. */
  559. X#endif
  560. X
  561. X#ifndef MAXPATHLEN
  562. X#define MAXPATHLEN    1024
  563. X#endif
  564. X
  565. Xextern char *getdesc () ;
  566. Xextern int setdesc () ;
  567. Xextern VOID enddesc () ;
  568. X
  569. Xstatic char *program_name ;
  570. X
  571. Xstatic VOID usage () ;
  572. Xstatic VOID set_description () ;
  573. Xstatic VOID set_from_file () ;
  574. Xstatic VOID list_descriptions () ;
  575. X
  576. Xstatic VOID describe_version () ;
  577. X
  578. X
  579. X
  580. Xint main (argc, argv)
  581. X   int argc ;
  582. X   char **argv ;
  583. X{
  584. X   extern int errno ;
  585. X   extern char *optarg ;
  586. X   extern int optind, opterr ;
  587. X   int option ;
  588. X   static char options[] = "dlcvf:" ;
  589. X
  590. X#define UNDEFINED    0
  591. X#define DELETE_DESC    'd'
  592. X#define LIST_DIR    'l'
  593. X#define COPY_DESC    'c'
  594. X#define SET_FROM_FILE    'f'
  595. X   int mode = UNDEFINED ;
  596. X
  597. X   char *description ;
  598. X   char *directory ;
  599. X   char *description_file ;
  600. X
  601. X   program_name = argv[0] ;
  602. X   while ((option = getopt (argc, argv, options)) != EOF) {
  603. X      if (option == 'v') {
  604. X         describe_version ();
  605. X         exit (0); }
  606. X
  607. X      if (mode != UNDEFINED)
  608. X     /* Can't do more than one thing at a time, dearie! */
  609. X     usage () ;
  610. X     
  611. X      if (option == ':' || strchr (options, (char) option) == NULL_CP)
  612. X     /* Bad option */
  613. X     usage () ;
  614. X
  615. X      if (option == SET_FROM_FILE)
  616. X     description_file = optarg ;
  617. X      mode = option ; }
  618. X
  619. X
  620. X   /* Do the work */
  621. X   switch (mode) {
  622. X      case SET_FROM_FILE:
  623. X         /* Set descriptions from file */
  624. X
  625. X         if (optind >= argc)
  626. X        directory = "." ;
  627. X     else
  628. X        directory = argv[optind] ;
  629. X     set_from_file (description_file, directory) ;
  630. X     break ;
  631. X
  632. X      case DELETE_DESC:
  633. X     /* Delete description(s) */
  634. X
  635. X     if (optind >= argc)
  636. X        usage () ;
  637. X
  638. X     for ( ; optind < argc ; optind++)
  639. X        set_description (argv[optind], NULL_CP, NULL_CP) ;
  640. X     break ;
  641. X
  642. X      case LIST_DIR:
  643. X     /* List directory */
  644. X
  645. X     if (optind >= argc)
  646. X        directory = "." ;
  647. X     else
  648. X        directory = argv[optind] ;
  649. X     list_descriptions (directory) ;
  650. X     break ;
  651. X
  652. X      case COPY_DESC:
  653. X     /* Copy description from another file or directory */
  654. X
  655. X     if (optind != (argc - 2))
  656. X        /* Not enough arguments */
  657. X        usage () ;
  658. X
  659. X     errno = 0 ;
  660. X     description = getdesc (argv[optind+1], NULL_CP, NULL_CP, 0) ;
  661. X     if (! errno) {
  662. X        char desc[1024] ;
  663. X
  664. X        strncpy (desc, description, sizeof (desc)) ;
  665. X        desc[sizeof (desc) - 1] = '\0' ;
  666. X        set_description (argv[optind], NULL_CP, desc) ; }
  667. X     else
  668. X        perror2 (program_name, argv[optind+1]) ;
  669. X     break ;
  670. X
  671. X      default:
  672. X     /* Set description of specified file */
  673. X
  674. X     if (argc != 3)
  675. X        usage () ;
  676. X
  677. X     set_description (argv[1], NULL_CP, argv[2]) ;
  678. X      }
  679. X
  680. X   enddesc () ;
  681. X
  682. X   exit (0) ;
  683. X   }
  684. X
  685. X
  686. Xstatic
  687. XVOID usage ()
  688. X{
  689. X   describe_version ();
  690. X
  691. X   fprintf (stderr, "\
  692. Xusage: %s <file> <description>\n\
  693. X   or: %s -c <file> <other-file>\n\
  694. X   or: %s -f <descriptions-file> [<directory>]\n\
  695. X   or: %s -d <file> ...\n\
  696. X   or: %s -l [<directory>]\n",
  697. X      program_name, program_name, program_name, program_name, program_name) ;
  698. X   exit (2) ;
  699. X   }
  700. X
  701. X
  702. Xstatic
  703. XVOID set_description (file, directory, description)
  704. X   char *file ;
  705. X   char *directory ;
  706. X   char *description ;
  707. X{
  708. X   struct stat status ;
  709. X
  710. X   if (stat (file, &status) == -1) {
  711. X      perror2 (program_name, file) ;
  712. X      exit (1) ; }
  713. X   if (! setdesc (file, directory, NULL_CP, status.st_ino, description))
  714. X      perror2 (program_name, file) ;
  715. X   }
  716. X
  717. X
  718. Xstatic
  719. XVOID set_from_file (file, directory)
  720. X   char *file ;
  721. X   char *directory ;
  722. X{
  723. X   FILE *descriptions ;
  724. X   char file_name[MAXPATHLEN+1] ;
  725. X   char buffer[1024] ;
  726. X   char description[256] ;
  727. X   struct stat status ;
  728. X   int n ;
  729. X
  730. X   if (strcmp (file, "-") == 0)
  731. X      descriptions = stdin ;
  732. X   else {
  733. X      if ((descriptions = fopen (file, "r")) == (FILE *) NULL) {
  734. X     perror2 (program_name, file) ;
  735. X     exit (1) ; } }
  736. X   if (chdir (directory) == -1) {
  737. X      perror2 (program_name, directory) ;
  738. X      exit (1) ; }
  739. X
  740. X   while (! feof (descriptions)) {
  741. X      if (fgets (buffer, sizeof (buffer), descriptions) != NULL_CP) {
  742. X     n = sscanf (buffer, "\"%[^\"]\" %[^\n]\n", file_name, description) ;
  743. X     if (n < 2)
  744. X        n = sscanf (buffer, "%s %[^\n]\n", file_name, description) ;
  745. X     if (n == 2 && file_name[0] != '#')
  746. X        set_description (file_name, directory, description) ;
  747. X         }
  748. X      }
  749. X
  750. X   fclose (descriptions) ;
  751. X   }
  752. X
  753. X
  754. Xstatic
  755. XVOID list_descriptions (directory)
  756. X   char *directory ;
  757. X{
  758. X   char file_name[MAXPATHLEN+1] ;
  759. X   int file_name_length ;
  760. X   int gap ;
  761. X   DIR *dir ;
  762. X   DIRENT *dir_entry ;
  763. X   char *desc ;
  764. X
  765. X   /*
  766. X    * Loop through all the files in this directory, seeing if we can
  767. X    * find a description for each one.
  768. X    */
  769. X
  770. X   if ((dir = opendir (*directory == EOS ? "." : directory)) == (DIR *) NULL) {
  771. X      perror ("opendir") ;
  772. X      exit (1) ; }
  773. X   while ((dir_entry = readdir (dir)) != (DIRENT *) NULL) {
  774. X
  775. X      if ((desc = getdesc (NULL_CP, directory, dir_entry->d_name,
  776. X        dir_entry->d_ino)) != NULL_CP) {
  777. X
  778. X     /* Print it out! */
  779. X#ifdef NO_D_NAMLEN
  780. X     file_name_length = strlen (dir_entry->d_name) ;
  781. X#else
  782. X     file_name_length = dir_entry->d_namlen ;
  783. X#endif
  784. X     strncpy (file_name, dir_entry->d_name, file_name_length) ;
  785. X     file_name[file_name_length] = EOS ;
  786. X
  787. X     if (strpbrk (file_name, " \t") != NULL_CP) {
  788. X        printc ('"') ;
  789. X        print (file_name) ;
  790. X        printc ('"') ;
  791. X        gap = 18 - file_name_length ; }
  792. X     else {
  793. X        print (file_name) ;
  794. X        gap = 20 - file_name_length ; }
  795. X     printc (' ') ;        /* We need at least one space */
  796. X     while (gap-- > 0)
  797. X        printc (' ') ;
  798. X     print (desc) ;
  799. X     printc ('\n') ; } }
  800. X
  801. X   }
  802. X
  803. X
  804. Xstatic
  805. XVOID describe_version ()
  806. X{
  807. X#include "version.h"
  808. X
  809. X#ifdef __STDC__
  810. X   fprint (stderr, "This is \"" PACKAGE_NAME "\", version "
  811. X      PACKAGE_VERSION "\n");
  812. X#else
  813. X   fprintf (stderr, "This is \"%s\", version %s\n",
  814. X      PACKAGE_NAME, PACKAGE_VERSION);
  815. X#endif
  816. X   }
  817. END_OF_FILE
  818.   if test 6025 -ne `wc -c <'describe.c'`; then
  819.     echo shar: \"'describe.c'\" unpacked with wrong size!
  820.   fi
  821.   # end of 'describe.c'
  822. fi
  823. if test -f 'dl.c' -a "${1}" != "-c" ; then 
  824.   echo shar: Will not clobber existing file \"'dl.c'\"
  825. else
  826.   echo shar: Extracting \"'dl.c'\" \(12166 characters\)
  827.   sed "s/^X//" >'dl.c' <<'END_OF_FILE'
  828. X/* dl.c -    Descriptive ls
  829. X *
  830. X * Copyright (c) 1991,1992 Tim Cook.
  831. X * Non-profit distribution allowed.  See README for details.
  832. X */
  833. X
  834. Xstatic char rcsid[] = "$Id: dl.c,v 1.13 1993/01/29 04:23:25 tim Exp tim $" ;
  835. X
  836. X#include "config.h"
  837. X#include <stdio.h>
  838. X#include <sys/param.h>
  839. X#include <sys/stat.h>
  840. X#include <sys/file.h>
  841. X#include <list.h>
  842. X
  843. X#ifdef SYSV
  844. X#include <time.h>
  845. X#else
  846. X#include <sys/time.h>
  847. X#endif
  848. X
  849. X#ifndef MAXPATHLEN
  850. X#define MAXPATHLEN    1024
  851. X#endif
  852. X
  853. X#ifndef NGROUPS
  854. X/* This is likely on (old?) SYSV */
  855. X#define NGROUPS        16        /* A safe guess */
  856. X#endif
  857. X
  858. X
  859. Xextern time_t time () ;
  860. Xextern UID_T getuid () ;
  861. Xextern int getgroups () ;
  862. X
  863. Xextern char *getdesc () ;
  864. Xextern VOID enddesc () ;
  865. Xextern char *pathname () ;
  866. X
  867. X#define strgencpy(new, old) \
  868. X    (new = strcpy ((char *) allocate (strlen (old) + 1), old))
  869. X
  870. Xstatic struct file_info {
  871. X   ino_t inode ;
  872. X   u_short mode ;
  873. X   short nlink ;
  874. X   off_t size ;
  875. X   time_t mtime ;
  876. X   char name[4] ;    /* This can actually contain a string of any
  877. X               length, I'm just giving the compiler the
  878. X               opportunity to align. */
  879. X   } ;
  880. X
  881. X/*
  882. X * How much space needed for a struct file_info that contains string "s"
  883. X */
  884. X#define file_info_size(s) \
  885. X    (sizeof (struct file_info) - 3 + strlen (s))
  886. X
  887. X/* options */
  888. Xstatic int show_date = FALSE ;
  889. Xstatic int sort_by_date = FALSE ;
  890. Xstatic int even_inaccessible = FALSE ;
  891. Xstatic int filename_columns = 14 ;
  892. Xstatic int recursive = FALSE ;
  893. X
  894. X/* other globals */
  895. X#define FROM_ARGV    0
  896. X#define FROM_DIR    1
  897. X
  898. Xstatic time_t six_months_ago ;
  899. Xstatic struct file_info not_there ;    /* Symbolic value */
  900. Xstatic int name_and_size_columns ;
  901. Xstatic int space = FALSE ;        /* If TRUE, we need to print a blank
  902. X                       line before anything else */
  903. Xstatic int printed_anything = FALSE ;
  904. Xstatic UID_T uid ;
  905. Xstatic int no_groups ;
  906. Xstatic UID_T groups[NGROUPS] ;
  907. X
  908. Xstatic VOID_PTR get_element_from_argv () ;
  909. Xstatic VOID build_and_sort_list () ;
  910. Xstatic struct file_info *get_file_info () ;
  911. Xstatic VOID list_file () ;
  912. Xstatic VOID list_directory () ;
  913. X
  914. X
  915. Xint main (argc, argv)
  916. X   int argc ;
  917. X   char **argv ;
  918. X{
  919. X   extern char *optarg ;
  920. X   extern int optind, opterr ;
  921. X
  922. X   int option ;
  923. X   struct list file_list, dir_list ;
  924. X   struct file_info *file_info ;
  925. X   char *dir_name ;
  926. X   int multiple_args ;
  927. X
  928. X   opterr = 0 ;
  929. X   while ((option = getopt (argc, argv, "deitf:R")) != EOF) {
  930. X      switch ((char) option) {
  931. X         case 'd' :
  932. X        show_date = TRUE ; break ;
  933. X         case 'e' :
  934. X     case 'i' :
  935. X        even_inaccessible = TRUE ; break ;
  936. X         case 't' :
  937. X        sort_by_date = TRUE ; break ;
  938. X         case 'f' :
  939. X        filename_columns = atoi (optarg) ; break ;
  940. X     case 'R' :
  941. X        recursive = TRUE ; break ;
  942. X     case '?' :
  943. X            break ; } }
  944. X
  945. X   multiple_args = (argc - optind) > 1 ;
  946. X
  947. X   name_and_size_columns = filename_columns + 8 ;
  948. X
  949. X   if (show_date)
  950. X      six_months_ago = time ((time_t *) 0) - (182 * 24 * 60 * 60) ;
  951. X
  952. X   if (! even_inaccessible) {
  953. X      uid = (UID_T) getuid () ;
  954. X      no_groups = getgroups (NGROUPS, groups) ; }
  955. X
  956. X   if (optind == argc) {
  957. X      list_directory ("", FALSE) ;
  958. X      enddesc () ;
  959. X      exit (0) ; }
  960. X
  961. X   list_init (&file_list) ;
  962. X   build_and_sort_list (&file_list, NULL_CP, FROM_ARGV, (char *) argv,
  963. X      (char *) &optind) ;
  964. X
  965. X   list_init (&dir_list) ;
  966. X   while ((file_info = get_file_info (&file_list, NULL_CP))
  967. X      != (struct file_info *) NULL) {
  968. X      if (file_info != ¬_there) {
  969. X     if (file_info->mode & S_IFDIR)
  970. X        /* Collect these for later */
  971. X            list_push (&dir_list, (VOID_PTR) file_info->name,
  972. X           strlen (file_info->name) + 1) ;
  973. X     else {
  974. X        list_file (file_info, NULL_CP) ; } } }
  975. X   list_free (&file_list) ;
  976. X
  977. X   /* Now, the directories we collected above */
  978. X   while ((dir_name = (char *) list_shift (&dir_list)))
  979. X      list_directory (dir_name, multiple_args) ;
  980. X   list_free (&dir_list) ;
  981. X
  982. X   enddesc () ;
  983. X   exit (0) ;
  984. X   }
  985. X
  986. X
  987. Xstatic
  988. XVOID_PTR get_element_from_argv (param_1, param_2)
  989. X   char *param_1, *param_2 ;
  990. X{
  991. X   int *argc ;
  992. X   char **argv ;
  993. X
  994. X   argv = (char **) param_1 ;
  995. X   argc = (int *) param_2 ;
  996. X   return (VOID_PTR) argv[(*argc)++] ;
  997. X   }
  998. X
  999. X
  1000. Xstatic
  1001. XVOID_PTR get_element_from_dir (param_1, param_2)
  1002. X   char *param_1 ;    /* directory pointer (DIR *) */
  1003. X   char *param_2 ;    /* name of directory */
  1004. X{
  1005. X   DIRENT *dir_entry ;
  1006. X
  1007. X   for (dir_entry = readdir ((DIR *) param_1) ;
  1008. X        dir_entry != (DIRENT *) NULL && dir_entry->d_name[0] == '.' ;
  1009. X    dir_entry = readdir ((DIR *) param_1)) ;
  1010. X   if (dir_entry == (DIRENT *) NULL)
  1011. X      return (VOID_PTR) NULL ;
  1012. X   return (VOID_PTR) dir_entry->d_name ;
  1013. X   }
  1014. X
  1015. X
  1016. Xstatic
  1017. Xint file_info_date_cmp (info_1, info_2)
  1018. X   struct file_info **info_1, **info_2 ;
  1019. X{
  1020. X   return (int) ((*info_2)->mtime - (*info_1)->mtime) ;
  1021. X   }
  1022. X
  1023. X
  1024. Xstatic
  1025. Xint compare_str (str_1, str_2)
  1026. X   char **str_1, **str_2 ;
  1027. X{
  1028. X   return strcmp (*str_1, *str_2) ;
  1029. X   }
  1030. X
  1031. X
  1032. Xstatic
  1033. XVOID build_and_sort_list (file_list, directory, where_from, param_1, param_2)
  1034. X   struct list *file_list ;
  1035. X   char *directory ;
  1036. X   int where_from ;
  1037. X   char *param_1, *param_2 ;
  1038. X{
  1039. X   VOID_PTR (*get_element) () ;
  1040. X   struct stat file_status ;
  1041. X   char *name ;
  1042. X
  1043. X   if (where_from == FROM_ARGV)
  1044. X      get_element = get_element_from_argv ;
  1045. X   else
  1046. X      get_element = get_element_from_dir ;
  1047. X
  1048. X   if (sort_by_date) {
  1049. X      struct file_info *file_info ;
  1050. X
  1051. X      file_info = (struct file_info *)
  1052. X     allocate (sizeof (struct file_info) + MAXPATHLEN) ;
  1053. X
  1054. X      while ((name = (char *) get_element (param_1, param_2)) != NULL_CP) {
  1055. X     if (lstat (pathname (directory, name), &file_status) == -1)
  1056. X        perror (name) ;
  1057. X     else {
  1058. X        file_info->inode = file_status.st_ino ;
  1059. X        file_info->mode = file_status.st_mode ;
  1060. X        file_info->nlink = file_status.st_nlink ;
  1061. X        file_info->size = file_status.st_size ;
  1062. X        file_info->mtime = file_status.st_mtime ;
  1063. X        strcpy (file_info->name, name) ;
  1064. X        list_push (file_list, (VOID_PTR) file_info,
  1065. X           file_info_size (name)) ;
  1066. X        } }
  1067. X
  1068. X      free ((VOID_PTR) file_info) ;
  1069. X
  1070. X      list_sort (file_list, file_info_date_cmp) ; }
  1071. X
  1072. X   else {    /* Sort by name */
  1073. X      while ((name = (char *) get_element (param_1, param_2)) != NULL_CP) {
  1074. X     list_push (file_list, (VOID_PTR) name,
  1075. X        ((where_from == FROM_ARGV) ? 0 : (strlen (name) + 1))) ; }
  1076. X      list_sort (file_list, compare_str) ; }
  1077. X   }
  1078. X
  1079. X
  1080. Xstatic
  1081. Xstruct file_info *get_file_info (file_list, directory)
  1082. X   struct list *file_list ;
  1083. X   char *directory ;
  1084. X{
  1085. X   static struct stat status ;    /* Tongue twister */
  1086. X   char *name ;
  1087. X   int listable ;
  1088. X   int n ;
  1089. X
  1090. X   if (sort_by_date)
  1091. X      return (struct file_info *) list_shift (file_list) ;
  1092. X   else {
  1093. X      name = (char *) list_shift (file_list) ;
  1094. X      if (name == (char *) NULL)
  1095. X     return (struct file_info *) NULL ;
  1096. X      else
  1097. X     if (lstat (pathname (directory, name), &status) == -1) {
  1098. X        perror (name) ;
  1099. X        return ¬_there ; }
  1100. X     else {
  1101. X        if (! even_inaccessible) {
  1102. X           if (uid == (UID_T) status.st_uid)
  1103. X          listable = status.st_mode & 0500 ;
  1104. X           else {
  1105. X          for (n = 0 ; n < no_groups ; n++) {
  1106. X             if (groups[n] == (GID_T) status.st_gid) {
  1107. X            listable = status.st_mode & 050 ;
  1108. X            n = no_groups + 1 ; } }
  1109. X          if (n == no_groups)
  1110. X             listable = status.st_mode & 05 ; } }
  1111. X        else
  1112. X           listable = TRUE ;
  1113. X        if (! listable)
  1114. X           return ¬_there ;
  1115. X        else {
  1116. X           static struct file_info *file_info ;
  1117. X
  1118. X           if (! file_info)
  1119. X          file_info = (struct file_info *)
  1120. X             allocate (sizeof (struct file_info) + MAXPATHLEN) ;
  1121. X           file_info->inode = status.st_ino ;
  1122. X           file_info->mode = status.st_mode ;
  1123. X           file_info->nlink = status.st_nlink ;
  1124. X           file_info->size = status.st_size ;
  1125. X           file_info->mtime = status.st_mtime ;
  1126. X           strcpy (file_info->name, name) ;
  1127. X           return file_info ; } } }
  1128. X   }
  1129. X
  1130. X
  1131. Xstatic
  1132. XVOID list_directory (directory_name, show_directory)
  1133. X   char *directory_name ;
  1134. X   int show_directory ;
  1135. X{
  1136. X   DIR *dirp ;
  1137. X   struct list file_list, dir_list ;
  1138. X   struct file_info *file_info ;
  1139. X
  1140. X   space = FALSE ;
  1141. X   if (show_directory) {
  1142. X      if (printed_anything) {
  1143. X     printc ('\n') ; }
  1144. X      printf ("%s:\n", directory_name) ;
  1145. X      printed_anything = TRUE ; }
  1146. X
  1147. X   if ((dirp = opendir (*directory_name == EOS ? "." : directory_name))
  1148. X         == (DIR *) NULL) {
  1149. X      perror (directory_name) ; }
  1150. X   else {
  1151. X      list_init (&file_list) ;
  1152. X      build_and_sort_list (&file_list, directory_name, FROM_DIR,
  1153. X         (char *) dirp, directory_name) ;
  1154. X      list_init (&dir_list) ;
  1155. X      while ((file_info = get_file_info (&file_list, directory_name))
  1156. X         != (struct file_info *) NULL) {
  1157. X     if (file_info != ¬_there) {
  1158. X        if (recursive && file_info->mode & S_IFDIR)
  1159. X           /* Save this for later */
  1160. X           list_push (&dir_list, (VOID_PTR) file_info->name,
  1161. X          strlen (file_info->name) + 1) ;
  1162. X        list_file (file_info, directory_name) ; } }
  1163. X      list_free (&file_list) ;
  1164. X      closedir (dirp) ;
  1165. X
  1166. X      if (recursive) {
  1167. X     char *saved_dir ;
  1168. X     char *path, *sub_dir ;
  1169. X
  1170. X         /* Now, the directories we saved earlier */
  1171. X     while ((saved_dir = (char *) list_shift (&dir_list))) {
  1172. X        path = pathname (directory_name, saved_dir) ;
  1173. X        list_directory (strgencpy (sub_dir, path), TRUE) ;
  1174. X        free ((VOID_PTR) sub_dir) ; }
  1175. X     list_free (&dir_list) ; } }
  1176. X
  1177. X   space = TRUE ;
  1178. X   }
  1179. X
  1180. X
  1181. X      
  1182. X
  1183. Xstatic
  1184. XVOID list_file (file_info, directory)
  1185. X   struct file_info *file_info ;
  1186. X   char *directory ;
  1187. X{
  1188. X   static char month[][12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1189. X      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
  1190. X   char out_name[MAXPATHLEN+2] ;    /* What to print */
  1191. X   char *desc ;
  1192. X#ifdef SHOW_SYMLINK
  1193. X   int symlink = 0 ;
  1194. X#endif
  1195. X   static char size[12] ;
  1196. X   static char date[16] ;
  1197. X   int name_len, size_len, gap ;
  1198. X   struct tm *tm_time ;
  1199. X
  1200. X   if (directory)
  1201. X      desc = getdesc (NULL_CP, directory, file_info->name, file_info->inode) ;
  1202. X   else
  1203. X      desc = getdesc (file_info->name, NULL_CP, NULL_CP, file_info->inode) ;
  1204. X
  1205. X#ifdef SHOW_SYMLINK
  1206. X   /* If file is a symbolic link, and has no description, we will */
  1207. X   /* generate a description that indicates what file it points to */
  1208. X#ifndef S_ISLNK
  1209. X#define S_ISLNK(m)    (((m)&S_IFMT) == S_IFLNK)
  1210. X#endif
  1211. X   if ((! desc) && S_ISLNK (file_info->mode)) {
  1212. X      desc = (char *) allocate (1024) ;
  1213. X
  1214. X      memzero (desc, 1024);
  1215. X      symlink = TRUE ;
  1216. X      strcpy (desc, "-> ") ;
  1217. X      if (readlink (pathname (directory, file_info->name), &(desc[3]), 1021)
  1218. X        == -1)
  1219. X     strcat (desc, "(symbolic link)") ;
  1220. X      }
  1221. X#endif
  1222. X
  1223. X   /* Now we only need what we will show */
  1224. X   strcpy (out_name, file_info->name) ;
  1225. X
  1226. X   name_len = strlen (out_name) ;
  1227. X   /* If it is a directory, make it obvious */
  1228. X   if (file_info->mode & S_IFDIR) {
  1229. X      strcat (out_name, "/") ;
  1230. X      name_len++ ;
  1231. X      size[1] = EOS ;
  1232. X      size_len = 1 ;
  1233. X      if (file_info->nlink > 2) {    /* Denotes a directory that contains */
  1234. X     size[0] = '=' ; }        /* one or more sub-directories */
  1235. X      else {
  1236. X     size[0] = '-' ; } }
  1237. X   else {
  1238. X      sprintf (size, "%d", file_info->size) ;
  1239. X      size_len = strlen (size) ; }
  1240. X   if (name_len + size_len < name_and_size_columns)
  1241. X      gap = name_and_size_columns - name_len ;
  1242. X   else {
  1243. X      print (out_name) ;
  1244. X      out_name[0] = '\n' ; out_name[1] = EOS ;
  1245. X      gap = name_and_size_columns ; }
  1246. X   if (show_date) {
  1247. X      tm_time = localtime (&file_info->mtime) ;
  1248. X      if (six_months_ago > file_info->mtime) {
  1249. X     /* The bloody thing is more than 6 months old! */
  1250. X#ifdef US_DATE_FORMAT
  1251. X     sprintf (date, " %s %2d  %d ", month[tm_time->tm_mon],
  1252. X        tm_time->tm_mday, tm_time->tm_year + 1900) ;
  1253. X#else
  1254. X     sprintf (date, " %2d %s  %d ", tm_time->tm_mday,
  1255. X        month[tm_time->tm_mon], tm_time->tm_year + 1900) ;
  1256. X#endif
  1257. X         }
  1258. X      else {
  1259. X#ifdef US_DATE_FORMAT
  1260. X     sprintf (date, " %s %2d %02d:%02d ", month[tm_time->tm_mon],
  1261. X        tm_time->tm_mday, tm_time->tm_hour, tm_time->tm_min) ;
  1262. X#else
  1263. X     sprintf (date, " %2d %s %02d:%02d ", tm_time->tm_mday,
  1264. X         month[tm_time->tm_mon], tm_time->tm_hour, tm_time->tm_min) ;
  1265. X#endif
  1266. X      } }
  1267. X   else {
  1268. X      date[0] = ' ' ;
  1269. X      date[1] = EOS ; }
  1270. X
  1271. X   if (space) {
  1272. X      printc ('\n') ;
  1273. X      space = FALSE ; }
  1274. X   printf ("%s %*s%s %s\n", out_name, gap, size, date,
  1275. X#ifdef PASS_NULL_TO_PRINTF
  1276. X      desc
  1277. X#else
  1278. X      (desc == NULL_CP) ? "" : desc
  1279. X#endif
  1280. X      ) ;
  1281. X   printed_anything = TRUE ;
  1282. X
  1283. X#ifdef SHOW_SYMLINK
  1284. X   if (symlink) {
  1285. X      free (desc); }
  1286. X#endif
  1287. X   }
  1288. END_OF_FILE
  1289.   if test 12166 -ne `wc -c <'dl.c'`; then
  1290.     echo shar: \"'dl.c'\" unpacked with wrong size!
  1291.   fi
  1292.   # end of 'dl.c'
  1293. fi
  1294. if test -f 'list.c' -a "${1}" != "-c" ; then 
  1295.   echo shar: Will not clobber existing file \"'list.c'\"
  1296. else
  1297.   echo shar: Extracting \"'list.c'\" \(6164 characters\)
  1298.   sed "s/^X//" >'list.c' <<'END_OF_FILE'
  1299. X/* list.c -    List manipulation routines
  1300. X *
  1301. X * SYNOPSIS
  1302. X *    #include <list.h>
  1303. X *
  1304. X *    void list_init (struct list *list) ;
  1305. X *
  1306. X *        Initializes the list.  Does not free any storage that
  1307. X *        may have been allocated to the list.
  1308. X *
  1309. X *    void list_free (struct list *list) ;
  1310. X *
  1311. X *        Deallocates and initializes the list.
  1312. X *
  1313. X *    void list_push (struct list *list, void *element, size_t length) ;
  1314. X *
  1315. X *        Adds the element to the end of the list.  If length is
  1316. X *        non-zero, a copy is made of the data pointed to by element,
  1317. X *        and the address of the copy is added to the list instead.
  1318. X *
  1319. X *    void *list_pop (struct list *list) ;
  1320. X *
  1321. X *        Returns the last element in the list and removes it.
  1322. X *
  1323. X *    void *list_shift (struct list *list) ;
  1324. X *
  1325. X *        Returns the first element in the list and removes it
  1326. X *
  1327. X *    void *list_element (struct list *list, int element_no) ;
  1328. X *
  1329. X *        Returns the specified element (elements are numbered
  1330. X *        starting from 0), or NULL if the list does not contain
  1331. X *        any elements.  Has no effect on the contents of the
  1332. X *        list.
  1333. X *
  1334. X *    int list_elements (struct list *list) ;
  1335. X *
  1336. X *        Returns the number of elements in the list.
  1337. X *
  1338. X *    int list_empty (struct list *list) ;
  1339. X *
  1340. X *        Returns non-zero if the list contains any elements,
  1341. X *        zero otherwise.
  1342. X *
  1343. X *    void list_sort (struct list *list, int (*compare) ()) ;
  1344. X *
  1345. X *        Sorts the list using compare() (like qsort(3))
  1346. X *
  1347. X * NOTE: list_init(), list_element(), list_elements() and list_empty()
  1348. X *     are implemented as macros.
  1349. X *
  1350. X * Copyright (c) 1991, 1992 Tim Cook.
  1351. X * Non-profit distribution allowed.  See README for details.
  1352. X */
  1353. X
  1354. Xstatic char rcsid[] = "$Id: list.c,v 1.6 1992/12/02 03:46:20 tim Exp $";
  1355. X
  1356. X#define _LIST_C_
  1357. X
  1358. X#define VOID_PTR    char *
  1359. X#define VOID_PTR_PTR    char **
  1360. X
  1361. X#include "config.h"
  1362. X#include <list.h>
  1363. X
  1364. X#ifndef NULL
  1365. X#define NULL    0
  1366. X#endif
  1367. X
  1368. Xextern VOID_PTR allocate () ;
  1369. Xextern VOID_PTR re_allocate () ;
  1370. X
  1371. X#ifndef INITIAL_LIST_ENTRIES
  1372. X#define INITIAL_LIST_ENTRIES    512
  1373. X#endif
  1374. X#ifndef DATA_BLOCK_SIZE
  1375. X#define DATA_BLOCK_SIZE        16384
  1376. X#endif
  1377. X
  1378. X/*
  1379. X * This must be defined to an unsigned integer data type to which
  1380. X * pointer types can be freely cast.
  1381. X */
  1382. X
  1383. X#define PTR_CARD    unsigned long
  1384. X
  1385. X
  1386. XVOID list_free (list)
  1387. X   struct list *list ;
  1388. X{
  1389. X   if (! list_empty (list) && list->s_start != (VOID_PTR_PTR) NULL) {
  1390. X      free ((VOID_PTR) list->s_start) ;
  1391. X      if (list->data) {
  1392. X     int i ;
  1393. X
  1394. X     for (i = 2 ; list->data[i] ; i++)
  1395. X        free (list->data[i]) ;
  1396. X     free ((VOID_PTR) list->data) ; }
  1397. X      list_init (list) ; }        /* May as well */
  1398. X   }
  1399. X
  1400. X
  1401. XVOID list_push (list, element, length)
  1402. X   struct list *list ;
  1403. X   VOID_PTR element ;
  1404. X   size_t length ;
  1405. X{
  1406. X   if (length) {
  1407. X      size_t data_block_size ;
  1408. X      int new_block = 0 ;
  1409. X
  1410. X#ifdef ALIGN
  1411. X      /* Make sure subsequent data is stored aligned */
  1412. X#if ALIGN == 2
  1413. X      if (length & 1)
  1414. X     length++ ;
  1415. X#else
  1416. X      /*
  1417. X       * ALIGN must be a power of 2 (reasonable to expect), but at
  1418. X       * least we don't need to do a divide.
  1419. X       */
  1420. X      if (length & (ALIGN - 1))
  1421. X     length += ALIGN - (length & (ALIGN - 1)) ;
  1422. X#endif
  1423. X#endif
  1424. X
  1425. X      if (length > DATA_BLOCK_SIZE)
  1426. X     data_block_size = length ;
  1427. X      else
  1428. X     data_block_size = DATA_BLOCK_SIZE ;
  1429. X
  1430. X      /*
  1431. X       * Allocate storage for data pointed to by list element
  1432. X       */
  1433. X      if (! list->data) {
  1434. X     /* No blocks allocated at all, set it up */
  1435. X     list->data = (VOID_PTR_PTR) allocate (sizeof (VOID_PTR_PTR) * 4) ;
  1436. X     new_block = 2 ; }
  1437. X      else {
  1438. X     /* We have some storage, but do we have enough? */
  1439. X     if ((PTR_CARD) list->data[0] + length > (PTR_CARD) list->data[1]) {
  1440. X        /* Nope, allocate new block */
  1441. X
  1442. X        for (new_block = 2 ; list->data[new_block] ; new_block++) ;
  1443. X        list->data = (VOID_PTR_PTR) re_allocate (list->data,
  1444. X           sizeof (VOID_PTR_PTR) * new_block + 2) ; } }
  1445. X
  1446. X      if (new_block) {
  1447. X     /*
  1448. X      * The contents of the array pointed to by list->data is as
  1449. X      * follows:
  1450. X      *
  1451. X      *    The first element points to the first free byte of storage.
  1452. X      *    The second to the first inaccessible byte.
  1453. X      *    Subsequent elements contain a NULL-terminated list of all
  1454. X      *    blocks.
  1455. X      */
  1456. X     list->data[new_block] = allocate (data_block_size) ;
  1457. X     list->data[new_block+1] = (VOID_PTR) NULL ;
  1458. X     list->data[0] = list->data[new_block] ;
  1459. X     list->data[1] = (VOID_PTR)
  1460. X           ((PTR_CARD) list->data[new_block] + data_block_size) ; }
  1461. X
  1462. X      /* Copy data pointed to by list element */
  1463. X      memcpy (list->data[0], element, length) ;
  1464. X      /* Now, make sure we add the right pointer to the list */
  1465. X      element = list->data[0] ;
  1466. X      /* Adjust free pointer */
  1467. X      list->data[0] = (VOID_PTR) ((PTR_CARD) list->data[0] + length) ;
  1468. X      }
  1469. X
  1470. X   /* Now, add the "pointer" itself */
  1471. X   if (list_empty (list)) {
  1472. X      list->s_start = (VOID_PTR_PTR) allocate (
  1473. X         sizeof (VOID_PTR) * INITIAL_LIST_ENTRIES) ;
  1474. X      list->s_end = list->s_start + INITIAL_LIST_ENTRIES ;
  1475. X      list->start = list->s_start ;
  1476. X      list->end = list->start ; }
  1477. X   else {
  1478. X      if (list->end >= list->s_end) {
  1479. X     /* We need to re-allocate */
  1480. X     register PTR_CARD x, y, z ;
  1481. X
  1482. X     x = (PTR_CARD) list->s_end - (PTR_CARD) list->s_start ;
  1483. X     y = (PTR_CARD) list->start - (PTR_CARD) list->s_start ;
  1484. X     z = (PTR_CARD) list->end - (PTR_CARD) list->s_start ;
  1485. X     x = x << 1 ;    /* Double allocation size */
  1486. X     list->s_start = (VOID_PTR_PTR) re_allocate (list->s_start, x) ;
  1487. X     list->s_end = (VOID_PTR_PTR) ((PTR_CARD) list->s_start + x) ;
  1488. X     list->start = (VOID_PTR_PTR) ((PTR_CARD) list->s_start + y) ;
  1489. X     list->end = (VOID_PTR_PTR) ((PTR_CARD) list->s_start + z) ; } }
  1490. X
  1491. X   *list->end = element ;
  1492. X   list->end++ ;
  1493. X   }
  1494. X
  1495. X
  1496. XVOID_PTR list_shift (list)
  1497. X   struct list *list ;
  1498. X{
  1499. X   if (list_empty (list))
  1500. X      return (VOID_PTR) NULL ;
  1501. X   else
  1502. X      if (list->start >= list->end)
  1503. X     return (VOID_PTR) NULL ;
  1504. X      else
  1505. X     return *list->start++ ;
  1506. X   }
  1507. X
  1508. X
  1509. XVOID_PTR list_pop (list)            /* WORK */
  1510. X   struct list *list ;
  1511. X{
  1512. X   if (list_empty (list))
  1513. X      return (VOID_PTR) NULL ;
  1514. X   else
  1515. X      if (list->end < list->start)             /* WORK */
  1516. X     return (VOID_PTR) NULL ;
  1517. X      else
  1518. X     return *list->end-- ;
  1519. X   }
  1520. X
  1521. X
  1522. XVOID list_sort (list, compare)
  1523. X   struct list *list ;
  1524. X   int (*compare) () ;
  1525. X{
  1526. X   if (! list_empty (list))
  1527. X      qsort (list->start, (int) list_elements (list),
  1528. X     sizeof (VOID_PTR), compare) ;
  1529. X   }
  1530. END_OF_FILE
  1531.   if test 6164 -ne `wc -c <'list.c'`; then
  1532.     echo shar: \"'list.c'\" unpacked with wrong size!
  1533.   fi
  1534.   # end of 'list.c'
  1535. fi
  1536. if test ! -d 'other' ; then
  1537.     echo shar: Creating directory \"'other'\"
  1538.     mkdir 'other'
  1539. fi
  1540. if test -f 'other/descopt' -a "${1}" != "-c" ; then 
  1541.   echo shar: Will not clobber existing file \"'other/descopt'\"
  1542. else
  1543.   echo shar: Extracting \"'other/descopt'\" \(349 characters\)
  1544.   sed "s/^X//" >'other/descopt' <<'END_OF_FILE'
  1545. X#!/bin/sh
  1546. X# descopt -    Optimize description database in a given directory
  1547. X
  1548. Xcase $# in
  1549. X   1 ) ;;
  1550. X   * )
  1551. X      echo "usage: $0 <directory>"
  1552. X      exit 1 ;;
  1553. X   esac
  1554. X
  1555. Xdirectory="$1"
  1556. X
  1557. Xdescribe -l "$directory" > "/tmp/descopt.$$"
  1558. X
  1559. Xrm -f "${directory}/.desc.pag" "${directory}/.desc.dir"
  1560. X
  1561. Xdescribe -f "/tmp/descopt.$$" "$directory"
  1562. X
  1563. Xrm -f "/tmp/descopt.$$"
  1564. END_OF_FILE
  1565.   if test 349 -ne `wc -c <'other/descopt'`; then
  1566.     echo shar: \"'other/descopt'\" unpacked with wrong size!
  1567.   fi
  1568.   # end of 'other/descopt'
  1569. fi
  1570. if test ! -d 'patches' ; then
  1571.     echo shar: Creating directory \"'patches'\"
  1572.     mkdir 'patches'
  1573. fi
  1574. if test -f 'patches/GNU-compress.patch' -a "${1}" != "-c" ; then 
  1575.   echo shar: Will not clobber existing file \"'patches/GNU-compress.patch'\"
  1576. else
  1577.   echo shar: Extracting \"'patches/GNU-compress.patch'\" \(3559 characters\)
  1578.   sed "s/^X//" >'patches/GNU-compress.patch' <<'END_OF_FILE'
  1579. XThis patch can be applied to GNU compress, to give it a "-s" flag
  1580. X("-d" and "-D" were taken already) which will instruct compress to
  1581. Xmove descriptions as it compresses or uncompresses files.
  1582. X
  1583. XTo create a file-descriptions-compatible GNU compress, follow these
  1584. Xinstructions:
  1585. X
  1586. X   1. Patch compress.c.
  1587. X      (Something like "cd [compress source directory] ; patch < [this-file]")
  1588. X
  1589. X   2. Compile compress.c with the DESCRIPTIONS macro defined.  It is
  1590. X      probably best to edit the Makefile that comes with compress,
  1591. X      adding "-DDESCRIPTIONS" to the CFLAGS macro.
  1592. X
  1593. X   3. Link compress.c, insuring you include getdesc.o, setdesc.o and
  1594. X      enddesc.o from dl/describe and the DBM library you used with
  1595. X      dl/describe.  Again, editing of the Makefile is recommended here
  1596. X
  1597. X   4. Install as appropriate.
  1598. X
  1599. X   5. (Suggestion) "% alias compress compress -s"
  1600. X
  1601. XThis patch was generated against compress.c from compress-4.0.1.tar.Z,
  1602. Xwhich is distributed via GNU.
  1603. X
  1604. X
  1605. X*** compress.c.dist    Wed Sep  7 04:32:07 1988
  1606. X--- compress.c    Mon May  4 17:47:55 1992
  1607. X***************
  1608. X*** 387,391 ****
  1609. X--- 387,395 ----
  1610. X      fprintf(stderr,"Usage: compress [-cdDfivV] [-b maxbits] [file ...]\n");
  1611. X  # else
  1612. X+ #  ifdef DESCRIPTIONS
  1613. X+     fprintf(stderr,"Usage: compress [-cdDfsvV] [-b maxbits] [file ...]\n");
  1614. X+ #  else
  1615. X      fprintf(stderr,"Usage: compress [-cdDfvV] [-b maxbits] [file ...]\n");
  1616. X+ #  endif /* DESCRIPTIONS */
  1617. X  # endif /* MSDOS */
  1618. X  
  1619. X***************
  1620. X*** 397,401 ****
  1621. X--- 401,409 ----
  1622. X      fprintf(stderr,"Usage: compress [-cdfivV] [-b maxbits] [file ...]\n");
  1623. X  # else
  1624. X+ #  ifdef DESCRIPTIONS
  1625. X+     fprintf(stderr,"Usage: compress [-cdfsvV] [-b maxbits] [file ...]\n");
  1626. X+ #  else
  1627. X      fprintf(stderr,"Usage: compress [-cdfvV] [-b maxbits] [file ...]\n");
  1628. X+ #  endif
  1629. X  # endif /* MSDOS */
  1630. X  
  1631. X***************
  1632. X*** 440,443 ****
  1633. X--- 448,458 ----
  1634. X  int do_decomp = 0;
  1635. X  
  1636. X+ #ifdef DESCRIPTIONS
  1637. X+ extern char *getdesc();
  1638. X+ extern int setdesc();
  1639. X+ 
  1640. X+ int descriptions = 0;
  1641. X+ #endif
  1642. X+ 
  1643. X  /*****************************************************************
  1644. X   * TAG( main )
  1645. X***************
  1646. X*** 470,473 ****
  1647. X--- 485,491 ----
  1648. X   *    -b:        Parameter limits the max number of bits/code.
  1649. X   *
  1650. X+  *    -s:        Output file is given same description as input file.
  1651. X+  *            This is subject to DESCRIPTIONS being #defined.
  1652. X+  *
  1653. X   *    file ...:   Files to be compressed.  If none specified, stdin
  1654. X   *            is used.
  1655. X***************
  1656. X*** 492,496 ****
  1657. X      char tempname[100];
  1658. X      char **filelist, **fileptr;
  1659. X!     char *cp, *rindex(), *malloc();
  1660. X      struct stat statbuf;
  1661. X      extern onintr();
  1662. X--- 510,514 ----
  1663. X      char tempname[100];
  1664. X      char **filelist, **fileptr;
  1665. X!     char *cp, *rindex(), *malloc(), *strcpy();
  1666. X      struct stat statbuf;
  1667. X      extern onintr();
  1668. X***************
  1669. X*** 618,621 ****
  1670. X--- 636,644 ----
  1671. X              quiet = 1;
  1672. X              break;
  1673. X+ #ifdef DESCRIPTIONS
  1674. X+             case 's':
  1675. X+             descriptions = 1;
  1676. X+             break;
  1677. X+ #endif
  1678. X              default:
  1679. X              fprintf(stderr, "Unknown flag: '%c'; ", **argv);
  1680. X***************
  1681. X*** 1498,1501 ****
  1682. X--- 1521,1536 ----
  1683. X          fprintf(stderr, " -- file unchanged");
  1684. X      } else {            /* ***** Successful Compression ***** */
  1685. X+ #ifdef DESCRIPTIONS
  1686. X+     if (descriptions) {            /* Copy description */
  1687. X+         char *description = getdesc (ifname, NULL, NULL, 0);
  1688. X+         if (description) {
  1689. X+         description = strcpy (
  1690. X+             (char *) malloc (strlen (description) + 1), description);
  1691. X+         if (! setdesc (ofname, NULL, NULL, 0, description))
  1692. X+             perror (ofname);
  1693. X+         free (description);
  1694. X+         }
  1695. X+     }
  1696. X+ #endif
  1697. X      exit_stat = 0;
  1698. X      mode = statbuf.st_mode & 07777;
  1699. END_OF_FILE
  1700.   if test 3559 -ne `wc -c <'patches/GNU-compress.patch'`; then
  1701.     echo shar: \"'patches/GNU-compress.patch'\" unpacked with wrong size!
  1702.   fi
  1703.   # end of 'patches/GNU-compress.patch'
  1704. fi
  1705. if test -f 'patches/GNU-mv.patch' -a "${1}" != "-c" ; then 
  1706.   echo shar: Will not clobber existing file \"'patches/GNU-mv.patch'\"
  1707. else
  1708.   echo shar: Extracting \"'patches/GNU-mv.patch'\" \(6151 characters\)
  1709.   sed "s/^X//" >'patches/GNU-mv.patch' <<'END_OF_FILE'
  1710. XThe enclosed patch can be applied to GNU mv (which is contained in the
  1711. XGNU Fileutils package) to give it a "-d" flag which will instruct mv
  1712. Xto move file descriptions with files.
  1713. X
  1714. XTo create a file-descriptions-compatible GNU mv, follow these
  1715. Xinstructions:
  1716. X
  1717. X   1.    Patch mv.c from the fileutils package
  1718. X    (something like "cd [fileutils-src-dir] ; patch < [this-file]).
  1719. X
  1720. X   2.   Compile mv.c with the DESCRIPTIONS macro defined.
  1721. X
  1722. X   3.   Link mv.c, insuring you include getdesc.o, setdesc.o and
  1723. X    enddesc.o from dl/describe and the DBM library you used with
  1724. X    dl/describe.
  1725. X
  1726. X   4.    Install as appropriate.
  1727. X
  1728. X   5.    (Suggestion:)  "% alias mv mv -d"
  1729. X
  1730. XNote that running the GNU fileutils "configure" script, then adjusting
  1731. Xthe generated Makefile is probably the best course of action to take
  1732. Xafter applying this patch.
  1733. X
  1734. XThis patch was generated against mv.c from the GNU fileutils package,
  1735. Xversion 3.2.
  1736. X
  1737. X
  1738. X*** mv.c.dist    Mon Mar  9 14:14:00 1992
  1739. X--- mv.c    Tue May  5 12:18:02 1992
  1740. X***************
  1741. X*** 78,81 ****
  1742. X--- 78,86 ----
  1743. X  int stdin_tty;
  1744. X  
  1745. X+ #ifdef DESCRIPTIONS
  1746. X+ /* If nonzero, move description with file (if possible) */
  1747. X+ int describe;
  1748. X+ #endif
  1749. X+ 
  1750. X  struct option long_options[] =
  1751. X  {
  1752. X***************
  1753. X*** 87,90 ****
  1754. X--- 92,98 ----
  1755. X    {"verbose", 0, &verbose, 1},
  1756. X    {"version-control", 1, NULL, 'V'},
  1757. X+ #ifdef DESCRIPTIONS
  1758. X+   {"describe", 0, NULL, 'd'},
  1759. X+ #endif
  1760. X    {NULL, 0, NULL, 0}
  1761. X  };
  1762. X***************
  1763. X*** 107,113 ****
  1764. X    interactive = override_mode = verbose = update = 0;
  1765. X    errors = 0;
  1766. X  
  1767. X!   while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, (int *) 0))
  1768. X!      != EOF)
  1769. X      {
  1770. X        switch (c)
  1771. X--- 115,129 ----
  1772. X    interactive = override_mode = verbose = update = 0;
  1773. X    errors = 0;
  1774. X+ #ifdef DESCRIPTIONS
  1775. X+   describe = 0;
  1776. X+ #endif
  1777. X  
  1778. X!   while ((c = getopt_long (argc, argv,
  1779. X! #ifdef DESCRIPTIONS
  1780. X!                "bfiuvdS:V:",
  1781. X! #else
  1782. X!                "bfiuvS:V:",
  1783. X! #endif
  1784. X!                long_options, (int *) 0)) != EOF)
  1785. X      {
  1786. X        switch (c)
  1787. X***************
  1788. X*** 138,141 ****
  1789. X--- 154,162 ----
  1790. X        version = optarg;
  1791. X        break;
  1792. X+ #ifdef DESCRIPTIONS
  1793. X+     case 'd':
  1794. X+       describe = 1;
  1795. X+       break;
  1796. X+ #endif
  1797. X      default:
  1798. X        usage ();
  1799. X***************
  1800. X*** 203,206 ****
  1801. X--- 224,232 ----
  1802. X  {
  1803. X    char *to_backup = NULL;
  1804. X+ #ifdef DESCRIPTIONS
  1805. X+   char *from_description = NULL;
  1806. X+ 
  1807. X+   extern int setdesc ();
  1808. X+ #endif
  1809. X  
  1810. X    if (lstat (from, &from_stats) != 0)
  1811. X***************
  1812. X*** 247,250 ****
  1813. X--- 273,289 ----
  1814. X      {
  1815. X        char *tmp_backup = find_backup_file_name (to);
  1816. X+ #ifdef DESCRIPTIONS
  1817. X+       char *to_description = NULL;
  1818. X+ 
  1819. X+       if (describe)
  1820. X+         {
  1821. X+           char *p = getdesc (to, NULL, NULL, to_stats.st_ino);
  1822. X+           if (p)
  1823. X+         {
  1824. X+           to_description = (char *) alloca (strlen (p) + 1);
  1825. X+           strcpy (to_description, p);
  1826. X+             }
  1827. X+         }
  1828. X+ #endif
  1829. X        if (tmp_backup == NULL)
  1830. X          error (1, 0, "virtual memory exhausted");
  1831. X***************
  1832. X*** 262,265 ****
  1833. X--- 301,315 ----
  1834. X          to_backup = NULL;
  1835. X          }
  1836. X+ #ifdef DESCRIPTIONS
  1837. X+       else if (describe)
  1838. X+         {
  1839. X+           if (! setdesc (to_backup, NULL, NULL, 0, to_description))
  1840. X+         {
  1841. X+           if (verbose)
  1842. X+             error (0, errno, "cannot set description on backup `%s'",
  1843. X+                to_backup);
  1844. X+             }
  1845. X+         }
  1846. X+ #endif
  1847. X      }
  1848. X      }
  1849. X***************
  1850. X*** 273,278 ****
  1851. X--- 323,354 ----
  1852. X      printf ("%s -> %s\n", from, to);
  1853. X  
  1854. X+ #ifdef DESCRIPTIONS
  1855. X+   if (describe)
  1856. X+     {
  1857. X+       char *p = getdesc (from, NULL, NULL, from_stats.st_ino);
  1858. X+ 
  1859. X+       if (p)
  1860. X+     {
  1861. X+       from_description = (char *) alloca (strlen (p) + 1);
  1862. X+       strcpy (from_description, p);
  1863. X+         }
  1864. X+     }
  1865. X+ #endif
  1866. X+ 
  1867. X    if (rename (from, to) == 0)
  1868. X      {
  1869. X+ #ifdef DESCRIPTIONS
  1870. X+       if (describe)
  1871. X+     {
  1872. X+       if (! setdesc (to, NULL, NULL, to_stats.st_ino, from_description))
  1873. X+         {
  1874. X+           if (verbose)
  1875. X+         error (0, errno, "cannot set description of `%s'", to);
  1876. X+         }
  1877. X+       else
  1878. X+         /* Delete the description for what the file used to be called */
  1879. X+         setdesc (from, NULL, NULL, from_stats.st_ino, NULL);
  1880. X+         }
  1881. X+ #endif
  1882. X        return 0;
  1883. X      }
  1884. X***************
  1885. X*** 288,292 ****
  1886. X    if (copy (from, to))
  1887. X      goto un_backup;
  1888. X!   
  1889. X    if (unlink (from))
  1890. X      {
  1891. X--- 364,381 ----
  1892. X    if (copy (from, to))
  1893. X      goto un_backup;
  1894. X! #ifdef DESCRIPTIONS
  1895. X!   else if (describe)
  1896. X!     {
  1897. X!       if (! setdesc (to, NULL, NULL, to_stats.st_ino, from_description))
  1898. X!     {
  1899. X!       if (verbose)
  1900. X!         error (0, errno, "cannot set description of `%s'", to);
  1901. X!         }
  1902. X!       else
  1903. X!     /* Delete description on original file */
  1904. X!     setdesc (from, NULL, NULL, from_stats.st_ino, NULL);
  1905. X!     }
  1906. X! #endif    
  1907. X! 
  1908. X    if (unlink (from))
  1909. X      {
  1910. X***************
  1911. X*** 302,305 ****
  1912. X--- 391,399 ----
  1913. X        if (rename (to_backup, to))
  1914. X      error (0, errno, "cannot un-backup `%s'", to);
  1915. X+ #ifdef DESCRIPTIONS
  1916. X+       else if (describe)
  1917. X+     /* Delete the description on the backup we have just deleted */
  1918. X+     setdesc (to_backup, NULL, NULL, 0, NULL);
  1919. X+ #endif
  1920. X      }
  1921. X    return 1;
  1922. X***************
  1923. X*** 426,436 ****
  1924. X  usage ()
  1925. X  {
  1926. X!   fprintf (stderr, "\
  1927. X  Usage: %s [options] source dest\n\
  1928. X         %s [options] source... directory\n\
  1929. X  Options:\n\
  1930. X         [-bfiuv] [-S backup-suffix] [-V {numbered,existing,simple}]\n\
  1931. X         [--backup] [--force] [--interactive] [--update] [--verbose]\n\
  1932. X         [--suffix=backup-suffix] [--version-control={numbered,existing,simple}]\n",
  1933. X         program_name, program_name);
  1934. X    exit (1);
  1935. X--- 520,541 ----
  1936. X  usage ()
  1937. X  {
  1938. X!   fprintf (stderr,
  1939. X! #ifdef DESCRIPTIONS
  1940. X! "\
  1941. X  Usage: %s [options] source dest\n\
  1942. X         %s [options] source... directory\n\
  1943. X  Options:\n\
  1944. X+        [-bdfiuv] [-S backup-suffix] [-V {numbered,existing,simple}]\n\
  1945. X+        [+backup] [+describe] [+force] [+interactive] [+update] [+verbose]\n\
  1946. X+        [+suffix=backup-suffix] [+version-control={numbered,existing,simple}]\n",
  1947. X+ #else
  1948. X+ "\
  1949. X+ Usage: %s [options] source dest\n\
  1950. X+        %s [options] source... directory\n\
  1951. X+ Options:\n\
  1952. X         [-bfiuv] [-S backup-suffix] [-V {numbered,existing,simple}]\n\
  1953. X         [--backup] [--force] [--interactive] [--update] [--verbose]\n\
  1954. X         [--suffix=backup-suffix] [--version-control={numbered,existing,simple}]\n",
  1955. X+ #endif
  1956. X         program_name, program_name);
  1957. X    exit (1);
  1958. END_OF_FILE
  1959.   if test 6151 -ne `wc -c <'patches/GNU-mv.patch'`; then
  1960.     echo shar: \"'patches/GNU-mv.patch'\" unpacked with wrong size!
  1961.   fi
  1962.   # end of 'patches/GNU-mv.patch'
  1963. fi
  1964. echo shar: End of archive 1 \(of 3\).
  1965. cp /dev/null ark1isdone
  1966. MISSING=""
  1967. for I in 1 2 3 ; do
  1968.     if test ! -f ark${I}isdone ; then
  1969.     MISSING="${MISSING} ${I}"
  1970.     fi
  1971. done
  1972. if test "${MISSING}" = "" ; then
  1973.     echo You have unpacked all 3 archives.
  1974.     rm -f ark[1-9]isdone
  1975. else
  1976.     echo You still must unpack the following archives:
  1977.     echo "        " ${MISSING}
  1978. fi
  1979. exit 0
  1980. exit 0 # Just in case...
  1981.