summaryrefslogtreecommitdiff
path: root/libpsx/src/libc.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/libc.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/libc.c')
-rw-r--r--libpsx/src/libc.c705
1 files changed, 705 insertions, 0 deletions
diff --git a/libpsx/src/libc.c b/libpsx/src/libc.c
new file mode 100644
index 0000000..8ad519b
--- /dev/null
+++ b/libpsx/src/libc.c
@@ -0,0 +1,705 @@
+/*
+ * small libc functions for the PSXSDK
+ *
+ * In this file, C functions either not implemented by the BIOS
+ * or very broken in the BIOS are implemented independently
+ *
+ * Some functions, such as printf, have both a BIOS implementation
+ * and an implementation here. The implementation here is prefixed
+ * with libc_ to not make confusion.
+ */
+
+#include <psx.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+char onesec_buf[2048];
+int errno;
+int __stdio_direction = STDIO_DIRECTION_BIOS;
+static unsigned int __sio_cr_mapped = 0;
+
+#define NUM_OF_FILE_STRUCTS 259
+
+FILE file_structs[NUM_OF_FILE_STRUCTS] =
+{
+ [0] = // stdin
+ {
+ .fildes = 0,
+ .pos = 0,
+ .mode = O_RDONLY,
+ .dev = FDEV_CONSOLE,
+ .size = 0,
+ .used = 1,
+ .eof = 0,
+ .error = 0
+ },
+ [1] = // stdout
+ {
+ .fildes = 1,
+ .pos = 0,
+ .mode = O_WRONLY,
+ .dev = FDEV_CONSOLE,
+ .size = 0,
+ .used = 1,
+ .eof = 0,
+ .error = 0
+ },
+ [2] = // stderr
+ {
+ .fildes = 2,
+ .pos = 0,
+ .mode = O_WRONLY,
+ .dev = FDEV_CONSOLE,
+ .size = 0,
+ .used = 1,
+ .eof = 0,
+ .error = 0
+ },
+};
+
+FILE *stdin = &file_structs[0];
+FILE *stdout = &file_structs[1];
+FILE *stderr = &file_structs[2];
+
+#define IS_CONS_IN(f) (f->fildes == 0)
+#define IS_CONS_OUT(f) (f->fildes == 1 || f->fildes == 2)
+
+//unsigned char file_state[NUM_OF_FILE_STRUCTS];
+
+int libc_get_transtbl_fname(const char *tofind, char *outstr, int outl);
+
+unsigned int fmode_to_desmode(const char *fmode)
+{
+ char rmode[16];
+ int x, y;
+
+ y = 0;
+
+ for(x=0;x<15;x++)
+ {
+ if(fmode[x] == 0)
+ break;
+ else
+ {
+ if(fmode[x] != 'b' && fmode[x] != 'f')
+ rmode[y++] = fmode[x];
+ }
+ }
+
+ rmode[y] = 0;
+
+ if(strcmp(rmode, "r") == 0)
+ {
+ dprintf("Open for reading.\n");
+ return O_RDONLY;
+ }
+ else if(strcmp(rmode, "r+") == 0)
+ {
+ dprintf("Open for reading and writing.\n");
+ return O_RDWR;
+ }
+ else if(strcmp(rmode, "w") == 0)
+ {
+ dprintf("Open for writing.\n");
+ return O_WRONLY | O_CREAT | O_TRUNC;
+ }
+ else if(strcmp(rmode, "w+") == 0)
+ {
+ dprintf("Open for writing. Truncate to zero or create file.\n");
+ return O_RDWR | O_CREAT | O_TRUNC;
+ }
+ else if(strcmp(rmode, "a") == 0)
+ {
+ dprintf("Append; open for writing. Create file if it doesn't exist.\n");
+ return O_WRONLY | O_APPEND;
+ }
+ else if(strcmp(rmode, "a+") == 0)
+ {
+ dprintf("Append; open for reading and writing. Create file if it doesn't exist.\n");
+ return O_RDWR | O_APPEND | O_CREAT;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+FILE *fdopen(int fildes, const char *mode)
+{
+// Adjust for malloc
+ int x;
+
+// Find a free file structure
+ for(x = 0; x < NUM_OF_FILE_STRUCTS; x++)
+ {
+ if(file_structs[x].used == 0)
+ {
+ bzero(&file_structs[x], sizeof(FILE));
+ file_structs[x].used = 1;
+ break;
+ }
+ }
+
+// If we found no free file structure, return NULL pointer
+
+ if(x == NUM_OF_FILE_STRUCTS)
+ return NULL;
+
+ file_structs[x].fildes = fildes;
+ file_structs[x].pos = lseek(fildes, 0, SEEK_CUR);
+ file_structs[x].mode = fmode_to_desmode(mode);
+
+ return &file_structs[x];
+}
+
+static FILE *fopen_internal(const char *path, const char *mode, FILE *f)
+{
+ int fd;
+ char *s = NULL;
+
+ if(strncmp(path, "cdromL:", 7) == 0)
+ {
+ s = malloc(1024);
+
+ if(libc_get_transtbl_fname(path+7, s, 1024) == 0)
+ return NULL;
+
+ fd = open(s, fmode_to_desmode(mode));
+ }
+ else
+ fd = open(path, fmode_to_desmode(mode));
+
+ if(fd == -1)
+ {
+ if(s!=NULL)free(s);
+ return NULL;
+ }
+
+ if(f == NULL)
+ f = fdopen(fd, mode);
+ else
+ {
+ f->fildes = fd;
+ f->pos = lseek(fd, 0, SEEK_CUR);
+ f->mode = fmode_to_desmode(mode);
+ }
+
+ if(f == NULL)
+ {
+ if(s!=NULL)free(s);
+ return NULL;
+ }
+
+ f->dev = FDEV_UNKNOWN;
+
+ if(strncmp(path, "cdrom", 5) == 0 || strncmp(path, "cdromL", 6) == 0)
+ f->dev = FDEV_CDROM;
+ else if(strncmp(path, "bu", 2) == 0)
+ f->dev = FDEV_MEMCARD;
+
+// nocash bios freezes at get_real_file_size(), due
+// to problems with firstfile()
+
+ if(s!=NULL)
+ {
+ f->size = get_real_file_size(s);
+ free(s);
+ }
+ else
+ f->size = get_real_file_size(path);
+
+ return f;
+}
+
+FILE *fopen(const char *path, const char *mode)
+{
+ return fopen_internal(path, mode, NULL);
+}
+
+int fclose(FILE *stream)
+{
+ stream->used = 0;
+ close(stream->fildes);
+ return 0;
+}
+
+/*
+ * fread doesn't require reads to be carried in block unit
+ * Notice that however seeks on the CD drive will be very slow - so avoid using non block units
+ *
+ * This is done to make programming and porting easier
+ */
+
+int fread(void *ptr, int size, int nmemb, FILE *f)
+{
+ int rsize = size * nmemb;
+ int csize = rsize;
+ int max;
+ int nsect = (f->pos + rsize) >> 11;
+ nsect -= f->pos >> 11;
+ nsect++;
+
+ //printf("f->dev = %d, f->pos = %d, rsize = %d\n", f->dev, f->pos, rsize);
+
+ if(f->dev == FDEV_CDROM)
+ {
+ // First sector
+ lseek(f->fildes, f->pos & (~0x7ff), SEEK_SET);
+ read(f->fildes, onesec_buf, 2048);
+
+ max = 2048 - (f->pos & 2047);
+
+ //printf("ptr(FIRST) = %d, %x\n", ptr, ptr);
+ printf("rsize = %d\n", rsize);
+
+ memcpy(ptr, onesec_buf + (f->pos & 2047), (rsize > max) ? max : rsize);
+
+ // Middle sector
+ ptr += max;
+
+ //printf("ptr(MIDDLEsex) = %d, %x\n", ptr, ptr);
+ nsect--;
+ csize -= max;
+
+ if(nsect > 1)
+ {
+ //lseek(f->fildes, (f->pos & (~0x7ff)) + 2048, SEEK_SET);
+
+//#warning "Check correctness of this calculation."
+
+ /*if(rsize & 2047)
+ sect_num = (rsize|2047)+1;
+ else
+ sect_num = rsize;
+
+ sect_num -= 4096;*/
+
+ //printf("read_middle=%d, sect_num = %d\n", read(f->fildes, ptr, sect_num), sect_num);
+
+ read(f->fildes, ptr, (nsect - 1) * 2048);
+
+ ptr += (nsect - 1) * 2048;
+ csize -= (nsect - 1) * 2048;
+ nsect = 1;
+ }
+
+ //printf("ptr(LAST) = %d, %x\n", ptr, ptr);
+
+ if(nsect == 1)
+ {
+ // Last sector
+ read(f->fildes, onesec_buf, 2048);
+
+ memcpy(ptr, onesec_buf, csize);
+ }
+ }
+ else if(f->dev == FDEV_CONSOLE)
+ return 0;
+
+
+ if(f->dev != FDEV_CONSOLE)
+ {
+ f->pos+= rsize;
+ f->eof = (f->pos > f->size);
+
+ if(f->eof)
+ f->pos = f->size;
+ }
+
+ return rsize;
+}
+
+int fgetc(FILE *f)
+{
+ unsigned char c;
+
+ if(f->pos >= f->size)
+ return EOF;
+
+ fread(&c, sizeof(char), 1, f);
+
+ return (int)c;
+}
+
+int ftell(FILE *f)
+{
+ return f->pos;
+}
+
+int fseek(FILE *f, int offset, int whence)
+{
+ switch(whence)
+ {
+ case SEEK_SET:
+ f->pos = offset;
+ break;
+ case SEEK_CUR:
+ f->pos+= offset;
+ break;
+ case SEEK_END:
+ f->pos = f->size + offset;
+ break;
+ default:
+ f->pos = whence + offset;
+ break;
+ }
+
+ return 0;
+}
+
+int toupper(int c)
+{
+ if(c >= 'a' && c <= 'z')
+ return (c-'a')+'A';
+
+ return c;
+}
+
+int tolower(int c)
+{
+ if(c >= 'A' && c <= 'Z')
+ return (c-'A')+'a';
+
+ return c;
+}
+
+int libc_get_transtbl_fname(const char *tofind, char *outstr, int outl)
+{
+ FILE *f;
+ int s;
+ int x;
+ int type;
+ int y;
+ int l = strlen(tofind);
+ int filename_found = 0;
+ int exit_loop = 0;
+ int otfp = 0;
+ int tfp = 0;
+ char transtbl[0x4000];
+ char orgname[16];
+ char newname[256];
+ char rootpath[256];
+
+ bzero(transtbl, 0x4000);
+ strcpy(rootpath, "cdrom:\\");
+
+ f = fopen("cdrom:\\TRANS.TBL;1", "rb");
+
+ if(f == NULL)
+ return 0;
+
+ fseek(f, 0, SEEK_END);
+ s = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ fread(transtbl, 1, s, f);
+ fclose(f);
+
+ outstr[0] = 0;
+
+ x = 0;
+
+ exit_loop = 0;
+ filename_found = 0;
+
+ for(tfp = 0; tofind[tfp] == '\\' || tofind[tfp] == '/'; tfp++);
+
+ otfp = tfp;
+
+ for(y = otfp; y < l; y++)
+ {
+ if(tofind[y] == '\0' || tofind[y] == '\\' || tofind[y] == '/')
+ break;
+ }
+
+ tfp = y;
+
+ while((x < s) && !exit_loop)
+ {
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ if(transtbl[x] == 'F')
+ type = 0;
+ else if(transtbl[x] == 'D')
+ type = 1;
+
+ x++;
+
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ y = 0;
+
+ while(!(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r'
+ || transtbl[x] == 0))
+ orgname[y++] = transtbl[x++];
+
+ orgname[y] = 0;
+ //printf("orgname = %s\n", orgname);
+
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ y = 0;
+
+ while(!(transtbl[x] == '\n' || transtbl[x] == '\r' || transtbl[x] == 0))
+ newname[y++] = transtbl[x++];
+
+ newname[y] = 0;
+
+ while(transtbl[x] == ' ' || transtbl[x] == '\t' || transtbl[x] == '\n' || transtbl[x] == '\r')
+ x++;
+
+ //printf("newname = %s\n", newname);
+
+ if(strncasecmp(&tofind[otfp], newname, tfp-otfp) == 0)
+ {
+ if(type == 0)
+ {
+ dprintf("Filename found: %s -> %s%s\n", tofind, rootpath, orgname);
+ filename_found = 1;
+ exit_loop = 1;
+
+ strncpy(outstr, rootpath, outl);
+ strncat(outstr, orgname, outl-strlen(rootpath));
+ }
+ else
+ {
+ //printf("Found directory! %s\n", newname);
+
+ //printf("tfp = %d\n", tfp);
+
+ if(tfp == l || tofind[l-1] == '/'
+ || tofind[l-1] == '\\')
+ {
+ dprintf("File not found. A directory was specified.\n");
+ exit_loop = 1;
+ continue;
+ }
+
+ //tfp++;
+ for(; tofind[tfp] == '\\' || tofind[tfp] == '/'; tfp++);
+
+ otfp = tfp;
+
+ for(y = otfp; y < l; y++)
+ {
+ if(tofind[y] == '\0' || tofind[y] == '\\' || tofind[y] == '/')
+ break;
+ }
+
+ tfp = y;
+
+ strcat(rootpath, orgname);
+ strcat(rootpath, "\\");
+
+ y = strlen(rootpath);
+ strcat(rootpath, "TRANS.TBL;1");
+
+ bzero(transtbl, 0x4000);
+
+ f = fopen(rootpath, "rb");
+
+ if(f == NULL)
+ {
+ dprintf("Couldn't find %s\n", rootpath);
+ exit_loop = 1;
+ continue;
+ }
+
+ rootpath[y] = 0;
+
+ fseek(f, 0, SEEK_END);
+ s = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ fread(transtbl, 1, s, f);
+ fclose(f);
+
+ x = 0;
+ }
+ }
+ }
+
+ return filename_found;
+}
+
+int isupper(int c)
+{
+ return (c >= 'A' && c <= 'Z');
+}
+
+int islower(int c)
+{
+ return (c >= 'a' && c <= 'z');
+}
+
+int isdigit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+int isxdigit(int c)
+{
+ return ((c >= '0' && c <= '9') || (c >= 'A' && c<='F') || (c >= 'a' && c<='f'));
+}
+
+int isalpha(int c)
+{
+ return ((c>='a' && c<='z') || (c>='A' && c<='Z'));
+}
+
+int isalnum(int c)
+{
+ return ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'));
+}
+
+int isspace(int c)
+{
+ return ((c == ' ') || (c == '\f') || (c == '\n') || (c == '\r') || (c == '\t') || (c == '\v'));
+}
+
+int isprint(int c)
+{
+ return (c >= 0x20) && (c <= 0x7E);
+}
+
+int isgraph(int c)
+{
+ return (c > 0x20) && (c <= 0x7E);
+}
+
+int iscntrl(int c)
+{
+ return (c < 0x20);
+}
+
+int isblank(int c)
+{
+ return ((c == ' ') || (c == '\t'));
+}
+
+void redirect_stdio_to_sio(void)
+{
+ __stdio_direction = STDIO_DIRECTION_SIO;
+}
+
+void sio_stdio_mapcr(unsigned int setting)
+{
+ __sio_cr_mapped = setting;
+}
+
+int sio_putchar(int c)
+{
+ if(c == '\n' && __sio_cr_mapped)
+ sio_putchar('\r');
+
+ while(!SIOCheckOutBuffer());
+
+ SIOSendByte(c);
+
+ return c;
+}
+
+int sio_puts(const char *str)
+{
+ while(*str)
+ sio_putchar(*(str++));
+
+ sio_putchar('\n');
+
+ return 1;
+}
+
+extern int bios_putchar(int c);
+extern int bios_puts(const char *str);
+
+int putchar(int c)
+{
+ switch(__stdio_direction)
+ {
+ case STDIO_DIRECTION_BIOS:
+ return bios_putchar(c);
+ break;
+ case STDIO_DIRECTION_SIO:
+ return sio_putchar(c);
+ break;
+ }
+
+ return EOF;
+}
+
+int puts(const char *str)
+{
+ switch(__stdio_direction)
+ {
+ case STDIO_DIRECTION_BIOS:
+ return bios_puts(str);
+ break;
+ case STDIO_DIRECTION_SIO:
+ return sio_puts(str);
+ break;
+ }
+
+ return EOF;
+}
+
+int fwrite(void *ptr, int size, int nmemb, FILE *f)
+{
+ if(IS_CONS_OUT(f)) // stdout or stderr
+ {
+ char *c = ptr;
+ int i;
+
+ for(i = 0; i < size; i++)
+ putchar(c[i]);
+
+ return size;
+ }
+
+ return 0;
+}
+
+int fputs(const char *str, FILE *stream)
+{
+ if(IS_CONS_OUT(stream))
+ return puts(str);
+
+ return EOF;
+}
+
+FILE *freopen(const char *path, const char *mode, FILE *stream)
+{
+ if(stream == NULL)
+ return NULL;
+
+ if(stream->used)
+ fclose(stream);
+
+ return fopen_internal(path, mode, stream);
+}
+
+void clearerr(FILE *stream)
+{
+ stream->eof = 0;
+ stream->error = 0;
+}
+
+int feof(FILE *stream)
+{
+ return stream->eof;
+}
+
+int ferror(FILE *stream)
+{
+ return stream->error;
+}
+
+int fileno(FILE *stream)
+{
+ return stream->fildes;
+}