diff options
| author | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
|---|---|---|
| committer | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-01-31 10:32:23 +0100 |
| commit | 7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch) | |
| tree | c28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/libc.c | |
| parent | a2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff) | |
| download | psxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz | |
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/libc.c')
| -rw-r--r-- | libpsx/src/libc.c | 705 |
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; +} |
