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