home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
diskutil
/
sosutil
/
src
/
sostree.c
< prev
Wrap
C/C++ Source or Header
|
1993-10-20
|
12KB
|
382 lines
/* ---------
* sostree.c (C) SuperOscar Softwares, Tommi Nieminen 1993.
* ---------
* SOS Tree directory tree drawer for OS/2.
* Programming language: Borland C++ for OS/2 1.0.
* Programmer: Tommi Nieminen.
*
* Spanish and Catalan messages by Xavier Caballen.
*
* 4-Jul-1993 v1.0: first PD version ready.
* 19-Oct-1993 v1.0a: different internal structure--the code should now
* be easier to translate. Spanish and Catalan translations
* by Xavier Caballe.
*/
#include <stdio.h> /* Standard I/O */
#include <stdarg.h> /* va_ functions */
#include <dir.h> /* findfirst(), findnext(), chdir() */
#include <string.h> /* String handling */
#include <alloc.h> /* malloc(), free() */
#include <dos.h> /* Symbolic names for file attributes */
#include <ctype.h> /* toupper() */
#define INCL_DOSNLS
#include <os2.h> /* Load NLS support */
#if defined(LANG_SUOMI)
#include "msg_suomi.inc" /* Finnish */
#elif defined(LANG_ESPANOL)
#include "msg_espanol.inc" /* Spanish */
#elif defined(LANG_CATALA)
#include "msg_catala.inc" /* Catalan */
#else
#include "msg_english.inc" /* English (default) */
#endif
/* Official program name string for messages */
const char *program_name = "SOS Tree v1.0a";
const char *copyright = "(C) SuperOscar Softwares, Tommi Nieminen 1993";
/* Program flags */
#define F_SHOW_TREE 0x0001
#define F_SHOW_FILES 0x0002
#define F_SHOW_DATES 0x0004
#define F_SHOW_SIZES 0x0008
#define F_SHOW_ATTRS 0x0010
#define F_SHOW_HIDDEN 0x0020
#define F_QUIET 0x0040
#define F_SHOW_HELP 0x8000
/* Error codes */
typedef enum {
NO_ERROR,
ERR_PATH_NOT_FOUND,
ERR_UNKNOWN_SWITCH,
ERR_CMDLINE_SYNTAX,
ERR_INTERNAL
} ERROR;
/* Global variables */
ERROR status = NO_ERROR; /* Global error status */
int datefmt, timefmt; /* Date and time formats */
char datesep, timesep; /* Date and time separators */
unsigned flags = F_SHOW_TREE; /* Program flags */
/* Macroes */
#define ISDIR(f) (f.ff_attrib & FA_DIREC)
#define ISDOTDIR(f) (!strcmp(f.ff_name, ".") || !strcmp(f.ff_name, ".."))
#define D_DAY(date) ((date) & 31)
#define D_MON(date) (((date) & 480) / 32)
#define D_YEAR(date) (((date) & 65024) / 512 + 80)
#define T_MIN(time) (((time) & 2016) / 32)
#define T_HOUR(time) (((time) & 63488) / 2048)
/* Function declarations */
char *cmdline_parse(int argc, char *argv[]);
int dir_exists(char *pathname);
void country_get(void);
void tree_draw(const char *mother);
char *path_cat(const char *part1, const char *part2);
char *date_format(unsigned short filedate);
char *time_format(unsigned short filetime);
void error_raise(ERROR err, ...);
void help(void);
int main(int argc, char *argv[])
{
char *base;
country_get();
base = cmdline_parse(argc, argv);
if (flags & F_SHOW_HELP)
help();
else if (!status)
if (!dir_exists(base))
error_raise(ERR_PATH_NOT_FOUND, base);
else {
if (!(flags & F_QUIET))
printf(header_line, base);
tree_draw(base);
}
free(base);
return(status);
}
char *cmdline_parse(int argc, char *argv[])
/* Parse command line. Return base directory name. */
{
char *dirname;
int ind = 1;
dirname = (char *) malloc(sizeof(char) * (MAXPATH + 1));
strcpy(dirname, ".");
if (-- argc) {
char *p;
if (argv[1][0] == '-') {
ind = 2;
for (p = &argv[1][1]; *p; p ++)
switch (*p) {
case 'a': flags |= F_SHOW_ATTRS;
break;
case 'd': flags |= F_SHOW_DATES;
break;
case 'f': flags |= F_SHOW_FILES;
break;
case 'h': flags |= F_SHOW_HIDDEN;
break;
case 'n': flags &= ~F_SHOW_TREE;
break;
case 'q': flags |= F_QUIET;
break;
case 'z': flags |= F_SHOW_SIZES;
break;
case '?': flags |= F_SHOW_HELP;
break;
default: error_raise(ERR_UNKNOWN_SWITCH, *p);
}
}
if (argc == ind) {
strncpy(dirname, argv[ind], MAXPATH);
dirname[MAXPATH] = '\0';
}
else if (argc > ind)
error_raise(ERR_CMDLINE_SYNTAX);
}
return(dirname);
}
int dir_exists(char *pathname)
/* Check if 'fname' is a directory. Return NULL if it isn't, and
* absolute path name if it is.
*/
{
char current_path[MAXDIR + 1],
drivestr[MAXDRIVE + 1];
int drive = 0,
current_drive,
exists = 0;
/* Note: 0 means A: drive in getdisk() and setdisk(), but `default'
* drive in getcurdir() (where A: is 1).
*/
/* Does 'fname' contain a drive letter? */
fnsplit(pathname, drivestr, NULL, NULL, NULL);
drive = (*drivestr) ? toupper(*drivestr) - '@' : 0;
/* Store current drive, and current directory on drive 'drive'. */
current_drive = getdisk();
getcurdir(drive, current_path);
/* Try to cd to 'fname' on drive 'drive'. */
if (drive)
setdisk(drive - 1);
if (!chdir(pathname)) {
char tmp[MAXDIR + 1];
getcurdir(drive, tmp);
strcpy(pathname, " :\\");
pathname[0] = (char) ((drive) ? drive + '@' : current_drive + 'A');
strcat(pathname, tmp);
exists = 1;
}
/* Restore directory if changed. */
chdir(current_path);
if (drive)
setdisk(current_drive);
return(exists);
}
void country_get(void)
/* Query current system date and time formats and separators. */
{
ULONG len;
COUNTRYCODE query;
COUNTRYINFO info;
APIRET rc;
query.country = 0;
query.codepage = 850;
rc = DosQueryCtryInfo(sizeof(info), &query, &info, &len);
if (!rc) {
datesep = *(info.szDateSeparator);
timesep = *(info.szTimeSeparator);
datefmt = info.fsDateFmt;
timefmt = info.fsTimeFmt;
}
else
error_raise(ERR_INTERNAL);
}
void tree_draw(const char *mother)
/* Recurse to all subdirectories of 'mother'. */
{
static char sequel_buffer[MAXPATH] = "";
char *search, *fullname;
struct ffblk this, newest;
int ok;
search = path_cat(mother, "*");
ok = findfirst(search, &newest, (flags & F_SHOW_HIDDEN) ?
FA_DIREC | FA_HIDDEN | FA_SYSTEM : FA_DIREC);
while (!ok) {
this = newest;
fullname = path_cat(mother, this.ff_name);
/* First check whether this directory is the last on its
* level or not.
*/
if (flags & F_SHOW_FILES)
ok = findnext(&newest);
else {
/* When not displaying ordinary files, more work is needed
* because findnext() always finds files too: we have to
* loop until we find a directory or run out of files.
*/
ok = findnext(&newest);
while (!ISDIR(newest) && !ok)
ok = findnext(&newest);
}
/* Discard "." and ".." */
if (!ISDOTDIR(this)) {
/* If 'this' is not a directory and F_SHOW_FILES flag isn't
* set, start next cycle
*/
if (!ISDIR(this) && !(flags & F_SHOW_FILES))
continue;
if (flags & F_SHOW_DATES)
printf("%s %s ", date_format(this.ff_fdate),
time_format(this.ff_ftime));
if (flags & F_SHOW_SIZES)
printf("%8lu ", this.ff_fsize);
if (flags & F_SHOW_ATTRS)
printf("%c%c%c%c%c ",
(this.ff_attrib & FA_ARCH) ? 'A' : '-',
(this.ff_attrib & FA_HIDDEN) ? 'H' : '-',
(this.ff_attrib & FA_RDONLY) ? 'R' : '-',
(this.ff_attrib & FA_SYSTEM) ? 'S' : '-',
(this.ff_attrib & FA_DIREC) ? 'D' : '-');
if (flags & F_SHOW_TREE)
printf("%s%c──%s\n", sequel_buffer, (ok) ? '└' : '├',
this.ff_name);
else
printf("%s\n", fullname);
/* If 'this' is a directory, try to recurse to sub-
* directories.
*/
if (ISDIR(this)) {
/* Update upper-level sequel buffer. */
strcat(sequel_buffer, (ok) ? " " : "│ ");
tree_draw(fullname);
/* Truncate sequel buffer to its previous value. */
sequel_buffer[strlen(sequel_buffer) - 3] = '\0';
}
}
free(fullname);
}
free(search);
}
char *path_cat(const char *part1, const char *part2)
/* Combine two path name components into one. Add a `\' between
* the parts if necessary.
*/
{
char *newpath;
newpath = (char *) malloc(sizeof(char) * (MAXPATH + 1));
strcpy(newpath, part1);
if (part1[strlen(part1) - 1] != '\\' && *part2 != '\\')
strcat(newpath, "\\");
strcat(newpath, part2);
return(newpath);
}
char *date_format(unsigned short filedate)
/* Format file date to a string of correct national format. */
{
static char outstr[11];
unsigned day, mon, year;
day = D_DAY(filedate);
mon = D_MON(filedate);
year = D_YEAR(filedate);
switch (datefmt) {
case 0: case 1:
sprintf(outstr, "%2d%c%2d%c%02d", (datefmt == 0) ? mon : day,
datesep, (datefmt == 0) ? day : mon, datesep, year);
break;
case 2:
sprintf(outstr, "%02d%c%02d%c%02d", year, datesep, mon, datesep,
day);
break;
}
return(outstr);
}
char *time_format(unsigned short filetime)
/* Format file time to a string of correct national format. */
{
static char outstr[8];
unsigned hour, min;
hour = T_HOUR(filetime);
if (!hour)
hour = 24;
min = T_MIN(filetime);
switch (timefmt) {
case 0:
sprintf(outstr, "%2d%c%02d%s", (hour <= 12) ? hour : hour - 12,
timesep, min, (hour <= 12) ? "am" : "pm");
break;
case 1:
sprintf(outstr, "%2d%c%02d", hour, timesep, min);
break;
}
return(outstr);
}
void error_raise(ERROR err, ...)
{
va_list argv;
fprintf(stderr, "%s: ", program_name);
va_start(argv, err);
vfprintf(stderr, errormsg[err - 1], argv);
va_end(argv);
fprintf(stderr, "\n");
status = err;
}
void help(void)
/* Display help text. */
{
int i;
printf("%s %s\n\n", program_name, copyright);
for (i = 0; i < HELP_SCREEN_HEIGHT; puts(helpmsg[i ++]))
;
}