Subversion Repositories SvarDOS

Rev

Rev 2063 | Rev 2065 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2019 mateusz.vi 1
/****************************************************************************
2
 
3
  TREE - Graphically displays the directory structure of a drive or path
4
 
5
****************************************************************************/
6
 
7
#define VERSION "1.04"
8
 
9
/****************************************************************************
10
 
11
  Written by: Kenneth J. Davis
12
  Date:       August, 2000
13
  Updated:    September, 2000; October, 2000; November, 2000; January, 2001;
14
              May, 2004; Sept, 2005
15
  Contact:    jeremyd@computer.org
16
 
17
 
18
Copyright (c): Public Domain [United States Definition]
19
 
20
Permission is hereby granted, free of charge, to any person obtaining a copy
21
of this software and associated documentation files (the "Software"), to deal
22
in the Software without restriction, including without limitation the rights
23
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
copies of the Software, and to permit persons to whom the Software is
25
furnished to do so, subject to the following conditions:
26
 
27
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
29
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30
NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR AUTHORS BE
31
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
32
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
33
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34
DEALINGS IN THE SOFTWARE.
35
 
36
****************************************************************************/
37
 
38
 
39
/* Include files */
2034 mateusz.vi 40
#include <dos.h>
2019 mateusz.vi 41
#include <stdlib.h>
42
#include <stdio.h>
43
#include <string.h>
44
 
45
#include "stack.h"
46
 
47
/* The default extended forms of the lines used. */
48
#define VERTBAR_STR  "\xB3   "                 /* |    */
49
#define TBAR_HORZBAR_STR "\xC3\xC4\xC4\xC4"    /* +--- */
50
#define CBAR_HORZBAR_STR "\xC0\xC4\xC4\xC4"    /* \--- */
51
 
52
/* Global flags */
53
#define SHOWFILESON    1  /* Display names of files in directories       */
54
#define SHOWFILESOFF   0  /* Don't display names of files in directories */
55
 
56
#define ASCIICHARS     1  /* Use ASCII [7bit] characters                 */
57
#define EXTENDEDCHARS  0  /* Use extended ASCII [8bit] characters        */
58
 
59
#define NOPAUSE        0  /* Default, don't pause after screenfull       */
60
#define PAUSE          1  /* Wait for keypress after each page           */
61
 
62
 
63
/* Global variables */
64
short showFiles = SHOWFILESOFF;
65
short charSet = EXTENDEDCHARS;
66
short pause = NOPAUSE;
67
 
68
short dspAll = 0;  /* if nonzero includes HIDDEN & SYSTEM files in output */
69
short dspSize = 0; /* if nonzero displays filesizes                       */
70
short dspAttr = 0; /* if nonzero displays file attributes [DACESHRBP]     */
71
short dspSumDirs = 0; /* show count of subdirectories  (per dir and total)*/
72
 
73
 
74
/* maintains total count, for > 4billion dirs, use a __int64 */
75
unsigned long totalSubDirCnt = 0;
76
 
77
 
78
/* text window size, used to determine when to pause,
79
   Note: rows is total rows available - 2
2022 mateusz.vi 80
   1 is for pause message and then one to prevent auto scroll up
2019 mateusz.vi 81
*/
82
short cols=80, rows=23;   /* determined these on startup (when possible)  */
83
 
84
 
85
 
86
/* Global constants */
87
#define SERIALLEN 16      /* Defines max size of volume & serial number   */
2055 mateusz.vi 88
#define VOLLEN 16
2019 mateusz.vi 89
 
2064 mateusz.vi 90
static char path[PATH_MAX];   /* Path to begin search from, default=current   */
2019 mateusz.vi 91
 
2055 mateusz.vi 92
#define MAXPADLEN (PATH_MAX*2) /* Must be large enough to hold the maximum padding */
93
/* (PATH_MAX/2)*4 == (max path len / min 2chars dirs "?\") * 4chars per padding    */
2019 mateusz.vi 94
 
95
/* The maximum size any line of text output can be, including room for '\0'*/
96
#define MAXLINE 160        /* Increased to fit two lines for translations  */
97
 
98
 
99
/* The hard coded strings used by the following show functions.            */
100
 
101
/* common to many functions [Set 1] */
102
char newLine[MAXLINE] = "\n";
103
 
104
/* showUsage [Set 2] - Each %c will be replaced with proper switch/option */
105
char treeDescription[MAXLINE] = "Graphically displays the directory structure of a drive or path.\n";
106
char treeUsage[MAXLINE] =       "TREE [drive:][path] [%c%c] [%c%c]\n";
107
char treeFOption[MAXLINE] =     "   %c%c   Display the names of the files in each directory.\n";
108
char treeAOption[MAXLINE] =     "   %c%c   Use ASCII instead of extended characters.\n";
109
 
110
/* showInvalidUsage [Set 3] */
111
char invalidOption[MAXLINE] = "Invalid switch - %s\n";  /* Must include the %s for option given. */
112
char useTreeHelp[MAXLINE] =   "Use TREE %c? for usage information.\n"; /* %c replaced with switch */
113
 
114
/* showVersionInfo [Set 4] */
115
/* also uses treeDescription */
116
char treeGoal[MAXLINE] =      "Written to work with FreeDOS\n";
117
char treePlatforms[MAXLINE] = "Win32(c) console and DOS with LFN support.\n";
118
char version[MAXLINE] =       "Version %s\n"; /* Must include the %s for version string. */
119
char writtenBy[MAXLINE] =     "Written by: Kenneth J. Davis\n";
120
char writtenDate[MAXLINE] =   "Date:       2000, 2001, 2004\n";
121
char contact[MAXLINE] =       "Contact:    jeremyd@computer.org\n";
122
char copyright[MAXLINE] =     "Copyright (c): Public Domain [United States Definition]\n";
123
 
124
/* showInvalidDrive [Set 5] */
125
char invalidDrive[MAXLINE] = "Invalid drive specification\n";
126
 
127
/* showInvalidPath [Set 6] */
128
char invalidPath[MAXLINE] = "Invalid path - %s\n"; /* Must include %s for the invalid path given. */
129
 
130
/* Misc Error messages [Set 7] */
2052 mateusz.vi 131
 
2019 mateusz.vi 132
/* showOutOfMemory */
133
/* %s required to display what directory we were processing when ran out of memory. */
134
char outOfMemory[MAXLINE] = "Out of memory on subdirectory: %s\n";
135
 
136
/* main [Set 1] */
137
char pathListingNoLabel[MAXLINE] = "Directory PATH listing\n";
138
char pathListingWithLabel[MAXLINE] = "Directory PATH listing for Volume %s\n"; /* %s for label */
139
char serialNumber[MAXLINE] = "Volume serial number is %s\n"; /* Must include %s for serial #   */
140
char noSubDirs[MAXLINE] = "No subdirectories exist\n\n";
141
char pauseMsg[MAXLINE]  = " --- Press any key to continue ---\n";
142
 
143
 
144
 
145
/* Procedures */
146
 
147
 
2044 mateusz.vi 148
/* returns the current drive (A=0, B=1, etc) */
149
static unsigned char getdrive(void);
150
#pragma aux getdrive = \
151
"mov ah, 0x19" \
152
"int 0x21" \
153
modify [ah] \
154
value [al]
155
 
156
 
2049 mateusz.vi 157
/* waits for a keypress, flushes keyb buffer, returns nothing */
158
static void waitkey(void);
159
#pragma aux waitkey = \
160
"mov ah, 0x08" \
161
"int 0x21" \
162
/* flush keyb buffer in case it was an extended key */ \
163
"mov ax, 0x0C0B" \
164
"int 0x21" \
165
modify [ax]
166
 
167
 
2050 mateusz.vi 168
/* checks if stdout appears to be redirected. returns 0 if not, non-zero otherwise. */
2051 mateusz.vi 169
static unsigned char is_stdout_redirected(void);
170
#pragma aux is_stdout_redirected = \
171
"mov ax, 0x4400"    /* DOS 2+, IOCTL Get Device Info */            \
172
"mov bx, 0x0001"    /* file handle (stdout) */                     \
173
"int 0x21" \
174
"jc DONE"           /* on error AL contains a non-zero err code */ \
175
"and dl, 0x80"      /* bit 7 of DL is the "CHAR" flag */           \
176
"xor dl, 0x80"      /* return 0 if CHAR bit is set */              \
177
"mov al, dl" \
178
"DONE:" \
179
modify [ax bx dx] \
180
value [al]
2034 mateusz.vi 181
 
182
 
2061 mateusz.vi 183
static _Packed struct {
184
  unsigned short infolevel;
185
  unsigned short serial2;
186
  unsigned short serial1;
187
  char label[11];
188
  short fstype[8];
189
} glob_drv_info;
190
 
191
/* drv is 1-based (A=1, B=2, ...) */
192
static void getdrvserial(unsigned char drv);
193
#pragma aux getdrvserial = \
194
"push ds" \
195
"xor bh, bh" \
196
"mov dx, offset glob_drv_info" \
197
"mov ax, seg glob_drv_info" \
198
"mov ds, ax" \
199
"mov ax, 0x6900" \
200
"int 0x21" \
201
"pop ds" \
202
parm [bl] \
203
modify [ax bx dx]
204
 
205
 
2052 mateusz.vi 206
static int truename(char *path, const char *origpath) {
207
  unsigned short origpath_seg = FP_SEG(origpath);
208
  unsigned short origpath_off = FP_OFF(origpath);
209
  unsigned short dstpath_seg = FP_SEG(path);
210
  unsigned short dstpath_off = FP_OFF(path);
211
  unsigned char cflag = 0;
212
 
213
  /* resolve path with truename */
214
  _asm {
215
    push ax
216
    push si
217
    push di
218
    push es
219
    push ds
220
 
221
    mov ah, 0x60          /* AH = 0x60 -> TRUENAME */
222
    mov di, dstpath_off   /* ES:DI -> dst buffer */
223
    mov es, dstpath_seg
224
    mov si, origpath_off  /* DS:SI -> src path */
225
    mov ds, origpath_seg
226
    int 0x21
227
    jnc DONE
228
    mov cflag, 1
229
    DONE:
230
 
231
    pop ds
232
    pop es
233
    pop di
234
    pop si
235
    pop ax
236
  }
237
 
238
  return(cflag);
239
}
240
 
241
 
2019 mateusz.vi 242
/* sets rows & cols to size of actual console window
243
 * force NOPAUSE if appears output redirected to a file or
244
 * piped to another program
245
 * Uses hard coded defaults and leaves pause flag unchanged
246
 * if unable to obtain information.
247
 */
2034 mateusz.vi 248
static void getConsoleSize(void) {
249
  unsigned short far *bios_cols = (unsigned short far *)MK_FP(0x40,0x4A);
250
  unsigned short far *bios_size = (unsigned short far *)MK_FP(0x40,0x4C);
2019 mateusz.vi 251
 
2050 mateusz.vi 252
  if (is_stdout_redirected() != 0) {
253
    /* e.g. redirected to a file, tree > filelist.txt */
254
    /* Output to a file or program, so no screen to fill (no max cols or rows) */
2034 mateusz.vi 255
      pause = NOPAUSE;   /* so ignore request to pause */
2050 mateusz.vi 256
  } else { /* e.g. the console */
257
    if ((*bios_cols == 0) || (*bios_size == 0)) { /* MDA does not report size */
258
      cols = 80;
259
      rows = 23;
260
    } else {
261
      cols = *bios_cols;
262
      rows = *bios_size / cols / 2;
263
      if (rows > 2) rows -= 2; /* necessary to keep screen from scrolling */
264
    }
2019 mateusz.vi 265
  }
266
}
267
 
2034 mateusz.vi 268
 
2019 mateusz.vi 269
/* when pause == NOPAUSE then identical to printf,
270
   otherwise counts lines printed and pauses as needed.
271
   Should be used for all messages printed that do not
272
   immediately exit afterwards (else printf may be used).
273
   May display N too many lines before pause if line is
274
   printed that exceeds cols [N=linelen%cols] and lacks
275
   any newlines (but this should not occur in tree).
276
*/
277
#include <stdarg.h>  /* va_list, va_start, va_end */
2037 mateusz.vi 278
static int pprintf(const char *msg, ...) {
2030 mateusz.vi 279
  static int lineCnt = -1;
2019 mateusz.vi 280
  static int lineCol = 0;
281
  va_list argptr;
282
  int cnt;
2055 mateusz.vi 283
  char buffer[MAXLINE];
2019 mateusz.vi 284
 
2030 mateusz.vi 285
  if (lineCnt == -1) lineCnt = rows;
286
 
2019 mateusz.vi 287
  va_start(argptr, msg);
288
  cnt = vsprintf(buffer, msg, argptr);
289
  va_end(argptr);
290
 
291
  if (pause == PAUSE)
292
  {
2030 mateusz.vi 293
    char *l = buffer;
294
    char *t;
2019 mateusz.vi 295
    /* cycle through counting newlines and lines > cols */
2030 mateusz.vi 296
    for (t = strchr(l, '\n'); t != NULL; t = strchr(l, '\n'))
2019 mateusz.vi 297
    {
2030 mateusz.vi 298
      char c;
2019 mateusz.vi 299
      t++;             /* point to character after newline */
2030 mateusz.vi 300
      c = *t;          /* store current value */
2019 mateusz.vi 301
      *t = '\0';       /* mark as end of string */
302
 
303
      /* print all but last line of a string that wraps across rows */
304
      /* adjusting for partial lines printed without the newlines   */
305
      while (strlen(l)+lineCol > cols)
306
      {
307
        char c = l[cols-lineCol];
308
        l[cols-lineCol] = '\0';
309
        printf("%s", l);
310
        l[cols-lineCol] = c;
311
        l += cols-lineCol;
312
 
313
        lineCnt--;  lineCol = 0;
2049 mateusz.vi 314
        if (!lineCnt) { lineCnt= rows;  fflush(NULL);  fprintf(stderr, "%s", pauseMsg);  waitkey(); }
2019 mateusz.vi 315
      }
316
 
317
      printf("%s", l); /* print out this line */
318
      *t = c;          /* restore value */
319
      l = t;           /* mark beginning of next line */
320
 
321
      lineCnt--;  lineCol = 0;
2049 mateusz.vi 322
      if (!lineCnt) { lineCnt= rows;  fflush(NULL);  fprintf(stderr, "%s", pauseMsg);  waitkey(); }
2019 mateusz.vi 323
    }
324
    printf("%s", l);   /* print rest of string that lacks newline */
325
    lineCol = strlen(l);
326
  }
327
  else  /* NOPAUSE */
328
    printf("%s", buffer);
329
 
330
  return cnt;
331
}
332
 
333
 
334
/* Displays to user valid options then exits program indicating no error */
2037 mateusz.vi 335
static void showUsage(void) {
2019 mateusz.vi 336
  printf("%s%s%s%s", treeDescription, newLine, treeUsage, newLine);
337
  printf("%s%s%s", treeFOption, treeAOption, newLine);
338
  exit(1);
339
}
340
 
341
 
342
/* Displays error message then exits indicating error */
2037 mateusz.vi 343
static void showInvalidUsage(char * badOption) {
2019 mateusz.vi 344
  printf(invalidOption, badOption);
345
  printf("%s%s", useTreeHelp, newLine);
346
  exit(1);
347
}
348
 
349
 
350
/* Displays author, copyright, etc info, then exits indicating no error. */
2037 mateusz.vi 351
static void showVersionInfo(void) {
2019 mateusz.vi 352
  printf("%s%s%s%s%s", treeDescription, newLine, treeGoal, treePlatforms, newLine);
353
  printf(version, VERSION);
354
  printf("%s%s%s%s%s", writtenBy, writtenDate, contact, newLine, newLine);
355
  printf("%s%s", copyright, newLine);
356
  exit(1);
357
}
358
 
359
 
360
/* Displays error messge for invalid drives and exits */
2037 mateusz.vi 361
static void showInvalidDrive(void) {
2019 mateusz.vi 362
  printf(invalidDrive);
363
  exit(1);
364
}
365
 
366
 
367
/* Takes a fullpath, splits into drive (C:, or \\server\share) and path */
2037 mateusz.vi 368
static void splitpath(char *fullpath, char *drive, char *path);
2019 mateusz.vi 369
 
370
/**
371
 * Takes a given path, strips any \ or / that may appear on the end.
372
 * Returns a pointer to its static buffer containing path
373
 * without trailing slash and any necessary display conversions.
374
 */
2037 mateusz.vi 375
static char *fixPathForDisplay(char *path);
2019 mateusz.vi 376
 
377
/* Displays error message for invalid path; Does NOT exit */
2037 mateusz.vi 378
static void showInvalidPath(char *path) {
2055 mateusz.vi 379
  char partialPath[PATH_MAX], dummy[PATH_MAX];
2019 mateusz.vi 380
 
381
  pprintf("%s\n", path);
382
  splitpath(path, dummy, partialPath);
383
  pprintf(invalidPath, fixPathForDisplay(partialPath));
384
}
385
 
386
/* Displays error message for out of memory; Does NOT exit */
2064 mateusz.vi 387
static void showOutOfMemory(const char *path) {
2019 mateusz.vi 388
  pprintf(outOfMemory, path);
389
}
390
 
391
 
392
/**
393
 * Takes a fullpath, splits into drive (C:, or \\server\share) and path
394
 * It assumes a colon as the 2nd character means drive specified,
395
 * a double slash \\ (\\, //, \/, or /\) specifies network share.
396
 * If neither drive nor network share, then assumes whole fullpath
397
 * is path, and sets drive to "".
398
 * If drive specified, then set drive to it and colon, eg "C:", with
399
 * the rest of fullpath being set in path.
400
 * If network share, the slash slash followed by the server name,
401
 * another slash and either the rest of fullpath or up to, but not
402
 * including, the next slash are placed in drive, eg "\\KJD\myshare";
403
 * the rest of the fullpath including the slash are placed in
404
 * path, eg "\mysubdir"; where fullpath is "\\KJD\myshare\mysubdir".
405
 * None of these may be NULL, and drive and path must be large
406
 * enough to hold fullpath.
407
 */
2037 mateusz.vi 408
static void splitpath(char *fullpath, char *drive, char *path) {
2027 mateusz.vi 409
  char *src = fullpath;
410
  char oldchar;
2019 mateusz.vi 411
 
412
  /* If either network share or path only starting at root directory */
413
  if ( (*src == '\\') || (*src == '/') )
414
  {
415
    src++;
416
 
417
    if ( (*src == '\\') || (*src == '/') ) /* network share */
418
    {
419
      src++;
420
 
421
      /* skip past server name */
422
      while ( (*src != '\\') && (*src != '/') && (*src != '\0') )
423
        src++;
424
 
425
      /* skip past slash (\ or /) separating  server from share */
426
      if (*src != '\0') src++;
427
 
428
      /* skip past share name */
429
      while ( (*src != '\\') && (*src != '/') && (*src != '\0') )
430
        src++;
431
 
432
      /* src points to start of path, either a slash or '\0' */
433
      oldchar = *src;
434
      *src = '\0';
435
 
436
      /* copy server name to drive */
437
      strcpy(drive, fullpath);
438
 
439
      /* restore character used to mark end of server name */
440
      *src = oldchar;
441
 
442
      /* copy path */
443
      strcpy(path, src);
444
    }
445
    else /* path only starting at root directory */
446
    {
447
      /* no drive, so set path to same as fullpath */
2064 mateusz.vi 448
      drive[0] = 0;
2019 mateusz.vi 449
      strcpy(path, fullpath);
450
    }
451
  }
452
  else
453
  {
454
    if (*src != '\0') src++;
455
 
456
    /* Either drive and path or path only */
457
    if (*src == ':')
458
    {
459
      /* copy drive specified */
460
      *drive = *fullpath;  drive++;
461
      *drive = ':';        drive++;
462
      *drive = '\0';
463
 
464
      /* copy path */
465
      src++;
466
      strcpy(path, src);
467
    }
468
    else
469
    {
470
      /* no drive, so set path to same as fullpath */
2064 mateusz.vi 471
      drive[0] = 0;
2019 mateusz.vi 472
      strcpy(path, fullpath);
473
    }
474
  }
475
}
476
 
477
 
478
/* Parses the command line and sets global variables. */
2064 mateusz.vi 479
static void parseArguments(int argc, char **argv) {
480
  int i;
2019 mateusz.vi 481
 
482
  /* if no drive specified on command line, use current */
2052 mateusz.vi 483
  if (truename(path, ".") != 0) showInvalidDrive();
2019 mateusz.vi 484
 
2064 mateusz.vi 485
  for (i = 1; i < argc; i++) {
486
 
2019 mateusz.vi 487
    /* Check if user is giving an option or drive/path */
2064 mateusz.vi 488
    if ((argv[i][0] != '/') && (argv[i][0] != '-') ) {
489
      if (truename(path, argv[i]) != 0) showInvalidPath(argv[i]);
490
      continue;
491
    }
2019 mateusz.vi 492
 
2064 mateusz.vi 493
    /* must be an option then */
494
    /* check multi character options 1st */
495
    if (argv[i][1] & 0xDF == 'D') {
496
      switch(argv[i][2] & 0xDF) {
497
        case 'A' :       /*  /DA  display attributes */
498
          dspAttr = 1;
499
          break;
500
        case 'F' :       /*  /DF  display filesizes  */
501
          dspSize = 1;
502
          break;
503
        case 'H' :       /*  /DH  display hidden & system files (normally not shown) */
504
          dspAll = 1;
505
          break;
506
        case 'R' :       /*  /DR  display results at end */
507
          dspSumDirs = 1;
508
          break;
509
        default:
2019 mateusz.vi 510
          showInvalidUsage(argv[i]);
511
      }
2064 mateusz.vi 512
      continue;
2019 mateusz.vi 513
    }
2064 mateusz.vi 514
 
515
    /* a 1 character option (or invalid) */
516
    if (argv[i][2] != 0) showInvalidUsage(argv[i]);
517
 
518
    switch(argv[i][1] & 0xDF) { /* upcase */
519
      case 'F': /* show files */
520
        showFiles = SHOWFILESON; /* set file display flag appropriately */
521
        break;
522
      case 'A': /* use ASCII only (7-bit) */
523
        charSet = ASCIICHARS;    /* set charset flag appropriately      */
524
        break;
525
      case 'V': /* Version information */
526
        showVersionInfo();       /* show version info and exit          */
527
        break;
528
      case 'P': /* wait for keypress after each page (pause) */
529
        pause = PAUSE;
530
        break;
531
      case '?':
532
        showUsage();             /* show usage info and exit            */
533
        break;
534
      default: /* Invalid or unknown option */
535
        showInvalidUsage(argv[i]);
536
    }
2019 mateusz.vi 537
  }
538
}
539
 
540
 
541
/**
542
 * Fills in the serial and volume variables with the serial #
543
 * and volume found using path.
544
 */
2037 mateusz.vi 545
static void GetVolumeAndSerial(char *volume, char *serial, char *path) {
2061 mateusz.vi 546
  getdrvserial((path[0] & 0xDF) - '@');
547
  memcpy(volume, glob_drv_info.label, 12);
548
  volume[11] = 0;
2019 mateusz.vi 549
 
2061 mateusz.vi 550
  sprintf(serial, "%04X:%04X", glob_drv_info.serial1, glob_drv_info.serial2);
2019 mateusz.vi 551
}
552
 
553
 
554
/**
555
 * Stores directory information obtained from FindFirst/Next that
556
 * we may wish to make use of when displaying directory entry.
557
 * e.g. attribute, dates, etc.
558
 */
2054 mateusz.vi 559
typedef struct DIRDATA {
560
  unsigned long subdirCnt;  /* how many subdirectories we have */
561
  unsigned long fileCnt;    /* how many [normal] files we have */
2056 mateusz.vi 562
  unsigned int attrib;      /* Directory attributes            */
2019 mateusz.vi 563
} DIRDATA;
564
 
565
/**
566
 * Contains the information stored in a Stack necessary to allow
567
 * non-recursive function to display directory tree.
568
 */
2062 mateusz.vi 569
struct SUBDIRINFO {
570
  struct SUBDIRINFO *parent; /* points to parent subdirectory                */
2019 mateusz.vi 571
  char *currentpath;    /* Stores the full path this structure represents     */
572
  char *subdir;         /* points to last subdir within currentpath           */
573
  char *dsubdir;        /* Stores a display ready directory name              */
574
  long subdircnt;       /* Initially a count of how many subdirs in this dir  */
2060 mateusz.vi 575
  struct find_t *findnexthnd; /* The handle returned by findfirst, used in findnext */
2019 mateusz.vi 576
  struct DIRDATA ddata; /* Maintain directory information, eg attributes      */
2062 mateusz.vi 577
};
2019 mateusz.vi 578
 
579
 
580
/**
581
 * Returns 0 if no subdirectories, count if has subdirs.
582
 * Path must end in slash \ or /
583
 * On error (invalid path) displays message and returns -1L.
584
 * Stores additional directory data in ddata if non-NULL
585
 * and path is valid.
586
 */
2037 mateusz.vi 587
static long hasSubdirectories(char *path, DIRDATA *ddata) {
2060 mateusz.vi 588
  struct find_t findData;
589
  char buffer[PATH_MAX + 4];
2063 mateusz.vi 590
  unsigned short hasSubdirs = 0;
2019 mateusz.vi 591
 
592
  /* get the handle to start with (using wildcard spec) */
593
  strcpy(buffer, path);
2060 mateusz.vi 594
  strcat(buffer, "*.*");
2019 mateusz.vi 595
 
2060 mateusz.vi 596
  if (_dos_findfirst(buffer, 0x37, &findData) != 0) {
2019 mateusz.vi 597
    showInvalidPath(path); /* Display error message */
2048 mateusz.vi 598
    return(-1);
2019 mateusz.vi 599
  }
600
 
601
  /*  cycle through entries counting directories found until no more entries */
602
  do {
2063 mateusz.vi 603
    if ((findData.attrib & _A_SUBDIR) == 0) continue; /* not a DIR */
604
      /* filter out system and hidden files, unless dspAll is on */
605
    if (dspAll == 0) {
606
      if (findData.attrib & _A_HIDDEN) continue;
607
      if (findData.attrib & _A_SYSTEM) continue;
2019 mateusz.vi 608
    }
2063 mateusz.vi 609
    if (findData.name[0] != '.') { /* ignore '.' and '..' */
610
      hasSubdirs++;      /* subdir of initial path found, so increment counter */
611
    }
2060 mateusz.vi 612
  } while(_dos_findnext(&findData) == 0);
2019 mateusz.vi 613
 
614
  /* prevent resource leaks, close the handle. */
2060 mateusz.vi 615
  _dos_findclose(&findData);
2019 mateusz.vi 616
 
617
  if (ddata != NULL)  // don't bother if user doesn't want them
618
  {
619
    /* The root directory of a volume (including non root paths
620
       corresponding to mount points) may not have a current (.) and
621
       parent (..) entry.  So we can't get attributes for initial
2022 mateusz.vi 622
       path in above loop from the FindFile call as it may not show up
2019 mateusz.vi 623
       (no . entry).  So instead we explicitly get them here.
624
    */
2056 mateusz.vi 625
    if (_dos_getfileattr(path, &(ddata->attrib)) != 0) {
2019 mateusz.vi 626
      //printf("ERROR: unable to get file attr, %i\n", GetLastError());
2047 mateusz.vi 627
      ddata->attrib = 0;
2019 mateusz.vi 628
    }
629
 
630
    /* a curiosity, for showing sum of directories process */
631
    ddata->subdirCnt = hasSubdirs;
632
  }
633
  totalSubDirCnt += hasSubdirs;
634
 
635
  return hasSubdirs;
636
}
637
 
638
 
639
/**
640
 * Allocates memory and stores the necessary stuff to allow us to
641
 * come back to this subdirectory after handling its subdirectories.
642
 * parentpath must end in \ or / or be NULL, however
643
 * parent should only be NULL for initialpath
644
 * if subdir does not end in slash, one is added to stored subdir
645
 * dsubdir is subdir already modified so ready to display to user
646
 */
2062 mateusz.vi 647
static struct SUBDIRINFO *newSubdirInfo(struct SUBDIRINFO *parent, char *subdir, char *dsubdir) {
2027 mateusz.vi 648
  int parentLen, subdirLen;
2062 mateusz.vi 649
  struct SUBDIRINFO *temp;
2019 mateusz.vi 650
 
651
  /* Get length of parent directory */
652
  if (parent == NULL)
653
    parentLen = 0;
654
  else
655
    parentLen = strlen(parent->currentpath);
656
 
657
  /* Get length of subdir, add 1 if does not end in slash */
658
  subdirLen = strlen(subdir);
659
  if ((subdirLen < 1) || ( (*(subdir+subdirLen-1) != '\\') && (*(subdir+subdirLen-1) != '/') ) )
660
    subdirLen++;
661
 
2062 mateusz.vi 662
  temp = malloc(sizeof(struct SUBDIRINFO));
663
  if (temp == NULL) {
2019 mateusz.vi 664
    showOutOfMemory(subdir);
665
    return NULL;
666
  }
667
  if ( ((temp->currentpath = (char *)malloc(parentLen+subdirLen+1)) == NULL) ||
668
       ((temp->dsubdir = (char *)malloc(strlen(dsubdir)+1)) == NULL) )
669
  {
670
    showOutOfMemory(subdir);
671
    if (temp->currentpath != NULL) free(temp->currentpath);
672
    free(temp);
673
    return NULL;
674
  }
675
  temp->parent = parent;
676
  if (parent == NULL)
677
    strcpy(temp->currentpath, "");
678
  else
679
    strcpy(temp->currentpath, parent->currentpath);
680
  strcat(temp->currentpath, subdir);
681
  /* if subdir[subdirLen-1] == '\0' then we must append a slash */
682
  if (*(subdir+subdirLen-1) == '\0')
683
    strcat(temp->currentpath, "\\");
684
  temp->subdir = temp->currentpath+parentLen;
685
  strcpy(temp->dsubdir, dsubdir);
686
  if ((temp->subdircnt = hasSubdirectories(temp->currentpath, &(temp->ddata))) == -1L)
687
  {
688
    free (temp->currentpath);
689
    free (temp->dsubdir);
690
    free(temp);
691
    return NULL;
692
  }
2048 mateusz.vi 693
  temp->findnexthnd = NULL;
2019 mateusz.vi 694
 
695
  return temp;
696
}
697
 
2048 mateusz.vi 698
 
2019 mateusz.vi 699
/**
700
 * Extends the padding with the necessary 4 characters.
701
 * Returns the pointer to the padding.
2022 mateusz.vi 702
 * padding should be large enough to hold the additional
2019 mateusz.vi 703
 * characters and '\0', moreSubdirsFollow specifies if
704
 * this is the last subdirectory in a given directory
705
 * or if more follow (hence if a | is needed).
706
 * padding must not be NULL
707
 */
2037 mateusz.vi 708
static char * addPadding(char *padding, int moreSubdirsFollow) {
709
  if (moreSubdirsFollow) {
710
    /* 1st char is | or a vertical bar */
711
    if (charSet == EXTENDEDCHARS) {
712
      strcat(padding, VERTBAR_STR);
713
    } else {
714
      strcat(padding, "|   ");
2019 mateusz.vi 715
    }
2037 mateusz.vi 716
  } else {
717
    strcat(padding, "    ");
718
  }
2019 mateusz.vi 719
 
2037 mateusz.vi 720
  return(padding);
2019 mateusz.vi 721
}
722
 
723
/**
2025 mateusz.vi 724
 * Removes the last padding added (last 4 characters added).
725
 * Does nothing if less than 4 characters in string.
2019 mateusz.vi 726
 * padding must not be NULL
727
 * Returns the pointer to padding.
728
 */
2037 mateusz.vi 729
static char *removePadding(char *padding) {
2027 mateusz.vi 730
  size_t len = strlen(padding);
2019 mateusz.vi 731
 
2025 mateusz.vi 732
  if (len < 4) return padding;
733
  *(padding + len - 4) = '\0';
2019 mateusz.vi 734
 
735
  return padding;
736
}
737
 
738
/**
739
 * Takes a given path, strips any \ or / that may appear on the end.
740
 * Returns a pointer to its static buffer containing path
741
 * without trailing slash and any necessary display conversions.
742
 */
2037 mateusz.vi 743
static char *fixPathForDisplay(char *path) {
2055 mateusz.vi 744
  static char buffer[PATH_MAX];
2027 mateusz.vi 745
  int pathlen;
2019 mateusz.vi 746
 
747
  strcpy(buffer, path);
748
  pathlen = strlen(buffer);
2037 mateusz.vi 749
  if (pathlen > 1) {
2019 mateusz.vi 750
    pathlen--;
2037 mateusz.vi 751
    if ((buffer[pathlen] == '\\') || (buffer[pathlen] == '/')) {
2019 mateusz.vi 752
      buffer[pathlen] = '\0'; // strip off trailing slash on end
2037 mateusz.vi 753
    }
2019 mateusz.vi 754
  }
755
 
756
  return buffer;
757
}
758
 
759
/**
760
 * Displays the current path, with necessary padding before it.
761
 * A \ or / on end of currentpath is not shown.
762
 * moreSubdirsFollow should be nonzero if this is not the last
763
 * subdirectory to be displayed in current directory, else 0.
764
 * Also displays additional information, such as attributes or
765
 * sum of size of included files.
766
 * currentpath is an ASCIIZ string of path to display
767
 *             assumed to be a displayable path (ie. OEM or UTF-8)
768
 * padding is an ASCIIZ string to display prior to entry.
769
 * moreSubdirsFollow is -1 for initial path else >= 0.
770
 */
2037 mateusz.vi 771
static void showCurrentPath(char *currentpath, char *padding, int moreSubdirsFollow, DIRDATA *ddata) {
2019 mateusz.vi 772
  if (padding != NULL)
773
    pprintf("%s", padding);
774
 
775
  /* print lead padding except for initial directory */
776
  if (moreSubdirsFollow >= 0)
777
  {
778
    if (charSet == EXTENDEDCHARS)
779
    {
780
      if (moreSubdirsFollow)
781
        pprintf("%s", TBAR_HORZBAR_STR);
782
      else
783
        pprintf("%s", CBAR_HORZBAR_STR);
2037 mateusz.vi 784
    } else {
2019 mateusz.vi 785
      if (moreSubdirsFollow)
786
        pprintf("+---");
787
      else
788
        pprintf("\\---");
789
    }
790
  }
791
 
792
  /* optional display data */
793
  if (dspAttr)  /* attributes */
2031 mateusz.vi 794
    pprintf("[%c%c%c%c%c] ",
2061 mateusz.vi 795
      (ddata->attrib & _A_SUBDIR)?'D':' ',  /* keep this one? its always true */
796
      (ddata->attrib & _A_ARCH)?'A':' ',
797
      (ddata->attrib & _A_SYSTEM)?'S':' ',
798
      (ddata->attrib & _A_HIDDEN)?'H':' ',
799
      (ddata->attrib & _A_RDONLY)?'R':' '
2019 mateusz.vi 800
    );
801
 
802
  /* display directory name */
803
  pprintf("%s\n", currentpath);
804
}
805
 
806
 
2022 mateusz.vi 807
/**
2019 mateusz.vi 808
 * Displays summary information about directory.
809
 * Expects to be called after displayFiles (optionally called)
810
 */
2037 mateusz.vi 811
static void displaySummary(char *padding, int hasMoreSubdirs, DIRDATA *ddata) {
2019 mateusz.vi 812
  addPadding(padding, hasMoreSubdirs);
813
 
2037 mateusz.vi 814
  if (dspSumDirs) {
815
    if (showFiles == SHOWFILESON) {
2019 mateusz.vi 816
      /* print File summary with lead padding, add filesize to it */
817
      pprintf("%s%lu files\n", padding, ddata->fileCnt);
818
    }
819
 
820
    /* print Directory summary with lead padding */
821
    pprintf("%s%lu subdirectories\n", padding, ddata->subdirCnt);
822
 
823
    /* show [nearly] blank line after summary */
824
    pprintf("%s\n", padding);
825
  }
826
 
827
  removePadding(padding);
828
}
829
 
2022 mateusz.vi 830
/**
2019 mateusz.vi 831
 * Displays files in directory specified by path.
832
 * Path must end in slash \ or /
833
 * Returns -1 on error,
834
 *          0 if no files, but no errors either,
835
 *      or  1 if files displayed, no errors.
836
 */
2047 mateusz.vi 837
static int displayFiles(const char *path, char *padding, int hasMoreSubdirs, DIRDATA *ddata) {
2060 mateusz.vi 838
  char buffer[PATH_MAX + 4];
839
  struct find_t entry;   /* current directory entry info    */
2019 mateusz.vi 840
  unsigned long filesShown = 0;
841
 
842
  /* get handle for files in current directory (using wildcard spec) */
843
  strcpy(buffer, path);
2060 mateusz.vi 844
  strcat(buffer, "*.*");
845
  if (_dos_findfirst(buffer, 0x37, &entry) != 0) return(-1);
2019 mateusz.vi 846
 
847
  addPadding(padding, hasMoreSubdirs);
848
 
849
  /* cycle through directory printing out files. */
2022 mateusz.vi 850
  do
2019 mateusz.vi 851
  {
852
    /* print padding followed by filename */
2061 mateusz.vi 853
    if ( ((entry.attrib & _A_SUBDIR) == 0) &&
854
         ( ((entry.attrib & (_A_HIDDEN | _A_SYSTEM)) == 0)  || dspAll) )
2019 mateusz.vi 855
    {
856
      /* print lead padding */
857
      pprintf("%s", padding);
858
 
859
      /* optional display data */
860
      if (dspAttr)  /* file attributes */
2031 mateusz.vi 861
        pprintf("[%c%c%c%c] ",
2061 mateusz.vi 862
          (entry.attrib & _A_ARCH)?'A':' ',
863
          (entry.attrib & _A_SYSTEM)?'S':' ',
864
          (entry.attrib & _A_HIDDEN)?'H':' ',
865
          (entry.attrib & _A_RDONLY)?'R':' '
2019 mateusz.vi 866
        );
867
 
2053 mateusz.vi 868
      if (dspSize) { /* file size */
2058 mateusz.vi 869
        if (entry.size < 1048576ul)  /* if less than a MB, display in bytes */
870
          pprintf("%10lu ", entry.size);
2053 mateusz.vi 871
        else                               /* otherwise display in KB */
2058 mateusz.vi 872
          pprintf("%8luKB ", entry.size / 1024ul);
2019 mateusz.vi 873
      }
874
 
875
      /* print filename */
2058 mateusz.vi 876
      pprintf("%s\n", entry.name);
2019 mateusz.vi 877
 
878
      filesShown++;
879
    }
2060 mateusz.vi 880
  } while(_dos_findnext(&entry) == 0);
2019 mateusz.vi 881
 
882
  if (filesShown)
883
  {
884
    pprintf("%s\n", padding);
885
  }
886
 
887
  removePadding(padding);
888
 
889
  /* store for summary display */
890
  if (ddata != NULL) ddata->fileCnt = filesShown;
891
 
892
  return (filesShown)? 1 : 0;
893
}
894
 
895
 
896
/**
897
 * Common portion of findFirstSubdir and findNextSubdir
898
 * Checks current FindFile results to determine if a valid directory
899
 * was found, and if so copies appropriate data into subdir and dsubdir.
900
 * It will repeat until a valid subdirectory is found or no more
901
 * are found, at which point it closes the FindFile search handle and
2048 mateusz.vi 902
 * return NULL.  If successful, returns FindFile handle.
2019 mateusz.vi 903
 */
2060 mateusz.vi 904
static struct find_t *cycleFindResults(struct find_t *entry, char *subdir, char *dsubdir) {
2025 mateusz.vi 905
  /* cycle through directory until 1st non . or .. directory is found. */
2057 mateusz.vi 906
  for (;;) {
2025 mateusz.vi 907
    /* skip files & hidden or system directories */
2061 mateusz.vi 908
    if ((((entry->attrib & _A_SUBDIR) == 0) ||
2058 mateusz.vi 909
         ((entry->attrib &
2061 mateusz.vi 910
          (_A_HIDDEN | _A_SYSTEM)) != 0  && !dspAll) ) ||
2058 mateusz.vi 911
        (entry->name[0] == '.')) {
2060 mateusz.vi 912
      if (_dos_findnext(entry) != 0) {
913
        _dos_findclose(entry);      // prevent resource leaks
2048 mateusz.vi 914
        return(NULL); // no subdirs found
2019 mateusz.vi 915
      }
2048 mateusz.vi 916
    } else {
2025 mateusz.vi 917
      /* set display name */
2058 mateusz.vi 918
      strcpy(dsubdir, entry->name);
2019 mateusz.vi 919
 
2058 mateusz.vi 920
      strcpy(subdir, entry->name);
2025 mateusz.vi 921
      strcat(subdir, "\\");
2057 mateusz.vi 922
      return(entry);
2025 mateusz.vi 923
    }
2057 mateusz.vi 924
  }
2025 mateusz.vi 925
 
2057 mateusz.vi 926
  return entry;
2019 mateusz.vi 927
}
928
 
929
 
930
/**
931
 * Given the current path, find the 1st subdirectory.
932
 * The subdirectory found is stored in subdir.
933
 * subdir is cleared on error or no subdirectories.
934
 * Returns the findfirst search HANDLE, which should be passed to
935
 * findclose when directory has finished processing, and can be
936
 * passed to findnextsubdir to find subsequent subdirectories.
2048 mateusz.vi 937
 * Returns NULL on error.
2019 mateusz.vi 938
 * currentpath must end in \
939
 */
2060 mateusz.vi 940
static struct find_t *findFirstSubdir(char *currentpath, char *subdir, char *dsubdir) {
941
  char buffer[PATH_MAX + 4];
942
  struct find_t *dir;         /* Current directory entry working with      */
2019 mateusz.vi 943
 
2060 mateusz.vi 944
  dir = malloc(sizeof(struct find_t));
2057 mateusz.vi 945
  if (dir == NULL) return(NULL);
946
 
2019 mateusz.vi 947
  /* get handle for files in current directory (using wildcard spec) */
948
  strcpy(buffer, currentpath);
2060 mateusz.vi 949
  strcat(buffer, "*.*");
2019 mateusz.vi 950
 
2060 mateusz.vi 951
  if (_dos_findfirst(buffer, 0x37, dir) != 0) {
2019 mateusz.vi 952
    showInvalidPath(currentpath);
2048 mateusz.vi 953
    return(NULL);
2019 mateusz.vi 954
  }
955
 
956
  /* clear result path */
957
  strcpy(subdir, "");
958
 
2057 mateusz.vi 959
  return cycleFindResults(dir, subdir, dsubdir);
2019 mateusz.vi 960
}
961
 
962
/**
2022 mateusz.vi 963
 * Given a search HANDLE, will find the next subdirectory,
2019 mateusz.vi 964
 * setting subdir to the found directory name.
2045 mateusz.vi 965
 * dsubdir is the name to display
2019 mateusz.vi 966
 * currentpath must end in \
967
 * If a subdirectory is found, returns 0, otherwise returns 1
968
 * (either error or no more files).
969
 */
2060 mateusz.vi 970
static int findNextSubdir(struct find_t *findnexthnd, char *subdir, char *dsubdir) {
2019 mateusz.vi 971
  /* clear result path */
2057 mateusz.vi 972
  subdir[0] = 0;
2019 mateusz.vi 973
 
2060 mateusz.vi 974
  if (_dos_findnext(findnexthnd) != 0) return(1); // no subdirs found
2019 mateusz.vi 975
 
2057 mateusz.vi 976
  if (cycleFindResults(findnexthnd, subdir, dsubdir) == NULL) {
2019 mateusz.vi 977
    return 1;
2048 mateusz.vi 978
  }
979
  return 0;
2019 mateusz.vi 980
}
981
 
982
/**
983
 * Given an initial path, displays the directory tree with
984
 * a non-recursive function using a Stack.
985
 * initialpath must be large enough to hold an added slash \ or /
986
 * if it does not already end in one.
987
 * Returns the count of subdirs in initialpath.
988
 */
2037 mateusz.vi 989
static long traverseTree(char *initialpath) {
2019 mateusz.vi 990
  long subdirsInInitialpath;
991
  char padding[MAXPADLEN] = "";
2055 mateusz.vi 992
  char subdir[PATH_MAX];
993
  char dsubdir[PATH_MAX];
2062 mateusz.vi 994
  struct SUBDIRINFO *sdi;
2019 mateusz.vi 995
 
996
  STACK s;
997
  stackDefaults(&s);
998
  stackInit(&s);
999
 
2048 mateusz.vi 1000
  if ( (sdi = newSubdirInfo(NULL, initialpath, initialpath)) == NULL) {
1001
    return(0);
1002
  }
2019 mateusz.vi 1003
  stackPushItem(&s, sdi);
1004
 
1005
  /* Store count of subdirs in initial path so can display message if none. */
1006
  subdirsInInitialpath = sdi->subdircnt;
1007
 
1008
  do
1009
  {
2062 mateusz.vi 1010
    sdi = (struct SUBDIRINFO *)stackPopItem(&s);
2019 mateusz.vi 1011
 
2048 mateusz.vi 1012
    if (sdi->findnexthnd == NULL) { // findfirst not called yet
2019 mateusz.vi 1013
      // 1st time this subdirectory processed, so display its name & possibly files
1014
      if (sdi->parent == NULL) // if initial path
1015
      {
1016
        // display initial path
1017
        showCurrentPath(/*sdi->dsubdir*/initialpath, NULL, -1, &(sdi->ddata));
1018
      }
1019
      else // normal processing (display path, add necessary padding)
1020
      {
1021
        showCurrentPath(sdi->dsubdir, padding, (sdi->parent->subdircnt > 0L)?1 : 0, &(sdi->ddata));
1022
        addPadding(padding, (sdi->parent->subdircnt > 0L)?1 : 0);
1023
      }
1024
 
1025
      if (showFiles == SHOWFILESON)  displayFiles(sdi->currentpath, padding, (sdi->subdircnt > 0L)?1 : 0, &(sdi->ddata));
2024 mateusz.vi 1026
      displaySummary(padding, (sdi->subdircnt > 0L)?1 : 0, &(sdi->ddata));
2019 mateusz.vi 1027
    }
1028
 
1029
    if (sdi->subdircnt > 0) /* if (there are more subdirectories to process) */
1030
    {
1031
      int flgErr;
2048 mateusz.vi 1032
      if (sdi->findnexthnd == NULL) {
2019 mateusz.vi 1033
        sdi->findnexthnd = findFirstSubdir(sdi->currentpath, subdir, dsubdir);
2048 mateusz.vi 1034
        flgErr = (sdi->findnexthnd == NULL);
1035
      } else {
2019 mateusz.vi 1036
        flgErr = findNextSubdir(sdi->findnexthnd, subdir, dsubdir);
1037
      }
1038
 
1039
      if (flgErr) // don't add invalid paths to stack
1040
      {
1041
        printf("INTERNAL ERROR: subdir count changed, expecting %li more!\n", sdi->subdircnt+1L);
1042
 
1043
        sdi->subdircnt = 0; /* force subdir counter to 0, none left */
1044
        stackPushItem(&s, sdi);
1045
      }
1046
      else
1047
      {
1048
        sdi->subdircnt = sdi->subdircnt - 1L; /* decrement subdirs left count */
1049
        stackPushItem(&s, sdi);
1050
 
1051
        /* store necessary information, validate subdir, and if no error store it. */
1052
        if ((sdi = newSubdirInfo(sdi, subdir, dsubdir)) != NULL)
1053
          stackPushItem(&s, sdi);
1054
      }
1055
    }
1056
    else /* this directory finished processing, so free resources */
1057
    {
1058
      /* Remove the padding for this directory, all but initial path. */
1059
      if (sdi->parent != NULL)
1060
        removePadding(padding);
1061
 
1062
      /* Prevent resource leaks, by ending findsearch and freeing memory. */
2060 mateusz.vi 1063
      _dos_findclose(sdi->findnexthnd);
2019 mateusz.vi 1064
      if (sdi != NULL)
1065
      {
1066
        if (sdi->currentpath != NULL)
1067
          free(sdi->currentpath);
1068
        free(sdi);
1069
      }
1070
    }
1071
  } while (stackTotalItems(&s)); /* while (stack is not empty) */
1072
 
1073
  stackTerm(&s);
1074
 
1075
  return subdirsInInitialpath;
1076
}
1077
 
1078
 
2037 mateusz.vi 1079
static void FixOptionText(void) {
2019 mateusz.vi 1080
  char buffer[MAXLINE];  /* sprintf can have problems with src==dest */
1081
 
1082
  /* Handle %c for options within messages using Set 8 */
1083
  strcpy(buffer, treeUsage);
2064 mateusz.vi 1084
  sprintf(treeUsage, buffer, '/', 'f', '/', 'a');
2019 mateusz.vi 1085
  strcpy(buffer, treeFOption);
2064 mateusz.vi 1086
  sprintf(treeFOption, buffer, '/', 'f');
2019 mateusz.vi 1087
  strcpy(buffer, treeAOption);
2064 mateusz.vi 1088
  sprintf(treeAOption, buffer, '/', 'a');
2019 mateusz.vi 1089
  strcpy(buffer, useTreeHelp);
2064 mateusz.vi 1090
  sprintf(useTreeHelp, buffer, '/');
2019 mateusz.vi 1091
}
1092
 
1093
 
2022 mateusz.vi 1094
/* Loads all messages from the message catalog. */
2037 mateusz.vi 1095
static void loadAllMessages(void) {
2019 mateusz.vi 1096
  /* Changes %c in certain lines with proper option characters. */
1097
  FixOptionText();
1098
}
1099
 
1100
 
2037 mateusz.vi 1101
int main(int argc, char **argv) {
2019 mateusz.vi 1102
  char serial[SERIALLEN]; /* volume serial #  0000:0000 */
1103
  char volume[VOLLEN];    /* volume name (label), possibly none */
1104
 
1105
  /* Load all text from message catalog (or uses hard coded text) */
1106
  loadAllMessages();
1107
 
1108
  /* Parse any command line arguments, obtain path */
1109
  parseArguments(argc, argv);
1110
 
1111
  /* Initialize screen size, may reset pause to NOPAUSE if redirected */
1112
  getConsoleSize();
1113
 
1114
  /* Get Volume & Serial Number */
1115
  GetVolumeAndSerial(volume, serial, path);
1116
  if (strlen(volume) == 0)
1117
    pprintf(pathListingNoLabel);
1118
  else
1119
    pprintf(pathListingWithLabel, volume);
1120
  if (serial[0] != '\0')  /* Don't print anything if no serial# found */
1121
    pprintf(serialNumber, serial);
1122
 
1123
  /* now traverse & print tree, returns nonzero if has subdirectories */
1124
  if (traverseTree(path) == 0)
1125
    pprintf(noSubDirs);
1126
  else if (dspSumDirs) /* show count of directories processed */
1127
    pprintf("\n    %lu total directories\n", totalSubDirCnt+1);
1128
 
1129
  return 0;
1130
}