/* dirutil.c - MS-DOS directory reading routines
 *
 * Bdale Garbee, N3EUA, Dave Trulli, NN2Z, and Phil Karn, KA9Q
 * Directory sorting by Mike Chepponis, K3MC
 * New version using regs.h by Russell Nelson.
 * Rewritten for Turbo-C 2.0 routines by Phil Karn, KA9Q 25 March 89
 *
 * Added path filter functions and applied to dodir
 * also used by ftpcli.c, added current directory
 * storage capability (11/92 WA3DSP)
 * Bugfixes in the above by WG7J
 */

#include "global.h"
#include "ctype.h"
#include "commands.h"
#include "hardware.h"
#include <sys/stat.h>

#ifndef UNIX
# ifndef S_ISDIR
#  define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
# endif
#else
# ifdef HAVE_SYS_STATFS_H
#  include <sys/statfs.h>
#  define f_bavail f_bfree
# else
#  if defined(HAVE_SYS_PARAM_H) && !defined(_lint)
#   include <sys/param.h>
#  endif
#  if defined(HAVE_SYS_MOUNT_H) && !defined(_lint)
#   include <sys/mount.h>
#  endif
#  ifdef HAVE_SYS_VFS_H
#   include <sys/vfs.h>
#  endif
# endif
#endif	/* UNIX */

#ifndef _lint
#include <time.h>
#endif
#if !defined (_lint) || !defined(MSDOS)
#include "proc.h"
#include "session.h"
#endif
#include "smtp.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: dirutil.c,v 1.34 2000/05/09 16:48:25 brian Exp $";
#endif


#ifdef CALLSERVER
#include <string.h>
#include <alloc.h>
extern char *CDROM;		/* buckbook.c: defines CDROM drive letter e.g. "s:"  */
#endif


struct dirsort {
	struct dirsort *next;
	struct ffblk de;
};


#define	NULLSORT (struct dirsort *)0

static int nextname (int command, const char *name, struct ffblk * sbuf);
static int dircmd (int argc,char *argv[],void *p);
static char const *wildcardize (char const *path);
static void commas (char *dest);
static int fncmp (char *a, char *b);
static void format_fname_full (FILE * file, struct ffblk * sbuf, int full, int n, const char *path);
static void free_clist (struct dirsort * this);
static void print_free_space (const char *path, FILE * file, int n);
char *defpath (struct cur_dirs * curdirs, char *path);
extern void crunch (char *buf, const char *path);

#ifdef TNOS_68K
#define REGFILE	(FA_DIREC)
#define ALLFILES "*"
#include <modes.h>
#else
#define REGFILE	(FA_HIDDEN|FA_SYSTEM|FA_DIREC)
#ifdef UNIX
#define ALLFILES "*"
#else
#define ALLFILES "*.*"
#endif
#endif

#define	insert_ptr(list,new)	(new->next = list,list = new)



/* Create a directory listing in a temp file and return the resulting file
 * descriptor. If full == 1, give a full listing; else return just a list
 * of names.
 */
FILE *
dir (char *path, int full)
{
FILE *fp;
char *path1;
char *path2;

	if ((fp = tmpfile ()) != NULLFILE) {
		path1 = strdup ((!path) ? Command->curdirs->dir : path);
		if (full == 1)
			fprintf (fp, "Directory of %s at %s\n\n", path1, Hostname);
		path2 = strdup (make_dir_path (2, path1, Command->curdirs->dir));
		(void) getdir (path2, full, fp);
		free (path1);
		free (path2);
		rewind (fp);
	}
	return fp;
}



/* find the first or next file and lowercase it. */
static int
nextname (int command, const char *name, struct ffblk *sbuf)
{
int found;

	switch (command) {
		case 0:
			found = findfirst (name, sbuf, REGFILE);
			break;
		default:
			found = findnext (sbuf);
	}
	found = (found == 0);
#ifndef UNIX
	if (found)
		(void) strlwr (sbuf->ff_name);
#endif

	return found;
}



/* wildcard filename lookup */
int
filedir (const char *name, int times, char *ret_str)
{
static struct ffblk sbuf;
int rval;

	switch (times) {
		case 0:
			rval = findfirst (name, &sbuf, REGFILE);
			break;
		default:
			rval = findnext (&sbuf);
			break;
	}
	if (rval != 0)
		ret_str[0] = '\0';
	else			/* Copy result to output */
		strcpy (ret_str, sbuf.ff_name);
	return rval;
}



/* do a directory list to the stream
 * full = 0 -> short form, 1 is long, 2 is long with "|" down center, and
 * -1 is short with two entries per line.
*/
int
getdir (char const *path, int full, FILE *file)
{
struct ffblk sbuf;
int command = 0;
int n = 0;
struct dirsort *head, *here, *new;

	path = wildcardize (path);
	head = NULLSORT;	/* No head of chain yet... */
	for (;;) {
		kwait (NULL);
		if (!nextname (command, path, &sbuf))
			break;
		command = 1;	/* Got first one already... */
#ifdef MSDOS
		if (sbuf.ff_name[0] == '.')	/* drop "." and ".." */
			continue;
#endif

		new = (struct dirsort *) mallocw (sizeof (struct dirsort));

		new->de = sbuf;	/* Copy contents of directory entry struct */

		/* insert it into the list */
		if (!head || fncmp (new->de.ff_name, head->de.ff_name) < 0)
			insert_ptr (head, new);
		else {
			register struct dirsort *this;

			for (this = head; this->next != NULLSORT; this = this->next)
				if (fncmp (new->de.ff_name, this->next->de.ff_name) < 0)
					break;
			insert_ptr (this->next, new);
		}
	}			/* infinite FOR loop */

	for (here = head; here; here = here->next)
		format_fname_full (file, &here->de, full, ++n, path);

	/* Give back all the memory we temporarily needed... */
	free_clist (head);

	if (full == 1)
		print_free_space (path, file, n);

	if ((full == -1) && (n & 1))
		fputs ("\n", file);

	return 0;
}



static int
fncmp (register char *a, register char *b)
{
int i;

	for (;;) {
#ifdef MSDOS
		if (*a == '.')
			return -1;
		if (*b == '.')
			return 1;
#endif
		if ((i = *a - *b++) != 0)
			return i;
		if (!*a++)
			return -1;
	}
}



#ifdef ALLCMD
/* Change working directory */
int
docd (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc > 1) {
		if (!dir_ok (argv[1], Command->curdirs)) {
			tprintf ("Invalid Drive/Directory - %s\n", argv[1]);
			return 1;
		}
	}
	tprintf ("Local Directory - %s\n", Command->curdirs->dir);
	return 0;
}



#ifdef MSDOS
/* Change working drive */
int
dodrive (int argc, char *argv[], void *p)
{
char **margv;

	margv = (char **) callocw (2, sizeof (char *));

	margv[1] = strdup (argv[0]);
	(void) docd (2, margv, p);
	free (margv[1]);
	free (margv);
	return 0;
}

#endif /* MSDOS*/
#endif /* ALLCMD */



char *
defpath (struct cur_dirs *curdirs OPTIONAL, char *path)
{
#ifdef MSDOS
int drive;

	drive = tolower (path[0]) - '`';
	if (strlen (path) == 2 && path[1] == ':' && curdirs->curdir[drive] != NULLCHAR)
		return curdirs->curdir[drive];
	else
#endif
		return path;
}



#if (defined(ALLCMD) || defined(ALLSESSIONS))
/* List directory to console */
static int
dircmd (int argc, char *argv[], void *p)
{
char *path, *file;
FILE *fp;
char tmpname[80];
char **margv;

	if (argc > 1) {
		file = strdup (make_fname (Command->curdirs->dir, defpath (Command->curdirs, argv[1])));
		path = strdup (make_dir_path (argc, file, Command->curdirs->dir));
		free (file);
	} else
		path = strdup (Command->curdirs->dir);
	margv = (char **) callocw (2, sizeof (char *));

	(void) tmpnam (tmpname);
	fp = fopen (tmpname, WRITE_TEXT);
	if (fp) {
		(void) getdir (path, 1, fp);
		free (path);
		(void) fclose (fp);
	}
	margv[1] = strdup (tmpname);
	(void) morecmd (2, margv, p);
	free (margv[1]);
	free (margv);
	unlink (tmpname);
	return 0;
}



int
dodir (int argc, char *argv[], void *p)
{
char **pargv;
int i;

	if (Curproc->input == Command->input) {
		/* Make private copy of argv and args,
		 * spawn off subprocess and return.
		 */
		pargv = (char **) callocw ((unsigned) argc + 1, sizeof (char *));

		for (i = 0; i < argc; i++)
			pargv[i] = strdup (argv[i]);
		pargv[i] = NULL;
		(void) newproc ("dir", 512, (void (*)(int, void *, void *)) dircmd, argc, (void *) pargv, p, 1);
	} else
		(void) dircmd (argc, argv, p);
	return 0;
}

#endif /* ALLCMD || ALLSESSIONS */



#ifdef ALLCMD
/* Create directory */
int
domkd (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
char path[128];

	strncpy (path, make_fname (Command->curdirs->dir, argv[1]), 128);

	if (mkdir (path, 0777) == -1)
		tprintf ("Can't make %s: %s\n", path, SYS_ERRLIST(errno));
	return 0;
}



/* Remove directory */
int
dormd (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
char path[128];

	strncpy (path, make_fname (Command->curdirs->dir, argv[1]), 128);
	if (rmdir (path) == -1)
		tprintf ("Can't remove %s: %s\n", path, SYS_ERRLIST(errno));
	return 0;
}

#endif /*ALLCMD*/



/*
 * Return a string with commas every 3 positions.
 * the original string is replace with the string with commas.
 *
 * The caller must be sure that there is enough room for the resultant
 * string.
 *
 *
 * k3mc 4 Dec 87
 */
static void
commas (char *dest)
{
char *src, *core;	/* Place holder for malloc */
unsigned cc;		/* The comma counter */
unsigned len;

	if (!dest)
		return;
	len = strlen (dest);
	/* Make a copy, so we can muck around */
	core = src = strdup (dest);

	cc = (len - 1) % 3 + 1;	/* Tells us when to insert a comma */

	while (*src != '\0') {
		*dest++ = *src++;
		if (((--cc) == 0) && *src) {
			*dest++ = ',';
			cc = 3;
		}
	}
	free (core);
	*dest = '\0';
}



/* fix up the filename so that it contains the proper wildcard set */
static char const *
wildcardize (char const *path)
{
#ifndef TNOS_68K
#define THISSIZE 64
#else
#ifdef UNIX
#define THISSIZE 1024
#else
#define THISSIZE 128
#endif
#endif
struct ffblk sbuf;
static char ourpath[THISSIZE];

	/* Root directory is a special case */
	if (path == NULLCHAR || *path == '\0' ||
	    strcmp (path, "\\") == 0 || strcmp (path, "/") == 0) {
#ifdef MSDOS
		path = "\\*.*";
#else
		path = "/*";
#endif
		return path;
	}
#ifdef MSDOS
	/* MSDOS Root directory can also have a drive letter prefix */
	if (isalpha (*path) &&
	  (strcmp (path + 1, ":\\") == 0 || strcmp (path + 1, ":/") == 0)) {
		sprintf (ourpath, "%c:/*.*", *path);
		return ourpath;
	}
#endif

#ifdef CALLSERVER
	if (CDROM != NULLCHAR && strcmp (path, CDROM) == 0) {
		path = (char *) mallocw (7);	/* THIS causes a memory leak ! - WG7J */
		sprintf (path, "%s/*.*", CDROM);
	}
#endif

	/* if they gave the name of a subdirectory, append \*.* to it */
	if (
#ifdef TNOS_68K
		   (*path == '/' && !(strchr (path + 1, '/'))) ||
#endif
		   (nextname (0, path, &sbuf) &&
		    (sbuf.ff_attrib & FA_DIREC) &&
		    !nextname (1, path, &sbuf))) {

		/* if there isn't enough room, give up -- it's invalid anyway */
		if (strlen (path) + 4 > (THISSIZE - 1))
			return path;
		strncpy (ourpath, path, THISSIZE - 4);
#ifndef MSDOS
		strcat (ourpath, "/*");
#else
		strcat (ourpath, "\\*.*");
#endif
		return ourpath;
	}
	return path;
}


#if defined(TNOS_68K) || defined(UNIX)

static void
format_fname_full (FILE *file, struct ffblk *sbuf, int full, int n, const char *path)
{
static char line_buf[1025];
static char cbuf[1025];
struct stat sb;
char *symlinkpath = NULLCHAR;
char *tcbuf;

	strncpy (cbuf, sbuf->ff_name, sizeof (sbuf->ff_name));
	if (sbuf->ff_attrib & FA_DIREC)
		strcat (cbuf, "/");
	if (full == 1) {
		/* Long form, give other info too */
		sprintf (line_buf, "%-14s", cbuf);
		if (strlen (cbuf) > 14)
			strcpy (&line_buf[12], "..");
		if (sbuf->ff_attrib & FA_DIREC)
			strcat (line_buf, "          ");	/* 10 spaces */
		else {
			sprintf (cbuf, "%ld", sbuf->ff_fsize);
			commas (cbuf);
			sprintf (line_buf + strlen (line_buf), "%9s ", cbuf);
		}
              /* Y2K Update by James Fuller N7VMR */
		sprintf (line_buf + strlen (line_buf), "%2d:%02d %2d/%02d/%02d%s",
			 sbuf->ff_ftime.tm_hour, sbuf->ff_ftime.tm_min,
			 sbuf->ff_ftime.tm_mon + 1, sbuf->ff_ftime.tm_mday,
			 (sbuf->ff_ftime.tm_year % 100),
			 (full == 2) ? " | \n" : (n & 1) ? "   " : "\n");
		fputs (line_buf, file);
	} else if (full == 2) {
		if (sbuf->ff_attrib & FA_DIREC)
			cbuf[strlen (cbuf) - 1] = 0;	/* strip off the '/' */

		tcbuf = mallocw (strlen(cbuf) + strlen(path) + 2);
		strcpy (tcbuf, path);
		if (tcbuf[strlen(tcbuf) - 1] == '*')
			tcbuf[strlen(tcbuf) - 1] = 0;
		strcat (tcbuf, cbuf);
		(void) lstat (tcbuf, &sb);
		if (S_ISLNK(sb.st_mode))	{
			symlinkpath = callocw (1024, 1);
			if (readlink (tcbuf, symlinkpath, 1024) < 0)	{
				free (symlinkpath);
				symlinkpath = NULLCHAR;
			}
		}

		sprintf (line_buf, "%c%c%c%c%c%c%c%c%c%c   1 tnos     tnos     %8ld %3.3s %2d %2d:%02d %s%s%s\n",
			 (S_ISDIR (sb.st_mode)) ? 'd' : (S_ISLNK (sb.st_mode)) ? 'l' : '-',
			 (sb.st_mode & S_IRUSR) ? 'r' : '-',
			 (sb.st_mode & S_IWUSR) ? 'w' : '-',
			 (sb.st_mode & S_IXUSR) ? 'x' : '-',
			 (sb.st_mode & S_IRGRP) ? 'r' : '-',
			 (sb.st_mode & S_IWGRP) ? 'w' : '-',
			 (sb.st_mode & S_IXGRP) ? 'x' : '-',
			 (sb.st_mode & S_IROTH) ? 'r' : '-',
			 (sb.st_mode & S_IWOTH) ? 'w' : '-',
			 (sb.st_mode & S_IXOTH) ? 'x' : '-',
			 sbuf->ff_fsize,
			 Months[sbuf->ff_ftime.tm_mon],
			 sbuf->ff_ftime.tm_mday,
			 sbuf->ff_ftime.tm_hour, sbuf->ff_ftime.tm_min,
			 cbuf,
			 (symlinkpath != NULLCHAR) ? " -> " : "",
			 (symlinkpath != NULLCHAR) ? symlinkpath : "");
		fputs (line_buf, file);
	} else {
		if (!full) {
			fputs (cbuf, file);
			fputs ("\n", file);
		} else {
			fprintf (file, "%-37.37s", cbuf);
			fputs ((n & 1) ? "   " : "\n", file);
		}
	}
}


#else		/* MSDOS */


static void
format_fname_full (FILE *file, struct ffblk *sbuf, int full, int n, const char *path)
{
char line_buf[80];	/* for long dirlist */
char cbuf[20];		/* for making line_buf */
char which;

	strncpy (cbuf, sbuf->ff_name, 20);
	if (sbuf->ff_attrib & FA_DIREC)
		strcat (cbuf, "/");
	if (full == 1) {
		/* Long form, give other info too */
		sprintf (line_buf, "%-13s", cbuf);
		if (sbuf->ff_attrib & FA_DIREC)
			strcat (line_buf, "           ");	/* 11 spaces */
		else {
			sprintf (cbuf, "%ld", sbuf->ff_fsize);
			commas (cbuf);
			sprintf (line_buf + strlen (line_buf), "%10s ", cbuf);
		}
		sprintf (line_buf + strlen (line_buf), "%2d:%02d %2d/%02d/%02d%s",
			 (sbuf->ff_ftime >> 11) & 0x1f,	/* hour */
			 (sbuf->ff_ftime >> 5) & 0x3f,	/* minute */
			 (sbuf->ff_fdate >> 5) & 0xf,	/* month */
			 (sbuf->ff_fdate) & 0x1f,	/* day */
			 (sbuf->ff_fdate >> 9) + 80,	/* year */
			 (full == 2) ? " | \n" : (n & 1) ? "   " : "\n");
		fputs (line_buf, file);
	} else if (full == 2) {
		if (sbuf->ff_attrib & FA_DIREC)
			cbuf[strlen (cbuf) - 1] = 0;	/* strip off the '/' */
		which = (sbuf->ff_attrib & FA_RDONLY) ? '-' : 'w';
		sprintf (line_buf, "%cr%c-r%c-r%c-   1 tnos     tnos     %8ld %3.3s %2d %2d:%02d %s\n",
			 (sbuf->ff_attrib & FA_DIREC) ? 'd' : '-', which, which, which,
			 sbuf->ff_fsize,
			 Months[(sbuf->ff_fdate >> 5) & 0xf],
			 (sbuf->ff_fdate) & 0x1f,	/* day */
			 (sbuf->ff_ftime >> 11) & 0x1f,	/* hour */
			 (sbuf->ff_ftime >> 5) & 0x3f,	/* minute */
			 cbuf);
		fputs (line_buf, file);
	} else {
		if (!full) {
			fputs (cbuf, file);
			fputs ("\n", file);
		} else {
			fprintf (file, "%-37.37s", cbuf);
			fputs ((n & 1) ? "   " : "\n", file);
		}
	}
}
#endif



/* Provide additional information only on DIR */
static void
print_free_space (const char *path, FILE *file, int n)
{
unsigned long free_bytes, total_bytes;
char s_free[20], s_total[20];
char cbuf[20];
#ifdef UNIX
char *pbuf;
struct statfs vfsb;
char *cp;

	pbuf = mallocw (1024);
	strncpy (pbuf, path, 1024 - 2);
	if ((cp = strrchr (pbuf, '/')) == 0)
		strcat (pbuf, "/.");
	else {
		*++cp = '.';
		*++cp = '\0';
	}
#if defined(HAVE_SYS_STATFS_H) && !defined(linux)
	statfs (pbuf, &vfsb, sizeof vfsb, 0);
#else
	(void) statfs (pbuf, &vfsb);
#endif
	free_bytes = (unsigned long) (vfsb.f_bsize * vfsb.f_bavail);
	total_bytes = (unsigned long) (vfsb.f_bsize * vfsb.f_blocks);
#else	/* MSDOS or TNOS_68K */
struct dfree dtable;
unsigned long bpcl;

#ifdef MSDOS
int drive;

	if (path[1] == ':')
		drive = toupper(path[0]) - '@';
	else
		drive = 0;
#endif
	/* Find disk free space */
#ifndef TNOS_68K
	getdfree (uchar(drive), &dtable);
#else
	getdfree (path, &dtable);
#endif

	bpcl = dtable.df_bsec * dtable.df_sclus;
	free_bytes = dtable.df_avail * bpcl;
	total_bytes = dtable.df_total * bpcl;
#endif

	if (n & 1)
		fputs ("\n", file);

	sprintf (s_free, "%ld", free_bytes);
	commas (s_free);
	sprintf (s_total, "%ld", total_bytes);
	commas (s_total);

	if (n)
		sprintf (cbuf, "%d", n);
	else
		strcpy (cbuf, "No");

	fprintf (file, "%s file%s. %s bytes free. Disk size %s bytes.\n",
		 cbuf, (n == 1 ? "" : "s"), s_free, s_total);
}



static void
free_clist (struct dirsort *this)
{
struct dirsort *next;

	while (this != NULLSORT) {
		next = this->next;
		free (this);
		this = next;
	}
}



/* Translate those %$#@!! backslashes to proper form */
void
undosify (char *s)
{
	if (s) {
		while (*s != '\0') {
			if (*s == '\\')
				*s = '/';
			s++;
		}
	}
}



char *
make_dir_path (int count, char *arg, const char *curdir)
{
char *tmpdir, *retval;
char path[1024], *q;

	undosify (arg);
	tmpdir = strdup (curdir);
	undosify (tmpdir);
	if (count >= 2) {
		q = arg;
		q += strlen (arg) - 1;
#ifndef TNOS_68K
		if (*q == '/' || *q == ':')
#else
		if (*q == '/')
#endif
		{
			strncpy (path, arg, 1024 - strlen (ALLFILES));
			strcat (path, ALLFILES);
		} else
			strncpy (path, arg, 1024);
	} else
		strncpy (path, ALLFILES, 1024);

	retval = make_fname (tmpdir, path);
	free (tmpdir);
	return (retval);
}



char *
make_fname (const char *curdir, const char *fname0)
{
char *p, *fname;
static char new_name[1024];

	strncpy (new_name, curdir, 1024);
	fname = strdup (fname0);
	if (fname)
		undosify (fname);
	if (fname && *fname) {
		if (*fname == '.') {
			if (*++fname == '/')
				fname++;
			else if (*fname == '.') {
				p = strrchr (new_name, '/');
				if (p)
					*p = 0;
				if (*++fname == '/')
					fname++;
			}
		}
#ifdef MSDOS
		if (fname[0] == '/' || (strchr (fname, ':') != NULLCHAR))
#else
		if (fname[0] == '/')
#endif
			return fname;
		else {
			p = new_name;
			p += strlen (p) - 1;
			if (*p == '/')
				*p = '\0';
			crunch (new_name, fname);
#ifdef MSDOS
			if (new_name[strlen (new_name) - 1] == ':')
				strcat (new_name, "/");
#endif
		}
	}
	return new_name;
}



/* Check Drive/Directory for validity - 1=OK, 0=NOGOOD */
int
dir_ok (char *newpath, struct cur_dirs *dirs)
{
int result;
char fullpath[1024];
#ifdef TNOS_68K
int new = 0;

	undosify (newpath);
	strlwr (newpath);
	result = ((access (newpath, S_IFDIR) == -1) ? 0 : 1);
	if (result) {
		/*		chdir (newpath);	*/
		new = (*newpath == '/');
		sprintf (fullpath, "%s%s%s", !new ? dirs->dir : "", !new ? "/" : "", newpath);
		free (dirs->dir);
		dirs->dir = strdup (fullpath);
	}
	return (result);
#else	/* either MSDOS or UNIX */
char curpath[1024];
char buf[128];

#ifdef MSDOS
int drive = dirs->drv;
#endif
struct stat sbuf;


	undosify (newpath);
	strncpy (buf, newpath, 128);
	strncpy (curpath, dirs->dir, 1024);

#ifdef MSDOS
	if (buf[1] == ':')	{
		strncpy (fullpath, buf, 1024);
	} else
#endif
	{
		if (*buf != '/')
			crunch (curpath, buf);
		else
			strncpy (curpath, buf + 1, 1024);

#ifdef UNIX
		sprintf (fullpath, "%s%s", (*curpath != '/' ? "/" : ""), curpath);
#else
		strncpy (fullpath, curpath, 1024);
#endif
	}

	if (stat (fullpath, &sbuf) == -1 || !S_ISDIR (sbuf.st_mode))
		result = 0;
	else if ((result = access (fullpath, 0) + 1) == 1) {
#ifdef UNIX
		free (dirs->dir);
		dirs->dir = strdup (fullpath);
#else
		if (dirs->curdir[drive])
			free (dirs->curdir[drive]);
		dirs->curdir[drive] = strdup (fullpath);
		dirs->drv = drive;
		dirs->dir = dirs->curdir[drive];
#endif
	}
	return result;
#endif
}



const char *
init_dirs (struct cur_dirs *dirs)
{
#ifdef UNIX
	dirs->dir = strdup (getcwd (NULL, 1024));
	return dirs->dir;
#endif
#ifdef TNOS_68K
char fullpath[1024];

	dirs->dir = strdup (getcwd (fullpath, 1024));
	return (dirs->dir);
#endif
#ifdef MSDOS
char buf[128], fullpath[128];
int x, drive;

	for (x = 0; x <= 26; x++)
		dirs->curdir[x] = 0;

	drive = getdisk () + 1;
	(void) getcwd (buf, 128);
	undosify (buf);
	(void) strlwr (buf);
	sprintf (fullpath, "%c:/%s", drive + '`', &buf[3]);
	dirs->curdir[drive] = strdup (fullpath);
	dirs->drv = drive;
	dirs->dir = dirs->curdir[drive];
	return dirs->curdir[drive];
#endif
}



void
free_dirs (struct cur_dirs *dirs)
{
#ifdef UNIX
	free (dirs->dir);
#else
#ifdef TNOS_68K
	free (dirs->dir);
#else
int x;

	for (x = 0; x <= 26; x++) {
		if (dirs->curdir[x])
			free (dirs->curdir[x]);
	}
#endif
#endif
}
