blob: 33c559d32a96d3aae27e69e318c1d36e670c0e56 [file] [log] [blame]
/*
* Copyright (c) 2004, Adam Dunkels.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
* Author: Adam Dunkels <adam@sics.se>
*
* $Id: posixdir.c,v 1.2 2004/09/12 20:30:04 adamdunkels Exp $
*/
/* posixdir.c written by groepaz */
// define to compile test program
//#define TEST
// define to compile test program for linux :=P
//#define LINUX
/*
first test for posix directory routines for the c64
kludges:
- currently uses cbm_open, which conflicts with standard i/o,
which in turn makes it infact kindof unuseable. this can
be easily changed however, since the only reason not to use
open/read was that it currently appends ,u,r to filenames
- the offset in current dir stream should better be calculated
from the values returned by "read".
- the type flag isnt filled in atm.
- scandir/alphasort/versionsort is missing
- some bits are currently untested (ie, unused in the testprogram)
27/02/2003 gpz
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#if defined(LINUX)
#include <sys/types.h>
#include <dirent.h>
#else
/*
contents of dirent.h ...
*/
#include <cbm.h>
/* 16 will only be enough if NO subdirs are supported! */
#define NAME_MAX 16
struct dirent
{
/* POSIX */
char d_name[NAME_MAX+1];
/* linux/bsd extensions */
// off_t d_off;
unsigned short d_off;
unsigned short d_reclen;
unsigned char d_type;
/* bsd extensions */
unsigned char d_namlen;
};
/* fields in the dir struct shouldnt be accessed by user */
typedef struct
{
unsigned char fd;
//off_t off;
unsigned short off;
char name[NAME_MAX+1];
} DIR;
DIR *opendir(const char *name);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);
off_t telldir(DIR *dir);
int dirfd(DIR *dir);
void seekdir(DIR *dir, off_t offset);
void rewinddir(DIR *dir);
/*
int scandir(const char *dir, struct dirent ***namelist,
int(*select)(const struct dirent *),
int(*compar)(const struct dirent **, const struct dirent **));
int alphasort(const void *a, const void *b);
int versionsort(const void *a, const void *b);
*/
//-------------------------------------------------------------------------------------------
// functions access the directory via reading the "$" file to provide max. compatibility
//
// disc header:
//
// $07 ignored
// $01 quote
// $10 volume/subdir name
// $01 quote
// $06 disc id
// $01 = $00
//
// file entry:
//
// $02 ignored (basic-line link)
// $02 file length in 254-byte blocks (basic-line nr)
// $xx spaces
//
// $01 quote if file-entry... | = 'b' if "blocks free"...
// $00-$10 file-name | $xx ignored
// $01 quote |
// $01 file-closed attrib (' 'or'*') | => file-length is free blocks
// $03 file-type |
// $01 file-protected attr. (' 'or'<') |
// $xx ignored |
// $01 = $00 (basic-line end) |
//-------------------------------------------------------------------------------------------
DIR *opendir(const char *name){
unsigned char buffer[(8+16+1+7)];
unsigned char fd;
DIR *dir;
dir=(DIR*) malloc(sizeof(DIR));
if(dir!=NULL)
{
/* handle dir name, go into
subdirs on 1581 etc... */
name=name;
// open dir "file"
// if((fd=dir->fd=open("$",O_RDONLY))==-1)
if(cbm_open(2, 8, CBM_READ, "$")!=0)
{
return(NULL);
}
fd=dir->fd=2;
dir->off=0;
// skip the disc header
//read(fd,buffer,0x08); // some info
//read(fd,buffer,0x10); // disc name
//read(fd,buffer,0x01); // quote
//read(fd,buffer,0x07); // disc id + $00
cbm_read(fd,buffer,(8+16+1+7));
}
return(dir);
}
int closedir(DIR *dir)
{
cbm_close(dir->fd);
free(dir);
}
int dirfd(DIR *dir)
{
return(dir->fd);
}
off_t telldir(DIR *dir)
{
return((off_t)(dir->off));
}
void seekdir(DIR *dir, off_t offset)
{
static unsigned char ch;
unsigned char fd;
char name[NAME_MAX+1];
if(offset<dir->off)
{
/* close and re-open */
strcpy(name,dir->name);
closedir(dir);
dir=opendir(name);
}
fd=dir->fd;
/* scan forward */
while(dir->off!=offset)
{
cbm_read(fd,&ch,0x01);
dir->off=dir->off+1;
}
}
void rewinddir(DIR *dir)
{
seekdir(dir,(off_t)0);
}
struct dirent *readdir(DIR *dir)
{
unsigned char buffer[0x40];
unsigned char temp;
unsigned char i,ii;
static struct dirent entry;
unsigned char fd;
static unsigned char ch;
fd=dirfd(dir);
entry.d_off=dir->off;
// basic line-link / file-length
cbm_read(fd,buffer,0x04);
dir->off=dir->off+4;
/*
len=(buffer[2]+(buffer[3]<<8));
blen=len*254;
*/
entry.d_reclen=254*(buffer[2]+(buffer[3]<<8));
// read file entry
i=0;do
{
cbm_read(fd,&ch,0x01);
buffer[i]=ch;
++i;
} while (ch!=0);
dir->off=dir->off+i;
// skip until either quote (file) or b (blocks free => end)
i=0;ii=0;
while(i==0){
temp=buffer[ii];ii++;
if(ii>16){
/* something went wrong...this shouldnt happen! */
return(NULL);
}
else if(temp=='\"') i++;
else if(temp=='b') {
/* "blocks free" */
return(NULL);
}
}
/* process file entry */
i=0; temp=buffer[ii];ii++;
while(temp!='\"'){
entry.d_name[i]=temp;
i++;
temp=buffer[ii];ii++;
}
entry.d_name[i]=0;
entry.d_namlen=i;
/*
ii=ii+(16-i); // pad
cattr=buffer[ii];ii++; // file closed attribute
ext[0]=buffer[ii];ii++; // filetype (text)
ext[1]=buffer[ii];ii++;
ext[2]=buffer[ii];ii++;
pattr=buffer[ii];ii++; // file protected attribute
*/
/* set type flag */
return(&entry);
}
#endif
#if defined (TEST)
int main(void)
{
char mydirname[NAME_MAX+1]=".";
DIR *mydir;
struct dirent *mydirent;
mydir=opendir(mydirname);
if(mydir==NULL)
{
printf("error:\n");
}
else
{
printf("contents of \"%s\" dirfd:%d\n",mydirname,dirfd(mydir));
while((mydirent=readdir(mydir))!=NULL)
{
printf("dirent.d_name[] : \"%s\"\n",mydirent->d_name);
#if !defined(LINUX)
printf("dirent.d_namlen : %10d\n",mydirent->d_namlen);
#endif
printf("dirent.d_reclen : %10d\n",mydirent->d_reclen);
printf("dirent.d_type : %10d\n",mydirent->d_type);
printf("dirent.d_off : %10d\n",(unsigned short)mydirent->d_off);
printf("telldir() : %10d\n",(unsigned short)telldir(mydir));
printf("---\n");
}
closedir(mydir);
}
}
#endif