diff --git a/.gitignore b/.gitignore index be91256..0c31482 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store *.o *.img +os/ \ No newline at end of file diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..ac88534 --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,176 @@ +/*****************************************************************************/ +/* */ +/* ctype.h */ +/* */ +/* Character handling */ +/* */ +/* */ +/* */ +/* (C) 1998-2004 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _CTYPE_H +#define _CTYPE_H + + +/* The array containing character classification data */ +extern unsigned char _ctype[256]; + +/* Bits used to specify characters classes */ +#define _CT_LOWER 0x01 /* 0 - Lower case char */ +#define _CT_UPPER 0x02 /* 1 - Upper case char */ +#define _CT_DIGIT 0x04 /* 2 - Numeric digit */ +#define _CT_XDIGIT 0x08 /* 3 - Hex digit (both, lower and upper) */ +#define _CT_CNTRL 0x10 /* 4 - Control character */ +#define _CT_SPACE 0x20 /* 5 - The space character itself */ +#define _CT_OTHER_WS 0x40 /* 6 - Other whitespace ('\f', '\n', '\r', '\t' and '\v') */ +#define _CT_SPACE_TAB 0x80 /* 7 - Space or tab character */ + +/* Bit combinations */ +#define _CT_ALNUM (_CT_LOWER | _CT_UPPER | _CT_DIGIT) +#define _CT_ALPHA (_CT_LOWER | _CT_UPPER) +#define _CT_NOT_GRAPH (_CT_CNTRL | _CT_SPACE) +#define _CT_NOT_PRINT (_CT_CNTRL) +#define _CT_NOT_PUNCT (_CT_SPACE | _CT_CNTRL | _CT_DIGIT | _CT_UPPER | _CT_LOWER) +#define _CT_WS (_CT_SPACE | _CT_OTHER_WS) + +/* Character classification functions */ +int __fastcall__ isalnum (int c); +int __fastcall__ isalpha (int c); +int __fastcall__ iscntrl (int c); +int __fastcall__ isdigit (int c); +int __fastcall__ isgraph (int c); +int __fastcall__ islower (int c); +int __fastcall__ isprint (int c); +int __fastcall__ ispunct (int c); +int __fastcall__ isspace (int c); +int __fastcall__ isupper (int c); +int __fastcall__ isxdigit (int c); +#if __CC65_STD__ >= __CC65_STD_C99__ +int __fastcall__ isblank (int c); /* New in C99 */ +#endif + +int __fastcall__ toupper (int c); /* Always external */ +int __fastcall__ tolower (int c); /* Always external */ + + + +/* When inlining of known function is enabled, overload most of the above + * functions by macros. The function prototypes are again available after + * #undef'ing the macros. + * Please note that the following macros do NOT handle EOF correctly, as + * stated in the manual. If you need correct behaviour for EOF, don't + * use -Os, or #undefine the following macros. + */ +#ifdef __OPT_s__ + +#define isalnum(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_ALNUM), \ + __AX__) + +#define isalpha(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_ALPHA), \ + __AX__) + +#if __CC65_STD__ >= __CC65_STD_C99__ +#define isblank(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_SPACE_TAB), \ + __AX__) +#endif + +#define iscntrl(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_CNTRL), \ + __AX__) + +#define isdigit(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_DIGIT), \ + __AX__) + +#define isgraph(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("eor #%b", _CT_NOT_GRAPH), \ + __asm__ ("and #%b", _CT_NOT_GRAPH), \ + __AX__) + +#define islower(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_LOWER), \ + __AX__) + +#define isprint(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("eor #%b", _CT_NOT_PRINT), \ + __asm__ ("and #%b", _CT_NOT_PRINT), \ + __AX__) + +#define ispunct(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("eor #%b", _CT_NOT_PUNCT), \ + __asm__ ("and #%b", _CT_NOT_PUNCT), \ + __AX__) + +#define isspace(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_WS), \ + __AX__) + +#define isupper(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_UPPER), \ + __AX__) + +#define isxdigit(c) (__AX__ = (c), \ + __asm__ ("tay"), \ + __asm__ ("lda %v,y", _ctype), \ + __asm__ ("and #%b", _CT_XDIGIT), \ + __AX__) + +#endif + + + +/* End of ctype.h */ +#endif + + + diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 0000000..edb4a0e --- /dev/null +++ b/include/errno.h @@ -0,0 +1,81 @@ +/*****************************************************************************/ +/* */ +/* errno.h */ +/* */ +/* Error codes */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _ERRNO_H +#define _ERRNO_H + + + +/* Operating system specific error codes */ +extern unsigned char _oserror; + +/* Mapper function, don't call directly */ +void _maperrno (void); + +/* This one is called under the hood. User callable. */ +int __fastcall__ _osmaperrno (unsigned char oserror); + +/* System error codes go here */ +extern int _errno; + +/* errno must be a macro, here the mapper is called */ +#define errno (_maperrno(), _errno) + + + +/* Possible error codes */ +#define ENOENT 1 /* No such file or directory */ +#define ENOMEM 2 /* Out of memory */ +#define EACCES 3 /* Permission denied */ +#define ENODEV 4 /* No such device */ +#define EMFILE 5 /* Too many open files */ +#define EBUSY 6 /* Device or resource busy */ +#define EINVAL 7 /* Invalid argument */ +#define ENOSPC 8 /* No space left on device */ +#define EEXIST 9 /* File exists */ +#define EAGAIN 10 /* Try again */ +#define EIO 11 /* I/O error */ +#define EINTR 12 /* Interrupted system call */ +#define ENOSYS 13 /* Function not implemented */ +#define ESPIPE 14 /* Illegal seek */ +#define ERANGE 15 /* Range error */ +#define EUNKNOWN 16 /* Unknown OS specific error */ + + + +#endif + + + diff --git a/include/limits.h b/include/limits.h new file mode 100644 index 0000000..d02d52d --- /dev/null +++ b/include/limits.h @@ -0,0 +1,72 @@ +/*****************************************************************************/ +/* */ +/* limits.h */ +/* */ +/* Sizes of integer types */ +/* */ +/* */ +/* */ +/* (C) 1998-2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _LIMITS_H +#define _LIMITS_H + + + +#define CHAR_BIT 8 + +#define SCHAR_MIN ((signed char) 0x80) +#define SCHAR_MAX 127 + +#define UCHAR_MAX 255 + +#define CHAR_MIN 0 +#define CHAR_MAX 255 + +#define SHRT_MIN ((short) 0x8000) +#define SHRT_MAX 32767 + +#define USHRT_MAX 65535U + +#define INT_MIN ((int) 0x8000) +#define INT_MAX 32767 + +#define UINT_MAX 65535U + +#define LONG_MAX 2147483647L +#define LONG_MIN ((long) 0x80000000) + +#define ULONG_MAX 4294967295UL + + + +/* End of limits.h */ +#endif + + + diff --git a/include/stdarg.h b/include/stdarg.h new file mode 100644 index 0000000..4fd822b --- /dev/null +++ b/include/stdarg.h @@ -0,0 +1,57 @@ +/*****************************************************************************/ +/* */ +/* stdarg.h */ +/* */ +/* Variable arguments */ +/* */ +/* */ +/* */ +/* (C) 1998-2004 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _STDARG_H +#define _STDARG_H + + + +typedef unsigned char* va_list; + +#define va_start(ap, fix) ap = ((va_list)&(fix)) +#define va_arg(ap,type) (*(type*)(ap -= ((sizeof (type) + 1) & ~1))) +#if __CC65_STD__ >= __CC65_STD_C99__ +#define va_copy(dest, src) ((dest)=(src)) +#endif +#define va_end(ap) + + + +/* End of stdarg.h */ +#endif + + + + diff --git a/include/stdbool.h b/include/stdbool.h new file mode 100644 index 0000000..638d35a --- /dev/null +++ b/include/stdbool.h @@ -0,0 +1,53 @@ +/*****************************************************************************/ +/* */ +/* stdbool.h */ +/* */ +/* C99 Boolean definitions */ +/* */ +/* */ +/* */ +/* (C) 2002 Greg King */ +/* */ +/* */ +/* This software is provided "as-is," without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment, in the product's documentation, */ +/* would be appreciated, but is not required. */ +/* 2. Alterred source versions must be marked plainly as such, */ +/* and must not be misrepresented as being the original software. */ +/* 3. This notice may not be removed or alterred */ +/* from any source distribution. */ +/*****************************************************************************/ + + + +#ifndef _STDBOOL_H +#define _STDBOOL_H + + + +#define bool _Bool +typedef unsigned char _Bool; + +/* Standard test-results. */ +#define false 0 +#define true 1 + +/* All three names are macroes. */ +#define __bool_true_false_are_defined 1 + + + +/* End of stdbool.h */ +#endif + + + diff --git a/include/stddef.h b/include/stddef.h new file mode 100644 index 0000000..eff0c55 --- /dev/null +++ b/include/stddef.h @@ -0,0 +1,70 @@ +/*****************************************************************************/ +/* */ +/* stddef.h */ +/* */ +/* Common definitions */ +/* */ +/* */ +/* */ +/* (C) 1998-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _STDDEF_H +#define _STDDEF_H + + + +/* Standard data types */ +#ifndef _HAVE_ptrdiff_t +#define _HAVE_ptrdiff_t +typedef int ptrdiff_t; +#endif +#ifndef _HAVE_wchar_t +#define _HAVE_wchar_t +typedef char wchar_t; +#endif +#ifndef _HAVE_size_t +#define _HAVE_size_t +typedef unsigned size_t; +#endif + +/* NULL pointer */ +#ifndef _HAVE_NULL +#define NULL 0 +#define _HAVE_NULL +#endif + +/* offsetof macro */ +#define offsetof(type, member) (size_t) (&((type*) 0)->member) + + + +/* End of stddef.h */ +#endif + + + diff --git a/include/stdint.h b/include/stdint.h new file mode 100644 index 0000000..0053a9b --- /dev/null +++ b/include/stdint.h @@ -0,0 +1,144 @@ +/*****************************************************************************/ +/* */ +/* stdint.h */ +/* */ +/* Standard integer types */ +/* */ +/* */ +/* */ +/* (C) 2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +/* Note: This file is not fully ISO 9899-1999 compliant because cc65 lacks + * a 64 bit data types. The declarations have been adjusted accordingly. + */ + + + +#ifndef _STDINT_H +#define _STDINT_H + + + +/* Exact-width integer types */ +typedef signed char int8_t; +typedef int int16_t; +typedef long int32_t; +typedef unsigned char uint8_t; +typedef unsigned uint16_t; +typedef unsigned long uint32_t; + +#define INT8_MIN ((int8_t) 0x80) +#define INT8_MAX ((int8_t) 0x7F) +#define INT16_MIN ((int16_t) 0x8000) +#define INT16_MAX ((int16_t) 0x7FFF) +#define INT32_MIN ((int32_t) 0x80000000) +#define INT32_MAX ((int32_t) 0x7FFFFFFF) +#define UINT8_MAX ((uint8_t) 0xFF) +#define UINT16_MAX ((uint16_t) 0xFFFF) +#define UINT32_MAX ((uint32_t) 0xFFFFFFFF) + +/* Minimum-width integer types */ +typedef signed char int_least8_t; +typedef int int_least16_t; +typedef long int_least32_t; +typedef unsigned char uint_least8_t; +typedef unsigned uint_least16_t; +typedef unsigned long uint_least32_t; + +#define INT_LEAST8_MIN ((int_least8_t) 0x80) +#define INT_LEAST8_MAX ((int_least8_t) 0x7F) +#define INT_LEAST16_MIN ((int_least16_t) 0x8000) +#define INT_LEAST16_MAX ((int_least16_t) 0x7FFF) +#define INT_LEAST32_MIN ((int_least32_t) 0x80000000) +#define INT_LEAST32_MAX ((int_least32_t) 0x7FFFFFFF) +#define UINT_LEAST8_MAX ((uint_least8_t) 0xFF) +#define UINT_LEAST16_MAX ((uint_least16_t) 0xFFFF) +#define UINT_LEAST32_MAX ((uint_least32_t) 0xFFFFFFFF) + +/* Fastest minimum-width integer types */ +typedef signed char int_fast8_t; +typedef int int_fast16_t; +typedef long int_fast32_t; +typedef unsigned char uint_fast8_t; +typedef unsigned uint_fast16_t; +typedef unsigned long uint_fast32_t; + +#define INT_FAST8_MIN ((int_fast8_t) 0x80) +#define INT_FAST8_MAX ((int_fast8_t) 0x7F) +#define INT_FAST16_MIN ((int_fast16_t) 0x8000) +#define INT_FAST16_MAX ((int_fast16_t) 0x7FFF) +#define INT_FAST32_MIN ((int_fast32_t) 0x80000000) +#define INT_FAST32_MAX ((int_fast32_t) 0x7FFFFFFF) +#define UINT_FAST8_MAX ((uint_fast8_t) 0xFF) +#define UINT_FAST16_MAX ((uint_fast16_t) 0xFFFF) +#define UINT_FAST32_MAX ((uint_fast32_t) 0xFFFFFFFF) + +/* Integer types capable of holding object pointers */ +typedef int intptr_t; +typedef unsigned uintptr_t; + +#define INTPTR_MIN ((intptr_t)0x8000) +#define INTPTR_MAX ((intptr_t)0x7FFF) +#define UINTPTR_MAX ((uintptr_t) 0xFFFF) + +/* Greatest width integer types */ +typedef long intmax_t; +typedef unsigned long uintmax_t; + +#define INTMAX_MIN ((intmax_t) 0x80000000) +#define INTMAX_MAX ((intmax_t) 0x7FFFFFFF) +#define UINTMAX_MAX ((uintmax_t) 0xFFFFFFFF) + +/* Limits of other integer types */ +#define PTRDIFF_MIN ((int) 0x8000) +#define PTRDIFF_MAX ((int) 0x7FFF) + +#define SIG_ATOMIC_MIN ((unsigned char) 0x00) +#define SIG_ATOMIC_MAX ((unsigned char) 0xFF) + +#define SIZE_MAX 0xFFFF + +/* Macros for minimum width integer constants */ +#define INT8_C(c) c +#define INT16_C(c) c +#define INT32_C(c) c##L +#define UINT8_C(c) c##U +#define UINT16_C(c) c##U +#define UINT32_C(c) c##UL + +/* Macros for greatest width integer constants */ +#define INTMAX_C(c) c##L +#define UINTMAX_C(c) c##UL + + + +/* End of stdint.h */ +#endif + + + diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..f160160 --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,150 @@ +/*****************************************************************************/ +/* */ +/* stdio.h */ +/* */ +/* Input/output */ +/* */ +/* */ +/* */ +/* (C) 1998-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _STDIO_H +#define _STDIO_H + + + +#ifndef _STDDEF_H +# include +#endif +#ifndef _STDARG_H +# include +#endif + + + +/* Types */ +typedef struct _FILE FILE; +typedef unsigned long fpos_t; + +/* Standard file descriptors */ +extern FILE* stdin; +extern FILE* stdout; +extern FILE* stderr; + +/* Standard defines */ +#define _IOFBF 0 +#define _IOLBF 1 +#define _IONBF 2 +#define BUFSIZ 256 +#define EOF -1 +#define FOPEN_MAX 8 +#define SEEK_CUR 0 +#define SEEK_END 1 +#define SEEK_SET 2 +#define TMP_MAX 256 + +/* Standard defines that are platform dependent */ +#if defined(__APPLE2__) || defined(__APPLE2ENH__) +# define FILENAME_MAX (64+1) +#elif defined(__ATARI__) +# define FILENAME_MAX (12+1) +#elif defined(__LUNIX__) +# define FILENAME_MAX (80+1) +#else +# define FILENAME_MAX (16+1) +#endif +#define L_tmpnam FILENAME_MAX + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +/* Functions */ +void __fastcall__ clearerr (FILE* f); +int __fastcall__ fclose (FILE* f); +int __fastcall__ feof (FILE* f); +int __fastcall__ ferror (FILE* f); +int __fastcall__ fflush (FILE* f); +int __fastcall__ fgetc (FILE* f); +char* __fastcall__ fgets (char* buf, size_t size, FILE* f); +FILE* __fastcall__ fopen (const char* name, const char* mode); +int fprintf (FILE* f, const char* format, ...); +int __fastcall__ fputc (int c, FILE* f); +int __fastcall__ fputs (const char* s, FILE* f); +size_t __fastcall__ fread (void* buf, size_t size, size_t count, FILE* f); +FILE* __fastcall__ freopen (const char* name, const char* mode, FILE* f); +size_t __fastcall__ fwrite (const void* buf, size_t size, size_t count, FILE* f); +int __fastcall__ fgetpos (FILE* f, fpos_t *pos); +int __fastcall__ fsetpos (FILE* f, const fpos_t* pos); +long __fastcall__ ftell (FILE* f); +int __fastcall__ fseek (FILE* f, long offset, int whence); +void __fastcall__ rewind (FILE *f); +int __fastcall__ getchar (void); +char* __fastcall__ gets (char* s); +void __fastcall__ perror (const char* s); +int printf (const char* format, ...); +int __fastcall__ putchar (int c); +int __fastcall__ puts (const char* s); +int __fastcall__ remove (const char* name); +int __fastcall__ rename (const char* oldname, const char* newname); +int snprintf (char* buf, size_t size, const char* format, ...); +int sprintf (char* buf, const char* format, ...); +int __fastcall__ ungetc (int c, FILE* f); +int __fastcall__ vfprintf (FILE* f, const char* format, va_list ap); +int __fastcall__ vprintf (const char* format, va_list ap); +int __fastcall__ vsnprintf (char* buf, size_t size, const char* format, va_list ap); +int __fastcall__ vsprintf (char* buf, const char* format, va_list ap); + +int scanf (const char* format, ...); +int fscanf (FILE* f, const char* format, ...); +int sscanf (const char* s, const char* format, ...); +int __fastcall__ vscanf (const char* format, va_list ap); +int __fastcall__ vsscanf (const char* s, const char* format, va_list ap); +int __fastcall__ vfscanf (FILE* f, const char* format, va_list ap); + +#if __CC65_STD__ == __CC65_STD_CC65__ +FILE* __fastcall__ fdopen (int fd, const char* mode); /* Unix */ +int __fastcall__ fileno (FILE* f); /* Unix */ +#endif +void __fastcall__ _poserror (const char* msg); /* cc65 */ + +/* Masking macros for some functions */ +#define getc(f) fgetc (f) /* ANSI */ +#define putc(c, f) fputc (c, f) /* ANSI */ + + + +/* End of stdio.h */ +#endif + + + diff --git a/include/stdlib.h b/include/stdlib.h new file mode 100644 index 0000000..a58d29c --- /dev/null +++ b/include/stdlib.h @@ -0,0 +1,136 @@ +/*****************************************************************************/ +/* */ +/* stdlib.h */ +/* */ +/* General utilities */ +/* */ +/* */ +/* */ +/* (C) 1998-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _STDLIB_H +#define _STDLIB_H + + + +/* size_t is needed */ +#ifndef _HAVE_size_t +typedef unsigned size_t; +#define _HAVE_size_t +#endif + +/* Standard exit codes */ +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +/* Return type of the div function */ +typedef struct { + int rem; + int quot; +} div_t; + +/* Return type of the ldiv function (which currently doesn't exist) */ +typedef struct { + long rem; + long quot; +} ldiv_t; + +/* Memory management */ +void* __fastcall__ malloc (size_t size); +void* __fastcall__ calloc (size_t count, size_t size); +void* __fastcall__ realloc (void* block, size_t size); +void __fastcall__ free (void* block); + +/* Non standard memory management functions */ + +#if __CC65_STD__ == __CC65_STD_CC65__ +int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size); +/* Allocate a block of memory with the given "size", which is aligned to a + * memory address that is a multiple of "alignment". "alignment" MUST NOT be + * zero, and MUST be a power of two; otherwise, this function will return + * EINVAL. The function returns ENOMEM if not enough memory is available + * to satisfy the request. "memptr" must point to a variable; that variable + * will return the address of the allocated memory. Use free() to release that + * allocated block. + */ +#endif + +void __fastcall__ _heapadd (void* mem, size_t size); +/* Add a block to the heap */ + +size_t __fastcall__ _heapblocksize (const void* block); +/* Return the size of an allocated block */ + +size_t __fastcall__ _heapmemavail (void); +/* Return the total free heap space */ + +size_t __fastcall__ _heapmaxavail (void); +/* Return the size of the largest free block on the heap */ + + +/* Random numbers */ +#define RAND_MAX 0x7FFF +int rand (void); +void __fastcall__ srand (unsigned seed); +void _randomize (void); /* Non-standard */ + +/* Other standard stuff */ +void abort (void); +int __fastcall__ abs (int val); +long __fastcall__ labs (long val); +int __fastcall__ atoi (const char* s); +long __fastcall__ atol (const char* s); +int __fastcall__ atexit (void (*exitfunc) (void)); +void* __fastcall__ bsearch (const void* key, const void* base, size_t n, + size_t size, int (*cmp) (const void*, const void*)); +div_t __fastcall__ div (int numer, int denom); +void __fastcall__ exit (int ret); +char* __fastcall__ getenv (const char* name); +void __fastcall__ qsort (void* base, size_t count, size_t size, + int (*compare) (const void*, const void*)); +long __fastcall__ strtol (const char* nptr, char** endptr, int base); +unsigned long __fastcall__ strtoul (const char* nptr, char** endptr, int base); +int __fastcall__ system (const char* s); + +/* Non-ANSI functions */ +void __fastcall__ _swap (void* p, void* q, size_t size); +#if __CC65_STD__ == __CC65_STD_CC65__ +char* __fastcall__ itoa (int val, char* buf, int radix); +char* __fastcall__ utoa (unsigned val, char* buf, int radix); +char* __fastcall__ ltoa (long val, char* buf, int radix); +char* __fastcall__ ultoa (unsigned long val, char* buf, int radix); +int __fastcall__ putenv (char* s); +#endif + + + +/* End of stdlib.h */ +#endif + + + diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..7eb6995 --- /dev/null +++ b/include/string.h @@ -0,0 +1,95 @@ +/*****************************************************************************/ +/* */ +/* string.h */ +/* */ +/* String handling */ +/* */ +/* */ +/* */ +/* (C) 1998-2008 Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef _STRING_H +#define _STRING_H + + + +#include + + + +char* __fastcall__ strcat (char* dest, const char* src); +char* __fastcall__ strchr (const char* s, int c); +int __fastcall__ strcmp (const char* s1, const char* s2); +int __fastcall__ strcoll (const char* s1, const char* s2); +char* __fastcall__ strcpy (char* dest, const char* src); +size_t __fastcall__ strcspn (const char* s1, const char* s2); +char* __fastcall__ strerror (int errcode); +size_t __fastcall__ strlen (const char* s); +char* __fastcall__ strncat (char* s1, const char* s2, size_t count); +int __fastcall__ strncmp (const char* s1, const char* s2, size_t count); +char* __fastcall__ strncpy (char* dest, const char* src, size_t count); +char* __fastcall__ strrchr (const char* s, int c); +size_t __fastcall__ strspn (const char* s1, const char* s2); +char* __fastcall__ strstr (const char* str, const char* substr); +char* __fastcall__ strtok (char* s1, const char* s2); +size_t __fastcall__ strxfrm (char* s1, const char* s2, size_t count); +void* __fastcall__ memchr (const void* mem, int c, size_t count); +int __fastcall__ memcmp (const void* p1, const void* p2, size_t count); +void* __fastcall__ memcpy (void* dest, const void* src, size_t count); +void* __fastcall__ memmove (void* dest, const void* src, size_t count); +void* __fastcall__ memset (void* s, int c, size_t count); + +/* The following is an internal function, the compiler will replace memset + * with it if the fill value is zero. Never use this one directly! + */ +void* __fastcall__ _bzero (void* ptr, size_t n); + +/* Non standard: */ +#if __CC65_STD__ == __CC65_STD_CC65__ +void __fastcall__ bzero (void* ptr, size_t n); /* BSD */ +char* __fastcall__ strdup (const char* s); /* SYSV/BSD */ +int __fastcall__ stricmp (const char* s1, const char* s2); /* DOS/Windows */ +int __fastcall__ strcasecmp (const char* s1, const char* s2); /* Same for Unix */ +int __fastcall__ strnicmp (const char* s1, const char* s2, size_t count); /* DOS/Windows */ +int __fastcall__ strncasecmp (const char* s1, const char* s2, size_t count); /* Same for Unix */ +char* __fastcall__ strlwr (char* s); +char* __fastcall__ strlower (char* s); +char* __fastcall__ strupr (char* s); +char* __fastcall__ strupper (char* s); +#endif + +const char* __fastcall__ _stroserror (unsigned char errcode); +/* Map an operating system error number to an error message. */ + + + +/* End of string.h */ +#endif + + + diff --git a/lib/asminc/ctype.inc b/lib/asminc/ctype.inc new file mode 100644 index 0000000..2e29c72 --- /dev/null +++ b/lib/asminc/ctype.inc @@ -0,0 +1,29 @@ +; +; Definitions for the character type tables +; +; Ullrich von Bassewitz, 08.09.2001 +; + +; Make the __ctype table an exported/imported symbol + + .global __ctype + +; Define bitmapped constants for the table entries + +CT_NONE = $00 ; Nothing special +CT_LOWER = $01 ; 0 - Lower case char +CT_UPPER = $02 ; 1 - Upper case char +CT_DIGIT = $04 ; 2 - Numeric digit +CT_XDIGIT = $08 ; 3 - Hex digit (both, lower and upper) +CT_CTRL = $10 ; 4 - Control character +CT_SPACE = $20 ; 5 - The space character itself +CT_OTHER_WS = $40 ; 6 - Other whitespace ('\f', '\n', '\r', '\t' and '\v') +CT_SPACE_TAB = $80 ; 7 - Space or tab character + +; Combined stuff +CT_ALNUM = (CT_LOWER | CT_UPPER | CT_DIGIT) +CT_ALPHA = (CT_LOWER | CT_UPPER) +CT_CTRL_SPACE = (CT_CTRL | CT_SPACE) +CT_NOT_PUNCT = (CT_SPACE | CT_CTRL | CT_DIGIT | CT_UPPER | CT_LOWER) + + diff --git a/lib/common/Makefile b/lib/common/Makefile index b4a5617..3c25b6f 100644 --- a/lib/common/Makefile +++ b/lib/common/Makefile @@ -35,11 +35,17 @@ CFLAGS = -Osir -g -T -t $(SYS) --forget-inc-paths -I . -I ../../include --cpu $( %.lst : %.s @$(AS) $(AFLAGS) -l -o /dev/null $< + #-------------------------------------------------------------------------- # Object files # From C source-files -# C_OBJS = _afailed.o \ + C_OBJS = strtok.o \ + strtol.o \ + strtoul.o \ + strxfrm.o + # strftime.o \ +#_afailed.o \ # _hextab.o \ # _poserror.o \ # _scanf.o \ @@ -70,134 +76,137 @@ CFLAGS = -Osir -g -T -t $(SYS) --forget-inc-paths -I . -I ../../include --cpu $( # realloc.o \ # rewind.o \ # sleep.o \ -# strftime.o \ -# strtok.o \ -# strtol.o \ -# strtoul.o \ -# strxfrm.o \ + # system.o \ # timezone.o # From assembly source-files -S_OBJS = zerobss.o copydata.o -#_cwd.o \ - # _environ.o \ - # _fdesc.o \ - # _file.o \ - # _fopen.o \ - # _heap.o \ - # _heapadd.o \ - # _heapblocksize.o\ - # _heapmaxavail.o \ - # _heapmemavail.o \ - # _oserror.o \ - # _printf.o \ - # _seterrno.o \ - # _swap.o \ - # _sys.o \ - # abs.o \ - # atexit.o \ - # atoi.o \ - # calloc.o \ - # chdir.o \ - # copydata.o \ - # creat.o \ - # ctime.o \ - # divt.o \ - # errno.o \ - # fclose.o \ - # fmisc.o \ - # fopen.o \ - # fprintf.o \ - # fread.o \ - # free.o \ - # fscanf.o \ - # fwrite.o \ - # getcpu.o \ - # getcwd.o \ - # getenv.o \ - # interrupt.o \ - # isalnum.o \ - # isalpha.o \ - # isblank.o \ - # iscntrl.o \ - # isdigit.o \ - # isgraph.o \ - # islower.o \ - # isprint.o \ - # ispunct.o \ - # isspace.o \ - # isupper.o \ - # isxdigit.o \ - # itoa.o \ - # labs.o \ - # longjmp.o \ - # ltoa.o \ - # malloc.o \ - # maperrno.o \ - # memchr.o \ - # memcmp.o \ - # memcpy.o \ - # memmove.o \ - # memset.o \ - # mkdir.o \ - # modfree.o \ - # modload.o \ - # oserrcheck.o \ - # printf.o \ - # putchar.o \ - # putenv.o \ - # rand.o \ - # raise.o \ - # remove.o \ - # rename.o \ - # rmdir.o \ - # scanf.o \ - # searchenv.o \ - # setjmp.o \ - # signal.o \ - # sigtable.o \ - # snprintf.o \ - # sprintf.o \ - # sscanf.o \ - # strcat.o \ - # strchr.o \ - # strcmp.o \ - # strcoll.o \ - # strcpy.o \ - # strcspn.o \ - # strdup.o \ - # strerror.o \ - # stricmp.o \ - # strlen.o \ - # strlower.o \ - # strncat.o \ - # strncmp.o \ - # strncpy.o \ - # strnicmp.o \ - # stroserr.o \ - # strpbrk.o \ - # strrchr.o \ - # strspn.o \ - # strstr.o \ - # strtoimax.o \ - # strtoumax.o \ - # strupper.o \ - # time.o \ - # tolower.o \ - # toupper.o \ - # uname.o \ - # ungetc.o \ - # unlink.o \ - # utscopy.o \ - # vfprintf.o \ - # vfscanf.o \ - # vprintf.o \ - # vscanf.o \ - # vsnprintf.o \ - # vsprintf.o \ - # vsscanf.o \ - # zerobss.o +S_OBJS = zerobss.o \ + copydata.o \ + abs.o \ + atoi.o \ + isalnum.o \ + isalpha.o \ + isblank.o \ + iscntrl.o \ + isdigit.o \ + isgraph.o \ + islower.o \ + isprint.o \ + ispunct.o \ + isspace.o \ + isupper.o \ + isxdigit.o \ + itoa.o \ + memchr.o \ + memcmp.o \ + memcpy.o \ + memmove.o \ + memset.o \ +# mkdir.o \ + strcat.o \ + strchr.o \ + strcmp.o \ + strcoll.o \ + strcpy.o \ + strcspn.o \ + strdup.o \ + strerror.o \ + stricmp.o \ + strlen.o \ + strlower.o \ + strncat.o \ + strncmp.o \ + strncpy.o \ + strnicmp.o \ + stroserr.o \ + strpbrk.o \ + strrchr.o \ + strspn.o \ + strstr.o \ + strtoimax.o \ + strtoumax.o \ + strupper.o \ + tolower.o \ + toupper.o + # _cwd.o \ + # _environ.o \ + # _fdesc.o \ + # _file.o \ + # _fopen.o \ + # _heap.o \ + # _heapadd.o \ + # _heapblocksize.o\ + # _heapmaxavail.o \ + # _heapmemavail.o \ + # _oserror.o \ + # _printf.o \ + # _seterrno.o \ + # _swap.o \ + # _sys.o \ + + # atexit.o \ + + # calloc.o \ + # chdir.o \ + # copydata.o \ + # creat.o \ + # ctime.o \ + # divt.o \ + # errno.o \ + # fclose.o \ + # fmisc.o \ + # fopen.o \ + # fprintf.o \ + # fread.o \ + # free.o \ + # fscanf.o \ + # fwrite.o \ + # getcpu.o \ + # getcwd.o \ + # getenv.o \ + # interrupt.o \ + + # labs.o \ + # longjmp.o \ + # ltoa.o \ + # malloc.o \ + # maperrno.o \ + + # modfree.o \ + # modload.o \ + # oserrcheck.o \ + # printf.o \ + # putchar.o \ + # putenv.o \ + # rand.o \ + # raise.o \ + # remove.o \ + # rename.o \ + # rmdir.o \ + # scanf.o \ + # searchenv.o \ + # setjmp.o \ + # signal.o \ + # sigtable.o \ + # snprintf.o \ + # sprintf.o \ + # sscanf.o \ + + # time.o \ + + # uname.o \ + # ungetc.o \ + # unlink.o \s + # utscopy.o \ + # vfprintf.o \ + # vfscanf.o \ + # vprintf.o \ + # vscanf.o \ + # vsnprintf.o \ + # vsprintf.o \ + # vsscanf.o \ + # zerobss.o #-------------------------------------------------------------------------- diff --git a/lib/common/abs.s b/lib/common/abs.s new file mode 100644 index 0000000..273ec1c --- /dev/null +++ b/lib/common/abs.s @@ -0,0 +1,16 @@ +; +; Ullrich von Bassewitz, 17.06.1998 +; +; int abs (int x); +; + + .export _abs + .import negax + +_abs: cpx #$00 ; test hi byte + bpl L1 + jmp negax ; Negate if negative +L1: rts + + + diff --git a/lib/common/atoi.s b/lib/common/atoi.s new file mode 100644 index 0000000..d55ddb9 --- /dev/null +++ b/lib/common/atoi.s @@ -0,0 +1,138 @@ +; +; Ullrich von Bassewitz, 05.06.1998 +; +; int atoi (const char* s); +; long atol (const char* s); +; + + .export _atoi, _atol + .import negeax, __ctype + .importzp sreg, ptr1, ptr2, tmp1 + + .include "ctype.inc" + +; +; Conversion routine (32 bit) +; + +_atoi: +_atol: sta ptr1 ; Store s + stx ptr1+1 + ldy #0 + sty ptr2 + sty ptr2+1 ; initial value (32 bit) + sty sreg + sty sreg+1 + +; Skip whitespace + +L1: lda (ptr1),y + tax + lda __ctype,x ; get character classification + and #CT_SPACE_TAB ; tab or space? + beq L2 ; jump if no + iny + bne L1 + inc ptr1+1 + bne L1 ; branch always + +; Check for a sign. The character is in X + +L2: txa ; get char + ldx #0 ; flag: positive + cmp #'+' ; ### portable? + beq L3 + cmp #'-' ; ### portable? + bne L5 + dex ; flag: negative +L3: iny + bne L5 + inc ptr1+1 + +; Store the sign flag and setup for conversion + +L5: stx tmp1 ; remember sign flag + +L6: lda (ptr1),y ; get next char + tax + lda __ctype,x ; get character classification + and #$04 ; digit? + beq L8 ; done + +; Multiply ptr2 (the converted value) by 10 + + jsr mul2 ; * 2 + + lda sreg+1 + pha + lda sreg + pha + lda ptr2+1 + pha + lda ptr2 + pha ; Save value + + jsr mul2 ; * 4 + jsr mul2 ; * 8 + + clc + pla + adc ptr2 + sta ptr2 + pla + adc ptr2+1 + sta ptr2+1 + pla + adc sreg + sta sreg + pla + adc sreg+1 + sta sreg+1 ; x*2 + x*8 = x*10 + +; Get the character back and add it + + txa ; get char back + sec + sbc #'0' ; make numeric value + clc + adc ptr2 + sta ptr2 + bcc L7 + inc ptr2+1 + bne L7 + inc sreg + bne L7 + inc sreg+1 + +; Next character + +L7: iny + bne L6 + inc ptr1+1 + bne L6 + +; Conversion done. Load the low 16 bit into A/X + +L8: lda ptr2 + ldx ptr2+1 + +; Negate the value if necessary, otherwise we're done + + ldy tmp1 ; sign + beq L9 ; Branch if positive + +; Negate the 32 bit value in ptr2/sreg + + jmp negeax + +; +; Helper functions +; + +mul2: asl ptr2 + rol ptr2+1 + rol sreg + rol sreg+1 ; * 2 +L9: rts + + diff --git a/lib/common/isalnum.s b/lib/common/isalnum.s new file mode 100644 index 0000000..26fd7a2 --- /dev/null +++ b/lib/common/isalnum.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isalnum (int c); +; + + .export _isalnum + .include "ctype.inc" + +_isalnum: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_ALNUM ; Mask character/digit bits + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isalpha.s b/lib/common/isalpha.s new file mode 100644 index 0000000..624dec6 --- /dev/null +++ b/lib/common/isalpha.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isalpha (int c); +; + + .export _isalpha + .include "ctype.inc" + +_isalpha: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_ALPHA ; Mask character bits + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isblank.s b/lib/common/isblank.s new file mode 100644 index 0000000..6da645a --- /dev/null +++ b/lib/common/isblank.s @@ -0,0 +1,23 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isblank (int c); +; +; cc65 (and GNU) extension. +; + + .export _isblank + .include "ctype.inc" + +_isblank: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_SPACE_TAB ; Mask blank bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/iscntrl.s b/lib/common/iscntrl.s new file mode 100644 index 0000000..d94fddc --- /dev/null +++ b/lib/common/iscntrl.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int iscntrl (int c); +; + + .export _iscntrl + .include "ctype.inc" + +_iscntrl: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_CTRL ; Mask control character bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isdigit.s b/lib/common/isdigit.s new file mode 100644 index 0000000..339fef6 --- /dev/null +++ b/lib/common/isdigit.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isdigit (int c); +; + + .export _isdigit + .include "ctype.inc" + +_isdigit: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_DIGIT ; Mask digit bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isgraph.s b/lib/common/isgraph.s new file mode 100644 index 0000000..e52ae34 --- /dev/null +++ b/lib/common/isgraph.s @@ -0,0 +1,22 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isgraph (int c); +; + + .export _isgraph + .include "ctype.inc" + +_isgraph: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + eor #CT_CTRL_SPACE ; NOT control and NOT space + and #CT_CTRL_SPACE ; Mask character bits + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/islower.s b/lib/common/islower.s new file mode 100644 index 0000000..0078366 --- /dev/null +++ b/lib/common/islower.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int islower (int c); +; + + .export _islower + .include "ctype.inc" + +_islower: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_LOWER ; Mask lower char bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isprint.s b/lib/common/isprint.s new file mode 100644 index 0000000..956b54b --- /dev/null +++ b/lib/common/isprint.s @@ -0,0 +1,22 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isprint (int c); +; + + .export _isprint + .include "ctype.inc" + +_isprint: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + eor #CT_CTRL ; NOT a control char + and #CT_CTRL ; Mask control char bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/ispunct.s b/lib/common/ispunct.s new file mode 100644 index 0000000..380cf38 --- /dev/null +++ b/lib/common/ispunct.s @@ -0,0 +1,22 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int ispunct (int c); +; + + .export _ispunct + .include "ctype.inc" + +_ispunct: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + eor #CT_NOT_PUNCT ; NOT (space | control | digit | alpha) + and #CT_NOT_PUNCT ; Mask relevant bits + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isspace.s b/lib/common/isspace.s new file mode 100644 index 0000000..67530c9 --- /dev/null +++ b/lib/common/isspace.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isspace (int c); +; + + .export _isspace + .include "ctype.inc" + +_isspace: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #(CT_SPACE | CT_OTHER_WS) ; Mask space bits + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isupper.s b/lib/common/isupper.s new file mode 100644 index 0000000..b9d53a6 --- /dev/null +++ b/lib/common/isupper.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isupper (int c); +; + + .export _isupper + .include "ctype.inc" + +_isupper: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_UPPER ; Mask upper char bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/isxdigit.s b/lib/common/isxdigit.s new file mode 100644 index 0000000..50146e8 --- /dev/null +++ b/lib/common/isxdigit.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int isxdigit (int c); +; + + .export _isxdigit + .include "ctype.inc" + +_isxdigit: + cpx #$00 ; Char range ok? + bne @L1 ; Jump if no + tay + lda __ctype,y ; Get character classification + and #CT_XDIGIT ; Mask xdigit bit + rts + +@L1: lda #$00 ; Return false + tax + rts + diff --git a/lib/common/itoa.s b/lib/common/itoa.s new file mode 100644 index 0000000..37544c4 --- /dev/null +++ b/lib/common/itoa.s @@ -0,0 +1,146 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; char* itoa (int value, char* s, int radix); +; char* utoa (unsigned value, char* s, int radix); +; + + .export _itoa, _utoa + .import addysp1 + .import __hextab + .importzp sp, sreg, ptr2, ptr3, tmp1 + +.rodata +specval: + .byte '-', '3', '2', '7', '6', '8', 0 +.code + +; +; Common subroutine to pop the parameters and put them into core +; + +dopop: sta tmp1 ; will loose high byte + ldy #0 + lda (sp),y + sta ptr2 + sta ptr3 + iny + lda (sp),y + sta ptr2+1 + sta ptr3+1 + iny + lda (sp),y + sta sreg + iny + lda (sp),y + sta sreg+1 + jmp addysp1 ; Bump stack pointer + +; +; itoa +; + +_itoa: jsr dopop ; pop the arguments + +; We must handle $8000 in a special way, since it is the only negative +; number that has no positive 16-bit counterpart + + ldy tmp1 ; get radix + cpy #10 + bne utoa + cmp #$00 + bne L2 + cpx #$80 + bne L2 + + ldy #6 +L1: lda specval,y ; copy -32768 + sta (ptr2),y + dey + bpl L1 + jmp L10 + +; Check if the value is negative. If so, write a - sign and negate the +; number. + +L2: lda sreg+1 ; get high byte + bpl utoa + lda #'-' + ldy #0 + sta (ptr2),y ; store sign + inc ptr2 + bne L3 + inc ptr2+1 + +L3: lda sreg + eor #$FF + clc + adc #$01 + sta sreg + lda sreg+1 + eor #$FF + adc #$00 + sta sreg+1 + jmp utoa + +; +; utoa +; + +_utoa: jsr dopop ; pop the arguments + +; Convert to string by dividing and push the result onto the stack + +utoa: lda #$00 + pha ; sentinel + +; Divide sreg/tmp1 -> sreg, remainder in a + +L5: ldy #16 ; 16 bit + lda #0 ; remainder +L6: asl sreg + rol sreg+1 + rol a + cmp tmp1 + bcc L7 + sbc tmp1 + inc sreg +L7: dey + bne L6 + + tay ; get remainder into y + lda __hextab,y ; get hex character + pha ; save char value on stack + + lda sreg + ora sreg+1 + bne L5 + +; Get the characters from the stack into the string + + ldy #0 +L9: pla + sta (ptr2),y + beq L10 ; jump if sentinel + iny + bne L9 ; jump always + +; Done! Return the target string + +L10: lda ptr3 + ldx ptr3+1 + rts + + + + + + + + + + + + + + diff --git a/lib/common/memchr.s b/lib/common/memchr.s new file mode 100644 index 0000000..c455637 --- /dev/null +++ b/lib/common/memchr.s @@ -0,0 +1,57 @@ +; +; Ullrich von Bassewitz, 2003-05-05 +; +; void* __fastcall__ memchr (const void* p, int c, size_t n); +; + + .export _memchr + .import popax, return0 + .importzp ptr1, ptr2 + + +.proc _memchr + + eor #$FF + sta ptr2 + txa + eor #$FF + sta ptr2+1 ; Save ones complement of n + jsr popax ; get c + pha + jsr popax ; get p + sta ptr1 + stx ptr1+1 + + ldy #$00 + pla ; Get c + ldx ptr2 ; Use X as low counter byte + +L1: inx + beq L3 +L2: cmp (ptr1),y + beq found + iny + bne L1 + inc ptr1+1 + bne L1 ; Branch always + +L3: inc ptr2+1 ; Bump counter high byte + bne L2 + +; Not found, return NULL + +notfound: + jmp return0 + +; Found, return pointer to char + +found: ldx ptr1+1 ; get high byte of pointer + tya ; low byte offset + clc + adc ptr1 + bcc L9 + inx +L9: rts + +.endproc + diff --git a/lib/common/memcmp.s b/lib/common/memcmp.s new file mode 100644 index 0000000..5d82aa6 --- /dev/null +++ b/lib/common/memcmp.s @@ -0,0 +1,72 @@ +; +; Ullrich von Bassewitz, 15.09.2000 +; +; int memcmp (const void* p1, const void* p2, size_t count); +; + + .export _memcmp + .import popax, return0 + .importzp ptr1, ptr2, ptr3 + +_memcmp: + +; Calculate (-count-1) and store it into ptr3. This is some overhead here but +; saves time in the compare loop + + eor #$FF + sta ptr3 + txa + eor #$FF + sta ptr3+1 + +; Get the pointer parameters + + jsr popax ; Get p2 + sta ptr2 + stx ptr2+1 + jsr popax ; Get p1 + sta ptr1 + stx ptr1+1 + +; Loop initialization + + ldx ptr3 ; Load low counter byte into X + ldy #$00 ; Initialize pointer + +; Head of compare loop: Test for the end condition + +Loop: inx ; Bump low byte of (-count-1) + beq BumpHiCnt ; Jump on overflow + +; Do the compare + +Comp: lda (ptr1),y + cmp (ptr2),y + bne NotEqual ; Jump if bytes not equal + +; Bump the pointers + + iny ; Increment pointer + bne Loop + inc ptr1+1 ; Increment high bytes + inc ptr2+1 + bne Loop ; Branch always (pointer wrap is illegal) + +; Entry on low counter byte overflow + +BumpHiCnt: + inc ptr3+1 ; Bump high byte of (-count-1) + bne Comp ; Jump if not done + jmp return0 ; Count is zero, areas are identical + +; Not equal, check which one is greater + +NotEqual: + bcs Greater + ldx #$FF ; Make result negative + rts + +Greater: + ldx #$01 ; Make result positive + rts + diff --git a/lib/common/memcpy.s b/lib/common/memcpy.s new file mode 100644 index 0000000..d432ffa --- /dev/null +++ b/lib/common/memcpy.s @@ -0,0 +1,80 @@ +; +; Ullrich von Bassewitz, 2003-08-20 +; Performance increase (about 20%) by +; Christian Krueger, 2009-09-13 +; +; void* __fastcall__ memcpy (void* dest, const void* src, size_t n); +; +; NOTE: This function contains entry points for memmove, which will ressort +; to memcpy for an upwards copy. Don't change this module without looking +; at memmove! +; + + .export _memcpy, memcpy_upwards, memcpy_getparams + .import popax + .importzp sp, ptr1, ptr2, ptr3 + +; ---------------------------------------------------------------------- +_memcpy: + jsr memcpy_getparams + +memcpy_upwards: ; assert Y = 0 + ldx ptr3+1 ; Get high byte of n + beq L2 ; Jump if zero + +L1: .repeat 2 ; Unroll this a bit to make it faster... + lda (ptr1),Y ; copy a byte + sta (ptr2),Y + iny + .endrepeat + bne L1 + inc ptr1+1 + inc ptr2+1 + dex ; Next 256 byte block + bne L1 ; Repeat if any + + ; the following section could be 10% faster if we were able to copy + ; back to front - unfortunately we are forced to copy strict from + ; low to high since this function is also used for + ; memmove and blocks could be overlapping! + ; { +L2: ; assert Y = 0 + ldx ptr3 ; Get the low byte of n + beq done ; something to copy + +L3: lda (ptr1),Y ; copy a byte + sta (ptr2),Y + iny + dex + bne L3 + + ; } + +done: jmp popax ; Pop ptr and return as result + +; ---------------------------------------------------------------------- +; Get the parameters from stack as follows: +; +; size --> ptr3 +; src --> ptr1 +; dest --> ptr2 +; First argument (dest) will remain on stack and is returned in a/x! + +memcpy_getparams: ; IMPORTANT! Function has to leave with Y=0! + sta ptr3 + stx ptr3+1 ; save n to ptr3 + + jsr popax + sta ptr1 + stx ptr1+1 ; save src to ptr1 + + ; save dest to ptr2 + ldy #1 ; (direct stack access is three cycles faster + ; (total cycle count with return)) + lda (sp),y + tax + stx ptr2+1 ; save high byte of ptr2 + dey ; Y = 0 + lda (sp),y ; Get ptr2 low + sta ptr2 + rts diff --git a/lib/common/memmove.s b/lib/common/memmove.s new file mode 100644 index 0000000..983b972 --- /dev/null +++ b/lib/common/memmove.s @@ -0,0 +1,84 @@ +; +; Ullrich von Bassewitz, 2003-08-20 +; Performance increase (about 20%) by +; Christian Krueger, 2009-09-13 +; +; void* __fastcall__ memmove (void* dest, const void* src, size_t size); +; +; NOTE: This function uses entry points from memcpy! +; + + .export _memmove + .import memcpy_getparams, memcpy_upwards, popax + .importzp ptr1, ptr2, ptr3, ptr4, tmp1 + + .macpack generic + .macpack longbranch + +; ---------------------------------------------------------------------- +_memmove: + jsr memcpy_getparams + +; Check for the copy direction. If dest < src, we must copy upwards (start at +; low addresses and increase pointers), otherwise we must copy downwards +; (start at high addresses and decrease pointers). + + sec + sbc ptr1 + txa + sbc ptr1+1 + jcc memcpy_upwards ; Branch if dest < src (upwards copy) + +; Copy downwards. Adjust the pointers to the end of the memory regions. + + lda ptr1+1 + add ptr3+1 + sta ptr1+1 + + lda ptr2+1 + add ptr3+1 + sta ptr2+1 + +; handle fractions of a page size first + + ldy ptr3 ; count, low byte + bne @entry ; something to copy? + beq PageSizeCopy ; here like bra... + +@copyByte: + lda (ptr1),y + sta (ptr2),y +@entry: + dey + bne @copyByte + lda (ptr1),y ; copy remaining byte + sta (ptr2),y + +PageSizeCopy: ; assert Y = 0 + ldx ptr3+1 ; number of pages + beq done ; none? -> done + +@initBase: + dec ptr1+1 ; adjust base... + dec ptr2+1 + dey ; in entry case: 0 -> FF + lda (ptr1),y ; need to copy this 'intro byte' + sta (ptr2),y ; to 'land' later on Y=0! (as a result of the '.repeat'-block!) + dey ; FF ->FE +@copyBytes: + .repeat 2 ; Unroll this a bit to make it faster... + lda (ptr1),y + sta (ptr2),y + dey + .endrepeat +@copyEntry: ; in entry case: 0 -> FF + bne @copyBytes + lda (ptr1),y ; Y = 0, copy last byte + sta (ptr2),y + dex ; one page to copy less + bne @initBase ; still a page to copy? + +; Done, return dest + +done: jmp popax ; Pop ptr and return as result + diff --git a/lib/common/memset.s b/lib/common/memset.s new file mode 100644 index 0000000..fcdbd98 --- /dev/null +++ b/lib/common/memset.s @@ -0,0 +1,95 @@ +; +; void* __fastcall__ memset (void* ptr, int c, size_t n); +; void* __fastcall__ _bzero (void* ptr, size_t n); +; void __fastcall__ bzero (void* ptr, size_t n); +; +; Ullrich von Bassewitz, 29.05.1998 +; Performance increase (about 20%) by +; Christian Krueger, 12.09.2009 +; +; NOTE: bzero will return it's first argument as memset does. It is no problem +; to declare the return value as void, since it may be ignored. _bzero +; (note the leading underscore) is declared with the proper return type, +; because the compiler will replace memset by _bzero if the fill value +; is zero, and the optimizer looks at the return type to see if the value +; in a/x is of any use. +; + + .export _memset, _bzero, __bzero + .import popax + .importzp sp, ptr1, ptr2, ptr3 + +_bzero: +__bzero: + sta ptr3 + stx ptr3+1 ; Save n + ldx #0 ; Fill with zeros + beq common + +_memset: + sta ptr3 ; Save n + stx ptr3+1 + jsr popax ; Get c + tax + +; Common stuff for memset and bzero from here + +common: ; Fill value is in X! + ldy #1 + lda (sp),y + sta ptr1+1 ; save high byte of ptr + dey ; Y = 0 + lda (sp),y ; Get ptr + sta ptr1 + + lsr ptr3+1 ; divide number of + ror ptr3 ; bytes by two to increase + bcc evenCount ; speed (ptr3 = ptr3/2) +oddCount: + ; y is still 0 here + txa ; restore fill value + sta (ptr1),y ; save value and increase + inc ptr1 ; dest. pointer + bne evenCount + inc ptr1+1 +evenCount: + lda ptr1 ; build second pointer section + clc + adc ptr3 ; ptr2 = ptr1 + (length/2) <- ptr3 + sta ptr2 + lda ptr1+1 + adc ptr3+1 + sta ptr2+1 + + txa ; restore fill value + ldx ptr3+1 ; Get high byte of n + beq L2 ; Jump if zero + +; Set 256/512 byte blocks + ; y is still 0 here +L1: .repeat 2 ; Unroll this a bit to make it faster + sta (ptr1),y ; Set byte in lower section + sta (ptr2),y ; Set byte in upper section + iny + .endrepeat + bne L1 + inc ptr1+1 + inc ptr2+1 + dex ; Next 256 byte block + bne L1 ; Repeat if any + +; Set the remaining bytes if any + +L2: ldy ptr3 ; Get the low byte of n + bne L3 ; something to set? + jmp popax ; no -> Pop ptr and return as result + +L3a: sta (ptr1),y ; set bytes in low + sta (ptr2),y ; and high section +L3: dey + bne L3a + sta (ptr1),y ; Set remaining byte(s) + sta (ptr2),y + jmp popax ; Pop ptr and return as result + + diff --git a/lib/common/strcat.s b/lib/common/strcat.s new file mode 100644 index 0000000..8640626 --- /dev/null +++ b/lib/common/strcat.s @@ -0,0 +1,55 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; char* strcat (char* dest, const char* src); +; + + .export _strcat + .import popax + .importzp ptr1, ptr2, tmp3 + +_strcat: + sta ptr1 ; Save src + stx ptr1+1 + jsr popax ; Get dest + sta ptr2 + stx ptr2+1 + sta tmp3 ; Remember for function return + ldy #0 + +; find end of dest + +sc1: lda (ptr2),y + beq sc2 + iny + bne sc1 + inc ptr2+1 + bne sc1 + +; end found, get offset in y into pointer + +sc2: tya + clc + adc ptr2 + sta ptr2 + bcc sc3 + inc ptr2+1 + +; copy src + +sc3: ldy #0 +sc4: lda (ptr1),y + sta (ptr2),y + beq sc5 + iny + bne sc4 + inc ptr1+1 + inc ptr2+1 + bne sc4 + +; done, return pointer to dest + +sc5: lda tmp3 ; X does still contain high byte + rts + + diff --git a/lib/common/strchr.s b/lib/common/strchr.s new file mode 100644 index 0000000..d1761b9 --- /dev/null +++ b/lib/common/strchr.s @@ -0,0 +1,48 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; const char* strchr (const char* s, int c); +; + + .export _strchr + .import popax + .importzp ptr1, tmp1 + +_strchr: + sta tmp1 ; Save c + jsr popax ; get s + sta ptr1 + stx ptr1+1 + ldy #0 + +Loop: lda (ptr1),y ; Get next char + beq EOS ; Jump on end of string + cmp tmp1 ; Found? + beq Found ; Jump if yes + iny + bne Loop + inc ptr1+1 + bne Loop ; Branch always + +; End of string. Check if we're searching for the terminating zero + +EOS: lda tmp1 ; Get the char we're searching for + bne NotFound ; Jump if not searching for terminator + +; Found. Calculate pointer to c. + +Found: ldx ptr1+1 ; Load high byte of pointer + tya ; Low byte offset + clc + adc ptr1 + bcc Found1 + inx +Found1: rts + +; Not found, return NULL + +NotFound: + lda #0 + tax + rts + diff --git a/lib/common/strcmp.s b/lib/common/strcmp.s new file mode 100644 index 0000000..db85d9b --- /dev/null +++ b/lib/common/strcmp.s @@ -0,0 +1,35 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; int strcmp (const char* s1, const char* s2); +; + + .export _strcmp + .import popax + .importzp ptr1, ptr2 + +_strcmp: + sta ptr2 ; Save s2 + stx ptr2+1 + jsr popax ; Get s1 + sta ptr1 + stx ptr1+1 + ldy #0 + +loop: lda (ptr1),y + cmp (ptr2),y + bne L1 + tax ; end of strings? + beq L3 + iny + bne loop + inc ptr1+1 + inc ptr2+1 + bne loop + +L1: bcs L2 + ldx #$FF + rts + +L2: ldx #$01 +L3: rts diff --git a/lib/common/strcoll.s b/lib/common/strcoll.s new file mode 100644 index 0000000..664d1f4 --- /dev/null +++ b/lib/common/strcoll.s @@ -0,0 +1,13 @@ +; +; Ullrich von Bassewitz, 11.12.1998 +; +; int strcoll (const char* s1, const char* s2); +; +; Since we don't have locales, this function is equivalent to strcmp. +; + + .export _strcoll + .import _strcmp + +_strcoll = _strcmp + diff --git a/lib/common/strcpy.s b/lib/common/strcpy.s new file mode 100644 index 0000000..a48f0e3 --- /dev/null +++ b/lib/common/strcpy.s @@ -0,0 +1,30 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; char* strcpy (char* dest, const char* src); +; + + .export _strcpy + .import popax + .importzp ptr1, ptr2 + +_strcpy: + sta ptr1 ; Save src + stx ptr1+1 + jsr popax ; Get dest + sta ptr2 + stx ptr2+1 + ldy #$00 + +L1: lda (ptr1),y + sta (ptr2),y + beq L9 + iny + bne L1 + inc ptr1+1 + inc ptr2+1 + bne L1 + +L9: lda ptr2 ; X still contains high byte + rts + diff --git a/lib/common/strcspn.s b/lib/common/strcspn.s new file mode 100644 index 0000000..6c12561 --- /dev/null +++ b/lib/common/strcspn.s @@ -0,0 +1,54 @@ +; +; Ullrich von Bassewitz, 11.06.1998 +; +; size_t strcspn (const char* s1, const char* s2); +; + + .export _strcspn + .import popax + .importzp ptr1, ptr2, tmp1, tmp2, tmp3 + +_strcspn: + sta ptr2 ; Save s2 + stx ptr2+1 + jsr popax ; Get s1 + sta ptr1 + stx ptr1+1 + ldx #0 ; low counter byte + stx tmp1 ; high counter byte + ldy #$00 + +L1: lda (ptr1),y ; get next char from s1 + beq L6 ; jump if done + sta tmp2 ; save char + iny + bne L2 + inc ptr1+1 +L2: sty tmp3 ; save index into s1 + + ldy #0 ; get index into s2 +L3: lda (ptr2),y ; + beq L4 ; jump if done + cmp tmp2 + beq L6 + iny + bne L3 + +; The character was not found in s2. Increment the counter and start over + +L4: ldy tmp3 ; reload index + inx + bne L1 + inc tmp1 + bne L1 + +; The character was found, or we reached the end of s1. Return count of +; characters + +L6: txa ; get low counter byte + ldx tmp1 ; get high counter byte + rts + + + + diff --git a/lib/common/strdup.s b/lib/common/strdup.s new file mode 100644 index 0000000..57cf914 --- /dev/null +++ b/lib/common/strdup.s @@ -0,0 +1,85 @@ +; +; Ullrich von Bassewitz, 18.07.2000 +; +; char* __fastcall__ strdup (const char* S); +; +; Note: The code knowns which zero page locations are used by malloc. +; + + .importzp sp, tmp1, ptr4 + .import pushax, decsp4, incsp4 + .import _strlen, _malloc, _memcpy + .export _strdup + + .macpack cpu + .macpack generic + +_strdup: + +; Since we need some place to store the intermediate results, allocate a +; stack frame. To make this somewhat more efficient, create the stackframe +; as needed for the final call to the memcpy function. + + pha ; decsp will destroy A (but not X) + jsr decsp4 ; Target/source + +; Store the pointer into the source slot + + ldy #1 + txa + sta (sp),y + pla +.if (.cpu .bitand CPU_ISET_65SC02) + sta (sp) +.else + dey + sta (sp),y +.endif + +; Get length of S (which is still in a/x) + + jsr _strlen + +; Calculate strlen(S)+1 (the space needed) + + add #1 + bcc @L1 + inx + +; Save the space we're about to allocate in ptr4 + +@L1: sta ptr4 + stx ptr4+1 + +; Allocate memory. _malloc will not use ptr4 + + jsr _malloc + +; Store the result into the target stack slot + + ldy #2 + sta (sp),y ; Store low byte + sta tmp1 + txa ; Get high byte + iny + sta (sp),y ; Store high byte + +; Check for a NULL pointer + + ora tmp1 + beq OutOfMemory + +; Copy the string. memcpy will return the target string which is exactly +; what we need here. It will also drop the allocated stack frame. + + lda ptr4 + ldx ptr4+1 ; Load size + jmp _memcpy ; Copy string, drop stackframe + +; Out of memory, return NULL (A = 0) + +OutOfMemory: + tax + jmp incsp4 ; Drop stack frame + + diff --git a/lib/common/strerror.s b/lib/common/strerror.s new file mode 100644 index 0000000..98a5725 --- /dev/null +++ b/lib/common/strerror.s @@ -0,0 +1,35 @@ +; +; Ullrich von Bassewitz, 17.05.2000 +; +; char* __fastcall__ strerror (int errcode); +; /* Map an error number to an error message */ +; + + .export _strerror + .import __sys_errlist + + .include "errno.inc" + +_strerror: + cpx #$00 ; High byte must be zero + bne @L1 ; Jump if invalid error + cmp #EMAX ; Valid error code (map EUNKNOWN to 0)? + bcc @L2 ; Jump if ok + +; The given error code is invalid + +@L1: lda #EINVAL ; = 0 + sta __errno+1 +; lda #$00 ; A contains zero: "Unknown error" + +; Load the pointer to the error message and return + +@L2: asl a ; * 2 + tay + ldx __sys_errlist+1,y + lda __sys_errlist,y + rts + + diff --git a/lib/common/strftime.c b/lib/common/strftime.c new file mode 100644 index 0000000..803c3d8 --- /dev/null +++ b/lib/common/strftime.c @@ -0,0 +1,224 @@ +/*****************************************************************************/ +/* */ +/* strftime.c */ +/* */ +/* Convert broken down time to a string in a user specified format */ +/* */ +/* */ +/* */ +/* (C) 2002 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@musoftware.de */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include +#include +#include + + + +/* Use static local variables for speed */ +#pragma staticlocals (on); + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +size_t __fastcall__ strftime (char* buf, size_t bufsize, const char* format, + const struct tm* tm) +{ + static const char* days[7] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }; + static const char* months[12] = { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }; + + unsigned count; + unsigned len; + char c; + char arg[40]; + const char* argptr; + + /* Copy until we reach the end of the format string or a format specifier */ + count = 0; + while (1) { + if (count >= bufsize) { + /* Not enough buffer space available */ + return 0; + } + if ((c = *format++) == '\0') { + /* End of format string reached */ + *buf = '\0'; + return count; + } + if (c == '%') { + /* Format specifier */ + argptr = arg; + switch (*format++) { + + case '%': + arg[0] = '%'; + arg[1] = '\0'; + break; + + case 'A': + argptr = days[tm->tm_wday]; + break; + + case 'B': + argptr = months[tm->tm_mon]; + break; + + case 'D': + sprintf (arg, "%02d/%02d/%02d", tm->tm_mon + 1, + tm->tm_mday, tm->tm_year % 100); + break; + + case 'F': + /* C99 */ + sprintf (arg, "%04d-%02d-%02d", tm->tm_year + 1900, + tm->tm_mon + 1, tm->tm_mday); + break; + + case 'H': + sprintf (arg, "%02d", tm->tm_hour); + break; + + case 'I': + sprintf (arg, "%02d", tm->tm_hour % 12); + break; + + case 'M': + sprintf (arg, "%02d", tm->tm_min); + break; + + case 'P': + /* GNU extension */ + argptr = (tm->tm_hour >= 12)? "pm" : "am"; + break; + + case 'S': + sprintf (arg, "%02d", tm->tm_sec); + break; + + case 'U': + sprintf (arg, "%02d", (tm->tm_yday + 7 - tm->tm_wday) / 7); + break; + + case 'W': + sprintf (arg, "%02d", + (tm->tm_yday + 7 - (tm->tm_wday? tm->tm_wday - 1 : 6)) / 7); + break; + + case 'X': + sprintf (arg, "%02d:%02d:%02d", tm->tm_hour, + tm->tm_min, tm->tm_sec); + break; + + case 'Y': + sprintf (arg, "%4d", tm->tm_year + 1900); + break; + + case 'Z': + argptr = tm->tm_isdst? _tz.dstname : _tz.tzname; + break; + + case 'a': + sprintf (arg, "%.3s", days[tm->tm_wday]); + break; + + case 'b': + sprintf (arg, "%.3s", months[tm->tm_mon]); + break; + + case 'c': + sprintf (arg, "%.3s %.3s%3d %02d:%02d:%02d %d", + days[tm->tm_wday], months[tm->tm_mon], + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec, tm->tm_year + 1900); + break; + + case 'd': + sprintf (arg, "%02d", tm->tm_mday); + break; + + case 'j': + sprintf (arg, "%03d", tm->tm_yday + 1); + break; + + case 'm': + sprintf (arg, "%02d", tm->tm_mon + 1); + break; + + case 'p': + argptr = (tm->tm_hour >= 12)? "PM" : "AM"; + break; + + case 'w': + sprintf (arg, "%d", tm->tm_wday); + break; + + case 'x': + sprintf (arg, "%04d-%02d-%02d", tm->tm_year + 1900, + tm->tm_mon + 1, tm->tm_mday); + break; + + case 'y': + sprintf (arg, "%02d", tm->tm_year % 100); + break; + + default: + /* Unknown format specifier, convert to empty string */ + arg[0] = '\0'; + break; + } + + /* Check if we have enough space to copy the argument string */ + len = strlen (argptr); + count += len; + if (count < bufsize) { + memcpy (buf, argptr, len); + buf += len; + } + + } else { + + /* No format character, just copy */ + *buf++ = c; + ++count; + + } + } +} + + + diff --git a/lib/common/stricmp.s b/lib/common/stricmp.s new file mode 100644 index 0000000..03638c8 --- /dev/null +++ b/lib/common/stricmp.s @@ -0,0 +1,60 @@ +; +; Ullrich von Bassewitz, 03.06.1998 +; +; int stricmp (const char* s1, const char* s2); /* DOS way */ +; int strcasecmp (const char* s1, const char* s2); /* UNIX way */ +; + + .export _stricmp, _strcasecmp + .import popax + .import __ctype + .importzp ptr1, ptr2, tmp1 + + .include "ctype.inc" + +_stricmp: +_strcasecmp: + sta ptr2 ; Save s2 + stx ptr2+1 + jsr popax ; get s1 + sta ptr1 + stx ptr1+1 + ldy #0 + +loop: lda (ptr2),y ; get char from second string + tax + lda __ctype,x ; get character classification + and #CT_LOWER ; lower case char? + beq L1 ; jump if no + txa ; get character back + clc + adc #<('A'-'a') ; make upper case char + tax ; +L1: stx tmp1 ; remember upper case equivalent + + lda (ptr1),y ; get character from first string + tax + lda __ctype,x ; get character classification + and #CT_LOWER ; lower case char? + beq L2 ; jump if no + txa ; get character back + clc + adc #<('A'-'a') ; make upper case char + tax + +L2: cpx tmp1 ; compare characters + bne L3 + txa ; end of strings? + beq L5 ; a/x both zero + iny + bne loop + inc ptr1+1 + inc ptr2+1 + bne loop + +L3: bcs L4 + ldx #$FF + rts + +L4: ldx #$01 +L5: rts diff --git a/lib/common/strlen.s b/lib/common/strlen.s new file mode 100644 index 0000000..6cef2ea --- /dev/null +++ b/lib/common/strlen.s @@ -0,0 +1,26 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; int strlen (const char* s); +; + + .export _strlen + .importzp ptr1 + +_strlen: + sta ptr1 ; Save s + stx ptr1+1 + ldx #0 ; YX used as counter + ldy #0 + +L1: lda (ptr1),y + beq L9 + iny + bne L1 + inc ptr1+1 + inx + bne L1 + +L9: tya ; get low byte of counter, hi's all set + rts + diff --git a/lib/common/strlower.s b/lib/common/strlower.s new file mode 100644 index 0000000..b76133c --- /dev/null +++ b/lib/common/strlower.s @@ -0,0 +1,47 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; char* strlower (char* s); +; char* strlwr (char* s); +; +; Non-ANSI +; + + .export _strlower, _strlwr + .import popax + .import __ctype + .importzp ptr1, ptr2 + + .include "ctype.inc" + +_strlower: +_strlwr: + sta ptr1 ; Save s (working copy) + stx ptr1+1 + sta ptr2 + sta ptr2+2 ; save function result + ldy #0 + +loop: lda (ptr1),y ; get character + beq L9 ; jump if done + tax + lda __ctype,x ; get character classification + and #CT_UPPER ; upper case char? + beq L1 ; jump if no + txa ; get character back into accu + sec + sbc #<('A'-'a') ; make lower case char + sta (ptr1),y ; store back +L1: iny ; next char + bne loop + inc ptr1+1 ; handle offset overflow + bne loop ; branch always + +; Done, return the argument string + +L9: lda ptr2 + ldx ptr2+1 + rts + + + diff --git a/lib/common/strncat.s b/lib/common/strncat.s new file mode 100644 index 0000000..5171ad9 --- /dev/null +++ b/lib/common/strncat.s @@ -0,0 +1,72 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; char* strncat (char* dest, const char* src, size_t n); +; + + .export _strncat + .import popax + .importzp ptr1, ptr2, ptr3, tmp1, tmp2 + +_strncat: + eor #$FF ; one's complement to count upwards + sta tmp1 + txa + eor #$FF + sta tmp2 + jsr popax ; get src + sta ptr1 + stx ptr1+1 + jsr popax ; get dest + sta ptr2 + stx ptr2+1 + sta ptr3 ; remember for function return + stx ptr3+1 + ldy #0 + +; find end of dest + +L1: lda (ptr2),y + beq L2 + iny + bne L1 + inc ptr2+1 + bne L1 + +; end found, get offset in y into pointer + +L2: tya + clc + adc ptr2 + sta ptr2 + bcc L3 + inc ptr2+1 + +; copy src. We've put the ones complement of the count into the counter, so +; we'll increment the counter on top of the loop + +L3: ldy #0 + ldx tmp1 ; low counter byte + +L4: inx + bne L5 + inc tmp2 + beq L6 ; jump if done +L5: lda (ptr1),y + sta (ptr2),y + beq L7 + iny + bne L4 + inc ptr1+1 + inc ptr2+1 + bne L4 + +; done, set the trailing zero and return pointer to dest + +L6: lda #0 + sta (ptr2),y +L7: lda ptr3 + ldx ptr3+1 + rts + + diff --git a/lib/common/strncmp.s b/lib/common/strncmp.s new file mode 100644 index 0000000..3af44fa --- /dev/null +++ b/lib/common/strncmp.s @@ -0,0 +1,81 @@ +; +; Ullrich von Bassewitz, 25.05.2000 +; +; int strncmp (const char* s1, const char* s2, unsigned n); +; + + .export _strncmp + .import popax + .importzp ptr1, ptr2, ptr3 + + +_strncmp: + +; Convert the given counter value in a/x from a downward counter into an +; upward counter, so we can increment the counter in the loop below instead +; of decrementing it. This adds some overhead now, but is cheaper than +; executing a more complex test in each iteration of the loop. We do also +; correct the value by one, so we can do the test on top of the loop. + + eor #$FF + sta ptr3 + txa + eor #$FF + sta ptr3+1 + +; Get the remaining arguments + + jsr popax ; get s2 + sta ptr2 + stx ptr2+1 + jsr popax ; get s1 + sta ptr1 + stx ptr1+1 + +; Loop setup + + ldy #0 + +; Start of compare loop. Check the counter. + +Loop: inc ptr3 + beq IncHi ; Increment high byte + +; Compare a byte from the strings + +Comp: lda (ptr1),y + cmp (ptr2),y + bne NotEqual ; Jump if strings different + tax ; End of strings? + beq Equal1 ; Jump if EOS reached, a/x == 0 + +; Increment the pointers + + iny + bne Loop + inc ptr1+1 + inc ptr2+1 + bne Loop ; Branch always + +; Increment hi byte + +IncHi: inc ptr3+1 + bne Comp ; Jump if counter not zero + +; Exit code if strings are equal. a/x not set + +Equal: lda #$00 + tax +Equal1: rts + +; Exit code if strings not equal + +NotEqual: + bcs L1 + ldx #$FF ; Make result negative + rts + +L1: ldx #$01 ; Make result positive + rts + + diff --git a/lib/common/strncpy.s b/lib/common/strncpy.s new file mode 100644 index 0000000..21de3a1 --- /dev/null +++ b/lib/common/strncpy.s @@ -0,0 +1,69 @@ +; +; Ullrich von Bassewitz, 2003-05-04 +; +; char* __fastcall__ strncpy (char* dest, const char* src, unsigned size); +; + + .export _strncpy + .import popax + .importzp ptr1, ptr2, tmp1, tmp2, tmp3 + +.proc _strncpy + + eor #$FF + sta tmp1 + txa + eor #$FF + sta tmp2 ; Store -size - 1 + + jsr popax ; get src + sta ptr1 + stx ptr1+1 + jsr popax ; get dest + sta ptr2 + stx ptr2+1 + stx tmp3 ; remember for function return + +; Copy src -> dest up to size bytes + + ldx tmp1 ; Load low byte of ones complement of size + ldy #$00 +L1: inx + bne L2 + inc tmp2 + beq L9 + +L2: lda (ptr1),y ; Copy one character + sta (ptr2),y + beq L5 ; Bail out if terminator reached (A = 0) + iny + bne L1 + inc ptr1+1 + inc ptr2+1 ; Bump high bytes + bne L1 ; Branch always + +; Fill the remaining bytes. + +L3: inx ; Counter low byte + beq L6 ; Branch on overflow +L4: sta (ptr2),y ; Clear one byte +L5: iny ; Bump pointer + bne L3 + inc ptr2+1 ; Bump high byte + bne L3 ; Branch always + +; Bump the counter high byte + +L6: inc tmp2 + bne L4 + +; Done, return dest + +L9: lda ptr2 ; Get low byte + ldx tmp3 ; Get unchanged high byte + rts + +.endproc + + + diff --git a/lib/common/strnicmp.s b/lib/common/strnicmp.s new file mode 100644 index 0000000..38bd21c --- /dev/null +++ b/lib/common/strnicmp.s @@ -0,0 +1,103 @@ +; +; Christian Groessler, 10.02.2009 +; derived from strncmp.s and stricmp.s +; +; int __fastcall__ strnicmp (const char* s1, const char* s2, size_t count); +; int __fastcall__ strncasecmp (const char* s1, const char* s2, size_t count); +; + + .export _strnicmp, _strncasecmp + .import popax, __ctype + .importzp ptr1, ptr2, ptr3, tmp1 + + .include "ctype.inc" + +_strnicmp: +_strncasecmp: + +; Convert the given counter value in a/x from a downward counter into an +; upward counter, so we can increment the counter in the loop below instead +; of decrementing it. This adds some overhead now, but is cheaper than +; executing a more complex test in each iteration of the loop. We do also +; correct the value by one, so we can do the test on top of the loop. + + eor #$FF + sta ptr3 + txa + eor #$FF + sta ptr3+1 + +; Get the remaining arguments + + jsr popax ; get s2 + sta ptr2 + stx ptr2+1 + jsr popax ; get s1 + sta ptr1 + stx ptr1+1 + +; Loop setup + + ldy #0 + +; Start of compare loop. Check the counter. + +Loop: inc ptr3 + beq IncHi ; Increment high byte + +; Compare a byte from the strings + +Comp: lda (ptr2),y + tax + lda __ctype,x ; get character classification + and #CT_LOWER ; lower case char? + beq L1 ; jump if no + txa ; get character back + sec + sbc #<('a'-'A') ; make upper case char + tax ; +L1: stx tmp1 ; remember upper case equivalent + + lda (ptr1),y ; get character from first string + tax + lda __ctype,x ; get character classification + and #CT_LOWER ; lower case char? + beq L2 ; jump if no + txa ; get character back + sec + sbc #<('a'-'A') ; make upper case char + tax + +L2: cpx tmp1 ; compare characters + bne NotEqual ; Jump if strings different + txa ; End of strings? + beq Equal1 ; Jump if EOS reached, a/x == 0 + +; Increment the pointers + + iny + bne Loop + inc ptr1+1 + inc ptr2+1 + bne Loop ; Branch always + +; Increment hi byte + +IncHi: inc ptr3+1 + bne Comp ; Jump if counter not zero + +; Exit code if strings are equal. a/x not set + +Equal: lda #$00 + tax +Equal1: rts + +; Exit code if strings not equal + +NotEqual: + bcs L3 + ldx #$FF ; Make result negative + rts + +L3: ldx #$01 ; Make result positive + rts diff --git a/lib/common/stroserr.s b/lib/common/stroserr.s new file mode 100644 index 0000000..c410b54 --- /dev/null +++ b/lib/common/stroserr.s @@ -0,0 +1,61 @@ +; +; Ullrich von Bassewitz, 17.07.2002 +; +; const char* __fastcall__ _stroserror (unsigned char errcode); +; /* Map an operating system error number to an error message. */ +; + + .export __stroserror + .import __sys_oserrlist + .importzp ptr1, tmp1 + + .macpack generic + + +; The table is built as a list of entries +; +; .byte entrylen +; .byte errorcode +; .asciiz errormsg +; +; and terminated by an entry with length zero that is returned if the +; error code could not be found. + +__stroserror: + sta tmp1 ; Save the error code + + ldy #<__sys_oserrlist + sty ptr1 + ldy #>__sys_oserrlist + sty ptr1+1 ; Setup pointer to message table + +@L1: ldy #0 + lda (ptr1),y ; Get the length + beq Done ; Bail out if end of list reached + + iny + lda (ptr1),y ; Compare the error code + cmp tmp1 + beq Done ; Jump if found + +; Not found, move pointer to next entry + + dey + clc + lda ptr1 + adc (ptr1),y + sta ptr1 + bcc @L1 + inc ptr1+1 + bcs @L1 ; Branch always + +; We've found the code or reached the end of the list + +Done: ldx ptr1+1 + lda ptr1 + add #2 ; Add a total of #2 + bcc @L1 + inx ; Bump high byte +@L1: rts + + diff --git a/lib/common/strpbrk.s b/lib/common/strpbrk.s new file mode 100644 index 0000000..e34468b --- /dev/null +++ b/lib/common/strpbrk.s @@ -0,0 +1,60 @@ +; +; Ullrich von Bassewitz, 11.06.1998 +; +; char* strpbrk (const char* s1, const char* s2); +; + + .export _strpbrk + .import popax, return0 + .importzp ptr1, ptr2, tmp1, tmp2, tmp3 + +_strpbrk: + jsr popax ; get s2 + sta ptr2 + stx ptr2+1 + jsr popax ; get s1 + sta ptr1 + stx ptr1+1 + ldy #$00 + +L1: lda (ptr1),y ; get next char from s1 + beq L9 ; jump if done + sta tmp2 ; save char + iny + bne L2 + inc ptr1+1 +L2: sty tmp3 ; save index into s1 + + ldy #0 ; get index into s2 +L3: lda (ptr2),y ; + beq L4 ; jump if done + cmp tmp2 + beq L6 + iny + bne L3 + +; The character was not found in s2. Increment the counter and start over + +L4: ldy tmp3 ; reload index + inx + bne L1 + inc tmp1 + bne L1 + +; A character was found. Calculate a pointer to this char in s1 and return it. + +L6: ldx ptr1+1 + lda tmp3 ; get y offset + clc + adc ptr1 + bcc L7 + inx +L7: rts + +; None of the characters in s2 was found - return NULL + +L9: jmp return0 + + + + diff --git a/lib/common/strrchr.s b/lib/common/strrchr.s new file mode 100644 index 0000000..bf09fbd --- /dev/null +++ b/lib/common/strrchr.s @@ -0,0 +1,47 @@ +; +; Ullrich von Bassewitz, 31.05.1998 +; +; char* strrchr (const char* s, int c); +; + + .export _strrchr + .import popax + .importzp ptr1, ptr2, tmp1 + +_strrchr: + sta tmp1 ; Save c + jsr popax ; get s + sta ptr1 + stx ptr1+1 + lda #0 ; function result = NULL + sta ptr2 + sta ptr2+1 + tay + +L1: lda (ptr1),y ; get next char + beq L3 ; jump if end of string + cmp tmp1 ; found? + bne L2 ; jump if no + +; Remember a pointer to the character + + tya + clc + adc ptr1 + sta ptr2 + lda ptr1+1 + adc #$00 + sta ptr2+1 + +; Next char + +L2: iny + bne L1 + inc ptr1+1 + bne L1 ; jump always + +; Return the pointer to the last occurrence + +L3: lda ptr2 + ldx ptr2+1 + rts diff --git a/lib/common/strspn.s b/lib/common/strspn.s new file mode 100644 index 0000000..884a337 --- /dev/null +++ b/lib/common/strspn.s @@ -0,0 +1,56 @@ +; +; Ullrich von Bassewitz, 11.06.1998 +; +; size_t strspn (const char* s1, const char* s2); +; + + .export _strspn + .import popax + .importzp ptr1, ptr2, tmp1, tmp2, tmp3 + +_strspn: + sta ptr2 ; Save s2 + stx ptr2+1 + jsr popax ; get s1 + sta ptr1 + stx ptr1+1 + ldx #0 ; low counter byte + stx tmp1 ; high counter byte + ldy #$00 + +L1: lda (ptr1),y ; get next char from s1 + beq L6 ; jump if done + sta tmp2 ; save char + iny + bne L2 + inc ptr1+1 +L2: sty tmp3 ; save index into s1 + + ldy #0 ; get index into s2 +L3: lda (ptr2),y ; + beq L6 ; jump if done + cmp tmp2 + beq L4 + iny + bne L3 + +; The character was found in s2. Increment the counter and start over + +L4: ldy tmp3 ; reload index + inx + bne L1 + inc tmp1 + bne L1 + +; The character was not found, or we reached the end of s1. Return count of +; characters + +L6: txa ; get low counter byte + ldx tmp1 ; get high counter byte + rts + + + + + + diff --git a/lib/common/strstr.s b/lib/common/strstr.s new file mode 100644 index 0000000..62e1944 --- /dev/null +++ b/lib/common/strstr.s @@ -0,0 +1,97 @@ +; +; Ullrich von Bassewitz, 11.12.1998 +; +; char* strstr (const char* haystack, const char* needle); +; + + .export _strstr + .import popax + .importzp ptr1, ptr2, ptr3, ptr4, tmp1 + +_strstr: + sta ptr2 ; Save needle + stx ptr2+1 + sta ptr4 ; Setup temp copy for later + + jsr popax ; Get haystack + sta ptr1 + stx ptr1+1 ; Save haystack + +; If needle is empty, return haystack + + ldy #$00 + lda (ptr2),y ; Get first byte of needle + beq @Found ; Needle is empty --> we're done + +; Search for the beginning of the string (this is not an optimal search +; strategy [in fact, it's pretty dumb], but it's simple to implement). + + sta tmp1 ; Save start of needle +@L1: lda (ptr1),y ; Get next char from haystack + beq @NotFound ; Jump if end + cmp tmp1 ; Start of needle found? + beq @L2 ; Jump if so + iny ; Next char + bne @L1 + inc ptr1+1 ; Bump high byte + bne @L1 ; Branch always + +; We found the start of needle in haystack + +@L2: tya ; Get offset + clc + adc ptr1 + sta ptr1 ; Make ptr1 point to start + bcc @L3 + inc ptr1+1 + +; ptr1 points to the start of needle now. Setup temporary pointers for the +; search. The low byte of ptr4 is already set. + +@L3: sta ptr3 + lda ptr1+1 + sta ptr3+1 + lda ptr2+1 + sta ptr4+1 + ldy #1 ; First char is identical, so start on second + +; Do the compare + +@L4: lda (ptr4),y ; Get char from needle + beq @Found ; Jump if end of needle (-> found) + cmp (ptr3),y ; Compare with haystack + bne @L5 ; Jump if not equal + iny ; Next char + bne @L4 + inc ptr3+1 + inc ptr4+1 ; Bump hi byte of pointers + bne @L4 ; Next char (branch always) + +; The strings did not compare equal, search next start of needle + +@L5: ldy #1 ; Start after this char + bne @L1 ; Branch always + +; We found the start of needle + +@Found: lda ptr1 + ldx ptr1+1 + rts + +; We reached end of haystack without finding needle + +@NotFound: + lda #$00 ; return NULL + tax + rts + + + + + + + + + + + diff --git a/lib/common/strtoimax.s b/lib/common/strtoimax.s new file mode 100644 index 0000000..10c0d42 --- /dev/null +++ b/lib/common/strtoimax.s @@ -0,0 +1,9 @@ +; +; Ullrich von Bassewitz, 2009-09-17 +; +; intmax_t __fastcall__ strtoimax (const char* nptr, char** endptr, int base); +; + + .import _strtol + .export _strtoimax = _strtol + diff --git a/lib/common/strtok.c b/lib/common/strtok.c new file mode 100644 index 0000000..3e5ff7d --- /dev/null +++ b/lib/common/strtok.c @@ -0,0 +1,77 @@ +/* + * strtok.c + * + * Ullrich von Bassewitz, 11.12.1998 + */ + + + +#include + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Memory location that holds the last input */ +static char* Last = 0; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +char* __fastcall__ strtok (register char* s1, const char* s2) +{ + char c; + char* start; + + /* Use the stored location if called with a NULL pointer */ + if (s1 == 0) { + s1 = Last; + } + + /* If s1 is empty, there are no more tokens. Return 0 in this case. */ + if (*s1 == '\0') { + return 0; + } + + /* Search the address of the first element in s1 that equals none + * of the characters in s2. + */ + while ((c = *s1) && strchr (s2, c) != 0) { + ++s1; + } + if (c == '\0') { + /* No more tokens found */ + Last = s1; + return 0; + } + + /* Remember the start of the token */ + start = s1; + + /* Search for the end of the token */ + while ((c = *s1) && strchr (s2, c) == 0) { + ++s1; + } + if (c == '\0') { + /* Last element */ + Last = s1; + } else { + *s1 = '\0'; + Last = s1 + 1; + } + + /* Return the start of the token */ + return start; +} + + + diff --git a/lib/common/strtok.s b/lib/common/strtok.s new file mode 100644 index 0000000..0318db2 --- /dev/null +++ b/lib/common/strtok.s @@ -0,0 +1,228 @@ +; +; File generated by cc65 v 2.13.3 +; + .fopt compiler,"cc65 v 2.13.3" + .setcpu "65C02" + .smart on + .autoimport on + .case on + .debuginfo on + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .dbg file, "strtok.c", 1493, 1356265749 + .dbg file, "../../include/string.h", 4883, 1234293382 + .dbg file, "../../include/stddef.h", 2972, 1253259480 + .import _strchr + .export _strtok + +.segment "DATA" + +_Last: + .word $0000 + +; --------------------------------------------------------------- +; __near__ unsigned char* __near__ __fastcall__ strtok (register __near__ unsigned char*, __near__ const unsigned char*) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _strtok: near + +.segment "CODE" + +; +; { +; + .dbg line, "strtok.c", 31 + jsr pushax + ldy #$02 + ldx #$04 + jsr regswap2 +; +; if (s1 == 0) { +; + .dbg line, "strtok.c", 36 + jsr decsp3 + lda regbank+4 + ora regbank+4+1 + bne L0004 +; +; s1 = Last; +; + .dbg line, "strtok.c", 37 + lda _Last + sta regbank+4 + lda _Last+1 + sta regbank+4+1 +; +; if (*s1 == '\0') { +; + .dbg line, "strtok.c", 41 +L0004: lda (regbank+4) + bne L0009 +; +; return 0; +; + .dbg line, "strtok.c", 42 + tax + jmp L0003 +; +; while ((c = *s1) && strchr (s2, c) != 0) { +; + .dbg line, "strtok.c", 48 +L0009: lda (regbank+4) + ldy #$02 + sta (sp),y + tax + beq L000D + ldy #$04 + lda (sp),y + tax + dey + lda (sp),y + jsr pushax + ldy #$04 + lda (sp),y + ldx #$00 + jsr _strchr + cpx #$00 + bne L000E + cmp #$00 + beq L000D +; +; ++s1; +; + .dbg line, "strtok.c", 49 +L000E: inc regbank+4 + bne L0009 + inc regbank+4+1 +; +; } +; + .dbg line, "strtok.c", 50 + bra L0009 +; +; if (c == '\0') { +; + .dbg line, "strtok.c", 51 +L000D: ldy #$02 + lda (sp),y + bne L0018 +; +; Last = s1; +; + .dbg line, "strtok.c", 53 + lda regbank+4 + sta _Last + lda regbank+4+1 + sta _Last+1 +; +; return 0; +; + .dbg line, "strtok.c", 54 + txa + bra L0003 +; +; start = s1; +; + .dbg line, "strtok.c", 58 +L0018: lda regbank+4 + ldx regbank+4+1 + jsr stax0sp +; +; while ((c = *s1) && strchr (s2, c) == 0) { +; + .dbg line, "strtok.c", 61 +L001F: lda (regbank+4) + ldy #$02 + sta (sp),y + tax + beq L0020 + ldy #$04 + lda (sp),y + tax + dey + lda (sp),y + jsr pushax + ldy #$04 + lda (sp),y + ldx #$00 + jsr _strchr + cpx #$00 + bne L0020 + cmp #$00 + bne L0020 +; +; ++s1; +; + .dbg line, "strtok.c", 62 + inc regbank+4 + bne L001F + inc regbank+4+1 +; +; } +; + .dbg line, "strtok.c", 63 + bra L001F +; +; if (c == '\0') { +; + .dbg line, "strtok.c", 64 +L0020: ldy #$02 + lda (sp),y + bne L002B +; +; Last = s1; +; + .dbg line, "strtok.c", 66 + lda regbank+4 + sta _Last + lda regbank+4+1 + sta _Last+1 +; +; } else { +; + .dbg line, "strtok.c", 67 + bra L002F +; +; *s1 = '\0'; +; + .dbg line, "strtok.c", 68 +L002B: lda #$00 + sta (regbank+4) +; +; Last = s1 + 1; +; + .dbg line, "strtok.c", 69 + lda regbank+4 + ldx regbank+4+1 + ina + bne L0034 + inx +L0034: sta _Last + stx _Last+1 +; +; return start; +; + .dbg line, "strtok.c", 73 +L002F: dey + lda (sp),y + tax + lda (sp) +; +; } +; + .dbg line, "strtok.c", 74 +L0003: pha + ldy #$05 + lda (sp),y + sta regbank+4 + iny + lda (sp),y + sta regbank+5 + pla + jmp incsp7 + .dbg line + +.endproc + diff --git a/lib/common/strtol.c b/lib/common/strtol.c new file mode 100644 index 0000000..b36dd89 --- /dev/null +++ b/lib/common/strtol.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include + + + +long __fastcall__ strtol (const char* nptr, char** endptr, int base) +/* Convert a string to a long int */ +{ + register const char* S = nptr; + unsigned long Val = 0; + unsigned char Minus = 0; + unsigned char Ovf = 0; + unsigned CvtCount = 0; + unsigned char DigitVal; + unsigned long MaxVal; + unsigned char MaxDigit; + + + /* Skip white space */ + while (isspace (*S)) { + ++S; + } + + /* Check for leading + or - sign */ + switch (*S) { + case '-': + Minus = 1; + /* FALLTHROUGH */ + case '+': + ++S; + } + + /* If base is zero, we may have a 0 or 0x prefix. If base is 16, we may + * have a 0x prefix. + */ + if (base == 0) { + if (*S == '0') { + ++S; + if (*S == 'x' || *S == 'X') { + ++S; + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base == 16 && *S == '0' && (S[1] == 'x' || S[1] == 'X')) { + S += 2; + } + + /* Determine the maximum valid number and (if the number is equal to this + * value) the maximum valid digit. + */ + if (Minus) { + MaxVal = LONG_MIN; + } else { + MaxVal = LONG_MAX; + } + MaxDigit = MaxVal % base; + MaxVal /= base; + + /* Convert the number */ + while (1) { + + /* Convert the digit into a numeric value */ + if (isdigit (*S)) { + DigitVal = *S - '0'; + } else if (isupper (*S)) { + DigitVal = *S - ('A' - 10); + } else if (islower (*S)) { + DigitVal = *S - ('a' - 10); + } else { + /* Unknown character */ + break; + } + + /* Don't accept a character that doesn't match base */ + if (DigitVal >= base) { + break; + } + + /* Don't accept anything that makes the final value invalid */ + if (Val > MaxVal || (Val == MaxVal && DigitVal > MaxDigit)) { + Ovf = 1; + } + + /* Calculate the next value if digit is not invalid */ + if (Ovf == 0) { + Val = (Val * base) + DigitVal; + ++CvtCount; + } + + /* Next character from input */ + ++S; + } + + /* Store the end pointer. If no conversion was performed, the value of + * nptr is returned in endptr. + */ + if (endptr) { + if (CvtCount > 0) { + *endptr = (char*) S - 1; + } else { + *endptr = (char*) nptr; + } + } + + /* Handle overflow */ + if (Ovf) { + errno = ERANGE; + if (Minus) { + return LONG_MIN; + } else { + return LONG_MAX; + } + } + + /* Return the result */ + if (Minus) { + return -(long)Val; + } else { + return Val; + } +} + diff --git a/lib/common/strtol.s b/lib/common/strtol.s new file mode 100644 index 0000000..7d3aef0 --- /dev/null +++ b/lib/common/strtol.s @@ -0,0 +1,592 @@ +; +; File generated by cc65 v 2.13.3 +; + .fopt compiler,"cc65 v 2.13.3" + .setcpu "65C02" + .smart on + .autoimport on + .case on + .debuginfo on + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .dbg file, "strtol.c", 2969, 1356265749 + .dbg file, "../../include/limits.h", 2978, 1039954353 + .dbg file, "../../include/ctype.h", 7770, 1087856531 + .dbg file, "../../include/errno.h", 3647, 1060696125 + .dbg file, "../../include/stdlib.h", 5578, 1253048480 + .import __ctype + .import __maperrno + .import __errno + .export _strtol + +; --------------------------------------------------------------- +; long __near__ __fastcall__ strtol (__near__ const unsigned char*, __near__ __near__ unsigned char**, int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _strtol: near + +.segment "CODE" + +; +; { +; + .dbg line, "strtol.c", 10 + jsr pushax +; +; register const char* S = nptr; +; + .dbg line, "strtol.c", 11 + lda regbank+4 + ldx regbank+5 + jsr pushax + ldy #$07 + lda (sp),y + tax + dey + lda (sp),y + sta regbank+4 + stx regbank+4+1 +; +; unsigned long Val = 0; +; + .dbg line, "strtol.c", 12 + ldx #$00 + txa + jsr push0ax +; +; unsigned char Minus = 0; +; + .dbg line, "strtol.c", 13 + jsr pusha +; +; unsigned char Ovf = 0; +; + .dbg line, "strtol.c", 14 + jsr pusha +; +; unsigned CvtCount = 0; +; + .dbg line, "strtol.c", 15 + jsr push0 +; +; while (isspace (*S)) { +; + .dbg line, "strtol.c", 22 + jsr decsp6 +L0009: lda (regbank+4) + tay + lda __ctype,y + and #$60 + beq L000A +; +; ++S; +; + .dbg line, "strtol.c", 23 + inc regbank+4 + bne L0009 + inc regbank+4+1 +; +; } +; + .dbg line, "strtol.c", 24 + bra L0009 +; +; switch (*S) { +; + .dbg line, "strtol.c", 27 +L000A: lda (regbank+4) +; +; } +; + .dbg line, "strtol.c", 33 + cmp #$2B + beq L001F + cmp #$2D + bne L0019 +; +; Minus = 1; +; + .dbg line, "strtol.c", 29 + lda #$01 + ldy #$09 + sta (sp),y +; +; ++S; +; + .dbg line, "strtol.c", 32 +L001F: inc regbank+4 + bne L0019 + inc regbank+4+1 +; +; if (base == 0) { +; + .dbg line, "strtol.c", 38 +L0019: ldy #$11 + lda (sp),y + tax + dey + lda (sp),y + cpx #$00 + bne L0022 + cmp #$00 + bne L0022 +; +; if (*S == '0') { +; + .dbg line, "strtol.c", 39 + lda (regbank+4) + cmp #$30 + bne L0025 +; +; ++S; +; + .dbg line, "strtol.c", 40 + inc regbank+4 + bne L0028 + inc regbank+4+1 +; +; if (*S == 'x' || *S == 'X') { +; + .dbg line, "strtol.c", 41 +L0028: lda (regbank+4) + cmp #$78 + beq L002A + lda (regbank+4) + cmp #$58 + bne L0029 +; +; ++S; +; + .dbg line, "strtol.c", 42 +L002A: inc regbank+4 + bne L002D + inc regbank+4+1 +; +; base = 16; +; + .dbg line, "strtol.c", 43 +L002D: tya +; +; } else { +; + .dbg line, "strtol.c", 44 + bra L00B0 +; +; base = 8; +; + .dbg line, "strtol.c", 45 +L0029: lda #$08 + ldy #$10 + jsr staxysp +; +; } else { +; + .dbg line, "strtol.c", 47 + bra L0037 +; +; base = 10; +; + .dbg line, "strtol.c", 48 +L0025: lda #$0A +L00B0: ldy #$10 + jsr staxysp +; +; } else if (base == 16 && *S == '0' && (S[1] == 'x' || S[1] == 'X')) { +; + .dbg line, "strtol.c", 50 + bra L0037 +L0022: iny + lda (sp),y + tax + dey + lda (sp),y + cpx #$00 + bne L0037 + cmp #$10 + bne L0037 + lda (regbank+4) + cmp #$30 + bne L0037 + ldy #$01 + lda (regbank+4),y + cmp #$78 + beq L0038 + lda (regbank+4),y + cmp #$58 + bne L0037 +; +; S += 2; +; + .dbg line, "strtol.c", 51 +L0038: lda #$02 + clc + adc regbank+4 + sta regbank+4 + bcc L0037 + inc regbank+4+1 +; +; if (Minus) { +; + .dbg line, "strtol.c", 57 +L0037: ldy #$09 + lda (sp),y + beq L0043 +; +; MaxVal = LONG_MIN; +; + .dbg line, "strtol.c", 58 + ldy #$01 + lda #$00 + sta (sp),y + iny + sta (sp),y + iny + sta (sp),y + lda #$80 +; +; } else { +; + .dbg line, "strtol.c", 59 + bra L00B1 +; +; MaxVal = LONG_MAX; +; + .dbg line, "strtol.c", 60 +L0043: ldy #$01 + dea + sta (sp),y + iny + sta (sp),y + iny + sta (sp),y + lda #$7F +L00B1: iny + sta (sp),y +; +; MaxDigit = MaxVal % base; +; + .dbg line, "strtol.c", 62 + jsr ldeaxysp + jsr pusheax + ldy #$15 + lda (sp),y + tax + dey + lda (sp),y + jsr axlong + jsr tosumodeax + sta (sp) +; +; MaxVal /= base; +; + .dbg line, "strtol.c", 63 + ldy #$04 + jsr ldeaxysp + jsr pusheax + ldy #$15 + lda (sp),y + tax + dey + lda (sp),y + jsr axlong + jsr tosudiveax + ldy #$01 + jsr steaxysp +; +; if (isdigit (*S)) { +; + .dbg line, "strtol.c", 69 +L004F: lda (regbank+4) + tay + lda __ctype,y + and #$04 + beq L0052 +; +; DigitVal = *S - '0'; +; + .dbg line, "strtol.c", 70 + lda (regbank+4) + sec + sbc #$30 +; +; } else if (isupper (*S)) { +; + .dbg line, "strtol.c", 71 + bra L00B3 +L0052: lda (regbank+4) + tay + lda __ctype,y + and #$02 + beq L0060 +; +; DigitVal = *S - ('A' - 10); +; + .dbg line, "strtol.c", 72 + lda (regbank+4) + sec + sbc #$37 +; +; } else if (islower (*S)) { +; + .dbg line, "strtol.c", 73 + bra L00B3 +L0060: lda (regbank+4) + tay + lda __ctype,y + and #$01 + jeq L0050 +; +; DigitVal = *S - ('a' - 10); +; + .dbg line, "strtol.c", 74 + lda (regbank+4) + sec + sbc #$57 +L00B3: ldy #$05 + sta (sp),y +; +; if (DigitVal >= base) { +; + .dbg line, "strtol.c", 81 + lda (sp),y + jsr pusha0 + ldy #$13 + lda (sp),y + tax + dey + lda (sp),y + jsr tosicmp +; +; break; +; + .dbg line, "strtol.c", 82 + bcs L0050 +; +; if (Val > MaxVal || (Val == MaxVal && DigitVal > MaxDigit)) { +; + .dbg line, "strtol.c", 86 + ldy #$0D + jsr ldeaxysp + jsr pusheax + ldy #$08 + jsr ldeaxysp + jsr tosugteax + bne L0081 + ldy #$0D + jsr ldeaxysp + jsr pusheax + ldy #$08 + jsr ldeaxysp + jsr toseqeax + beq L0080 + ldy #$05 + lda (sp),y + sec + sbc (sp) + sta tmp1 + lda tmp1 + beq L0080 + bcc L0080 +; +; Ovf = 1; +; + .dbg line, "strtol.c", 87 +L0081: lda #$01 + ldy #$08 + sta (sp),y +; +; if (Ovf == 0) { +; + .dbg line, "strtol.c", 91 +L0080: ldy #$08 + lda (sp),y + bne L0088 +; +; Val = (Val * base) + DigitVal; +; + .dbg line, "strtol.c", 92 + ldy #$0D + jsr ldeaxysp + jsr pusheax + ldy #$15 + lda (sp),y + tax + dey + lda (sp),y + jsr axlong + jsr tosumuleax + jsr pusheax + ldy #$09 + ldx #$00 + lda (sp),y + jsr tosadd0ax + ldy #$0A + jsr steaxysp +; +; ++CvtCount; +; + .dbg line, "strtol.c", 93 + ldy #$06 + ldx #$00 + lda #$01 + jsr addeqysp +; +; ++S; +; + .dbg line, "strtol.c", 97 +L0088: inc regbank+4 + jne L004F + inc regbank+4+1 +; +; } +; + .dbg line, "strtol.c", 98 + jmp L004F +; +; if (endptr) { +; + .dbg line, "strtol.c", 103 +L0050: ldy #$13 + lda (sp),y + dey + ora (sp),y + beq L0098 +; +; if (CvtCount > 0) { +; + .dbg line, "strtol.c", 104 + ldy #$07 + lda (sp),y + tax + dey + lda (sp),y + cpx #$00 + bne L00AF + cmp #$00 + beq L0092 +; +; *endptr = (char*) S - 1; +; + .dbg line, "strtol.c", 105 +L00AF: ldy #$13 + lda (sp),y + tax + dey + lda (sp),y + sta sreg + stx sreg+1 + lda regbank+4 + ldx regbank+4+1 + sec + sbc #$01 + bcs L0097 + dex +L0097: sta (sreg) + ldy #$01 + txa + sta (sreg),y +; +; } else { +; + .dbg line, "strtol.c", 106 + bra L0098 +; +; *endptr = (char*) nptr; +; + .dbg line, "strtol.c", 107 +L0092: ldy #$13 + lda (sp),y + tax + dey + lda (sp),y + jsr pushax + ldy #$17 + lda (sp),y + tax + dey + lda (sp),y + ldy #$00 + jsr staxspidx +; +; if (Ovf) { +; + .dbg line, "strtol.c", 112 +L0098: ldy #$08 + lda (sp),y + beq L00A5 +; +; errno = ERANGE; +; + .dbg line, "strtol.c", 113 + jsr __maperrno + ldx #$00 + lda #$0F + sta __errno + stz __errno+1 +; +; if (Minus) { +; + .dbg line, "strtol.c", 114 + ldy #$09 + lda (sp),y + beq L00A1 +; +; return LONG_MIN; +; + .dbg line, "strtol.c", 115 + stz sreg + lda #$80 + sta sreg+1 + txa + bra L00AA +; +; return LONG_MAX; +; + .dbg line, "strtol.c", 117 +L00A1: dex + stx sreg + lda #$7F + sta sreg+1 + txa + bra L00AA +; +; if (Minus) { +; + .dbg line, "strtol.c", 122 +L00A5: iny + lda (sp),y + beq L00A7 +; +; return -(long)Val; +; + .dbg line, "strtol.c", 123 + ldy #$0D + jsr ldeaxysp + jsr negeax + bra L00AA +; +; return Val; +; + .dbg line, "strtol.c", 125 +L00A7: ldy #$0D + jsr ldeaxysp +; +; } +; + .dbg line, "strtol.c", 127 +L00AA: pha + ldy #$0E + lda (sp),y + sta regbank+4 + iny + lda (sp),y + sta regbank+5 + pla + ldy #$16 + jmp addysp + .dbg line + +.endproc + diff --git a/lib/common/strtoul.c b/lib/common/strtoul.c new file mode 100644 index 0000000..15b01ec --- /dev/null +++ b/lib/common/strtoul.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + + + +unsigned long __fastcall__ strtoul (const char* nptr, char** endptr, int base) +/* Convert a string to a long unsigned int */ +{ + register const char* S = nptr; + unsigned long Val = 0; + unsigned char Minus = 0; + unsigned char Ovf = 0; + unsigned CvtCount = 0; + unsigned char DigitVal; + unsigned long MaxVal; + unsigned char MaxDigit; + + + /* Skip white space */ + while (isspace (*S)) { + ++S; + } + + /* Check for leading + or - sign */ + switch (*S) { + case '-': + Minus = 1; + /* FALLTHROUGH */ + case '+': + ++S; + } + + /* If base is zero, we may have a 0 or 0x prefix. If base is 16, we may + * have a 0x prefix. + */ + if (base == 0) { + if (*S == '0') { + ++S; + if (*S == 'x' || *S == 'X') { + ++S; + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base == 16 && *S == '0' && (S[1] == 'x' || S[1] == 'X')) { + S += 2; + } + + /* Determine the maximum valid number and (if the number is equal to this + * value) the maximum valid digit. + */ + MaxDigit = ULONG_MAX % base; + MaxVal = ULONG_MAX / base; + + /* Convert the number */ + while (1) { + + /* Convert the digit into a numeric value */ + if (isdigit (*S)) { + DigitVal = *S - '0'; + } else if (isupper (*S)) { + DigitVal = *S - ('A' - 10); + } else if (islower (*S)) { + DigitVal = *S - ('a' - 10); + } else { + /* Unknown character */ + break; + } + + /* Don't accept a character that doesn't match base */ + if (DigitVal >= base) { + break; + } + + /* Don't accept anything that makes the final value invalid */ + if (Val > MaxVal || (Val == MaxVal && DigitVal > MaxDigit)) { + Ovf = 1; + } + + /* Calculate the next value if digit is not invalid */ + if (Ovf == 0) { + Val = (Val * base) + DigitVal; + ++CvtCount; + } + + /* Next character from input */ + ++S; + } + + /* Store the end pointer. If no conversion was performed, the value of + * nptr is returned in endptr. + */ + if (endptr) { + if (CvtCount > 0) { + *endptr = (char*) S - 1; + } else { + *endptr = (char*) nptr; + } + } + + /* Handle overflow */ + if (Ovf) { + errno = ERANGE; + return ULONG_MAX; + } + + /* Return the result */ + if (Minus) { + return (unsigned long) -(long)Val; + } else { + return Val; + } +} + diff --git a/lib/common/strtoul.s b/lib/common/strtoul.s new file mode 100644 index 0000000..b251c7c --- /dev/null +++ b/lib/common/strtoul.s @@ -0,0 +1,541 @@ +; +; File generated by cc65 v 2.13.3 +; + .fopt compiler,"cc65 v 2.13.3" + .setcpu "65C02" + .smart on + .autoimport on + .case on + .debuginfo on + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .dbg file, "strtoul.c", 2843, 1356265749 + .dbg file, "../../include/limits.h", 2978, 1039954353 + .dbg file, "../../include/ctype.h", 7770, 1087856531 + .dbg file, "../../include/errno.h", 3647, 1060696125 + .dbg file, "../../include/stdlib.h", 5578, 1253048480 + .import __ctype + .import __maperrno + .import __errno + .export _strtoul + +; --------------------------------------------------------------- +; unsigned long __near__ __fastcall__ strtoul (__near__ const unsigned char*, __near__ __near__ unsigned char**, int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _strtoul: near + +.segment "CODE" + +; +; { +; + .dbg line, "strtoul.c", 10 + jsr pushax +; +; register const char* S = nptr; +; + .dbg line, "strtoul.c", 11 + lda regbank+4 + ldx regbank+5 + jsr pushax + ldy #$07 + lda (sp),y + tax + dey + lda (sp),y + sta regbank+4 + stx regbank+4+1 +; +; unsigned long Val = 0; +; + .dbg line, "strtoul.c", 12 + ldx #$00 + txa + jsr push0ax +; +; unsigned char Minus = 0; +; + .dbg line, "strtoul.c", 13 + jsr pusha +; +; unsigned char Ovf = 0; +; + .dbg line, "strtoul.c", 14 + jsr pusha +; +; unsigned CvtCount = 0; +; + .dbg line, "strtoul.c", 15 + jsr push0 +; +; while (isspace (*S)) { +; + .dbg line, "strtoul.c", 22 + jsr decsp6 +L0009: lda (regbank+4) + tay + lda __ctype,y + and #$60 + beq L000A +; +; ++S; +; + .dbg line, "strtoul.c", 23 + inc regbank+4 + bne L0009 + inc regbank+4+1 +; +; } +; + .dbg line, "strtoul.c", 24 + bra L0009 +; +; switch (*S) { +; + .dbg line, "strtoul.c", 27 +L000A: lda (regbank+4) +; +; } +; + .dbg line, "strtoul.c", 33 + cmp #$2B + beq L001F + cmp #$2D + bne L0019 +; +; Minus = 1; +; + .dbg line, "strtoul.c", 29 + lda #$01 + ldy #$09 + sta (sp),y +; +; ++S; +; + .dbg line, "strtoul.c", 32 +L001F: inc regbank+4 + bne L0019 + inc regbank+4+1 +; +; if (base == 0) { +; + .dbg line, "strtoul.c", 38 +L0019: ldy #$11 + lda (sp),y + tax + dey + lda (sp),y + cpx #$00 + bne L0022 + cmp #$00 + bne L0022 +; +; if (*S == '0') { +; + .dbg line, "strtoul.c", 39 + lda (regbank+4) + cmp #$30 + bne L0025 +; +; ++S; +; + .dbg line, "strtoul.c", 40 + inc regbank+4 + bne L0028 + inc regbank+4+1 +; +; if (*S == 'x' || *S == 'X') { +; + .dbg line, "strtoul.c", 41 +L0028: lda (regbank+4) + cmp #$78 + beq L002A + lda (regbank+4) + cmp #$58 + bne L0029 +; +; ++S; +; + .dbg line, "strtoul.c", 42 +L002A: inc regbank+4 + bne L002D + inc regbank+4+1 +; +; base = 16; +; + .dbg line, "strtoul.c", 43 +L002D: tya +; +; } else { +; + .dbg line, "strtoul.c", 44 + bra L00A2 +; +; base = 8; +; + .dbg line, "strtoul.c", 45 +L0029: lda #$08 + ldy #$10 + jsr staxysp +; +; } else { +; + .dbg line, "strtoul.c", 47 + bra L0037 +; +; base = 10; +; + .dbg line, "strtoul.c", 48 +L0025: lda #$0A +L00A2: ldy #$10 + jsr staxysp +; +; } else if (base == 16 && *S == '0' && (S[1] == 'x' || S[1] == 'X')) { +; + .dbg line, "strtoul.c", 50 + bra L0037 +L0022: iny + lda (sp),y + tax + dey + lda (sp),y + cpx #$00 + bne L0037 + cmp #$10 + bne L0037 + lda (regbank+4) + cmp #$30 + bne L0037 + ldy #$01 + lda (regbank+4),y + cmp #$78 + beq L0038 + lda (regbank+4),y + cmp #$58 + bne L0037 +; +; S += 2; +; + .dbg line, "strtoul.c", 51 +L0038: lda #$02 + clc + adc regbank+4 + sta regbank+4 + bcc L0037 + inc regbank+4+1 +; +; MaxDigit = ULONG_MAX % base; +; + .dbg line, "strtoul.c", 57 +L0037: ldx #$FF + stx sreg + stx sreg+1 + txa + jsr pusheax + ldy #$15 + lda (sp),y + tax + dey + lda (sp),y + jsr axlong + jsr tosumodeax + sta (sp) +; +; MaxVal = ULONG_MAX / base; +; + .dbg line, "strtoul.c", 58 + ldx #$FF + stx sreg + stx sreg+1 + txa + jsr pusheax + ldy #$15 + lda (sp),y + tax + dey + lda (sp),y + jsr axlong + jsr tosudiveax + ldy #$01 + jsr steaxysp +; +; if (isdigit (*S)) { +; + .dbg line, "strtoul.c", 64 +L0047: lda (regbank+4) + tay + lda __ctype,y + and #$04 + beq L004A +; +; DigitVal = *S - '0'; +; + .dbg line, "strtoul.c", 65 + lda (regbank+4) + sec + sbc #$30 +; +; } else if (isupper (*S)) { +; + .dbg line, "strtoul.c", 66 + bra L00A4 +L004A: lda (regbank+4) + tay + lda __ctype,y + and #$02 + beq L0058 +; +; DigitVal = *S - ('A' - 10); +; + .dbg line, "strtoul.c", 67 + lda (regbank+4) + sec + sbc #$37 +; +; } else if (islower (*S)) { +; + .dbg line, "strtoul.c", 68 + bra L00A4 +L0058: lda (regbank+4) + tay + lda __ctype,y + and #$01 + jeq L0048 +; +; DigitVal = *S - ('a' - 10); +; + .dbg line, "strtoul.c", 69 + lda (regbank+4) + sec + sbc #$57 +L00A4: ldy #$05 + sta (sp),y +; +; if (DigitVal >= base) { +; + .dbg line, "strtoul.c", 76 + lda (sp),y + jsr pusha0 + ldy #$13 + lda (sp),y + tax + dey + lda (sp),y + jsr tosicmp +; +; break; +; + .dbg line, "strtoul.c", 77 + bcs L0048 +; +; if (Val > MaxVal || (Val == MaxVal && DigitVal > MaxDigit)) { +; + .dbg line, "strtoul.c", 81 + ldy #$0D + jsr ldeaxysp + jsr pusheax + ldy #$08 + jsr ldeaxysp + jsr tosugteax + bne L0079 + ldy #$0D + jsr ldeaxysp + jsr pusheax + ldy #$08 + jsr ldeaxysp + jsr toseqeax + beq L0078 + ldy #$05 + lda (sp),y + sec + sbc (sp) + sta tmp1 + lda tmp1 + beq L0078 + bcc L0078 +; +; Ovf = 1; +; + .dbg line, "strtoul.c", 82 +L0079: lda #$01 + ldy #$08 + sta (sp),y +; +; if (Ovf == 0) { +; + .dbg line, "strtoul.c", 86 +L0078: ldy #$08 + lda (sp),y + bne L0080 +; +; Val = (Val * base) + DigitVal; +; + .dbg line, "strtoul.c", 87 + ldy #$0D + jsr ldeaxysp + jsr pusheax + ldy #$15 + lda (sp),y + tax + dey + lda (sp),y + jsr axlong + jsr tosumuleax + jsr pusheax + ldy #$09 + ldx #$00 + lda (sp),y + jsr tosadd0ax + ldy #$0A + jsr steaxysp +; +; ++CvtCount; +; + .dbg line, "strtoul.c", 88 + ldy #$06 + ldx #$00 + lda #$01 + jsr addeqysp +; +; ++S; +; + .dbg line, "strtoul.c", 92 +L0080: inc regbank+4 + jne L0047 + inc regbank+4+1 +; +; } +; + .dbg line, "strtoul.c", 93 + jmp L0047 +; +; if (endptr) { +; + .dbg line, "strtoul.c", 98 +L0048: ldy #$13 + lda (sp),y + dey + ora (sp),y + beq L0090 +; +; if (CvtCount > 0) { +; + .dbg line, "strtoul.c", 99 + ldy #$07 + lda (sp),y + tax + dey + lda (sp),y + cpx #$00 + bne L00A1 + cmp #$00 + beq L008A +; +; *endptr = (char*) S - 1; +; + .dbg line, "strtoul.c", 100 +L00A1: ldy #$13 + lda (sp),y + tax + dey + lda (sp),y + sta sreg + stx sreg+1 + lda regbank+4 + ldx regbank+4+1 + sec + sbc #$01 + bcs L008F + dex +L008F: sta (sreg) + ldy #$01 + txa + sta (sreg),y +; +; } else { +; + .dbg line, "strtoul.c", 101 + bra L0090 +; +; *endptr = (char*) nptr; +; + .dbg line, "strtoul.c", 102 +L008A: ldy #$13 + lda (sp),y + tax + dey + lda (sp),y + jsr pushax + ldy #$17 + lda (sp),y + tax + dey + lda (sp),y + ldy #$00 + jsr staxspidx +; +; if (Ovf) { +; + .dbg line, "strtoul.c", 107 +L0090: ldy #$08 + lda (sp),y + beq L0093 +; +; errno = ERANGE; +; + .dbg line, "strtoul.c", 108 + jsr __maperrno + lda #$0F + sta __errno + stz __errno+1 +; +; return ULONG_MAX; +; + .dbg line, "strtoul.c", 109 + ldx #$FF + stx sreg + stx sreg+1 + txa + bra L009D +; +; if (Minus) { +; + .dbg line, "strtoul.c", 113 +L0093: iny + lda (sp),y + beq L009A +; +; return (unsigned long) -(long)Val; +; + .dbg line, "strtoul.c", 114 + ldy #$0D + jsr ldeaxysp + jsr negeax + bra L009D +; +; return Val; +; + .dbg line, "strtoul.c", 116 +L009A: ldy #$0D + jsr ldeaxysp +; +; } +; + .dbg line, "strtoul.c", 118 +L009D: pha + ldy #$0E + lda (sp),y + sta regbank+4 + iny + lda (sp),y + sta regbank+5 + pla + ldy #$16 + jmp addysp + .dbg line + +.endproc + diff --git a/lib/common/strtoumax.s b/lib/common/strtoumax.s new file mode 100644 index 0000000..c59d51c --- /dev/null +++ b/lib/common/strtoumax.s @@ -0,0 +1,9 @@ +; +; Ullrich von Bassewitz, 2009-09-17 +; +; uintmax_t __fastcall__ strtoumax (const char* nptr, char** endptr, int base); +; + + .import _strtoul + .export _strtoumax = _strtoul + diff --git a/lib/common/strupper.s b/lib/common/strupper.s new file mode 100644 index 0000000..70b593f --- /dev/null +++ b/lib/common/strupper.s @@ -0,0 +1,47 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; char* strupper (char* s); +; char* strupr (char* s); +; +; Non-ANSI +; + + .export _strupper, _strupr + .import popax + .import __ctype + .importzp ptr1, ptr2 + + .include "ctype.inc" + +_strupper: +_strupr: + sta ptr1 ; Save s (working copy) + stx ptr1+1 + sta ptr2 + sta ptr2+2 ; save function result + ldy #0 + +loop: lda (ptr1),y ; get character + beq L9 ; jump if done + tax + lda __ctype,x ; get character classification + and #CT_LOWER ; lower case char? + beq L1 ; jump if no + txa ; get character back into accu + clc + adc #<('A'-'a') ; make upper case char + sta (ptr1),y ; store back +L1: iny ; next char + bne loop + inc ptr1+1 ; handle offset overflow + bne loop ; branch always + +; Done, return the argument string + +L9: lda ptr2 + ldx ptr2+1 + rts + + + diff --git a/lib/common/strxfrm.c b/lib/common/strxfrm.c new file mode 100644 index 0000000..8bf9795 --- /dev/null +++ b/lib/common/strxfrm.c @@ -0,0 +1,20 @@ +/* + * strxfrm.c + * + * Ullrich von Bassewitz, 11.12.1998 + */ + + + +#include + + + +size_t __fastcall__ strxfrm (char* dest, const char* src, size_t count) +{ + strncpy (dest, src, count); + return strlen (src); +} + + + diff --git a/lib/common/strxfrm.s b/lib/common/strxfrm.s new file mode 100644 index 0000000..3a299a5 --- /dev/null +++ b/lib/common/strxfrm.s @@ -0,0 +1,82 @@ +; +; File generated by cc65 v 2.13.3 +; + .fopt compiler,"cc65 v 2.13.3" + .setcpu "65C02" + .smart on + .autoimport on + .case on + .debuginfo on + .importzp sp, sreg, regsave, regbank, tmp1, ptr1, ptr2 + .macpack longbranch + .dbg file, "strxfrm.c", 222, 1356265749 + .dbg file, "../../include/string.h", 4883, 1234293382 + .dbg file, "../../include/stddef.h", 2972, 1253259480 + .import _strlen + .import _strncpy + .export _strxfrm + +; --------------------------------------------------------------- +; unsigned int __near__ __fastcall__ strxfrm (__near__ unsigned char*, __near__ const unsigned char*, unsigned int) +; --------------------------------------------------------------- + +.segment "CODE" + +.proc _strxfrm: near + +.segment "CODE" + +; +; { +; + .dbg line, "strxfrm.c", 14 + jsr pushax +; +; strncpy (dest, src, count); +; + .dbg line, "strxfrm.c", 15 + jsr decsp4 + ldy #$09 + lda (sp),y + tax + dey + lda (sp),y + ldy #$02 + sta (sp),y + iny + txa + sta (sp),y + ldy #$07 + lda (sp),y + tax + dey + lda (sp),y + sta (sp) + ldy #$01 + txa + sta (sp),y + ldy #$05 + lda (sp),y + tax + dey + lda (sp),y + jsr _strncpy +; +; return strlen (src); +; + .dbg line, "strxfrm.c", 16 + ldy #$03 + lda (sp),y + tax + dey + lda (sp),y + jsr _strlen +; +; } +; + .dbg line, "strxfrm.c", 17 + jmp incsp6 + .dbg line + +.endproc + diff --git a/lib/common/tolower.s b/lib/common/tolower.s new file mode 100644 index 0000000..f44aa9c --- /dev/null +++ b/lib/common/tolower.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int tolower (int c); +; + + .export _tolower + .import __ctype + +_tolower: + cpx #$00 ; Outside valid range? + bne L9 ; If so, return the argument unchanged + tay ; Get C into Y + lda __ctype,y ; Get character classification + lsr a + lsr a ; Get bit 1 (upper case char) into carry + tya ; Get char back into A + bcc L9 ; Jump if no upper case char + sbc #<('A'-'a') ; Make lower case char (carry already set) +L9: rts + diff --git a/lib/common/toupper.s b/lib/common/toupper.s new file mode 100644 index 0000000..adc3d4a --- /dev/null +++ b/lib/common/toupper.s @@ -0,0 +1,21 @@ +; +; Ullrich von Bassewitz, 02.06.1998 +; +; int toupper (int c); +; + + .export _toupper + .import __ctype + +_toupper: + cpx #$00 ; Outside valid range? + bne L9 ; If so, return the argument unchanged + tay ; Get c into Y + lda __ctype,y ; Get character classification + lsr a ; Get bit 0 (lower char) into carry + tya ; Get C back into A + bcc L9 ; Jump if not lower char + clc + adc #<('A'-'a') ; make upper case char +L9: rts ; CC are set + diff --git a/lib/rpc8e.lib b/lib/rpc8e.lib index 59d3d69..61a67af 100644 Binary files a/lib/rpc8e.lib and b/lib/rpc8e.lib differ diff --git a/lib/rpc8e/Makefile b/lib/rpc8e/Makefile index c30a725..db84454 100644 --- a/lib/rpc8e/Makefile +++ b/lib/rpc8e/Makefile @@ -29,7 +29,8 @@ CFLAGS = -Osir -g -T -t $(SYS) --forget-inc-paths -I . -I ../../include --cpu $( # Object files OBJS = crt0.o \ - redbus.o + redbus.o \ + ctype.o #-------------------------------------------------------------------------- # Targets diff --git a/lib/rpc8e/ctype.s b/lib/rpc8e/ctype.s new file mode 100644 index 0000000..ebf1706 --- /dev/null +++ b/lib/rpc8e/ctype.s @@ -0,0 +1,161 @@ +; +; Stefan Haubenthal with minor changes from Ullrich von Bassewitz, 2003-05-02 +; +; Character specification table. +; + + .include "ctype.inc" + +; The tables are readonly, put them into the rodata segment + +.rodata + +; The following 256 byte wide table specifies attributes for the isxxx type +; of functions. Doing it by a table means some overhead in space, but it +; has major advantages: +; +; * It is fast. If it were'nt for the slow parameter passing of cc65, one +; could even define macros for the isxxx functions (this is usually +; done on other platforms). +; +; * It is highly portable. The only unportable part is the table itself, +; all real code goes into the common library. +; +; * We save some code in the isxxx functions. + + +__ctype: + .repeat 2 + .byte CT_CTRL ; 0/00 ___ctrl_@___ + .byte CT_CTRL ; 1/01 ___ctrl_A___ + .byte CT_CTRL ; 2/02 ___ctrl_B___ + .byte CT_CTRL ; 3/03 ___ctrl_C___ + .byte CT_CTRL ; 4/04 ___ctrl_D___ + .byte CT_CTRL ; 5/05 ___ctrl_E___ + .byte CT_CTRL ; 6/06 ___ctrl_F___ + .byte CT_CTRL ; 7/07 ___ctrl_G___ + .byte CT_CTRL ; 8/08 ___ctrl_H___ + .byte CT_CTRL | CT_OTHER_WS | CT_SPACE_TAB + ; 9/09 ___ctrl_I___ + .byte CT_CTRL | CT_OTHER_WS ; 10/0a ___ctrl_J___ + .byte CT_CTRL | CT_OTHER_WS ; 11/0b ___ctrl_K___ + .byte CT_CTRL | CT_OTHER_WS ; 12/0c ___ctrl_L___ + .byte CT_CTRL | CT_OTHER_WS ; 13/0d ___ctrl_M___ + .byte CT_CTRL ; 14/0e ___ctrl_N___ + .byte CT_CTRL ; 15/0f ___ctrl_O___ + .byte CT_CTRL ; 16/10 ___ctrl_P___ + .byte CT_CTRL ; 17/11 ___ctrl_Q___ + .byte CT_CTRL ; 18/12 ___ctrl_R___ + .byte CT_CTRL ; 19/13 ___ctrl_S___ + .byte CT_CTRL ; 20/14 ___ctrl_T___ + .byte CT_CTRL ; 21/15 ___ctrl_U___ + .byte CT_CTRL ; 22/16 ___ctrl_V___ + .byte CT_CTRL ; 23/17 ___ctrl_W___ + .byte CT_CTRL ; 24/18 ___ctrl_X___ + .byte CT_CTRL ; 25/19 ___ctrl_Y___ + .byte CT_CTRL ; 26/1a ___ctrl_Z___ + .byte CT_CTRL ; 27/1b ___ctrl_[___ + .byte CT_CTRL ; 28/1c ___ctrl_\___ + .byte CT_CTRL ; 29/1d ___ctrl_]___ + .byte CT_CTRL ; 30/1e ___ctrl_^___ + .byte CT_CTRL ; 31/1f ___ctrl_____ + .byte CT_SPACE | CT_SPACE_TAB ; 32/20 ___SPACE___ + .byte CT_NONE ; 33/21 _____!_____ + .byte CT_NONE ; 34/22 _____"_____ + .byte CT_NONE ; 35/23 _____#_____ + .byte CT_NONE ; 36/24 _____$_____ + .byte CT_NONE ; 37/25 _____%_____ + .byte CT_NONE ; 38/26 _____&_____ + .byte CT_NONE ; 39/27 _____'_____ + .byte CT_NONE ; 40/28 _____(_____ + .byte CT_NONE ; 41/29 _____)_____ + .byte CT_NONE ; 42/2a _____*_____ + .byte CT_NONE ; 43/2b _____+_____ + .byte CT_NONE ; 44/2c _____,_____ + .byte CT_NONE ; 45/2d _____-_____ + .byte CT_NONE ; 46/2e _____._____ + .byte CT_NONE ; 47/2f _____/_____ + .byte CT_DIGIT | CT_XDIGIT ; 48/30 _____0_____ + .byte CT_DIGIT | CT_XDIGIT ; 49/31 _____1_____ + .byte CT_DIGIT | CT_XDIGIT ; 50/32 _____2_____ + .byte CT_DIGIT | CT_XDIGIT ; 51/33 _____3_____ + .byte CT_DIGIT | CT_XDIGIT ; 52/34 _____4_____ + .byte CT_DIGIT | CT_XDIGIT ; 53/35 _____5_____ + .byte CT_DIGIT | CT_XDIGIT ; 54/36 _____6_____ + .byte CT_DIGIT | CT_XDIGIT ; 55/37 _____7_____ + .byte CT_DIGIT | CT_XDIGIT ; 56/38 _____8_____ + .byte CT_DIGIT | CT_XDIGIT ; 57/39 _____9_____ + .byte CT_NONE ; 58/3a _____:_____ + .byte CT_NONE ; 59/3b _____;_____ + .byte CT_NONE ; 60/3c _____<_____ + .byte CT_NONE ; 61/3d _____=_____ + .byte CT_NONE ; 62/3e _____>_____ + .byte CT_NONE ; 63/3f _____?_____ + + .byte CT_NONE ; 64/40 _____@_____ + .byte CT_UPPER | CT_XDIGIT ; 65/41 _____A_____ + .byte CT_UPPER | CT_XDIGIT ; 66/42 _____B_____ + .byte CT_UPPER | CT_XDIGIT ; 67/43 _____C_____ + .byte CT_UPPER | CT_XDIGIT ; 68/44 _____D_____ + .byte CT_UPPER | CT_XDIGIT ; 69/45 _____E_____ + .byte CT_UPPER | CT_XDIGIT ; 70/46 _____F_____ + .byte CT_UPPER ; 71/47 _____G_____ + .byte CT_UPPER ; 72/48 _____H_____ + .byte CT_UPPER ; 73/49 _____I_____ + .byte CT_UPPER ; 74/4a _____J_____ + .byte CT_UPPER ; 75/4b _____K_____ + .byte CT_UPPER ; 76/4c _____L_____ + .byte CT_UPPER ; 77/4d _____M_____ + .byte CT_UPPER ; 78/4e _____N_____ + .byte CT_UPPER ; 79/4f _____O_____ + .byte CT_UPPER ; 80/50 _____P_____ + .byte CT_UPPER ; 81/51 _____Q_____ + .byte CT_UPPER ; 82/52 _____R_____ + .byte CT_UPPER ; 83/53 _____S_____ + .byte CT_UPPER ; 84/54 _____T_____ + .byte CT_UPPER ; 85/55 _____U_____ + .byte CT_UPPER ; 86/56 _____V_____ + .byte CT_UPPER ; 87/57 _____W_____ + .byte CT_UPPER ; 88/58 _____X_____ + .byte CT_UPPER ; 89/59 _____Y_____ + .byte CT_UPPER ; 90/5a _____Z_____ + .byte CT_NONE ; 91/5b _____[_____ + .byte CT_NONE ; 92/5c _____\_____ + .byte CT_NONE ; 93/5d _____]_____ + .byte CT_NONE ; 94/5e _____^_____ + .byte CT_NONE ; 95/5f _UNDERLINE_ + .byte CT_NONE ; 96/60 ___grave___ + .byte CT_LOWER | CT_XDIGIT ; 97/61 _____a_____ + .byte CT_LOWER | CT_XDIGIT ; 98/62 _____b_____ + .byte CT_LOWER | CT_XDIGIT ; 99/63 _____c_____ + .byte CT_LOWER | CT_XDIGIT ; 100/64 _____d_____ + .byte CT_LOWER | CT_XDIGIT ; 101/65 _____e_____ + .byte CT_LOWER | CT_XDIGIT ; 102/66 _____f_____ + .byte CT_LOWER ; 103/67 _____g_____ + .byte CT_LOWER ; 104/68 _____h_____ + .byte CT_LOWER ; 105/69 _____i_____ + .byte CT_LOWER ; 106/6a _____j_____ + .byte CT_LOWER ; 107/6b _____k_____ + .byte CT_LOWER ; 108/6c _____l_____ + .byte CT_LOWER ; 109/6d _____m_____ + .byte CT_LOWER ; 110/6e _____n_____ + .byte CT_LOWER ; 111/6f _____o_____ + .byte CT_LOWER ; 112/70 _____p_____ + .byte CT_LOWER ; 113/71 _____q_____ + .byte CT_LOWER ; 114/72 _____r_____ + .byte CT_LOWER ; 115/73 _____s_____ + .byte CT_LOWER ; 116/74 _____t_____ + .byte CT_LOWER ; 117/75 _____u_____ + .byte CT_LOWER ; 118/76 _____v_____ + .byte CT_LOWER ; 119/77 _____w_____ + .byte CT_LOWER ; 120/78 _____x_____ + .byte CT_LOWER ; 121/79 _____y_____ + .byte CT_LOWER ; 122/7a _____z_____ + .byte CT_NONE ; 123/7b _____{_____ + .byte CT_NONE ; 124/7c _____|_____ + .byte CT_NONE ; 125/7d _____}_____ + .byte CT_NONE ; 126/7e _____~_____ + .byte CT_OTHER_WS ; 127/7f ____DEL____ + .endrepeat + +