view os2/dirent.c @ 404:720e61df8cf6

An even better combobox drawing fix. Only add 100 pixels to the size of the combobox when the list needs to be shown. This way it won't screw up clipping of items below it in the box. So OS/2 comboboxes can now be safely used in vertical boxes without worries.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sat, 10 May 2003 10:33:54 +0000
parents 0e6f09149eaa
children 2ff26b697877
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "platform/dirent.h"
#include <errno.h>

/*#ifndef __EMX__ 
#include <libx.h>
#endif */

#define INCL_DOSFILEMGR
#define INCL_DOSERRORS
#include <os2.h>

# define FFBUF	FILEFINDBUF3
# define Word	ULONG
  /*
   * LS20 recommends a request count of 100, but according to the
   * APAR text it does not lead to missing files, just to funny
   * numbers of returned entries.
   *
   * LS30 HPFS386 requires a count greater than 2, or some files
   * are missing (those starting with a character less that '.').
   *
   * Novell looses entries which overflow the buffer. In previous
   * versions of dirent2, this could have lead to missing files
   * when the average length of 100 directory entries was 40 bytes
   * or more (quite unlikely for files on a Novell server).
   *
   * Conclusion: Make sure that the entries all fit into the buffer
   * and that the buffer is large enough for more than 2 entries
   * (each entry is at most 300 bytes long). And ignore the LS20
   * effect.
   */
# define Count	25
# define BufSz	(25 * (sizeof(FILEFINDBUF3)+1))

#if defined(__IBMC__) || defined(__IBMCPP__)
  #define error(rc) _doserrno = rc, errno = EOS2ERR
#else
  #define error(rc) errno = 255
#endif

struct _dirdescr {
	HDIR		handle;		/* DosFindFirst handle */
	char		fstype;		/* filesystem type */
	Word		count;		/* valid entries in <ffbuf> */
	long		number;		/* absolute number of next entry */
	int		index;		/* relative number of next entry */
	FFBUF *		next;		/* pointer to next entry */
	char		name[MAXPATHLEN+3]; /* directory name */
	unsigned	attrmask;	/* attribute mask for seekdir */
	struct dirent	entry;		/* buffer for directory entry */
	BYTE		ffbuf[BufSz];
};

/*
 * Return first char of filesystem type, or 0 if unknown.
 */
static char
getFSType(const char *path)
{
	static char cache[1+26];
	char drive[3], info[512];
	Word unit, infolen;
	char r;

	if (isalpha((int)path[0]) && path[1] == ':') {
		unit = toupper(path[0]) - '@';
		path += 2;
	} else {
		ULONG driveMap;
		if (DosQueryCurrentDisk(&unit, &driveMap))
			return 0;
	}

	if ((path[0] == '\\' || path[0] == '/')
	 && (path[1] == '\\' || path[1] == '/'))
		return 0;

	if (cache [unit])
		return cache [unit];

	drive[0] = '@' + unit;
	drive[1] = ':';
	drive[2] = '\0';
	infolen = sizeof info;
	if (DosQueryFSAttach(drive, 0, FSAIL_QUERYNAME, (PVOID)info, &infolen))
		return 0;
	if (infolen >= sizeof(FSQBUFFER2)) {
		FSQBUFFER2 *p = (FSQBUFFER2 *)info;
		r = p->szFSDName[p->cbName];
	} else
		r = 0;
	return cache [unit] = r;
}

char *
_abs_path(const char *name, char *buffer, int len)
{
	char buf[4];
	if (isalpha((int)name[0]) && name[1] == ':' && name[2] == '\0') {
		buf[0] = name[0];
		buf[1] = name[1];
		buf[2] = '.';
		buf[3] = '\0';
		name = buf;
	}
	if (DosQueryPathInfo((PSZ)name, FIL_QUERYFULLNAME, buffer, len))
		return NULL;
	return buffer;
}

DIR *
_openxdir(const char *path, unsigned att_mask)
{
	DIR *dir;
	char name[MAXPATHLEN+3];
	Word rc;

	if(!path)
		return NULL;

	dir = malloc(sizeof(DIR));
	if (dir == NULL) {
		errno = ENOMEM;
		return NULL;
	}

	strncpy(name, path, MAXPATHLEN);
	name[MAXPATHLEN] = '\0';
	switch (name[strlen(name)-1]) {
	default:
		strcat(name, "\\");
	case '\\':
	case '/':
	case ':':
		;
	}
	strcat(name, ".");
	if (!abs_path(name, dir->name, MAXPATHLEN+1))
		strcpy(dir->name, name);
	if (dir->name[strlen(dir->name)-1] == '\\')
		strcat(dir->name, "*");
	else
		strcat(dir->name, "\\*");

	dir->fstype = getFSType(dir->name);
	dir->attrmask = att_mask | A_DIR;

	dir->handle = HDIR_CREATE;
	dir->count = 100;
	rc = DosFindFirst(dir->name, &dir->handle, dir->attrmask,
		dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
	switch (rc) {
	default:
		free(dir);
		error(rc);
		return NULL;
	case NO_ERROR:
	case ERROR_NO_MORE_FILES:
		;
	}

	dir->number = 0;
	dir->index = 0;
	dir->next = (FFBUF *)dir->ffbuf;

	return (DIR *)dir;
}

DIR *
_opendir(const char *pathname)
{
	return openxdir(pathname, 0);
}

struct dirent *
_readdir(DIR *dir)
{
	static int dummy_ino = 2;

	if (dir->index == dir->count) {
		Word rc;
		dir->count = 100;
		rc = DosFindNext(dir->handle, dir->ffbuf,
			sizeof dir->ffbuf, &dir->count);
		if (rc) {
			error(rc);
			return NULL;
		}

		dir->index = 0;
		dir->next = (FFBUF *)dir->ffbuf;
	}

	if (dir->index == dir->count)
		return NULL;

	memcpy(dir->entry.d_name, dir->next->achName, dir->next->cchName);
	dir->entry.d_name[dir->next->cchName] = '\0';
	dir->entry.d_ino = dummy_ino++;
	dir->entry.d_reclen = dir->next->cchName;
	dir->entry.d_namlen = dir->next->cchName;
	dir->entry.d_size = dir->next->cbFile;
	dir->entry.d_attribute = dir->next->attrFile;
	dir->entry.d_time = *(USHORT *)&dir->next->ftimeLastWrite;
	dir->entry.d_date = *(USHORT *)&dir->next->fdateLastWrite;

	switch (dir->fstype) {
	case 'F': /* FAT */
	case 'C': /* CDFS */
		if (dir->next->attrFile & FILE_DIRECTORY)
			strupr(dir->entry.d_name);
		else
			strlwr(dir->entry.d_name);
	}

	dir->next = (FFBUF *)((BYTE *)dir->next + dir->next->oNextEntryOffset);
	++dir->number;
	++dir->index;

	return &dir->entry;
}

long
_telldir(DIR *dir)
{
	return dir->number;
}

void
_seekdir(DIR *dir, long off)
{
	if (dir->number > off) {
		char name[MAXPATHLEN+2];
		Word rc;

		DosFindClose(dir->handle);

		strcpy(name, dir->name);
		strcat(name, "*");

		dir->handle = HDIR_CREATE;
		dir->count = 32767;
		rc = DosFindFirst(name, &dir->handle, dir->attrmask,
			dir->ffbuf, sizeof dir->ffbuf, &dir->count, FIL_STANDARD);
		switch (rc) {
		default:
			error(rc);
			return;
		case NO_ERROR:
		case ERROR_NO_MORE_FILES:
			;
		}

		dir->number = 0;
		dir->index = 0;
		dir->next = (FFBUF *)dir->ffbuf;
	}

	while (dir->number < off && readdir(dir))
		;
}

void
_closedir(DIR *dir)
{
	DosFindClose(dir->handle);
	free(dir);
}

/*****************************************************************************/

#ifdef TEST

main(int argc, char **argv)
{
	int i;
	DIR *dir;
	struct dirent *ep;

	for (i = 1; i < argc; ++i) {
		dir = opendir(argv[i]);
		if (!dir)
			continue;
		while (ep = readdir(dir))
			if (strchr("\\/:", argv[i] [strlen(argv[i]) - 1]))
				printf("%s%s\n", argv[i], ep->d_name);
			else
				printf("%s/%s\n", argv[i], ep->d_name);
		closedir(dir);
	}

	return 0;
}

#endif