home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1986 / 03 / holublst.mar < prev    next >
Text File  |  1986-03-31  |  32KB  |  793 lines

  1.                              Listing 6 -- skipto.c
  2.  ------------------------------------------------------------------------------
  3.   1 char    *skipto( c, p, esc )
  4.   2 register char   *p ;
  5.   3 register int    c, esc  ;
  6.   4 {
  7.   5         /*      Skip to c or to end of string. If c is preceeded by
  8.   6          *      the esc character it is skipped over.
  9.   7          */
  10.   8 
  11.   9         while( *p &&  *p != c )
  12.  10         {
  13.  11                 if ( *p != esc )
  14.  12                         p++ ;
  15.  13 
  16.  14                 else if ( *++p )        /* skip over escaped characters */
  17.  15                         p++;
  18.  16         }
  19.  17 
  20.  18         return(p);
  21.  19 }
  22.                                 Listing 7 -- dir.h
  23.  ------------------------------------------------------------------------------
  24.   1 /*
  25.   2  * DIR.H
  26.   3  *      #defines and typedefs needed to talk to the routine dir().
  27.   4  *      A pointer to the DIRECTORY structure is passed to dir().
  28.   5  *      DIRECTORY structures are created by mk_dir() and deleted with
  29.   6  *      del_dir().
  30.   7  *
  31.   8  *      On entry:
  32.   9  *           dirv     is the first of an uninitialized array of character
  33.  10  *                                                           pointers.
  34.  11  *           lastdir  should be initialized to point at dirv.
  35.  12  *           maxdirs  is the size of the above
  36.  13  *           nfiles  
  37.  14  *           ndirs   
  38.  15  *           nbytes   is the total file count, the total directory count
  39.  16  *                    and the total byte count. These will be incremented
  40.  17  *                    as appropriate and are usually set to 0 before
  41.  18  *                    calling dir().
  42.  19  *           width    should be initialized to 0 before calling dir().
  43.  20  *           vol_label is undefined on entry to dir().
  44.  21  *           longf    is 1 if entrys are to be printed in long format
  45.  22  *           files    is 1 if files are included in the list.
  46.  23  *           dirs     is 1 if directors are included in the list.
  47.  24  *           graphics is 1 if directories are highlighted with boldface.
  48.  25  *           hidden   is 1 if hidden files are to be included in the list.
  49.  26  *           path     is 1 if the path name is to be included in the list.
  50.  27  *           label    is 1 if you want to get the volume label
  51.  28  *           exp      is 1 if you want the contents of a subdirectory to
  52.  29  *                    be listed rather than the directory name when. This
  53.  30  *                    is only looked at if no wild cards are present in
  54.  31  *                    the file spec.
  55.  32  *           sort    is 1 if you want the list sorted.
  56.  33  *
  57.  34  *   all other fields are ignored. On exit the structure will have been
  58.  35  *   updated as follows:
  59.  36  *
  60.  37  *           lastdir  will be incremented to point at the last entry added
  61.  38  *                    to the dirv table.
  62.  39  *           maxdirs will be decremented to reflect the added entries.
  63.  40  *           nfiles  is the number of added entries which are files.
  64.  41  *           ndirs   is the number of added entries which are directories.
  65.  42  *                   Note that the equivalent of argc can be derrived by
  66.  43  *                   adding ndirs and nfiles together.
  67.  44  *           nbytes  will have the total size in bytes of all files added
  68.  45  *                   to dirv. This number is the number of bytes actually
  69.  46  *                   occupied by the file, ie. the size returned by DOS
  70.  47  *                   rounded up to the nearest multiple of the disk's
  71.  48  *                   cluster size.
  72.  49  *           vol_label will hold the volume lable provided that "label" was
  73.  50  *                   set on entry.
  74.  51  *           width   will hold the length of the widest entry added to dirv
  75.  52  *
  76.  53  *   all other fields will have the same values they had on entry.
  77.  54  */
  78.  55 
  79.  56 typedef struct 
  80.  57 {
  81.  58         char     **lastdir ;    /* Most recent addition to dirv         */
  82.  59         int      maxdirs   ;    /* # of free slots in dirv              */
  83.  60         int      nfiles    ;    /* # of used slots that are files       */
  84.  61         int      ndirs     ;    /* # of used slots that are directories */
  85.  62         long     nbytes    ;    /* byte count of files                  */
  86.  63         char     vol_label[12]; /* volume lable if requested            */
  87.  64         unsigned width    : 7 ; /* Width of widest element in dirv      */
  88.  65 
  89.  66                                 /* Various flags control how dir works: */
  90.  67         unsigned longf    : 1 ; /* Use long format for entries          */
  91.  68         unsigned files    : 1 ; /* Include files in list                */
  92.  69         unsigned dirs     : 1 ; /* Include directories in list          */
  93.  70         unsigned graphics : 1 ; /* Use graphics around directory names  */
  94.  71         unsigned hidden   : 1 ; /* List hidden files                    */
  95.  72         unsigned path     : 1 ; /* List complete path if given          */
  96.  73         unsigned label    : 1 ; /* Load vol_label with volume label     */
  97.  74         unsigned exp      : 1 ; /* Expand sub-directories               */
  98.  75         unsigned sort     : 1 ; /* Sort added entries                   */
  99.  76 
  100.  77         char     dirv[1];       /* The first of the dirv entries        */
  101.  78 }
  102.  79 DIRECTORY;
  103.                                 Listing 8 -- dir.c
  104.  ------------------------------------------------------------------------------
  105.   1 #include <stdio.h>
  106.   2 #include <getargs.h>
  107.   3 #include <mydos.h>
  108.   4 #include <dir.h>
  109.   5 
  110.   6 /*----------------------------------------------------------------------+
  111.   7  *  DIR.C: An MSDOS directory access function.                          |
  112.   8  *                                                                      |
  113.   9  *       (c) Copyright 1985, Allen I. Holub. All rights reserved.       |
  114.  10  *----------------------------------------------------------------------+
  115.  11  *  11/22/85    Modified so that the total amount of disk space used    |
  116.  12  *              (ie. # of clusters) is put into the total, rather       |
  117.  13  *              than the file size.                                     |
  118.  14  *----------------------------------------------------------------------+
  119.  15  */
  120.  16 
  121.  17 /* ROUND(n,u):  if n is an even multiple of u, evaluate to n, else
  122.  18  *              round n up to the next even multiple of u.
  123.  19  */
  124.  20 
  125.  21 #define ROUND(n,u) ( !((n) % (u)) ? (n) : (((n) / (u)) + 1) * (u))
  126.  22 
  127.  23 
  128.  24 #define BOLDFACE  "\033[1m"  /* Ansi esc sequence to turn bold face on  */
  129.  25 #define ALL_OFF   "\033[0m"  /*                 "        attributes off */
  130.  26 
  131.  27 #define ATTRIBUTES      (READONLY | DIRTY | SYSTEM | HIDDEN | SUBDIR)
  132.  28 #define iswhite(c)      ((c) == ' ' || (c) == '\t')
  133.  29 
  134.  30 /*----------------------------------------------------------------------*/
  135.  31 
  136.  32 extern char     *calloc (unsigned,unsigned); /* In standard library     */
  137.  33 extern char     *cptolower(char*,char*);     /* In /src/tools/cptolow.c */
  138.  34 extern char     *cpy    (char*,char*);       /* In /src/tools/cpy.c     */
  139.  35 extern int      dos     (REGS *);            /* In /src/tools/dos.asm   */
  140.  36 extern void     gregs   (REGS *);            /* In /src/tools/dos.asm   */
  141.  37 extern char     *malloc (unsigned);          /* In standard library     */
  142.  38 extern char     *next   (char**,int,int);    /* In /src/tools/next.c    */
  143.  39 extern void     ssort  (char*,int,int,int(*)());/*in /src/tools/ssort.c */
  144.  40 extern int      strcmp  (char*, char*);      /* in standard library     */
  145.  41 
  146.  42 /*----------------------------------------------------------------------*/
  147.  43 
  148.  44 static unsigned   Longfmt = 0;  /* True if we're using long format. This
  149.  45                                  * has to be global for the comparison
  150.  46                                  * routine used for sroting to work.
  151.  47                                  */
  152.  48 
  153.  49 static unsigned   Cluster_size;         /* Number of bytes per cluster on
  154.  50                                          * requested disk.
  155.  51                                          */
  156.  52 
  157.  53 /*----------------------------------------------------------------------*/
  158.  54 /*      Do a DOS system call using the dos() routine    */
  159.  55 
  160.  56 #define DOSCALL(id,regs) { regs.h.ah = id ; dos( ®s ); }
  161.  57 
  162.  58 /*----------------------------------------------------------------------*/
  163.  59 
  164.  60 static int  find_first( filespec, attributes, regp )
  165.  61 char     *filespec ;
  166.  62 short           attributes;
  167.  63 register REGS   *regp;
  168.  64 {
  169.  65         /*      Get directory information for the indicated file.
  170.  66          *      Ambiguous file references are ok but you have to use
  171.  67          *      find_next to get the rest of the file references.
  172.  68          *      In this case, The regs structure used by find_first
  173.  69          *      must be passed to find_next. 0 is returned on success,
  174.  70          *      otherwise the DOS error code is returned.
  175.  71          */
  176.  72 
  177.  73         regp->h.ah = (char)  FINDFIRST  ;
  178.  74         regp->x.dx = (short) filespec   ;
  179.  75         regp->x.cx = attributes         ;
  180.  76 
  181.  77         return (int)( (dos(regp) & CARRY)  ?  regp->x.ax  :  0 );
  182.  78 }
  183.  79 
  184.  80 /*----------------------------------------------------------------------*/
  185.  81 
  186.  82 static  int     find_next ( regp )
  187.  83 REGS    *regp;
  188.  84 {
  189.  85         /*      Get the next file in an ambiguous file reference. A
  190.  86          *      call to this function must be preceded by a 
  191.  87          *      find_first call. The regp argument must be the
  192.  88          *      same register image used by the find_first call.
  193.  89          *      0 is returned on success, otherwise the error code
  194.  90          *      generated by DOS is returned.
  195.  91          */
  196.  92 
  197.  93         regp->h.ah = FINDNEXT ;
  198.  94         return (int)(  (dos(regp) & CARRY)  ?  regp->x.ax  :  0 );
  199.  95 }
  200.  96 
  201.  97 /*----------------------------------------------------------------------*/
  202.  98 
  203.  99 int     haswild(s)
  204. 100 register char   *s;
  205. 101 {
  206. 102         /*      Return true if s has a unix wild card in it.    */
  207. 103 
  208. 104         for( ; *s ; s++)
  209. 105                 if( *s == '*' || *s == '?' )
  210. 106                         return 1;
  211. 107         return 0;
  212. 108 }
  213. 109 
  214. 110 /*----------------------------------------------------------------------*/
  215. 111 
  216. 112 static   int    isrootdir( name )
  217. 113 register char   *name;
  218. 114 {
  219. 115         /*      return true if name is explicitly specifying the root
  220. 116          *      directory (ie. is one of:  d:/  d:\   /   \  where
  221. 117          *      'd' can be any disk designator.
  222. 118          */
  223. 119 
  224. 120         if( *name && name[1] == ':' )
  225. 121                 name += 2;
  226. 122 
  227. 123         return( (*name == '\\' || *name == '/') && !name[1] );
  228. 124 }
  229. 125 
  230. 126 /*----------------------------------------------------------------------*/
  231. 127 
  232. 128 has_only( str, inclusion_set )
  233. 129 register char   *str;
  234. 130 char            *inclusion_set;
  235. 131 {
  236. 132         /*      Return true only if every character in str is also in
  237. 133          *      inclusion_set. True is returned if str is empty.
  238. 134          */
  239. 135 
  240. 136         register char   *p;
  241. 137 
  242. 138         for(; *str ; str++)
  243. 139         {
  244. 140                 for( p = inclusion_set ; *p && *p != *str ; p++ )
  245. 141                         ;
  246. 142 
  247. 143                 if( !*p )
  248. 144                         return 0;
  249. 145         }
  250. 146 
  251. 147         return 1;
  252. 148 }
  253. 149 
  254. 150 /*----------------------------------------------------------------------*/
  255. 151 
  256. 152 static  char    *fixup_name( name, regs, info )
  257. 153 register char   *name;
  258. 154 REGS            *regs;
  259. 155 FILE_INFO       *info;
  260. 156 {
  261. 157         /*  If the name specifies an implicit file (ie. it asks for
  262. 158          *  the directory rather than the files in the directory),
  263. 159          *  modify it to ask for files (eg. ".." becomes "..\*.*").
  264. 160          *  If the name is actually modified, a pointer to a modified
  265. 161          *  copy of the original name is returned. Otherwise the
  266. 162          *  original buffer is returned.
  267. 163          */
  268. 164 
  269. 165         static   char   buf[80]  ;          /* Place to put modified name */
  270. 166         register char   *p = buf ;          /* Always points into buf     */
  271. 167         char            *start_name = name; /* Remember start of name     */
  272. 168 
  273. 169         if( isrootdir(name) || (name[0] && name[1]==':' && !name[2]) )
  274. 170         {
  275. 171                 /* Handle an explicitly requested root directory or
  276. 172                  * the current directory on another disk.
  277. 173                  */
  278. 174 
  279. 175                 sprintf(buf, "%s*.*", name );
  280. 176         }
  281. 177         else if( !find_first( name, ALL, regs) )
  282. 178         {
  283. 179                 /* Look for the indicated name & see if it's a directory.
  284. 180                  * If so, append  slash-*.* to the requested name
  285. 181                  */
  286. 182 
  287. 183                 if( !IS_SUBDIR(info) )
  288. 184                         return name;
  289. 185                 else
  290. 186                         sprintf(buf, "%s/*.*", name );
  291. 187         }
  292. 188         else
  293. 189         {
  294. 190                 /*      If we get here then a non-existant file or directory
  295. 191                  *      was requested.
  296. 192                  *      If the name consists of nothing but the characters
  297. 193                  *      \ / . or a drive designator, assume that the root
  298. 194                  *      directory was requested and adjust the name 
  299. 195                  *      accordingly.
  300. 196                  */
  301. 197 
  302. 198                 if( *name && name[1] == ':') /* Copy drive designator if */
  303. 199                 {                            /* one's present.          */
  304. 200                         *p++ = *name++ ;
  305. 201                         *p++ = *name++ ;
  306. 202                 }
  307. 203 
  308. 204                 if( has_only(name, ".\\/") )
  309. 205                         strcpy( p, "/*.*" );
  310. 206                 else
  311. 207                         return( start_name );
  312. 208         }
  313. 209 
  314. 210         return( buf );
  315. 211 }
  316. 212 
  317. 213 /*----------------------------------------------------------------------*/
  318. 214 
  319. 215 static int  dirtoa( target, infop, graphics, pathname )
  320. 216 register char       *target   ;
  321. 217 char                *pathname ;
  322. 218 register FILE_INFO  *infop    ;
  323. 219 unsigned            graphics;
  324. 220 {
  325. 221         /*      Convert directory entry held in infop to an ascii string
  326. 222          *      in target. If Longfmt use a long format, if graphics then
  327. 223          *      directory names are printed in bold face, else they're
  328. 224          *      printed as "<name>." If pathname is true then the name
  329. 225          *      will be preceeded with the full pathname.
  330. 226          */
  331. 227 
  332. 228         char *startstr = target;
  333. 229         int  i;
  334. 230 
  335. 231         if( Longfmt )
  336. 232         {
  337. 233                 *target++ = ( IS_READONLY(infop) ) ? 'r' : '.' ;
  338. 234                 *target++ = ( IS_HIDDEN  (infop) ) ? 'h' : '.' ;
  339. 235                 *target++ = ( IS_SYSTEM  (infop) ) ? 's' : '.' ;
  340. 236                 *target++ = ( IS_SUBDIR  (infop) ) ? 'd' : '.' ;
  341. 237                 *target++ = ( IS_DIRTY   (infop) ) ? 'm' : '.' ;
  342. 238 
  343. 239                 sprintf(target, " %6ld %2d/%02d/%02d %2d:%02d:%02d - ",
  344. 240                         infop->fi_fsize,
  345. 241                         C_MONTH(infop), C_DAY(infop), C_YEAR(infop)-1900,
  346. 242                         C_HR(infop),    C_MIN(infop), C_SEC(infop)        );
  347. 243 
  348. 244                 while( *target )
  349. 245                         target++;
  350. 246         }
  351. 247 
  352. 248         if( IS_SUBDIR(infop) && graphics )
  353. 249                 target = cpy( target, BOLDFACE );
  354. 250 
  355. 251         target = cpy      ( target, pathname );
  356. 252         target = cptolower( target, infop->fi_name );
  357. 253 
  358. 254         if( IS_SUBDIR(infop) && graphics )
  359. 255                 target = cpy( target, ALL_OFF );
  360. 256 
  361. 257         return( target - startstr );
  362. 258 }
  363. 259 
  364. 260 /*----------------------------------------------------------------------*/
  365. 261 
  366. 262 static int      add_entry( infop, dp, path )
  367. 263 FILE_INFO               *infop  ;
  368. 264 register DIRECTORY      *dp     ;
  369. 265 char                    *path   ;
  370. 266 {
  371. 267         /*      Add an entry to the DIRECTORY structure. Return 0 if
  372. 268          *      it was added, one if it wasn't.
  373. 269          */
  374. 270         
  375. 271         char            buf[128] ;
  376. 272         register int    len   ;
  377. 273 
  378. 274         /*
  379. 275          *      If we're not printing hidden directories but the current
  380. 276          *      directory is nonetheless hidden, return immediately.
  381. 277          *      Similarly, return if the directory is full.
  382. 278          */
  383. 279 
  384. 280         if( !dp->hidden && (IS_HIDDEN(infop) || *infop->fi_name == '.')  )
  385. 281                 return 1;
  386. 282 
  387. 283         if( dp->maxdirs <= 0  )         /* No more room in dirv. return */
  388. 284                 return 0;               /* error status                 */
  389. 285 
  390. 286         /*
  391. 287          *      Update the directory count or the file count as appropriate
  392. 288          *      return immeadialy if we're looking at a file and we aren't
  393. 289          *      supposed to list file. The same with directories.
  394. 290          */
  395. 291 
  396. 292         if( IS_SUBDIR(infop) )  
  397. 293         {
  398. 294                 if( dp->dirs )
  399. 295                         dp->ndirs++  ;
  400. 296                 else
  401. 297                         return 1;
  402. 298         }
  403. 299         else
  404. 300         {
  405. 301                 if( dp->files )
  406. 302                         dp->nfiles++  ;
  407. 303                 else
  408. 304                         return 1;
  409. 305         }
  410. 306 
  411. 307         /*
  412. 308          *      Convert the FILE_INFO structure to an ascii string and put
  413. 309          *      it into buf. Then malloc a chunk of memory the correct size,
  414. 310          *      copy the ascii string there, and put the malloced memory
  415. 311          *      into dirv at the correct place.
  416. 312          */
  417. 313 
  418. 314         Longfmt = dp->longf;
  419. 315 
  420. 316         len = dirtoa( buf, infop, dp->graphics, path );
  421. 317 
  422. 318         if( len > dp->width )
  423. 319                 dp->width = len ;
  424. 320                 
  425. 321         if( *dp->lastdir = malloc(len + 1) )
  426. 322         {
  427. 323                 strcpy( *dp->lastdir++, buf )    ;
  428. 324 
  429. 325                 /* Add file size to total. Note that the actual amount
  430. 326                  * of space (# of clusters) used by the file on the
  431. 327                  * disk is used.
  432. 328                  */
  433. 329 
  434. 330                 dp->nbytes += ROUND( infop->fi_fsize, Cluster_size );
  435. 331 
  436. 332                 --dp->maxdirs;
  437. 333                 return 1;
  438. 334         }
  439. 335 
  440. 336         fprintf(stderr,"Can't get memory for directory\n");
  441. 337         return 0;
  442. 338 }
  443. 339 
  444. 340 /*----------------------------------------------------------------------*/
  445. 341 
  446. 342 
  447. 343 static  void    copy_path( dest, src )
  448. 344 char    *dest, *src;
  449. 345 {
  450. 346         /*      Copy only the pathname part of the file spec contained in
  451. 347          *      src to dest. Path names longer than 64 characters are
  452. 348          *      truncated so dest must be at least 64 characters long.
  453. 349          */
  454. 350 
  455. 351         register char   *p, *slash;
  456. 352 
  457. 353         for( p = slash = src ; *p ; p++ )
  458. 354                 if( *p == '/' || *p == '\\' || *p == ':' )
  459. 355                         slash = p + 1;
  460. 356 
  461. 357         for(p = src; p < slash  &&  p - src < 64 ; *dest++ = *p++ )
  462. 358                         ;
  463. 359 
  464. 360         *dest = 0;
  465. 361 }
  466. 362 
  467. 363 /*----------------------------------------------------------------------*/
  468. 364 
  469. 365 static  void    clab( dest, src )
  470. 366 register char   *dest, *src;
  471. 367 {
  472. 368         for(; *src ;  src++, dest++ )
  473. 369                 if( *src != '.')
  474. 370                         *dest = *src ;
  475. 371 }
  476. 372 
  477. 373 /*----------------------------------------------------------------------*/
  478. 374 
  479. 375 static  int  cmp( pp1, pp2 )
  480. 376 char    **pp1, **pp2;
  481. 377 {
  482. 378         /*      Comparison routine needed for ssort()   */
  483. 379 
  484. 380         register char   *p1 = *pp1;
  485. 381         register char   *p2 = *pp2;
  486. 382 
  487. 383         if( Longfmt )
  488. 384         {
  489. 385                 /*      Skip forward to the '-' that will preceede
  490. 386                  *      the filename.
  491. 387                  */
  492. 388 
  493. 389                 while( *p1 && *p1 != '-' )
  494. 390                         p1++;
  495. 391 
  496. 392                 while( *p2 && *p2 != '-' )
  497. 393                         p2++;
  498. 394         }
  499. 395 
  500. 396         return( strcmp(p1, p2) );
  501. 397 }
  502. 398 
  503. 399 /*----------------------------------------------------------------------*/
  504. 400 
  505. 401 DIRECTORY  *mk_dir( size )
  506. 402 register unsigned size;
  507. 403 {
  508. 404         /*      Make a DIRECTORY with the indicated number of dirv entries.
  509. 405          *      Note that since one dirv entry is declared as part of the
  510. 406          *      DIRECTORY header, we'll actually have size+1 entries
  511. 407          *      available, though the last one is never used. We allocate
  512. 408          *      it so that we can terminate the list with a null
  513. 409          *      entry, even if the list is full.
  514. 410          */
  515. 411 
  516. 412         register DIRECTORY  *dp;
  517. 413 
  518. 414 
  519. 415 
  520. 416 
  521. 417         if( !( dp = (DIRECTORY *)calloc( (unsigned)1,
  522. 418                         sizeof(DIRECTORY) + (size * sizeof(char *))) ))
  523. 419                 return 0;
  524. 420 
  525. 421         dp->maxdirs = size ;
  526. 422         dp->lastdir = (char **) dp->dirv;
  527. 423         return dp;
  528. 424 }
  529. 425 
  530. 426 /*----------------------------------------------------------------------*/
  531. 427 
  532. 428 del_dir( dp )
  533. 429 register DIRECTORY      *dp;
  534. 430 {
  535. 431         /*      Delete a directory made with a previous mk_dir call.
  536. 432          *      Note that all the strings pointed to by dirv entries
  537. 433          *      are assumed to have been gotten from malloc (this is
  538. 434          *      always true if dir() is used to fill the strings.
  539. 435          */
  540. 436 
  541. 437         register char   **v;
  542. 438 
  543. 439         for( v = (char **) dp->dirv; v < dp->lastdir ; free( *v++ ) )
  544. 440                 ;
  545. 441 
  546. 442         free( dp );
  547. 443 }
  548. 444 
  549. 445 /*----------------------------------------------------------------------*/
  550. 446 
  551. 447 dir( spec, dp )
  552. 448 char       *spec;
  553. 449 DIRECTORY  *dp;
  554. 450 {
  555. 451         /*      Get a directory for the indicated spec. DOS wildcards are
  556. 452          *      permitted. If the DIRECTORY pointed to by dp already has
  557. 453          *      entries in it, new ones will be appended onto the existing
  558. 454          *      ones. If *spec is null, no files will be gotten, this is
  559. 455          *      useful if all you want is the volume label.
  560. 456          *
  561. 457          *      Note that the DTA is not modified by this routine. It
  562. 458          *      sets the DTA to its own address, but then restores the
  563. 459          *      DTA before returning.
  564. 460          */
  565. 461 
  566. 462         REGS          regs      ;       /* Needed for DOS calls         */
  567. 463         FILE_INFO     info      ;       /* DOS puts dirs here           */
  568. 464         char          path[80]  ;       /* place to put path            */
  569. 465         char          **firstdir;       /* Used for sorting             */
  570. 466         short         seg,off   ;       /* Segment and offset of        */
  571. 467                                         /* original DTA                 */
  572. 468         unsigned      sec_per_cluster,  /* Used to compute number of    */
  573. 469                       bytes_per_sector, /* bytes in a cluster           */
  574. 470                       garbage;
  575. 471 
  576. 472         gregs( ®s );                 /* Get the original DTA         */
  577. 473         DOSCALL( GETDTA, regs );
  578. 474 
  579. 475         seg = regs.x.es ;               /* remember it in set:off       */
  580. 476         off = regs.x.bx ;
  581. 477 
  582. 478         regs.x.dx = (word) &info;       /* Change the Disk Transfer Addr  */
  583. 479         DOSCALL( SETDTA, regs );        /* to point at info structure     */
  584. 480 
  585. 481 
  586. 482         /*      Find the number of bytes/cluster on the indicated
  587. 483          *      disk drive (or on the current drive if none is
  588. 484          *      specified.
  589. 485          */
  590. 486 
  591. 487         if( !diskinfo( (!*spec||spec[1]!=':') ? 0 : (toupper(*spec)-'A')+1,
  592. 488                    &sec_per_cluster, &bytes_per_sector, &garbage, &garbage))
  593. 489             fprintf(stderr,"dir: Can't access indicated disk\n");
  594. 490 
  595. 491         Cluster_size = sec_per_cluster * bytes_per_sector ;
  596. 492 
  597. 493 
  598. 494         /*      If a volume label is requested, get it and copy it into
  599. 495          *      dp->vol_lab. Any imbedded '.'s are stripped by clab.
  600. 496          *      If no volume label is present, the string is nulled.
  601. 497          */
  602. 498 
  603. 499         if( dp->label )
  604. 500         {
  605. 501                 *dp->vol_label = 0;
  606. 502 
  607. 503                 if( spec[1] != ':' )
  608. 504                         strcpy( path, "/*.*" );
  609. 505                 else
  610. 506                 {
  611. 507                         *path = *spec ;
  612. 508                         strcpy( path+1, ":/*.*" );
  613. 509                 }
  614. 510 
  615. 511                 if( !find_first(path, LABEL, ®s) )
  616. 512                         clab( dp->vol_label, info.fi_name );
  617. 513         }
  618. 514 
  619. 515         /*
  620. 516          *      Now get the directories:
  621. 517          */
  622. 518 
  623. 519         if( dp->exp && !haswild(spec) ) 
  624. 520                 spec = fixup_name( spec, ®s, &info );
  625. 521 
  626. 522         copy_path( path, dp->path ? spec : "" );
  627. 523 
  628. 524         firstdir = dp->lastdir;
  629. 525 
  630. 526         /*      Now go look for the file:
  631. 527          */
  632. 528 
  633. 529         if( !find_first(spec, ATTRIBUTES, ®s)  )
  634. 530                 if( !add_entry(&info, dp, path) )       
  635. 531                         goto abort;
  636. 532 
  637. 533         if( haswild(spec) )
  638. 534                 while( !find_next( ®s ) )
  639. 535                         if( !add_entry(&info, dp, path) )
  640. 536                                 goto abort;
  641. 537 
  642. 538         if( dp->sort )
  643. 539                 ssort( (char *)firstdir, dp->lastdir - firstdir,
  644. 540                                         sizeof(char*), cmp);
  645. 541 
  646. 542 abort:
  647. 543         regs.x.ds = seg ;               /* Restore the original disk    */
  648. 544         regs.x.dx = off ;               /* transfer address.            */
  649. 545         DOSCALL( SETDTA, regs );
  650. 546 }
  651.                              Listing 9 -- reargv.c
  652.  ------------------------------------------------------------------------------
  653.   1 #include <stdio.h>
  654.   2 #include <ctype.h>
  655.   3 
  656.   4 #define MAXARGC         (unsigned)128
  657.   5 #define isquote(c)      ((c)=='"' || (c)=='\'')
  658.   6 
  659.   7 extern  char    *getenv( char*    );
  660.   8 extern  char    *malloc( unsigned );
  661.   9 
  662.  10 /*----------------------------------------------------------------------*/
  663.  11 
  664.  12 static char     *nextarg( pp )
  665.  13 char            **pp;
  666.  14 {
  667.  15         register char   *p;
  668.  16         char            *start;
  669.  17         register int    term;
  670.  18 
  671.  19         if( !*(p = *pp)  )
  672.  20                 return (char *) 0;
  673.  21 
  674.  22         while( isspace(*p) )
  675.  23                 p++;
  676.  24 
  677.  25         if( isquote(*p) )       /* Can't use a conditional because */
  678.  26                 term = *p++;    /* of order of evaluation problems */
  679.  27         else
  680.  28                 term = ' ';
  681.  29 
  682.  30         for( start = p; *p ; p++)
  683.  31         {
  684.  32                 if( *p == term &&  *(p-1) != '\\' )
  685.  33                 {
  686.  34                         *p++ = '\0';
  687.  35                         break;
  688.  36                 }
  689.  37         }
  690.  38 
  691.  39         *pp = p;
  692.  40 
  693.  41         return start;
  694.  42 }
  695.  43 
  696.  44 /*----------------------------------------------------------------------*/
  697.  45 
  698.  46 int     reargv( argcp, argvp )
  699.  47 char    ***argvp;
  700.  48 int     *argcp;
  701.  49 {
  702.  50         register int    argc = 0 ;
  703.  51         register int    maxc = MAXARGC ;
  704.  52         char            **argv, **start_argv ;
  705.  53         char            *env, *p ;
  706.  54 
  707.  55         if( !(env = getenv("CMDLINE")) ||  !*env )
  708.  56                 return 0;
  709.  57 
  710.  58         if( !(p = malloc( strlen(env)+1 )))
  711.  59                 return 0;
  712.  60 
  713.  61         if( !(argv = (char **) malloc( MAXARGC * sizeof(char *)) ))
  714.  62                 return 0;
  715.  63 
  716.  64         strcpy(p, env);
  717.  65         start_argv = argv;
  718.  66         for( maxc=MAXARGC; --maxc >= 0 && (*argv++ = nextarg(&p)); argc++)
  719.  67                 ;
  720.  68 
  721.  69         if( maxc < 0 )
  722.  70                 fprintf(stderr, "Command line truncated\n");
  723.  71 
  724.  72         *argcp = argc;
  725.  73         *argvp = start_argv;
  726.  74         return 1;
  727.  75 }
  728.  76 
  729.  77 /*----------------------------------------------------------------------*/
  730.  78 
  731.  79 #ifdef DEBUG
  732.  80 
  733.  81 main( argc, argv )
  734.  82 char    **argv;
  735.  83 {
  736.  84         printf("Original command line is: |");
  737.  85         while( --argc >= 0 )
  738.  86                 printf("%s|", *argv++ );
  739.  87 
  740.  88         if( !reargv( &argc, &argv ) )
  741.  89                 printf("\nCMDLINE not present\n");
  742.  90         else
  743.  91         {
  744.  92                 printf("New argc = %d\n", argc );
  745.  93                 printf("\nModified command line is: |");
  746.  94 
  747.  95                 while( --argc >= 0 )
  748.  96                         printf("%s|", *argv++ );
  749.  97 
  750.  98                 printf("\n");
  751.  99         }
  752. 100 }
  753. 101 
  754. 102 #endif
  755.                               Listing 10 -- ssort.c
  756.  ------------------------------------------------------------------------------
  757.  
  758.   1 /*      SSORT.C         Works just like qsort() except that a shell
  759.   2  *                      sort, rather than a quick sort, is used. This
  760.   3  *      is more efficient than quicksort for small numbers of elements
  761.   4  *      and it's not recursive so will use much less stack space.
  762.   5  *
  763.   6  *      Copyright (C) 1985, Allen I. Holub.  All rights reserved
  764.   7  */
  765.   8 
  766.   9 void    ssort( base, nel, width, cmp )
  767.  10 char    *base;
  768.  11 int     nel, width;
  769.  12 int     (*cmp)();
  770.  13 {
  771.  14         register int    i, j;
  772.  15         int             gap, k, tmp ;
  773.  16         char            *p1, *p2;
  774.  17 
  775.  18         for( gap = nel >>1 ;  gap > 0  ; gap >>=1 )
  776.  19                 for( i = gap; i < nel; i++ )
  777.  20                         for( j = i-gap; j >= 0 ; j -= gap )
  778.  21                         {
  779.  22                                 p1 = base + ( j      * width);
  780.  23                                 p2 = base + ((j+gap) * width);
  781.  24 
  782.  25                                 if( (*cmp)( p1, p2 ) <= 0 )
  783.  26                                         break;
  784.  27 
  785.  28                                 for( k = width; --k >= 0 ;)
  786.  29                                 {
  787.  30                                         tmp   = *p1;
  788.  31                                         *p1++ = *p2;
  789.  32                                         *p2++ = tmp;
  790.  33                                 }
  791.  34                         }
  792.  35 }
  793.